alphadogg
alphadogg

Reputation: 12900

Loading Associations In Sequelize

I'm integrating Sequelize into ActionHero. My initializer does the following:

// configure the singleton
api.sequelize.sequelize = new Sequelize(
  api.config.sequelize.database,
  api.config.sequelize.username,
  api.config.sequelize.password,
  api.config.sequelize
);

// import models
var dir = path.normalize(api.projectRoot + '/models');

fs.readdirSync(dir).forEach(function(file){
  var nameParts = file.split("/");
  var name = nameParts[(nameParts.length - 1)].split(".")[0];
  api.models[name] = api.sequelize.sequelize.import(dir + '/' + file);
});

// import associations
var dir = path.normalize(api.projectRoot + '/models/associations');

// ???

Here's an example model in one file in /models:

module.exports = function(sequelize, DataTypes) {

  return sequelize.define(
    "Party", 
    {
      id: {
        type: DataTypes.BIGINT,
        primaryKey: true,
        autoIncrement: true
      },
      name: {
        type: DataTypes.STRING(256),
        allowNull: false,
        unique: true,
        comment: "The legal name for the Party."
      },
      dbaName: {
        type: DataTypes.STRING(256),
        comment: "The 'does business as' name for the Party."
      }
    },
    {
      comment: "A Party is a person or group of persons composing a single entity with one or more roles in the system."
    }
  )

}

Not sure how to define and load an association in Sequelize. I'd like to have them in separate files and loaded after all models are loaded, to tie them together. For example, there would be a PartyOperator.js file that would contain the association between those two entities.

What would the ??? section in the initializer and a sample association file look like?

Upvotes: 2

Views: 1407

Answers (1)

alphadogg
alphadogg

Reputation: 12900

I ended up using the approach below, because it keeps the associations with the object (and file) it's related to. When one opens, for example, the Party model in the Party.js file, one sees both the columns and any relations.

In an initializer in ActionHero, I first load the models via Sequelize's import(), then I iterate through all the loaded models and call a known class method called associate(), if it exists, on each model to create the associations.

// import models
var dir = path.normalize(api.projectRoot + '/models');

api.log('loading models found in ' + dir, 'info');
var files = readdir.readSync(dir, ['**.js']);
files.forEach(function(file) {
  var pathArray = file.split('/');
  var name = pathArray[(pathArray.length - 1)].split('.')[0];
  api.log('importing models/' + file + ' as ' + name, 'info');
  api.models[name] = api.sequelize.sequelize.import(dir + '/' + file);
});
api.log('running associations', 'info');

api.lodash.forEach(api.models, function(val, key) {
  if(api.lodash.isFunction(val.associate)) {
    val.associate(api.models);
  }
});

Here's an example of a model:

sequelize.define(
  "Party",
  {
    id: {
      type: DataTypes.BIGINT,

      primaryKey: true,
      autoIncrement: true
    },
    name: {
      type: DataTypes.STRING(256),
      allowNull: false,
      unique: true,
      comment: "The legal name for the Party."
    },
    dbaName: {
      type: DataTypes.STRING(256),
      comment: "The 'does business as' name for the Party."
    }
  },
  {
    comment: "A Party is a person or group of persons composing a single entity with one or more roles in the system.",
    classMethods: {
      associate: function(models) {
        models.Party.hasMany(models.Operator, {foreignKey: 'Party_operatorID'});
      }
    }
  }
)

Upvotes: 3

Related Questions