'Cannot read property 'source' of undefined when trying to add association in queryGenerator.SelectQuery in Sequelize ORM

I am trying to generate a query using QueryGenerator.selectQuery.

let query = models.sequelize.dialect.QueryGenerator.selectQuery('table', {
    include: [{
        model: models.Users,
        where: {
            deleted: false
        },
        required: true,
        attributes: ['id']
    }],
    where: {
        createdAt: {
            [Op.between]: [o.start, o.end]
        },
        deleted: false
    },
    attributes: [[models.sequelize.fn("COUNT", models.sequelize.col("Table.id")), 'count']]
}, models.Table).slice(0, -1);

T‌his is the error I am getting.

TypeError: Cannot read property 'source' of undefined at Object.generateJoin (/node_modules/sequelize/lib/dialects/abstract/query-generator.js:1433:30) at Object.generateInclude (/node_modules/sequelize/lib/dialects/abstract/query-generator.js:1358:24) at Object.selectQuery (/node_modules/sequelize/lib/dialects/abstract/query-generator.js:1001:34)

github issue tracker https://github.com/sequelize/sequelize/issues/8751



Solution 1:[1]

Going through with the same errors as you and finally solve the problem.

Because QueryGenerator is used internally for Sequelize, it doesn't have specific docs about this (unfortunately). We should "parse" the options using object Model before we passing the parameter into selectQuery.

Based on your query, I think you could do this. Please be aware the codes below are untested and use es6 style

// Import sequelize model library
const Model = require("sequelize/lib/model");

// Separate your query options
const queryOptions = {
    include: [{
        model: models.Users,
        where: {
            deleted: false
        },
        required: true,
        attributes: ['id']
    }],
    where: {
        createdAt: {
            [Op.between]: [o.start, o.end]
        },
        deleted: false
    },
    attributes: [[models.sequelize.fn("COUNT", models.sequelize.col("Table.id")), 'count']]
};

// Parse the queryOptions, this operation would serialize the queryOptions
// and this is the important process about building the query
Model._validateIncludedElements.bind(DB.SuitCase)(queryOptions);

// Execute with serialized options object 
let query = models.sequelize.dialect.QueryGenerator.selectQuery('table', queryOptions, models.Table);

Hope this may help you.

Solution 2:[2]

I would like to add the following to Aditya Kresna Permana's answer;

DB.SuitCase here should be replaced with the model of your top query (Which in the case of the OP would be "models.Table". For people who are familiar with the bind function, this might seem logical (Which is why he might not have added it), but it took me a while to figure out!

Example:

Model._validateIncludedElements.bind(models.Table)(queryOptions);

Solution 3:[3]

For future references this worked for me

const Model = require('sequelize/lib/model');

const queryInterface = await db.sequelize.getQueryInterface();
const queryGenerator: any = queryInterface.queryGenerator;

Model._validateIncludedElements.bind(models.TableName)(
  queryObject
);
      
const sqlQuery = queryGenerator.selectQuery(
  'table_name',
   queryObject,
   models.TableName
);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Brord van Wierst
Solution 3 Abdullah Akram