最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to extend a Sequelize model? - Stack Overflow

programmeradmin5浏览0评论

Is there a way that I could use a base class that has all the common attributes and methods for my models but not linked with a database table, and then I could extend this base class when defining new models.

Here I have created the base, person model in node express. I need the person class to be extended from the base class.

const person = sequelizeClient.define('person', {
    name: {
      type: DataTypes.STRING,
      allowNull: false
    }
  }, {
    hooks: {
      beforeCount(options) {
        options.raw = true;
      }
    }
  });

  const base = sequelizeClient.define('base', {
    id: {
      type: Sequelize.INTEGER,
      autoIncrement: true,
      primaryKey: true
    },
    createdBy: {
      type: Sequelize.INTEGER,
    },
    updatedBy: {
      type: Sequelize.INTEGER,
    },
    deletedBy: {
      type: Sequelize.INTEGER,
    }
  }, {
    hooks: {
      beforeCount(options) {
        options.raw = true;
      }
    }
  });

In the documentation it's stated that

Sequelize Models are ES6 classes.You can very easily add custom instance or class level methods.

How can I do this using ES6 extends class pattern?

There's a question similar to this but has not been updated recently. How to extend Sequelize model

Is there a way that I could use a base class that has all the common attributes and methods for my models but not linked with a database table, and then I could extend this base class when defining new models.

Here I have created the base, person model in node express. I need the person class to be extended from the base class.

const person = sequelizeClient.define('person', {
    name: {
      type: DataTypes.STRING,
      allowNull: false
    }
  }, {
    hooks: {
      beforeCount(options) {
        options.raw = true;
      }
    }
  });

  const base = sequelizeClient.define('base', {
    id: {
      type: Sequelize.INTEGER,
      autoIncrement: true,
      primaryKey: true
    },
    createdBy: {
      type: Sequelize.INTEGER,
    },
    updatedBy: {
      type: Sequelize.INTEGER,
    },
    deletedBy: {
      type: Sequelize.INTEGER,
    }
  }, {
    hooks: {
      beforeCount(options) {
        options.raw = true;
      }
    }
  });

In the documentation it's stated that

Sequelize Models are ES6 classes.You can very easily add custom instance or class level methods.

How can I do this using ES6 extends class pattern?

There's a question similar to this but has not been updated recently. How to extend Sequelize model

Share Improve this question edited Nov 28, 2017 at 9:53 ANJYR 2,6236 gold badges42 silver badges61 bronze badges asked Nov 28, 2017 at 9:38 v1shvav1shva 1,5993 gold badges16 silver badges33 bronze badges 2
  • What version of Sequelize are you using? – IzumiSy Commented Nov 28, 2017 at 13:43
  • sequelize version is v4.23.1 – v1shva Commented Nov 29, 2017 at 3:29
Add a comment  | 

3 Answers 3

Reset to default 10

How can I do this using ES6 extends class pattern?

The statement in Sequelize docs is a little bit confusing for developers. That does not mean that you can extend the defined model with ES6 class syntax as follow.

const User = db.define('User', {
  name: sequelize.STRING,
  age: sequelize.INTEGER
});

// This is impossible.
class Staff extends User {
  ...
}

But you can define instance methods by accessing protoype like below.

const User = db.define('User', {
  name: sequelize.STRING,
  age: sequelize.INTEGER
});

User.Instance.prototype.test = function() {
  return `Name: ${this.name}, Age: ${this.age}`
}

User.create({ name: "John", age: 10 });
User.findOne().then((user) => {
  console.log(user.test()) // "Name: John, Age: 10"
});

The statement you mentioned in Sequelize doc actually says is that you can enhance model behaviour using prototype based extension, so you cannot do something like model inheritance you try to do in the question.

There are lots of discussion about implementation proposal of ES6 class syntax in Sequelize like this, but it is still under discussion it looks.

As it seems that extending class model is not possible with Sequelize, how about extending the config object of the sequelize object? It is slighlty more work, but provides the closest experience and remains relatively clean. Of course using both attributes and options parameters requires using 2 separate classes or proper destructuring of a combined class.

class Base {
    constructor() {
        this.id = {
            type: Sequelize.INTEGER,
            autoIncrement: true,
            primaryKey: true
        };
        ...
    }
}

class Person extends Base {
    constructor() {
        super();
        this.name = {
            type: DataTypes.STRING,
            allowNull: false
        };
        ...
    }
}

// using separate class for attributes
const person = sequelize.define('person', new Person());

// possible destructuring of attributes/options
const someModel= sequelize.define('someModel', (new SomeModel()).attributes, (new SomeModel()).options);

I think this functionality is not supported yet (09/2021). But, I am working now in a solution for this. The following example resolves two needs:

  1. We have two entities in the same table (inheriting and adding new attributes) and;
  2. There's a way for we have common attributes for all models:
const ModelDiscriminators = {
  Dish: 1,
  Item: 2,
  ItemWithEmail: 3
}

//Basic field attributes for all entities
const BasicModelAttributes = { 
  id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true } 
};

//Table dish have id, name, veg, discriminator attributes
const Dish = sequelize.define('dish', Object.assign( {}, BasicModelAttributes, {   
  name: { type: DataTypes.STRING },
  veg: { type: DataTypes.BOOLEAN },
  discriminator: { type: DataTypes.INTEGER, defaultValue: () => ModelDiscriminators.Dish }
} ) );

//Two entities sharing same table. Table Item has id, name, type, discriminator e email(see model ItemWithEmail) atributes
//Model Item
const Item = sequelize.define('item', Object.assign( {}, BasicModelAttributes, {   
  name: { type: DataTypes.STRING },
  type: { type: DataTypes.STRING },
  discriminator: { type: DataTypes.INTEGER, defaultValue: () => ModelDiscriminators.Item }
} ) );

//Model ItemWithEmail inherits all Item attributes and define a new one: e-mail
//We use the discriminator attribute to query the right records when we make a query or .findAll(+where)
const ItemWithEmail = sequelize.define('item', Object.assign({}, Item.rawAttributes, { 
  email: { type: DataTypes.STRING },
  discriminator: { type: DataTypes.INTEGER, defaultValue: () => ModelDiscriminators.ItemWithEmail }
} ) );

I think that this approach could be a default way supported by Sequelize. We could have a inherits relation, so we could write:

ItemWithEmail.inherits( Item )
发布评论

评论列表(0)

  1. 暂无评论