123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- 'use strict';
- const chai = require('chai');
- const expect = chai.expect;
- const sinon = require('sinon');
- const Support = require('../support');
- const { DataTypes } = require('@sequelize/core');
- const current = Support.sequelize;
- if (current.dialect.supports.groupedLimit) {
- describe(Support.getTestDialectTeaser('Include'), () => {
- describe('separate', () => {
- it('should run a hasMany association in a separate query', async function () {
- const User = this.sequelize.define('User', {});
- const Task = this.sequelize.define('Task', {});
- const sqlSpy = sinon.spy();
- User.Tasks = User.hasMany(Task, { as: 'tasks' });
- await this.sequelize.sync({ force: true });
- await Promise.all([
- User.create(
- {
- id: 1,
- tasks: [{}, {}, {}],
- },
- {
- include: [User.Tasks],
- },
- ),
- User.create(
- {
- id: 2,
- tasks: [{}],
- },
- {
- include: [User.Tasks],
- },
- ),
- ]);
- const users = await User.findAll({
- include: [{ association: User.Tasks, separate: true }],
- order: [['id', 'ASC']],
- logging: sqlSpy,
- });
- expect(users[0].get('tasks')).to.be.ok;
- expect(users[0].get('tasks').length).to.equal(3);
- expect(users[1].get('tasks')).to.be.ok;
- expect(users[1].get('tasks').length).to.equal(1);
- expect(users[0].get('tasks')[0].createdAt).to.be.ok;
- expect(users[0].get('tasks')[0].updatedAt).to.be.ok;
- expect(sqlSpy).to.have.been.calledTwice;
- });
- it('should work even if the id was not included', async function () {
- const User = this.sequelize.define('User', {
- name: DataTypes.STRING,
- });
- const Task = this.sequelize.define('Task', {});
- const sqlSpy = sinon.spy();
- User.Tasks = User.hasMany(Task, { as: 'tasks' });
- await this.sequelize.sync({ force: true });
- await User.create(
- {
- id: 1,
- tasks: [{}, {}, {}],
- },
- {
- include: [User.Tasks],
- },
- );
- const users = await User.findAll({
- attributes: ['name'],
- include: [{ association: User.Tasks, separate: true }],
- order: [['id', 'ASC']],
- logging: sqlSpy,
- });
- expect(users[0].get('tasks')).to.be.ok;
- expect(users[0].get('tasks').length).to.equal(3);
- expect(sqlSpy).to.have.been.calledTwice;
- });
- it('should work even if include does not specify foreign key attribute with custom sourceKey', async function () {
- const User = this.sequelize.define('User', {
- name: DataTypes.STRING,
- userExtraId: {
- type: DataTypes.INTEGER,
- unique: true,
- },
- });
- const Task = this.sequelize.define('Task', {
- title: DataTypes.STRING,
- });
- const sqlSpy = sinon.spy();
- User.Tasks = User.hasMany(Task, {
- as: 'tasks',
- foreignKey: 'userId',
- sourceKey: 'userExtraId',
- });
- await this.sequelize.sync({ force: true });
- await User.create(
- {
- id: 1,
- userExtraId: 222,
- tasks: [{}, {}, {}],
- },
- {
- include: [User.Tasks],
- },
- );
- const users = await User.findAll({
- attributes: ['name'],
- include: [
- {
- attributes: ['title'],
- association: User.Tasks,
- separate: true,
- },
- ],
- order: [['id', 'ASC']],
- logging: sqlSpy,
- });
- expect(users[0].get('tasks')).to.be.ok;
- expect(users[0].get('tasks').length).to.equal(3);
- expect(sqlSpy).to.have.been.calledTwice;
- });
- it('should not break a nested include with null values', async function () {
- const User = this.sequelize.define('User', {});
- const Team = this.sequelize.define('Team', {});
- const Company = this.sequelize.define('Company', {});
- User.Team = User.belongsTo(Team);
- Team.Company = Team.belongsTo(Company);
- await this.sequelize.sync({ force: true });
- await User.create({});
- await User.findAll({
- include: [{ association: User.Team, include: [Team.Company] }],
- });
- });
- it('should run a hasMany association with limit in a separate query', async function () {
- const User = this.sequelize.define('User', {});
- const Task = this.sequelize.define('Task', {
- userId: {
- type: DataTypes.INTEGER,
- field: 'user_id',
- },
- });
- const sqlSpy = sinon.spy();
- User.Tasks = User.hasMany(Task, { as: 'tasks', foreignKey: 'userId' });
- await this.sequelize.sync({ force: true });
- await Promise.all([
- User.create(
- {
- id: 1,
- tasks: [{}, {}, {}],
- },
- {
- include: [User.Tasks],
- },
- ),
- User.create(
- {
- id: 2,
- tasks: [{}, {}, {}, {}],
- },
- {
- include: [User.Tasks],
- },
- ),
- ]);
- const users = await User.findAll({
- include: [{ association: User.Tasks, limit: 2 }],
- order: [['id', 'ASC']],
- logging: sqlSpy,
- });
- expect(users[0].get('tasks')).to.be.ok;
- expect(users[0].get('tasks').length).to.equal(2);
- expect(users[1].get('tasks')).to.be.ok;
- expect(users[1].get('tasks').length).to.equal(2);
- expect(sqlSpy).to.have.been.calledTwice;
- });
- it('should run a nested (from a non-separate include) hasMany association in a separate query', async function () {
- const User = this.sequelize.define('User', {});
- const Company = this.sequelize.define('Company');
- const Task = this.sequelize.define('Task', {});
- const sqlSpy = sinon.spy();
- User.Company = User.belongsTo(Company, { as: 'company' });
- Company.Tasks = Company.hasMany(Task, { as: 'tasks' });
- await this.sequelize.sync({ force: true });
- await Promise.all([
- User.create(
- {
- id: 1,
- company: {
- tasks: [{}, {}, {}],
- },
- },
- {
- include: [{ association: User.Company, include: [Company.Tasks] }],
- },
- ),
- User.create(
- {
- id: 2,
- company: {
- tasks: [{}],
- },
- },
- {
- include: [{ association: User.Company, include: [Company.Tasks] }],
- },
- ),
- ]);
- const users = await User.findAll({
- include: [
- {
- association: User.Company,
- include: [{ association: Company.Tasks, separate: true }],
- },
- ],
- order: [['id', 'ASC']],
- logging: sqlSpy,
- });
- expect(users[0].get('company').get('tasks')).to.be.ok;
- expect(users[0].get('company').get('tasks').length).to.equal(3);
- expect(users[1].get('company').get('tasks')).to.be.ok;
- expect(users[1].get('company').get('tasks').length).to.equal(1);
- expect(sqlSpy).to.have.been.calledTwice;
- });
- it('should work having a separate include between a parent and child include', async function () {
- const User = this.sequelize.define('User', {});
- const Project = this.sequelize.define('Project');
- const Company = this.sequelize.define('Company');
- const Task = this.sequelize.define('Task', {});
- const sqlSpy = sinon.spy();
- Company.Users = Company.hasMany(User, { as: 'users' });
- User.Tasks = User.hasMany(Task, { as: 'tasks' });
- Task.Project = Task.belongsTo(Project, { as: 'project' });
- await this.sequelize.sync({ force: true });
- await Promise.all([
- Company.create(
- {
- id: 1,
- users: [
- {
- tasks: [{ project: {} }, { project: {} }, { project: {} }],
- },
- ],
- },
- {
- include: [
- {
- association: Company.Users,
- include: [
- {
- association: User.Tasks,
- include: [Task.Project],
- },
- ],
- },
- ],
- },
- ),
- ]);
- const companies = await Company.findAll({
- include: [
- {
- association: Company.Users,
- include: [
- {
- association: User.Tasks,
- separate: true,
- include: [Task.Project],
- },
- ],
- },
- ],
- order: [['id', 'ASC']],
- logging: sqlSpy,
- });
- expect(sqlSpy).to.have.been.calledTwice;
- expect(companies[0].users[0].tasks[0].project).to.be.ok;
- });
- it('should run two nested hasMany association in a separate queries', async function () {
- const User = this.sequelize.define('User', {});
- const Project = this.sequelize.define('Project', {});
- const Task = this.sequelize.define('Task', {});
- const sqlSpy = sinon.spy();
- User.Projects = User.hasMany(Project, { as: 'projects' });
- Project.Tasks = Project.hasMany(Task, { as: 'tasks' });
- await this.sequelize.sync({ force: true });
- await Promise.all([
- User.create(
- {
- id: 1,
- projects: [
- {
- id: 1,
- tasks: [{}, {}, {}],
- },
- {
- id: 2,
- tasks: [{}],
- },
- ],
- },
- {
- include: [{ association: User.Projects, include: [Project.Tasks] }],
- },
- ),
- User.create(
- {
- id: 2,
- projects: [
- {
- id: 3,
- tasks: [{}, {}],
- },
- ],
- },
- {
- include: [{ association: User.Projects, include: [Project.Tasks] }],
- },
- ),
- ]);
- const users = await User.findAll({
- include: [
- {
- association: User.Projects,
- separate: true,
- include: [{ association: Project.Tasks, separate: true }],
- },
- ],
- order: [['id', 'ASC']],
- logging: sqlSpy,
- });
- const u1projects = users[0].get('projects');
- expect(u1projects).to.be.ok;
- expect(u1projects[0].get('tasks')).to.be.ok;
- expect(u1projects[1].get('tasks')).to.be.ok;
- expect(u1projects.length).to.equal(2);
- // WTB ES2015 syntax ...
- expect(u1projects.find(p => p.id === 1).get('tasks').length).to.equal(3);
- expect(u1projects.find(p => p.id === 2).get('tasks').length).to.equal(1);
- expect(users[1].get('projects')).to.be.ok;
- expect(users[1].get('projects')[0].get('tasks')).to.be.ok;
- expect(users[1].get('projects').length).to.equal(1);
- expect(users[1].get('projects')[0].get('tasks').length).to.equal(2);
- expect(sqlSpy).to.have.been.calledThrice;
- });
- it('should work with two schema models in a hasMany association', async function () {
- const User = this.sequelize.define('User', {}, { schema: 'archive' });
- const Task = this.sequelize.define(
- 'Task',
- {
- id: { type: DataTypes.INTEGER, primaryKey: true },
- title: DataTypes.STRING,
- },
- { schema: 'archive' },
- );
- User.Tasks = User.hasMany(Task, { as: 'tasks' });
- await this.sequelize.createSchema('archive');
- await this.sequelize.sync({ force: true });
- await Promise.all([
- User.create(
- {
- id: 1,
- tasks: [
- { id: 1, title: 'b' },
- { id: 2, title: 'd' },
- { id: 3, title: 'c' },
- { id: 4, title: 'a' },
- ],
- },
- {
- include: [User.Tasks],
- },
- ),
- User.create(
- {
- id: 2,
- tasks: [
- { id: 5, title: 'a' },
- { id: 6, title: 'c' },
- { id: 7, title: 'b' },
- ],
- },
- {
- include: [User.Tasks],
- },
- ),
- ]);
- const result = await User.findAll({
- include: [{ model: Task, limit: 2, as: 'tasks', order: [['id', 'ASC']] }],
- order: [['id', 'ASC']],
- });
- expect(result[0].tasks.length).to.equal(2);
- expect(result[0].tasks[0].title).to.equal('b');
- expect(result[0].tasks[1].title).to.equal('d');
- expect(result[1].tasks.length).to.equal(2);
- expect(result[1].tasks[0].title).to.equal('a');
- expect(result[1].tasks[1].title).to.equal('c');
- await this.sequelize.queryInterface.dropAllTables({ schema: 'archive' });
- await this.sequelize.dropSchema('archive');
- const schemas = await this.sequelize.queryInterface.listSchemas();
- expect(schemas).to.not.include('archive');
- });
- it('should work with required non-separate parent and required child', async function () {
- const User = this.sequelize.define('User', {});
- const Task = this.sequelize.define('Task', {});
- const Company = this.sequelize.define('Company', {});
- Task.User = Task.belongsTo(User);
- User.Tasks = User.hasMany(Task);
- User.Company = User.belongsTo(Company);
- await this.sequelize.sync({ force: true });
- const task = await Task.create({ id: 1 });
- const user = await task.createUser({ id: 2 });
- await user.createCompany({ id: 3 });
- const results = await Task.findAll({
- include: [
- {
- association: Task.User,
- required: true,
- include: [
- {
- association: User.Tasks,
- attributes: ['userId'],
- separate: true,
- include: [
- {
- association: Task.User,
- attributes: ['id'],
- required: true,
- include: [
- {
- association: User.Company,
- },
- ],
- },
- ],
- },
- ],
- },
- ],
- });
- expect(results.length).to.equal(1);
- expect(results[0].id).to.equal(1);
- expect(results[0].user.id).to.equal(2);
- expect(results[0].user.tasks.length).to.equal(1);
- expect(results[0].user.tasks[0].user.id).to.equal(2);
- expect(results[0].user.tasks[0].user.company.id).to.equal(3);
- });
- });
- });
- }
|