Double include when reloading an instance with scopes
See original GitHub issueWhat are you doing?
Trying to use a scope within an include. The example is contrived but in our codebase we actually reuse lots of named scopes. (This is a reopen of #10501 , as the bug appears to still exist on version 5.8.6.)
/**
* Model definitions
*/
const User = sequelize.define('user', {
id: { type: Sequelize.INTEGER, primaryKey: true },
name: Sequelize.STRING
})
const Project = sequelize.define('project', {
id: { type: Sequelize.INTEGER, primaryKey: true },
title: Sequelize.STRING,
userid: { type: Sequelize.INTEGER, references: { model: 'user', key: 'id' } }
})
const Task = sequelize.define('task', {
id: { type: Sequelize.INTEGER, primaryKey: true },
description: Sequelize.STRING,
projectid: { type: Sequelize.INTEGER, references: { model: 'project', key: 'id' } }
})
/**
* Associations
*/
Project.belongsTo(User, { foreignKey: 'userid' })
Task.belongsTo(Project, { foreignKey: 'projectid' })
/**
* Go for bug
*/
Task.findByPk(1, {
include: [
Project.scope({ include: [User] }) // This is the offending include
]
}).then(task => {
// The reload() will crash because it will try to include Project->User twice
task.reload().then(task => {
console.log(task)
})
})
To Reproduce
- Fetch Sequelize instance with a scope containing an include
- Try to reload that instance
What do you expect to happen?
The task instance should just reload.
What is actually happening?
I get an SQL error and a crash :
sqlite: Unhandled rejection SequelizeDatabaseError: SQLITE_ERROR: ambiguous column name: project->user.id
PostgreSQL : Unhandled rejection SequelizeDatabaseError: table name "project->user" specified more than once
The offending SQL looks like this (sqlite)
select
`task`.`id`,
`task`.`description`,
`task`.`projectid`,
`project`.`id` as `project.id`,
`project`.`title` as `project.title`,
`project`.`userid` as `project.userid`,
`project->user`.`id` as `project.user.id`,
`project->user`.`name` as `project.user.name`,
`project->user`.`id` as `project.user.id`,
`project->user`.`name` as `project.user.name`
from
`task` as `task`
left outer join `project` as `project` on
`task`.`projectid` = `project`.`id`
left outer join `user` as `project->user` on
`project`.`userid` = `project->user`.`id`
left outer join `user` as `project->user` on
`project`.`userid` = `project->user`.`id`
where
`task`.`id` = 1;
Environment
-
Dialect:
- postgres
- sqlite
-
Dialect library version:
"sqlite3": "^4.0.6"
,"pg": "^7.4.1"
-
Database version: XXX
-
Sequelize version:
5.8.6
-
Node Version:
v10.15.3
-
OS:
Ubuntu 19.04
-
Tested with latest release:
- No
- Yes, specify that version:
5.8.6
Issue Analytics
- State:
- Created 4 years ago
- Reactions:5
- Comments:12 (4 by maintainers)
Top Results From Across the Web
Using Sequelize with associations and scopes with includes ...
I'm loading the model files ordered alphabetically. When I rename Task to, lets say Zask , I get an error since Zask is...
Read more >Scopes - Sequelize
Observe how the four scopes were merged into one. The includes of scopes are merged based on the model being included. If one...
Read more >How to preload Rails scopes - Justin Weiss
In your example, includes(:product) won't necessarily add the product table to the SQL clause. It could also do a second SQL call to...
Read more >Authenticate workloads using service accounts - Google Cloud
You can enable multiple virtual machine instances to use the same service ... The combination of access scopes granted to the virtual machine...
Read more >pytest fixtures: explicit, modular, scalable
Multiple test functions in a test module will thus each receive the same smtp_connection fixture instance, thus saving time. Possible values for scope...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
example to reproduce in sequelize 6.3.5
digging in the code I could see that reload uses
this._options.include
https://github.com/sequelize/sequelize/blob/master/src/model.js#L4331 from the reloaded model and inject the scopes again in thefindAll
method which is called byfindOne
, in findAllthis._conformIncludes
https://github.com/sequelize/sequelize/blob/master/src/model.js#L1807 does not call tothis._uniqIncludes
https://github.com/sequelize/sequelize/blob/master/src/model.js#L850 that does the include deduplication, but it also fails in this case because of the omit function that uses${include.model && include.model.name}-${include.as}
https://github.com/sequelize/sequelize/blob/master/src/model.js#L854.I fixed it by adding
this._uniqIncludes
right afterthis._conformIncludes
and explicitly setting the alias in the scopeHello, as said upper, this is still present in Sequelize v6.5 too
After some investigation the issue is happening in sequelize/lib/model.js line 4070 (reload function)
as a workaround I made this in my reload call
Would be good if this case could be resolved still … scopes are useful