Skip to content

Scopes' includes are not shallowly merged as the documentation claims #9087

@papb

Description

@papb

What are you doing?

I am testing with a minimal example whether or not scopes' includes are shallowly merged, as the documentation claims: limit, offset, order, paranoid, lock and raw are overwritten, while where and include are shallowly merged. (source: http://docs.sequelizejs.com/manual/tutorial/scopes.html)

const Sequelize = require("sequelize");
const sequelize = new Sequelize({ dialect: "sqlite", storage: "db.sqlite" });
const Foo = sequelize.define("foo", { name: Sequelize.STRING }, { timestamps: false });
const Bar = sequelize.define("bar", { name: Sequelize.STRING }, { timestamps: false });
Foo.hasMany(Bar, { foreignKey: "fooId" });
Foo.addScope("testScope", {
    include: [{
        model: Bar,
        where: {
            name: "bar1"
        }
    }]
});
sequelize.sync({ force: true })
    .then(() => Foo.create({ name: "foo1" }))
    .then(foo1 => Bar.create({ name: "bar1", fooId: foo1.id }))
    .then(() => Foo.create({ name: "foo2" }))
    .then(foo2 => Bar.create({ name: "bar2", fooId: foo2.id }))
    .then(() => Foo.scope("testScope").findAll({
        include: [{
            model: Bar,
            attributes: { exclude: ["name"] }
        }]
    }))
    .then(result => console.log(JSON.stringify(result, null, 4)));

What do you expect to happen?

I expected the scope to be merged with the findAll options, which should yield the following output:

[
    {
        "id": 1,
        "name": "foo1",
        "bars": [
            {
                "id": 1,
                "fooId": 1
            }
        ]
    }
]

What is actually happening?

The output was:

[
    {
        "id": 1,
        "name": "foo1",
        "bars": [
            {
                "id": 1,
                "fooId": 1
            }
        ]
    },
    {
        "id": 2,
        "name": "foo2",
        "bars": [
            {
                "id": 2,
                "fooId": 2
            }
        ]
    }
]

Clearly, the scope was completely overwritten by the findAll options.

I wanted my code to behave exactly as if I had called the following:

Foo.scope("testScope").findAll({
    include: [{
        model: Bar,
        where: {
            name: "bar1"
        },
        attributes: { exclude: ["name"] }
    }]
})

Dialect: sqlite (sqlite3 v3.1.13)
Dialect version: 3.1.13
Sequelize version: 4.33.4
Tested with latest release: Yes

Note: if somehow this is the correct behavior, honestly the docs should be clarified. The include field is an array of objects, and "shallowly merging" an array of objects is not perfectly clear, does it mean that the arrays are concatenated? I hope not. I understand that the behavior I'm expecting is not trivial to code, but if the documentation claims it, it should do it. My understanding of "shallowly merging" in this context would be that the objects in the include arrays are "matched" to each other based on the "model-as" pairs, shallowly merging the other fields (and hopefully, recursively, since I could have nested includes in my scopes).

Thank you very much in advance, sequelize has been very useful so far 😁

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: in discussionFor issues and PRs. Community and maintainers are discussing the applicability of the issue.type: bugDEPRECATED: replace with the "bug" issue type

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions