Yasiru Nilan
Yasiru Nilan

Reputation: 457

How to add associations to Models generated from Sequelize-Auto

For an existing MySQL database, I used Sequelize-auto package to generate the models. But the associations don't come with model classes.

I have an MySQL database and I'm using it for NodeJS web project. Also I'm using Sequelize as the ORM. Since database is already there I wanted to generate the model classes as the entities. So I used sequelize-auto

https://github.com/sequelize/sequelize-auto to generate the model classes. But when they were generated attributes have been correctly set but the associations doesn't come up with the model classes. So I have faced problem when fetching the data from the database.

Here are the two model classes that were generated with sequlize-auto. There are two table in the database named as department and category. department.js and category.js are the two model classes that were generated

department.js

module.exports = function(sequelize, DataTypes) {
  return sequelize.define('department', {
        department_id: {
            type: DataTypes.INTEGER(11),
            allowNull: false,
            primaryKey: true,
            autoIncrement: true
        },
        name: {
            type: DataTypes.STRING(100),
            allowNull: false
        },
        description: {
            type: DataTypes.STRING(1000),
            allowNull: true
        }
    }, {
        tableName: 'department',
        timestamps: false,
    });
};

category.js

module.exports = function(sequelize, DataTypes) {
  return sequelize.define('category', {
        category_id: {
            type: DataTypes.INTEGER(11),
            allowNull: false,
            primaryKey: true,
            autoIncrement: true
        },
        department_id: {
            type: DataTypes.INTEGER(11),
            allowNull: false
        },
        name: {
            type: DataTypes.STRING(100),
            allowNull: false
        },
        description: {
            type: DataTypes.STRING(1000),
            allowNull: true
        }
    }, {
        tableName: 'category',
        timestamps: false,
    });
};

So what else needs to be done in order to get the associations and to fetch data successfully. Can some one help me here. Table structure is as following. enter image description here

Upvotes: 5

Views: 2525

Answers (3)

T Ramdhan
T Ramdhan

Reputation: 1

I followed the pattern demonstrated in the typescript example on sequelize-auto (init-models.ts) - within the existing initModels function, works fine in js.

export function initModels(sequelize: Sequelize) {
  Product.initModel(sequelize);
  Supplier.initModel(sequelize);
  
  Supplier.hasMany(Product, { as: "products", foreignKey: "supplierId"});
  
  return {...

Upvotes: 0

ThunD3eR
ThunD3eR

Reputation: 3436

To add to @CodingLittles answer which he based from here.

I added the following for making many to many assosiations:

enum Junctions {
  user = 'user',
  roles = 'roles',
}

enum JuntiontThrough {
  userroles = 'userroles',
}


interface JunctionObject {
  junctionBelongsTo?: any;
}

const checkIfAttrExists= (obj, value) => {
  return Object.prototype.hasOwnProperty.call(obj, value);
};

const checkRefrence = (obj, attr, value) => {
  return obj.rawAttributes[attr].references[value];
};


export const getJunction = (junc: Junctions): JunctionObject => {
  const junctions = {
    user: {
      junctionBelongsTo: [
        { key: Junctions.roles, value: juntiontThrough.userroles }
      ],
    },
    roles: {
      junctionBelongsTo: [{ key: Junctions.user, value: juntiontThrough.userroles }],
    },
  }[junc];

  if (!junctions) return {};

  return junctions;
};


  const models = Object.getOwnPropertyNames(db);

models.forEach(modelName => {
  const currentModel = db[modelName];
  const junction = getJunction(modelName as Junctions);

  if (!_.isEmpty(junction)) {
    // eslint-disable-next-line array-callback-return
    junction.junctionBelongsTo.reduce((key, value) => {
      currentModel.belongsToMany(db[value.key], {
        through: db[value.value],
      });
    }, {});
  }

  const attributes = Object.getOwnPropertyNames(currentModel.rawAttributes);

  attributes.forEach(attributeName => {
    if (
      checkIfAttrExists(currentModel.rawAttributes[attributeName], 'references') &&
      checkIfAttrExists(currentModel.rawAttributes[attributeName].references, 'model') &&
      checkIfAttrExists(currentModel.rawAttributes[attributeName].references, 'key')
    ) {
      if (
        !(
          checkRefrence(currentModel, attributeName, 'model') &&
          checkRefrence(currentModel, attributeName, 'key')
        )
      ) {
        return;
      }

      const referencedTable =
        tableModel[currentModel.rawAttributes[attributeName].references.model];

      if (!(modelName.toString() in juntiontThrough)) {
        console.log(
          `${modelName} ${attributeName} references a model ${currentModel.rawAttributes[attributeName].references.model} with key ${currentModel.rawAttributes[attributeName].references.key}`
        );
        currentModel.belongsTo(referencedTable, { foreignKey: attributeName });
        referencedTable.hasMany(currentModel, { foreignKey: attributeName });
      }
    }
  });
})

Note that for the many to many relations to work you have to add the relations manually like I did in the getJunction function

Upvotes: 1

CodingLittle
CodingLittle

Reputation: 1857

1) inside of your models folder create an index.js file and add the following code

import Sequelize from 'sequelize';

const fs = require('fs');
const path = require('path');

const basename = path.basename(__filename);

const db = {};

// @ts-ignore
const sequelize = new Sequelize('dbname', 'dbUser', 'password', {
  host: '127.0.0.1',
  port: 'PORT',
  dialect: 'mysql',
  define: {
    freezeTableName: true,
    timestamps: false,
  },
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000,
  },
  // <http://docs.sequelizejs.com/manual/tutorial/querying.html#operators>
  operatorsAliases: false,
});

const tableModel = {};

fs.readdirSync(__dirname)
  .filter(file => file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js')
  .forEach(file => {
    const model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
    tableModel[model.name] = model;
  });

Object.getOwnPropertyNames(db).forEach(modelName => {
  const currentModel = db[modelName];
  Object.getOwnPropertyNames(currentModel.rawAttributes).forEach(attributeName => {
    if (
      Object.prototype.hasOwnProperty.call(
        currentModel.rawAttributes[attributeName],
        'references'
      ) &&
      Object.prototype.hasOwnProperty.call(
        currentModel.rawAttributes[attributeName].references,
        'model'
      ) &&
      Object.prototype.hasOwnProperty.call(
        currentModel.rawAttributes[attributeName].references,
        'key'
      )
    ) {
      if (
        !(
          currentModel.rawAttributes[attributeName].references.model &&
          currentModel.rawAttributes[attributeName].references.key
        )
      ) {
        console.log(
          `*SKIPPED* ${modelName} ${attributeName} references a model ${currentModel.rawAttributes[attributeName].references.model} with key ${currentModel.rawAttributes[attributeName].references.key}`
        );
        return;
      }

      console.log(
        `${modelName} ${attributeName} references a model ${currentModel.rawAttributes[attributeName].references.model} with key ${currentModel.rawAttributes[attributeName].references.key}`
      );
      const referencedTable =
        tableModel[currentModel.rawAttributes[attributeName].references.model];

      currentModel.belongsTo(referencedTable, { foreignKey: attributeName });
      referencedTable.hasMany(currentModel, { foreignKey: attributeName });

    }
  });
});

// @ts-ignore
db.sequelize = sequelize;
// @ts-ignore
db.Sequelize = Sequelize;

// eslint-disable-next-line eol-last
module.exports = db;

2) inside of your resolver just reference the above:

const db = require('../assets/models/index');

Upvotes: 2

Related Questions