123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- 'use strict';
- const { expect } = require('chai');
- const { DataTypes, Op } = require('@sequelize/core');
- describe('Model scope with associations', () => {
- beforeEach(async function () {
- const sequelize = this.sequelize;
- this.ScopeMe = this.sequelize.define(
- 'ScopeMe',
- {
- username: DataTypes.STRING,
- email: DataTypes.STRING,
- access_level: DataTypes.INTEGER,
- other_value: DataTypes.INTEGER,
- parent_id: DataTypes.INTEGER,
- },
- {
- defaultScope: {
- where: {
- access_level: {
- [Op.gte]: 5,
- },
- },
- },
- scopes: {
- isTony: {
- where: {
- username: 'tony',
- },
- },
- includeActiveProjects() {
- return {
- include: [
- {
- model: sequelize.models.getOrThrow('company'),
- include: [sequelize.models.getOrThrow('project').withScope('active')],
- },
- ],
- };
- },
- },
- },
- );
- this.Project = this.sequelize.define(
- 'project',
- {
- active: DataTypes.BOOLEAN,
- },
- {
- scopes: {
- active: {
- where: {
- active: true,
- },
- },
- },
- },
- );
- this.Company = this.sequelize.define(
- 'company',
- {
- active: DataTypes.BOOLEAN,
- },
- {
- defaultScope: {
- where: { active: true },
- },
- scopes: {
- notActive: {
- where: {
- active: false,
- },
- },
- reversed: {
- order: [['id', 'DESC']],
- },
- },
- },
- );
- this.Profile = this.sequelize.define(
- 'profile',
- {
- active: DataTypes.BOOLEAN,
- },
- {
- defaultScope: {
- where: { active: true },
- },
- scopes: {
- notActive: {
- where: {
- active: false,
- },
- },
- },
- },
- );
- this.Project.belongsToMany(this.Company, { through: 'CompanyProjects' });
- this.Company.belongsToMany(this.Project, { through: 'CompanyProjects' });
- this.ScopeMe.hasOne(this.Profile, { foreignKey: 'userId' });
- this.ScopeMe.belongsTo(this.Company);
- this.UserAssociation = this.Company.hasMany(this.ScopeMe, { as: 'users' });
- await this.sequelize.sync({ force: true });
- const [u1, u2, u3, u4, u5, c1, c2] = await Promise.all([
- this.ScopeMe.create({
- id: 1,
- username: 'dan',
- email: 'dan@sequelizejs.com',
- access_level: 5,
- other_value: 10,
- parent_id: 1,
- }),
- this.ScopeMe.create({
- id: 2,
- username: 'tobi',
- email: 'tobi@fakeemail.com',
- access_level: 10,
- other_value: 11,
- parent_id: 2,
- }),
- this.ScopeMe.create({
- id: 3,
- username: 'tony',
- email: 'tony@sequelizejs.com',
- access_level: 3,
- other_value: 7,
- parent_id: 1,
- }),
- this.ScopeMe.create({
- id: 4,
- username: 'fred',
- email: 'fred@foobar.com',
- access_level: 3,
- other_value: 7,
- parent_id: 1,
- }),
- this.ScopeMe.create({
- id: 5,
- username: 'bob',
- email: 'bob@foobar.com',
- access_level: 1,
- other_value: 9,
- parent_id: 5,
- }),
- this.Company.create({ id: 1, active: true }),
- this.Company.create({ id: 2, active: false }),
- ]);
- await Promise.all([c1.setUsers([u1, u2, u3, u4]), c2.setUsers([u5])]);
- });
- describe('include', () => {
- it('should scope columns properly', async function () {
- // Will error with ambigous column if id is not scoped properly to `Company`.`id`
- await expect(
- this.Company.findAll({
- where: { id: 1 },
- include: [this.UserAssociation],
- }),
- ).not.to.be.rejected;
- });
- it('should apply default scope when including an associations', async function () {
- const obj = await this.Company.findAll({
- include: [this.UserAssociation],
- });
- const company = await obj[0];
- expect(company.users).to.have.length(2);
- });
- it('should apply default scope when including a model', async function () {
- const obj = await this.Company.findAll({
- include: [{ model: this.ScopeMe, as: 'users' }],
- });
- const company = await obj[0];
- expect(company.users).to.have.length(2);
- });
- it('should be able to include a scoped model', async function () {
- const obj = await this.Company.findAll({
- include: [{ model: this.ScopeMe.withScope('isTony'), as: 'users' }],
- });
- const company = await obj[0];
- expect(company.users).to.have.length(1);
- expect(company.users[0].get('username')).to.equal('tony');
- });
- });
- describe('get', () => {
- beforeEach(async function () {
- const [p, companies] = await Promise.all([
- this.Project.create(),
- this.Company.withoutScope().findAll(),
- ]);
- await p.setCompanies(companies);
- });
- describe('it should be able to unscope', () => {
- it('hasMany', async function () {
- const company = await this.Company.findByPk(1);
- const users = await company.getUsers({ scope: false });
- expect(users).to.have.length(4);
- });
- it('hasOne', async function () {
- await this.Profile.create({
- active: false,
- userId: 1,
- });
- const user = await this.ScopeMe.findByPk(1);
- const profile = await user.getProfile({ scope: false });
- expect(profile).to.be.ok;
- });
- it('belongsTo', async function () {
- const user = await this.ScopeMe.withoutScope().findOne({ where: { username: 'bob' } });
- const company = await user.getCompany({ scope: false });
- expect(company).to.be.ok;
- });
- it('belongsToMany', async function () {
- const obj = await this.Project.findAll();
- const p = await obj[0];
- const companies = await p.getCompanies({ scope: false });
- expect(companies).to.have.length(2);
- });
- });
- describe('it should apply default scope', () => {
- it('hasMany', async function () {
- const company = await this.Company.findByPk(1);
- const users = await company.getUsers();
- expect(users).to.have.length(2);
- });
- it('hasOne', async function () {
- await this.Profile.create({
- active: false,
- userId: 1,
- });
- const user = await this.ScopeMe.findByPk(1);
- const profile = await user.getProfile();
- expect(profile).not.to.be.ok;
- });
- it('belongsTo', async function () {
- const user = await this.ScopeMe.withoutScope().findOne({ where: { username: 'bob' } });
- const company = await user.getCompany();
- expect(company).not.to.be.ok;
- });
- it('belongsToMany', async function () {
- const obj = await this.Project.findAll();
- const p = await obj[0];
- const companies = await p.getCompanies();
- expect(companies).to.have.length(1);
- expect(companies[0].get('active')).to.be.ok;
- });
- });
- describe('it should be able to apply another scope', () => {
- it('hasMany', async function () {
- const company = await this.Company.findByPk(1);
- const users = await company.getUsers({ scope: 'isTony' });
- expect(users).to.have.length(1);
- expect(users[0].get('username')).to.equal('tony');
- });
- it('hasOne', async function () {
- await this.Profile.create({
- active: true,
- userId: 1,
- });
- const user = await this.ScopeMe.findByPk(1);
- const profile = await user.getProfile({ scope: 'notActive' });
- expect(profile).not.to.be.ok;
- });
- it('belongsTo', async function () {
- const user = await this.ScopeMe.withoutScope().findOne({ where: { username: 'bob' } });
- const company = await user.getCompany({ scope: 'notActive' });
- expect(company).to.be.ok;
- });
- it('belongsToMany', async function () {
- const obj = await this.Project.findAll();
- const p = await obj[0];
- const companies = await p.getCompanies({ scope: 'reversed' });
- expect(companies).to.have.length(2);
- expect(companies[0].id).to.equal(2);
- expect(companies[1].id).to.equal(1);
- });
- });
- });
- describe('scope with includes', () => {
- beforeEach(async function () {
- const [c, p1, p2] = await Promise.all([
- this.Company.findByPk(1),
- this.Project.create({ id: 1, active: true }),
- this.Project.create({ id: 2, active: false }),
- ]);
- await c.setProjects([p1, p2]);
- });
- it('should scope columns properly', async function () {
- await expect(this.ScopeMe.withScope('includeActiveProjects').findAll()).not.to.be.rejected;
- });
- it('should apply scope conditions', async function () {
- const user = await this.ScopeMe.withScope('includeActiveProjects').findOne({
- where: { id: 1 },
- });
- expect(user.company.projects).to.have.length(1);
- });
- describe('with different format', () => {
- it('should not throw error', async function () {
- const Child = this.sequelize.define('Child');
- const Parent = this.sequelize.define(
- 'Parent',
- {},
- {
- defaultScope: {
- include: [{ model: Child }],
- },
- scopes: {
- children: {
- include: [Child],
- },
- },
- },
- );
- Parent.addScope('alsoChildren', {
- include: [{ model: Child }],
- });
- Child.belongsTo(Parent);
- Parent.hasOne(Child);
- await this.sequelize.sync({ force: true });
- const [child, parent] = await Promise.all([Child.create(), Parent.create()]);
- await parent.setChild(child);
- await Parent.withScope('children', 'alsoChildren').findOne();
- });
- });
- describe('with find options', () => {
- it('should merge includes correctly', async function () {
- const Child = this.sequelize.define('Child', { name: DataTypes.STRING });
- const Parent = this.sequelize.define('Parent', { name: DataTypes.STRING });
- Parent.addScope('testScope1', {
- include: [
- {
- model: Child,
- where: {
- name: 'child2',
- },
- },
- ],
- });
- Parent.hasMany(Child);
- await this.sequelize.sync({ force: true });
- await Promise.all([
- Parent.create({ name: 'parent1' }).then(parent => parent.createChild({ name: 'child1' })),
- Parent.create({ name: 'parent2' }).then(parent => parent.createChild({ name: 'child2' })),
- ]);
- const parent = await Parent.withScope('testScope1').findOne({
- include: [
- {
- model: Child,
- attributes: { exclude: ['name'] },
- },
- ],
- });
- expect(parent.get('name')).to.equal('parent2');
- expect(parent.children).to.have.length(1);
- expect(parent.children[0].dataValues).not.to.have.property('name');
- });
- });
- });
- describe('scope with options', () => {
- it('should return correct object included foreign_key', async function () {
- const Child = this.sequelize.define(
- 'Child',
- {
- secret: DataTypes.STRING,
- },
- {
- scopes: {
- public: {
- attributes: {
- exclude: ['secret'],
- },
- },
- },
- },
- );
- const Parent = this.sequelize.define('Parent');
- Child.belongsTo(Parent);
- Parent.hasOne(Child);
- await this.sequelize.sync({ force: true });
- await Child.create({ secret: 'super secret' });
- const user = await Child.withScope('public').findOne();
- expect(user.dataValues).to.have.property('parentId');
- expect(user.dataValues).not.to.have.property('secret');
- });
- it('should return correct object included foreign_key with defaultScope', async function () {
- const Child = this.sequelize.define(
- 'Child',
- {
- secret: DataTypes.STRING,
- },
- {
- defaultScope: {
- attributes: {
- exclude: ['secret'],
- },
- },
- },
- );
- const Parent = this.sequelize.define('Parent');
- Child.belongsTo(Parent);
- await this.sequelize.sync({ force: true });
- await Child.create({ secret: 'super secret' });
- const user = await Child.findOne();
- expect(user.dataValues).to.have.property('parentId');
- expect(user.dataValues).not.to.have.property('secret');
- });
- it('should not throw error', async function () {
- const Clientfile = this.sequelize.define('clientfile');
- const Mission = this.sequelize.define('mission', { secret: DataTypes.STRING });
- const Building = this.sequelize.define('building');
- const MissionAssociation = Clientfile.hasOne(Mission);
- const BuildingAssociation = Clientfile.hasOne(Building);
- await this.sequelize.sync({ force: true });
- await Clientfile.findAll({
- include: [
- {
- association: 'mission',
- where: {
- secret: 'foo',
- },
- },
- {
- association: 'building',
- },
- ],
- });
- await Clientfile.findAll({
- include: [
- {
- association: MissionAssociation,
- where: {
- secret: 'foo',
- },
- },
- {
- association: BuildingAssociation,
- },
- ],
- });
- });
- });
- });
|