KIRAN K J
KIRAN K J

Reputation: 732

model.hasMany called with something that's not a subclass of Sequelize.Model

I am getting the below error whenever I tried to call any call from serverless framework lambda

[offline] _____ HANDLER RESOLVED _____
offline: Failure: product.hasMany called with something that's not a subclass of Sequelize.Model
Error: product.hasMany called with something that's not a subclass of Sequelize.Model
    at Function.hasMany (C:\Users\Kiran\Documents\Projects\Rentals-Backend\node_modules\sequelize\lib\associations\mixin.js:18:13)
    at Function.Product.associate (C:\Users\Kiran\Documents\Projects\Rentals-Backend\entity\product.js:21:17)

IMPORTANT

Below code is the answer for the above error. You might missed any steps. So you can refer and fix. Thanks Anatoly who helped me to solve the problem.

Product model:

const { STRING, BOOLEAN, INTEGER } = require("sequelize");

module.exports = (sequelize, DataTypes) => {
    const Product = sequelize.define("product", {
        id: { type: INTEGER, primaryKey: true, autoIncrement: true },
        name: { type: STRING },
        description: { type: STRING, allowNull: true },
        purchase_price: { type: STRING },
        tax: { type: STRING },
        sale_price: { type: STRING },
        categoryId: { type: STRING },
        status: { type: BOOLEAN, defaultValue: 0 },
        created_on: { type: INTEGER, allowNull: true },
        updated_on: { type: INTEGER, allowNull: true },
    }, {
        timestamps: false,
        freezeTableName: true,
    })
    Product.associate = function (models) {
        Product.hasMany(models.product_image, { as: "images" });
        Product.belongsTo(models.product_category, { as: "category", foreignKey: 'categoryId' });
    };
    return Product;

}

Image model:

const { STRING, BOOLEAN, INTEGER } = require("sequelize");

module.exports = (sequelize, DataTypes) => {
    const ProductImage = sequelize.define("product_image", {
        id: { type: INTEGER, primaryKey: true, autoIncrement: true },
        productId: { type: INTEGER },
        fileName: { type: STRING },
        url: { type: STRING },
        position: { type: INTEGER },
        isDefault: { type: BOOLEAN, defaultValue: 0 },
        shopId: { type: STRING },
        status: { type: BOOLEAN, defaultValue: 0 },
        created_on: { type: INTEGER, allowNull: true },
        updated_on: { type: INTEGER, allowNull: true },
    }, {
        timestamps: false,
        freezeTableName: true,
    })

    return ProductImage;
}

Category model:

const { STRING, BOOLEAN, INTEGER } = require("sequelize");


module.exports = (sequelize, DataTypes) => {
    const ProductCategory = sequelize.define("product_category", {
        id: { type: INTEGER, primaryKey: true, autoIncrement: true },
        name: { type: STRING },
        description: { type: STRING, allowNull: true },
        status: { type: BOOLEAN, defaultValue: 0 },
        created_on: { type: INTEGER, allowNull: true },
        updated_on: { type: INTEGER, allowNull: true },
    }, {
        timestamps: false,
        freezeTableName: true,
    });
    return ProductCategory;
}

This is the config file where we initialize sequelize

Config file

    const Sequelize = require('sequelize')
    const fs = require('fs')
    const path = require('path')
    const db = {}
    const models = path.join(__dirname, '..', 'entity')
    var basename = path.basename(module.filename)
    
    const sequelize = new Sequelize(
        process.env.DB_NAME,
        process.env.DB_USER,
        process.env.DB_PASSWORD,
        {
            dialect: 'mysql',
            host: process.env.DB_HOST,
            port: process.env.DB_PORT,
            logging: false
        }
    )
    
    fs
      .readdirSync(models)
      .filter(function (file) {
        return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js')
      })
      .forEach(function (file) {
        var model = require(path.join(models, file))(
          sequelize,
          Sequelize.DataTypes
        );
        db[model.name] = model;
        
      })
    
    Object.keys(db).forEach(function (modelName) {
      if (db[modelName].associate) {
        db[modelName].associate(db)
      }
    })
    
    db.Sequelize = Sequelize
    db.sequelize = sequelize
    
    module.exports = db

Here we are calling product details.

Calling function

    const db = require('../config/sequelize-config');
    exports.getProductById = (query, username, shopId) => {
        return new Promise((resolve, reject) => {
            db.product.findOne({
                where: {
                    id: query.id
                },
                attributes: ['id', 'name', 'description', ['purchase_price', 'purchasePrice'], 'tax', ['sale_price', 'salePrice']],
                include: [{
                    model: db.product_image,
                    as: 'images',
                    where: {
                        status: 1
                    },
                    required: false,
                    attributes: ['id', 'fileName', 'position', 'url']
                },
                {
                    model: db.product_category,
                    as: 'category',
                    required: false,
                    attributes: ['id', 'name']
                }]
            }).then(product => {
                if (product) {
                    resolve({ [KEY_STATUS]: 1, [KEY_MESSAGE]: "Product details fetched successfully", [KEY_DATA]: product });
                } else {
                    reject({ [KEY_STATUS]: 0, [KEY_MESSAGE]: "Product details fetch failed" });
                }
            }).catch(error => {
                reject({ [KEY_STATUS]: 0, [KEY_MESSAGE]: "Product details fetch failed", [KEY_ERROR]: error.message });
            });
        })
    }

Upvotes: 2

Views: 1359

Answers (1)

Anatoly
Anatoly

Reputation: 22783

To avoid cross-reference errors and similar ones I recommend converting model definitions to functions and registering models and associations in the same one module, see this answer and the question

Upvotes: 1

Related Questions