Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 644
Shareef Avatar asked Dec 05 '17 11:12

Shareef


2 Answers

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.

like image 63
Aditya Kresna Permana Avatar answered Nov 18 '22 16:11

Aditya Kresna Permana


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);
like image 2
Brord van Wierst Avatar answered Nov 18 '22 16:11

Brord van Wierst