不要怂,就是干,撸起袖子干!

Commit c013246b by Andy Edwards Committed by GitHub

test: asyncify integration/associations (#12227)

1 parent c14972b9
......@@ -5,78 +5,68 @@ const chai = require('chai'),
Support = require('../support');
describe(Support.getTestDialectTeaser('Alias'), () => {
it('should uppercase the first letter in alias getter, but not in eager loading', function() {
it('should uppercase the first letter in alias getter, but not in eager loading', async function() {
const User = this.sequelize.define('user', {}),
Task = this.sequelize.define('task', {});
User.hasMany(Task, { as: 'assignments', foreignKey: 'userId' });
Task.belongsTo(User, { as: 'owner', foreignKey: 'userId' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ id: 1 });
}).then(user => {
expect(user.getAssignments).to.be.ok;
return Task.create({ id: 1, userId: 1 });
}).then(task => {
expect(task.getOwner).to.be.ok;
return Promise.all([
User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'assignments' }] }),
Task.findOne({ where: { id: 1 }, include: [{ model: User, as: 'owner' }] })
]);
}).then(([user, task]) => {
expect(user.assignments).to.be.ok;
expect(task.owner).to.be.ok;
});
await this.sequelize.sync({ force: true });
const user0 = await User.create({ id: 1 });
expect(user0.getAssignments).to.be.ok;
const task0 = await Task.create({ id: 1, userId: 1 });
expect(task0.getOwner).to.be.ok;
const [user, task] = await Promise.all([
User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'assignments' }] }),
Task.findOne({ where: { id: 1 }, include: [{ model: User, as: 'owner' }] })
]);
expect(user.assignments).to.be.ok;
expect(task.owner).to.be.ok;
});
it('shouldnt touch the passed alias', function() {
it('shouldnt touch the passed alias', async function() {
const User = this.sequelize.define('user', {}),
Task = this.sequelize.define('task', {});
User.hasMany(Task, { as: 'ASSIGNMENTS', foreignKey: 'userId' });
Task.belongsTo(User, { as: 'OWNER', foreignKey: 'userId' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ id: 1 });
}).then(user => {
expect(user.getASSIGNMENTS).to.be.ok;
return Task.create({ id: 1, userId: 1 });
}).then(task => {
expect(task.getOWNER).to.be.ok;
return Promise.all([
User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'ASSIGNMENTS' }] }),
Task.findOne({ where: { id: 1 }, include: [{ model: User, as: 'OWNER' }] })
]);
}).then(([user, task]) => {
expect(user.ASSIGNMENTS).to.be.ok;
expect(task.OWNER).to.be.ok;
});
await this.sequelize.sync({ force: true });
const user0 = await User.create({ id: 1 });
expect(user0.getASSIGNMENTS).to.be.ok;
const task0 = await Task.create({ id: 1, userId: 1 });
expect(task0.getOWNER).to.be.ok;
const [user, task] = await Promise.all([
User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'ASSIGNMENTS' }] }),
Task.findOne({ where: { id: 1 }, include: [{ model: User, as: 'OWNER' }] })
]);
expect(user.ASSIGNMENTS).to.be.ok;
expect(task.OWNER).to.be.ok;
});
it('should allow me to pass my own plural and singular forms to hasMany', function() {
it('should allow me to pass my own plural and singular forms to hasMany', async function() {
const User = this.sequelize.define('user', {}),
Task = this.sequelize.define('task', {});
User.hasMany(Task, { as: { singular: 'task', plural: 'taskz' } });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ id: 1 });
}).then(user => {
expect(user.getTaskz).to.be.ok;
expect(user.addTask).to.be.ok;
expect(user.addTaskz).to.be.ok;
}).then(() => {
return User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'taskz' }] });
}).then(user => {
expect(user.taskz).to.be.ok;
});
await this.sequelize.sync({ force: true });
const user0 = await User.create({ id: 1 });
expect(user0.getTaskz).to.be.ok;
expect(user0.addTask).to.be.ok;
expect(user0.addTaskz).to.be.ok;
const user = await User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'taskz' }] });
expect(user.taskz).to.be.ok;
});
it('should allow me to define plural and singular forms on the model', function() {
it('should allow me to define plural and singular forms on the model', async function() {
const User = this.sequelize.define('user', {}),
Task = this.sequelize.define('task', {}, {
name: {
......@@ -87,16 +77,12 @@ describe(Support.getTestDialectTeaser('Alias'), () => {
User.hasMany(Task);
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ id: 1 });
}).then(user => {
expect(user.getAssignments).to.be.ok;
expect(user.addAssignment).to.be.ok;
expect(user.addAssignments).to.be.ok;
}).then(() => {
return User.findOne({ where: { id: 1 }, include: [Task] });
}).then(user => {
expect(user.assignments).to.be.ok;
});
await this.sequelize.sync({ force: true });
const user0 = await User.create({ id: 1 });
expect(user0.getAssignments).to.be.ok;
expect(user0.addAssignment).to.be.ok;
expect(user0.addAssignments).to.be.ok;
const user = await User.findOne({ where: { id: 1 }, include: [Task] });
expect(user.assignments).to.be.ok;
});
});
This diff could not be displayed because it is too large.
......@@ -27,129 +27,108 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
describe('get', () => {
describe('multiple', () => {
it('should fetch associations for multiple instances', function() {
it('should fetch associations for multiple instances', async function() {
const User = this.sequelize.define('User', {}),
Task = this.sequelize.define('Task', {});
Task.User = Task.belongsTo(User, { as: 'user' });
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([Task.create({
id: 1,
user: { id: 1 }
}, {
include: [Task.User]
}), Task.create({
id: 2,
user: { id: 2 }
}, {
include: [Task.User]
}), Task.create({
id: 3
})]);
}).then(tasks => {
return Task.User.get(tasks).then(result => {
expect(result[tasks[0].id].id).to.equal(tasks[0].user.id);
expect(result[tasks[1].id].id).to.equal(tasks[1].user.id);
expect(result[tasks[2].id]).to.be.undefined;
});
});
await this.sequelize.sync({ force: true });
const tasks = await Promise.all([Task.create({
id: 1,
user: { id: 1 }
}, {
include: [Task.User]
}), Task.create({
id: 2,
user: { id: 2 }
}, {
include: [Task.User]
}), Task.create({
id: 3
})]);
const result = await Task.User.get(tasks);
expect(result[tasks[0].id].id).to.equal(tasks[0].user.id);
expect(result[tasks[1].id].id).to.equal(tasks[1].user.id);
expect(result[tasks[2].id]).to.be.undefined;
});
});
});
describe('getAssociation', () => {
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.belongsTo(User);
return sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Group.create({ name: 'bar' }).then(group => {
return sequelize.transaction().then(t => {
return group.setUser(user, { transaction: t }).then(() => {
return Group.findAll().then(groups => {
return groups[0].getUser().then(associatedUser => {
expect(associatedUser).to.be.null;
return Group.findAll({ transaction: t }).then(groups => {
return groups[0].getUser({ transaction: t }).then(associatedUser => {
expect(associatedUser).to.be.not.null;
return t.rollback();
});
});
});
});
});
});
});
});
});
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.belongsTo(User);
await sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const group = await Group.create({ name: 'bar' });
const t = await sequelize.transaction();
await group.setUser(user, { transaction: t });
const groups = await Group.findAll();
const associatedUser = await groups[0].getUser();
expect(associatedUser).to.be.null;
const groups0 = await Group.findAll({ transaction: t });
const associatedUser0 = await groups0[0].getUser({ transaction: t });
expect(associatedUser0).to.be.not.null;
await t.rollback();
});
}
it('should be able to handle a where object that\'s a first class citizen.', function() {
it('should be able to handle a where object that\'s a first class citizen.', async function() {
const User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING, gender: Sequelize.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING, status: Sequelize.STRING });
Task.belongsTo(User);
return User.sync({ force: true }).then(() => {
// Can't use Promise.all cause of foreign key references
return Task.sync({ force: true });
}).then(() => {
return Promise.all([
User.create({ username: 'foo', gender: 'male' }),
User.create({ username: 'bar', gender: 'female' }),
Task.create({ title: 'task', status: 'inactive' })
]);
}).then(([userA, , task]) => {
return task.setUserXYZ(userA).then(() => {
return task.getUserXYZ({ where: { gender: 'female' } });
});
}).then(user => {
expect(user).to.be.null;
});
await User.sync({ force: true });
// Can't use Promise.all cause of foreign key references
await Task.sync({ force: true });
const [userA, , task] = await Promise.all([
User.create({ username: 'foo', gender: 'male' }),
User.create({ username: 'bar', gender: 'female' }),
Task.create({ title: 'task', status: 'inactive' })
]);
await task.setUserXYZ(userA);
const user = await task.getUserXYZ({ where: { gender: 'female' } });
expect(user).to.be.null;
});
it('supports schemas', function() {
it('supports schemas', async function() {
const User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING, gender: Sequelize.STRING }).schema('archive'),
Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING, status: Sequelize.STRING }).schema('archive');
Task.belongsTo(User);
return Support.dropTestSchemas(this.sequelize).then(() => {
return this.sequelize.createSchema('archive');
}).then(() => {
return User.sync({ force: true });
}).then(() => {
return Task.sync({ force: true });
}).then(() => {
return Promise.all([
User.create({ username: 'foo', gender: 'male' }),
Task.create({ title: 'task', status: 'inactive' })
]);
}).then(([user, task]) => {
return task.setUserXYZ(user).then(() => {
return task.getUserXYZ();
});
}).then(user => {
expect(user).to.be.ok;
return this.sequelize.dropSchema('archive').then(() => {
return this.sequelize.showAllSchemas().then(schemas => {
if (dialect === 'postgres' || dialect === 'mssql' || dialect === 'mariadb') {
expect(schemas).to.not.have.property('archive');
}
});
});
});
await Support.dropTestSchemas(this.sequelize);
await this.sequelize.createSchema('archive');
await User.sync({ force: true });
await Task.sync({ force: true });
const [user0, task] = await Promise.all([
User.create({ username: 'foo', gender: 'male' }),
Task.create({ title: 'task', status: 'inactive' })
]);
await task.setUserXYZ(user0);
const user = await task.getUserXYZ();
expect(user).to.be.ok;
await this.sequelize.dropSchema('archive');
const schemas = await this.sequelize.showAllSchemas();
if (dialect === 'postgres' || dialect === 'mssql' || dialect === 'mariadb') {
expect(schemas).to.not.have.property('archive');
}
});
it('supports schemas when defining custom foreign key attribute #9029', function() {
it('supports schemas when defining custom foreign key attribute #9029', async function() {
const User = this.sequelize.define('UserXYZ', {
uid: {
type: Sequelize.INTEGER,
......@@ -167,160 +146,120 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
Task.belongsTo(User, { foreignKey: 'user_id' });
return Support.dropTestSchemas(this.sequelize).then(() => {
return this.sequelize.createSchema('archive');
}).then(() => {
return User.sync({ force: true });
}).then(() => {
return Task.sync({ force: true });
}).then(() => {
return User.create({});
}).then(user => {
return Task.create({}).then(task => {
return task.setUserXYZ(user).then(() => {
return task.getUserXYZ();
});
});
}).then(user => {
expect(user).to.be.ok;
return this.sequelize.dropSchema('archive');
});
await Support.dropTestSchemas(this.sequelize);
await this.sequelize.createSchema('archive');
await User.sync({ force: true });
await Task.sync({ force: true });
const user0 = await User.create({});
const task = await Task.create({});
await task.setUserXYZ(user0);
const user = await task.getUserXYZ();
expect(user).to.be.ok;
await this.sequelize.dropSchema('archive');
});
});
describe('setAssociation', () => {
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.belongsTo(User);
return sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Group.create({ name: 'bar' }).then(group => {
return sequelize.transaction().then(t => {
return group.setUser(user, { transaction: t }).then(() => {
return Group.findAll().then(groups => {
return groups[0].getUser().then(associatedUser => {
expect(associatedUser).to.be.null;
return t.rollback();
});
});
});
});
});
});
});
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.belongsTo(User);
await sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const group = await Group.create({ name: 'bar' });
const t = await sequelize.transaction();
await group.setUser(user, { transaction: t });
const groups = await Group.findAll();
const associatedUser = await groups[0].getUser();
expect(associatedUser).to.be.null;
await t.rollback();
});
}
it('can set the association with declared primary keys...', function() {
it('can set the association with declared primary keys...', async function() {
const User = this.sequelize.define('UserXYZ', { user_id: { type: DataTypes.INTEGER, primaryKey: true }, username: DataTypes.STRING }),
Task = this.sequelize.define('TaskXYZ', { task_id: { type: DataTypes.INTEGER, primaryKey: true }, title: DataTypes.STRING });
Task.belongsTo(User, { foreignKey: 'user_id' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ user_id: 1, username: 'foo' }).then(user => {
return Task.create({ task_id: 1, title: 'task' }).then(task => {
return task.setUserXYZ(user).then(() => {
return task.getUserXYZ().then(user => {
expect(user).not.to.be.null;
return task.setUserXYZ(null).then(() => {
return task.getUserXYZ().then(user => {
expect(user).to.be.null;
});
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ user_id: 1, username: 'foo' });
const task = await Task.create({ task_id: 1, title: 'task' });
await task.setUserXYZ(user);
const user1 = await task.getUserXYZ();
expect(user1).not.to.be.null;
await task.setUserXYZ(null);
const user0 = await task.getUserXYZ();
expect(user0).to.be.null;
});
it('clears the association if null is passed', function() {
it('clears the association if null is passed', async function() {
const User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: DataTypes.STRING });
Task.belongsTo(User);
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return task.setUserXYZ(user).then(() => {
return task.getUserXYZ().then(user => {
expect(user).not.to.be.null;
return task.setUserXYZ(null).then(() => {
return task.getUserXYZ().then(user => {
expect(user).to.be.null;
});
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await task.setUserXYZ(user);
const user1 = await task.getUserXYZ();
expect(user1).not.to.be.null;
await task.setUserXYZ(null);
const user0 = await task.getUserXYZ();
expect(user0).to.be.null;
});
it('should throw a ForeignKeyConstraintError if the associated record does not exist', function() {
it('should throw a ForeignKeyConstraintError if the associated record does not exist', async function() {
const User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: DataTypes.STRING });
Task.belongsTo(User);
return this.sequelize.sync({ force: true }).then(() => {
return expect(Task.create({ title: 'task', UserXYZId: 5 })).to.be.rejectedWith(Sequelize.ForeignKeyConstraintError).then(() => {
return Task.create({ title: 'task' }).then(task => {
return expect(Task.update({ title: 'taskUpdate', UserXYZId: 5 }, { where: { id: task.id } })).to.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
});
});
});
await this.sequelize.sync({ force: true });
await expect(Task.create({ title: 'task', UserXYZId: 5 })).to.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
const task = await Task.create({ title: 'task' });
await expect(Task.update({ title: 'taskUpdate', UserXYZId: 5 }, { where: { id: task.id } })).to.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
});
it('supports passing the primary key instead of an object', function() {
it('supports passing the primary key instead of an object', async function() {
const User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: DataTypes.STRING });
Task.belongsTo(User);
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ id: 15, username: 'jansemand' }).then(user => {
return Task.create({}).then(task => {
return task.setUserXYZ(user.id).then(() => {
return task.getUserXYZ().then(user => {
expect(user.username).to.equal('jansemand');
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ id: 15, username: 'jansemand' });
const task = await Task.create({});
await task.setUserXYZ(user.id);
const user0 = await task.getUserXYZ();
expect(user0.username).to.equal('jansemand');
});
it('should support logging', function() {
it('should support logging', async function() {
const User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: DataTypes.STRING }),
spy = sinon.spy();
Task.belongsTo(User);
return this.sequelize.sync({ force: true }).then(() => {
return User.create().then(user => {
return Task.create({}).then(task => {
return task.setUserXYZ(user, { logging: spy }).then(() => {
expect(spy.called).to.be.ok;
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create();
const task = await Task.create({});
await task.setUserXYZ(user, { logging: spy });
expect(spy.called).to.be.ok;
});
it('should not clobber atributes', function() {
it('should not clobber atributes', async function() {
const Comment = this.sequelize.define('comment', {
text: DataTypes.STRING
});
......@@ -332,23 +271,22 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
Post.hasOne(Comment);
Comment.belongsTo(Post);
return this.sequelize.sync().then(() => {
return Post.create({
title: 'Post title'
}).then(post => {
return Comment.create({
text: 'OLD VALUE'
}).then(comment => {
comment.text = 'UPDATED VALUE';
return comment.setPost(post).then(() => {
expect(comment.text).to.equal('UPDATED VALUE');
});
});
});
await this.sequelize.sync();
const post = await Post.create({
title: 'Post title'
});
const comment = await Comment.create({
text: 'OLD VALUE'
});
comment.text = 'UPDATED VALUE';
await comment.setPost(post);
expect(comment.text).to.equal('UPDATED VALUE');
});
it('should set the foreign key value without saving when using save: false', function() {
it('should set the foreign key value without saving when using save: false', async function() {
const Comment = this.sequelize.define('comment', {
text: DataTypes.STRING
});
......@@ -360,17 +298,15 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
Post.hasMany(Comment, { foreignKey: 'post_id' });
Comment.belongsTo(Post, { foreignKey: 'post_id' });
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([Post.create(), Comment.create()]).then(async ([post, comment]) => {
expect(comment.get('post_id')).not.to.be.ok;
await this.sequelize.sync({ force: true });
const [post, comment] = await Promise.all([Post.create(), Comment.create()]);
expect(comment.get('post_id')).not.to.be.ok;
const setter = await comment.setPost(post, { save: false });
const setter = await comment.setPost(post, { save: false });
expect(setter).to.be.undefined;
expect(comment.get('post_id')).to.equal(post.get('id'));
expect(comment.changed('post_id')).to.be.true;
});
});
expect(setter).to.be.undefined;
expect(comment.get('post_id')).to.equal(post.get('id'));
expect(comment.changed('post_id')).to.be.true;
});
it('supports setting same association twice', async function() {
......@@ -390,48 +326,38 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
});
describe('createAssociation', () => {
it('creates an associated model instance', function() {
it('creates an associated model instance', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
Task = this.sequelize.define('Task', { title: DataTypes.STRING });
Task.belongsTo(User);
return this.sequelize.sync({ force: true }).then(() => {
return Task.create({ title: 'task' }).then(task => {
return task.createUser({ username: 'bob' }).then(user => {
expect(user).not.to.be.null;
expect(user.username).to.equal('bob');
});
});
});
await this.sequelize.sync({ force: true });
const task = await Task.create({ title: 'task' });
const user = await task.createUser({ username: 'bob' });
expect(user).not.to.be.null;
expect(user.username).to.equal('bob');
});
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.belongsTo(User);
return sequelize.sync({ force: true }).then(() => {
return Group.create({ name: 'bar' }).then(group => {
return sequelize.transaction().then(t => {
return group.createUser({ username: 'foo' }, { transaction: t }).then(() => {
return group.getUser().then(user => {
expect(user).to.be.null;
return group.getUser({ transaction: t }).then(user => {
expect(user).not.to.be.null;
return t.rollback();
});
});
});
});
});
});
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.belongsTo(User);
await sequelize.sync({ force: true });
const group = await Group.create({ name: 'bar' });
const t = await sequelize.transaction();
await group.createUser({ username: 'foo' }, { transaction: t });
const user = await group.getUser();
expect(user).to.be.null;
const user0 = await group.getUser({ transaction: t });
expect(user0).not.to.be.null;
await t.rollback();
});
}
});
......@@ -457,7 +383,7 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
expect(User.rawAttributes.AccountId.field).to.equal('AccountId');
});
it('should support specifying the field of a foreign key', function() {
it('should support specifying the field of a foreign key', async function() {
const User = this.sequelize.define('User', { username: Sequelize.STRING }, { underscored: false }),
Account = this.sequelize.define('Account', { title: Sequelize.STRING }, { underscored: false });
......@@ -471,31 +397,29 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
expect(User.rawAttributes.AccountId).to.exist;
expect(User.rawAttributes.AccountId.field).to.equal('account_id');
return Account.sync({ force: true }).then(() => {
// Can't use Promise.all cause of foreign key references
return User.sync({ force: true });
}).then(() => {
return Promise.all([
User.create({ username: 'foo' }),
Account.create({ title: 'pepsico' })
]);
}).then(([user, account]) => {
return user.setAccount(account).then(() => {
return user.getAccount();
});
}).then(user => {
expect(user).to.not.be.null;
return User.findOne({
where: { username: 'foo' },
include: [Account]
});
}).then(user => {
// the sql query should correctly look at account_id instead of AccountId
expect(user.Account).to.exist;
await Account.sync({ force: true });
// Can't use Promise.all cause of foreign key references
await User.sync({ force: true });
const [user1, account] = await Promise.all([
User.create({ username: 'foo' }),
Account.create({ title: 'pepsico' })
]);
await user1.setAccount(account);
const user0 = await user1.getAccount();
expect(user0).to.not.be.null;
const user = await User.findOne({
where: { username: 'foo' },
include: [Account]
});
// the sql query should correctly look at account_id instead of AccountId
expect(user.Account).to.exist;
});
it('should set foreignKey on foreign table', function() {
it('should set foreignKey on foreign table', async function() {
const Mail = this.sequelize.define('mail', {}, { timestamps: false });
const Entry = this.sequelize.define('entry', {}, { timestamps: false });
const User = this.sequelize.define('user', {}, { timestamps: false });
......@@ -542,230 +466,192 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
}
});
return this.sequelize.sync({ force: true })
.then(() => User.create({}))
.then(() => Mail.create({}))
.then(mail =>
Entry.create({ mailId: mail.id, ownerId: 1 })
.then(() => Entry.create({ mailId: mail.id, ownerId: 1 }))
// set recipients
.then(() => mail.setRecipients([1]))
)
.then(() => Entry.findAndCountAll({
offset: 0,
limit: 10,
order: [['id', 'DESC']],
include: [
{
association: Entry.associations.mail,
include: [
{
association: Mail.associations.recipients,
through: {
where: {
recipientId: 1
}
},
required: true
}
],
required: true
}
]
})).then(result => {
expect(result.count).to.equal(2);
expect(result.rows[0].get({ plain: true })).to.deep.equal(
{
id: 2,
ownerId: 1,
mailId: 1,
mail: {
id: 1,
recipients: [{
id: 1,
MailRecipients: {
mailId: 1,
await this.sequelize.sync({ force: true });
await User.create({});
const mail = await Mail.create({});
await Entry.create({ mailId: mail.id, ownerId: 1 });
await Entry.create({ mailId: mail.id, ownerId: 1 });
// set recipients
await mail.setRecipients([1]);
const result = await Entry.findAndCountAll({
offset: 0,
limit: 10,
order: [['id', 'DESC']],
include: [
{
association: Entry.associations.mail,
include: [
{
association: Mail.associations.recipients,
through: {
where: {
recipientId: 1
}
}]
},
required: true
}
}
);
});
],
required: true
}
]
});
expect(result.count).to.equal(2);
expect(result.rows[0].get({ plain: true })).to.deep.equal(
{
id: 2,
ownerId: 1,
mailId: 1,
mail: {
id: 1,
recipients: [{
id: 1,
MailRecipients: {
mailId: 1,
recipientId: 1
}
}]
}
}
);
});
});
describe('foreign key constraints', () => {
it('are enabled by default', function() {
it('are enabled by default', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
Task.belongsTo(User); // defaults to SET NULL
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return task.setUser(user).then(() => {
return user.destroy().then(() => {
return task.reload().then(() => {
expect(task.UserId).to.equal(null);
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await task.setUser(user);
await user.destroy();
await task.reload();
expect(task.UserId).to.equal(null);
});
it('sets to NO ACTION if allowNull: false', function() {
it('sets to NO ACTION if allowNull: false', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
Task.belongsTo(User, { foreignKey: { allowNull: false } }); // defaults to NO ACTION
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task', UserId: user.id }).then(() => {
return expect(user.destroy()).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError).then(() => {
return Task.findAll().then(tasks => {
expect(tasks).to.have.length(1);
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
await Task.create({ title: 'task', UserId: user.id });
await expect(user.destroy()).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
const tasks = await Task.findAll();
expect(tasks).to.have.length(1);
});
it('should be possible to disable them', function() {
it('should be possible to disable them', async function() {
const Task = this.sequelize.define('Task', { title: Sequelize.STRING }),
User = this.sequelize.define('User', { username: Sequelize.STRING });
Task.belongsTo(User, { constraints: false });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return task.setUser(user).then(() => {
return user.destroy().then(() => {
return task.reload().then(() => {
expect(task.UserId).to.equal(user.id);
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await task.setUser(user);
await user.destroy();
await task.reload();
expect(task.UserId).to.equal(user.id);
});
it('can cascade deletes', function() {
it('can cascade deletes', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
Task.belongsTo(User, { onDelete: 'cascade' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return task.setUser(user).then(() => {
return user.destroy().then(() => {
return Task.findAll().then(tasks => {
expect(tasks).to.have.length(0);
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await task.setUser(user);
await user.destroy();
const tasks = await Task.findAll();
expect(tasks).to.have.length(0);
});
if (current.dialect.supports.constraints.restrict) {
it('can restrict deletes', function() {
it('can restrict deletes', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
Task.belongsTo(User, { onDelete: 'restrict' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return task.setUser(user).then(() => {
return expect(user.destroy()).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError).then(() => {
return Task.findAll().then(tasks => {
expect(tasks).to.have.length(1);
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await task.setUser(user);
await expect(user.destroy()).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
const tasks = await Task.findAll();
expect(tasks).to.have.length(1);
});
it('can restrict updates', function() {
it('can restrict updates', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
Task.belongsTo(User, { onUpdate: 'restrict' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return task.setUser(user).then(() => {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
return expect(
user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id })
).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError).then(() => {
// Should fail due to FK restriction
return Task.findAll().then(tasks => {
expect(tasks).to.have.length(1);
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await task.setUser(user);
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
await expect(
user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id })
).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
// Should fail due to FK restriction
const tasks = await Task.findAll();
expect(tasks).to.have.length(1);
});
}
// NOTE: mssql does not support changing an autoincrement primary key
if (Support.getTestDialect() !== 'mssql') {
it('can cascade updates', function() {
it('can cascade updates', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
Task.belongsTo(User, { onUpdate: 'cascade' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return task.setUser(user).then(() => {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
return user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id })
.then(() => {
return Task.findAll().then(tasks => {
expect(tasks).to.have.length(1);
expect(tasks[0].UserId).to.equal(999);
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await task.setUser(user);
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
await user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id });
const tasks = await Task.findAll();
expect(tasks).to.have.length(1);
expect(tasks[0].UserId).to.equal(999);
});
}
});
describe('association column', () => {
it('has correct type and name for non-id primary keys with non-integer type', function() {
it('has correct type and name for non-id primary keys with non-integer type', async function() {
const User = this.sequelize.define('UserPKBT', {
username: {
type: DataTypes.STRING
......@@ -781,36 +667,33 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
User.belongsTo(Group);
return this.sequelize.sync({ force: true }).then(() => {
expect(User.rawAttributes.GroupPKBTName.type).to.an.instanceof(DataTypes.STRING);
});
await this.sequelize.sync({ force: true });
expect(User.rawAttributes.GroupPKBTName.type).to.an.instanceof(DataTypes.STRING);
});
it('should support a non-primary key as the association column on a target without a primary key', function() {
it('should support a non-primary key as the association column on a target without a primary key', async function() {
const User = this.sequelize.define('User', { username: { type: DataTypes.STRING, unique: true } });
const Task = this.sequelize.define('Task', { title: DataTypes.STRING });
User.removeAttribute('id');
Task.belongsTo(User, { foreignKey: 'user_name', targetKey: 'username' });
return this.sequelize.sync({ force: true })
.then(() => User.create({ username: 'bob' }))
.then(newUser => Task.create({ title: 'some task' })
.then(newTask => newTask.setUser(newUser)))
.then(() => Task.findOne({ where: { title: 'some task' } }))
.then(foundTask => foundTask.getUser())
.then(foundUser => expect(foundUser.username).to.equal('bob'))
.then(() => this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks'))
.then(foreignKeysDescriptions => {
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'username',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
await this.sequelize.sync({ force: true });
const newUser = await User.create({ username: 'bob' });
const newTask = await Task.create({ title: 'some task' });
await newTask.setUser(newUser);
const foundTask = await Task.findOne({ where: { title: 'some task' } });
const foundUser = await foundTask.getUser();
await expect(foundUser.username).to.equal('bob');
const foreignKeysDescriptions = await this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks');
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'username',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
it('should support a non-primary unique key as the association column', function() {
it('should support a non-primary unique key as the association column', async function() {
const User = this.sequelize.define('User', {
username: {
type: DataTypes.STRING,
......@@ -824,24 +707,22 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
Task.belongsTo(User, { foreignKey: 'user_name', targetKey: 'username' });
return this.sequelize.sync({ force: true })
.then(() => User.create({ username: 'bob' }))
.then(newUser => Task.create({ title: 'some task' })
.then(newTask => newTask.setUser(newUser)))
.then(() => Task.findOne({ where: { title: 'some task' } }))
.then(foundTask => foundTask.getUser())
.then(foundUser => expect(foundUser.username).to.equal('bob'))
.then(() => this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks'))
.then(foreignKeysDescriptions => {
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'user_name',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
await this.sequelize.sync({ force: true });
const newUser = await User.create({ username: 'bob' });
const newTask = await Task.create({ title: 'some task' });
await newTask.setUser(newUser);
const foundTask = await Task.findOne({ where: { title: 'some task' } });
const foundUser = await foundTask.getUser();
await expect(foundUser.username).to.equal('bob');
const foreignKeysDescriptions = await this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks');
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'user_name',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
it('should support a non-primary key as the association column with a field option', function() {
it('should support a non-primary key as the association column with a field option', async function() {
const User = this.sequelize.define('User', {
username: {
type: DataTypes.STRING,
......@@ -854,24 +735,22 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
User.removeAttribute('id');
Task.belongsTo(User, { foreignKey: 'user_name', targetKey: 'username' });
return this.sequelize.sync({ force: true })
.then(() => User.create({ username: 'bob' }))
.then(newUser => Task.create({ title: 'some task' })
.then(newTask => newTask.setUser(newUser)))
.then(() => Task.findOne({ where: { title: 'some task' } }))
.then(foundTask => foundTask.getUser())
.then(foundUser => expect(foundUser.username).to.equal('bob'))
.then(() => this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks'))
.then(foreignKeysDescriptions => {
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'the_user_name_field',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
await this.sequelize.sync({ force: true });
const newUser = await User.create({ username: 'bob' });
const newTask = await Task.create({ title: 'some task' });
await newTask.setUser(newUser);
const foundTask = await Task.findOne({ where: { title: 'some task' } });
const foundUser = await foundTask.getUser();
await expect(foundUser.username).to.equal('bob');
const foreignKeysDescriptions = await this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks');
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'the_user_name_field',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
it('should support a non-primary key as the association column in a table with a composite primary key', function() {
it('should support a non-primary key as the association column in a table with a composite primary key', async function() {
const User = this.sequelize.define('User', {
username: {
type: DataTypes.STRING,
......@@ -893,26 +772,24 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
Task.belongsTo(User, { foreignKey: 'user_name', targetKey: 'username' });
return this.sequelize.sync({ force: true })
.then(() => User.create({ username: 'bob', age: 18, weight: 40 }))
.then(newUser => Task.create({ title: 'some task' })
.then(newTask => newTask.setUser(newUser)))
.then(() => Task.findOne({ where: { title: 'some task' } }))
.then(foundTask => foundTask.getUser())
.then(foundUser => expect(foundUser.username).to.equal('bob'))
.then(() => this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks'))
.then(foreignKeysDescriptions => {
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'the_user_name_field',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
await this.sequelize.sync({ force: true });
const newUser = await User.create({ username: 'bob', age: 18, weight: 40 });
const newTask = await Task.create({ title: 'some task' });
await newTask.setUser(newUser);
const foundTask = await Task.findOne({ where: { title: 'some task' } });
const foundUser = await foundTask.getUser();
await expect(foundUser.username).to.equal('bob');
const foreignKeysDescriptions = await this.sequelize.getQueryInterface().getForeignKeyReferencesForTable('Tasks');
expect(foreignKeysDescriptions[0]).to.includes({
referencedColumnName: 'the_user_name_field',
referencedTableName: 'Users',
columnName: 'user_name'
});
});
});
describe('association options', () => {
it('can specify data type for auto-generated relational keys', function() {
it('can specify data type for auto-generated relational keys', async function() {
const User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING }),
dataTypes = [DataTypes.INTEGER, DataTypes.BIGINT, DataTypes.STRING],
Tasks = {};
......@@ -923,10 +800,9 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
Tasks[dataType].belongsTo(User, { foreignKey: 'userId', keyType: dataType, constraints: false });
});
return this.sequelize.sync({ force: true }).then(() => {
dataTypes.forEach(dataType => {
expect(Tasks[dataType].rawAttributes.userId.type).to.be.an.instanceof(dataType);
});
await this.sequelize.sync({ force: true });
dataTypes.forEach(dataType => {
expect(Tasks[dataType].rawAttributes.userId.type).to.be.an.instanceof(dataType);
});
});
......@@ -1019,53 +895,53 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
});
});
it('should load with an alias', function() {
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
}).then(([individual, hat]) => {
return individual.setPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ model: this.Hat, as: 'personwearinghat' }]
});
}).then(individual => {
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
}).then(() => {
return this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{
model: this.Hat,
as: { singular: 'personwearinghat' }
}]
});
}).then(individual => {
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
it('should load with an alias', async function() {
await this.sequelize.sync({ force: true });
const [individual1, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
await individual1.setPersonwearinghat(hat);
const individual0 = await this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ model: this.Hat, as: 'personwearinghat' }]
});
expect(individual0.name).to.equal('Foo Bar');
expect(individual0.personwearinghat.name).to.equal('Baz');
const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{
model: this.Hat,
as: { singular: 'personwearinghat' }
}]
});
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
});
it('should load all', function() {
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
}).then(([individual, hat]) => {
return individual.setPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ all: true }]
});
}).then(individual => {
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
it('should load all', async function() {
await this.sequelize.sync({ force: true });
const [individual0, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
await individual0.setPersonwearinghat(hat);
const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ all: true }]
});
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
});
});
});
......@@ -27,82 +27,83 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
});
describe('count', () => {
it('should not fail due to ambiguous field', function() {
it('should not fail due to ambiguous field', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
Task = this.sequelize.define('Task', { title: DataTypes.STRING, active: DataTypes.BOOLEAN });
User.hasMany(Task);
const subtasks = Task.hasMany(Task, { as: 'subtasks' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({
username: 'John',
Tasks: [{
title: 'Get rich', active: true
}]
}, {
include: [Task]
});
}).then(user => {
return Promise.all([
user.get('Tasks')[0].createSubtask({ title: 'Make a startup', active: false }),
user.get('Tasks')[0].createSubtask({ title: 'Engage rock stars', active: true })
]).then(() => user);
}).then(user => {
return expect(user.countTasks({
attributes: [Task.primaryKeyField, 'title'],
include: [{
attributes: [],
association: subtasks,
where: {
active: true
}
}],
group: this.sequelize.col(Task.name.concat('.', Task.primaryKeyField))
})).to.eventually.equal(1);
await this.sequelize.sync({ force: true });
const user0 = await User.create({
username: 'John',
Tasks: [{
title: 'Get rich', active: true
}]
}, {
include: [Task]
});
await Promise.all([
user0.get('Tasks')[0].createSubtask({ title: 'Make a startup', active: false }),
user0.get('Tasks')[0].createSubtask({ title: 'Engage rock stars', active: true })
]);
const user = user0;
await expect(user.countTasks({
attributes: [Task.primaryKeyField, 'title'],
include: [{
attributes: [],
association: subtasks,
where: {
active: true
}
}],
group: this.sequelize.col(Task.name.concat('.', Task.primaryKeyField))
})).to.eventually.equal(1);
});
});
describe('get', () => {
if (current.dialect.supports.groupedLimit) {
describe('multiple', () => {
it('should fetch associations for multiple instances', function() {
it('should fetch associations for multiple instances', async function() {
const User = this.sequelize.define('User', {}),
Task = this.sequelize.define('Task', {});
User.Tasks = User.hasMany(Task, { as: 'tasks' });
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([User.create({
id: 1,
tasks: [
{},
{},
{}
]
}, {
include: [User.Tasks]
}), User.create({
id: 2,
tasks: [
{}
]
}, {
include: [User.Tasks]
}), User.create({
id: 3
})]);
}).then(users => {
return User.Tasks.get(users).then(result => {
expect(result[users[0].id].length).to.equal(3);
expect(result[users[1].id].length).to.equal(1);
expect(result[users[2].id].length).to.equal(0);
});
});
await this.sequelize.sync({ force: true });
const users = await Promise.all([User.create({
id: 1,
tasks: [
{},
{},
{}
]
}, {
include: [User.Tasks]
}), User.create({
id: 2,
tasks: [
{}
]
}, {
include: [User.Tasks]
}), User.create({
id: 3
})]);
const result = await User.Tasks.get(users);
expect(result[users[0].id].length).to.equal(3);
expect(result[users[1].id].length).to.equal(1);
expect(result[users[2].id].length).to.equal(0);
});
it('should fetch associations for multiple instances with limit and order', function() {
it('should fetch associations for multiple instances with limit and order', async function() {
const User = this.sequelize.define('User', {}),
Task = this.sequelize.define('Task', {
title: DataTypes.STRING
......@@ -110,44 +111,44 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
User.Tasks = User.hasMany(Task, { as: 'tasks' });
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([User.create({
tasks: [
{ title: 'b' },
{ title: 'd' },
{ title: 'c' },
{ title: 'a' }
]
}, {
include: [User.Tasks]
}), User.create({
tasks: [
{ title: 'a' },
{ title: 'c' },
{ title: 'b' }
]
}, {
include: [User.Tasks]
})]);
}).then(users => {
return User.Tasks.get(users, {
limit: 2,
order: [
['title', 'ASC']
]
}).then(result => {
expect(result[users[0].id].length).to.equal(2);
expect(result[users[0].id][0].title).to.equal('a');
expect(result[users[0].id][1].title).to.equal('b');
expect(result[users[1].id].length).to.equal(2);
expect(result[users[1].id][0].title).to.equal('a');
expect(result[users[1].id][1].title).to.equal('b');
});
await this.sequelize.sync({ force: true });
const users = await Promise.all([User.create({
tasks: [
{ title: 'b' },
{ title: 'd' },
{ title: 'c' },
{ title: 'a' }
]
}, {
include: [User.Tasks]
}), User.create({
tasks: [
{ title: 'a' },
{ title: 'c' },
{ title: 'b' }
]
}, {
include: [User.Tasks]
})]);
const result = await User.Tasks.get(users, {
limit: 2,
order: [
['title', 'ASC']
]
});
expect(result[users[0].id].length).to.equal(2);
expect(result[users[0].id][0].title).to.equal('a');
expect(result[users[0].id][1].title).to.equal('b');
expect(result[users[1].id].length).to.equal(2);
expect(result[users[1].id][0].title).to.equal('a');
expect(result[users[1].id][1].title).to.equal('b');
});
it('should fetch multiple layers of associations with limit and order with separate=true', function() {
it('should fetch multiple layers of associations with limit and order with separate=true', async function() {
const User = this.sequelize.define('User', {}),
Task = this.sequelize.define('Task', {
title: DataTypes.STRING
......@@ -159,97 +160,97 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
User.Tasks = User.hasMany(Task, { as: 'tasks' });
Task.SubTasks = Task.hasMany(SubTask, { as: 'subtasks' });
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([User.create({
id: 1,
tasks: [
{ title: 'b', subtasks: [
{ title: 'c' },
{ title: 'a' }
] },
{ title: 'd' },
{ title: 'c', subtasks: [
{ title: 'b' },
{ title: 'a' },
{ title: 'c' }
] },
{ title: 'a', subtasks: [
{ title: 'c' },
{ title: 'a' },
{ title: 'b' }
] }
]
}, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }]
}), User.create({
id: 2,
tasks: [
{ title: 'a', subtasks: [
{ title: 'b' },
{ title: 'a' },
{ title: 'c' }
] },
{ title: 'c', subtasks: [
{ title: 'a' }
] },
{ title: 'b', subtasks: [
{ title: 'a' },
{ title: 'b' }
] }
]
}, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }]
})]);
}).then(() => {
return User.findAll({
include: [{
association: User.Tasks,
limit: 2,
order: [['title', 'ASC']],
separate: true,
as: 'tasks',
include: [
{
association: Task.SubTasks,
order: [['title', 'DESC']],
separate: true,
as: 'subtasks'
}
]
}],
order: [
['id', 'ASC']
await this.sequelize.sync({ force: true });
await Promise.all([User.create({
id: 1,
tasks: [
{ title: 'b', subtasks: [
{ title: 'c' },
{ title: 'a' }
] },
{ title: 'd' },
{ title: 'c', subtasks: [
{ title: 'b' },
{ title: 'a' },
{ title: 'c' }
] },
{ title: 'a', subtasks: [
{ title: 'c' },
{ title: 'a' },
{ title: 'b' }
] }
]
}, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }]
}), User.create({
id: 2,
tasks: [
{ title: 'a', subtasks: [
{ title: 'b' },
{ title: 'a' },
{ title: 'c' }
] },
{ title: 'c', subtasks: [
{ title: 'a' }
] },
{ title: 'b', subtasks: [
{ title: 'a' },
{ title: 'b' }
] }
]
}, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }]
})]);
const users = await User.findAll({
include: [{
association: User.Tasks,
limit: 2,
order: [['title', 'ASC']],
separate: true,
as: 'tasks',
include: [
{
association: Task.SubTasks,
order: [['title', 'DESC']],
separate: true,
as: 'subtasks'
}
]
}).then(users => {
expect(users[0].tasks.length).to.equal(2);
expect(users[0].tasks[0].title).to.equal('a');
expect(users[0].tasks[0].subtasks.length).to.equal(3);
expect(users[0].tasks[0].subtasks[0].title).to.equal('c');
expect(users[0].tasks[0].subtasks[1].title).to.equal('b');
expect(users[0].tasks[0].subtasks[2].title).to.equal('a');
expect(users[0].tasks[1].title).to.equal('b');
expect(users[0].tasks[1].subtasks.length).to.equal(2);
expect(users[0].tasks[1].subtasks[0].title).to.equal('c');
expect(users[0].tasks[1].subtasks[1].title).to.equal('a');
expect(users[1].tasks.length).to.equal(2);
expect(users[1].tasks[0].title).to.equal('a');
expect(users[1].tasks[0].subtasks.length).to.equal(3);
expect(users[1].tasks[0].subtasks[0].title).to.equal('c');
expect(users[1].tasks[0].subtasks[1].title).to.equal('b');
expect(users[1].tasks[0].subtasks[2].title).to.equal('a');
expect(users[1].tasks[1].title).to.equal('b');
expect(users[1].tasks[1].subtasks.length).to.equal(2);
expect(users[1].tasks[1].subtasks[0].title).to.equal('b');
expect(users[1].tasks[1].subtasks[1].title).to.equal('a');
});
}],
order: [
['id', 'ASC']
]
});
expect(users[0].tasks.length).to.equal(2);
expect(users[0].tasks[0].title).to.equal('a');
expect(users[0].tasks[0].subtasks.length).to.equal(3);
expect(users[0].tasks[0].subtasks[0].title).to.equal('c');
expect(users[0].tasks[0].subtasks[1].title).to.equal('b');
expect(users[0].tasks[0].subtasks[2].title).to.equal('a');
expect(users[0].tasks[1].title).to.equal('b');
expect(users[0].tasks[1].subtasks.length).to.equal(2);
expect(users[0].tasks[1].subtasks[0].title).to.equal('c');
expect(users[0].tasks[1].subtasks[1].title).to.equal('a');
expect(users[1].tasks.length).to.equal(2);
expect(users[1].tasks[0].title).to.equal('a');
expect(users[1].tasks[0].subtasks.length).to.equal(3);
expect(users[1].tasks[0].subtasks[0].title).to.equal('c');
expect(users[1].tasks[0].subtasks[1].title).to.equal('b');
expect(users[1].tasks[0].subtasks[2].title).to.equal('a');
expect(users[1].tasks[1].title).to.equal('b');
expect(users[1].tasks[1].subtasks.length).to.equal(2);
expect(users[1].tasks[1].subtasks[0].title).to.equal('b');
expect(users[1].tasks[1].subtasks[1].title).to.equal('a');
});
it('should fetch associations for multiple instances with limit and order and a belongsTo relation', function() {
it('should fetch associations for multiple instances with limit and order and a belongsTo relation', async function() {
const User = this.sequelize.define('User', {}),
Task = this.sequelize.define('Task', {
title: DataTypes.STRING,
......@@ -263,49 +264,49 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
User.Tasks = User.hasMany(Task, { as: 'tasks' });
Task.Category = Task.belongsTo(Category, { as: 'category', foreignKey: 'categoryId' });
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([User.create({
tasks: [
{ title: 'b', category: {} },
{ title: 'd', category: {} },
{ title: 'c', category: {} },
{ title: 'a', category: {} }
]
}, {
include: [{ association: User.Tasks, include: [Task.Category] }]
}), User.create({
tasks: [
{ title: 'a', category: {} },
{ title: 'c', category: {} },
{ title: 'b', category: {} }
]
}, {
include: [{ association: User.Tasks, include: [Task.Category] }]
})]);
}).then(users => {
return User.Tasks.get(users, {
limit: 2,
order: [
['title', 'ASC']
],
include: [Task.Category]
}).then(result => {
expect(result[users[0].id].length).to.equal(2);
expect(result[users[0].id][0].title).to.equal('a');
expect(result[users[0].id][0].category).to.be.ok;
expect(result[users[0].id][1].title).to.equal('b');
expect(result[users[0].id][1].category).to.be.ok;
expect(result[users[1].id].length).to.equal(2);
expect(result[users[1].id][0].title).to.equal('a');
expect(result[users[1].id][0].category).to.be.ok;
expect(result[users[1].id][1].title).to.equal('b');
expect(result[users[1].id][1].category).to.be.ok;
});
await this.sequelize.sync({ force: true });
const users = await Promise.all([User.create({
tasks: [
{ title: 'b', category: {} },
{ title: 'd', category: {} },
{ title: 'c', category: {} },
{ title: 'a', category: {} }
]
}, {
include: [{ association: User.Tasks, include: [Task.Category] }]
}), User.create({
tasks: [
{ title: 'a', category: {} },
{ title: 'c', category: {} },
{ title: 'b', category: {} }
]
}, {
include: [{ association: User.Tasks, include: [Task.Category] }]
})]);
const result = await User.Tasks.get(users, {
limit: 2,
order: [
['title', 'ASC']
],
include: [Task.Category]
});
expect(result[users[0].id].length).to.equal(2);
expect(result[users[0].id][0].title).to.equal('a');
expect(result[users[0].id][0].category).to.be.ok;
expect(result[users[0].id][1].title).to.equal('b');
expect(result[users[0].id][1].category).to.be.ok;
expect(result[users[1].id].length).to.equal(2);
expect(result[users[1].id][0].title).to.equal('a');
expect(result[users[1].id][0].category).to.be.ok;
expect(result[users[1].id][1].title).to.equal('b');
expect(result[users[1].id][1].category).to.be.ok;
});
it('supports schemas', function() {
it('supports schemas', async function() {
const User = this.sequelize.define('User', {}).schema('work'),
Task = this.sequelize.define('Task', {
title: DataTypes.STRING
......@@ -317,109 +318,103 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
User.Tasks = User.hasMany(Task, { as: 'tasks' });
Task.SubTasks = Task.hasMany(SubTask, { as: 'subtasks' });
return Support.dropTestSchemas(this.sequelize).then(() => {
return this.sequelize.createSchema('work');
}).then(() => {
return User.sync({ force: true });
}).then(() => {
return Task.sync({ force: true });
}).then(() => {
return SubTask.sync({ force: true });
}).then(() => {
return Promise.all([User.create({
id: 1,
tasks: [
{ title: 'b', subtasks: [
{ title: 'c' },
{ title: 'a' }
] },
{ title: 'd' },
{ title: 'c', subtasks: [
{ title: 'b' },
{ title: 'a' },
{ title: 'c' }
] },
{ title: 'a', subtasks: [
{ title: 'c' },
{ title: 'a' },
{ title: 'b' }
] }
]
}, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }]
}), User.create({
id: 2,
tasks: [
{ title: 'a', subtasks: [
{ title: 'b' },
{ title: 'a' },
{ title: 'c' }
] },
{ title: 'c', subtasks: [
{ title: 'a' }
] },
{ title: 'b', subtasks: [
{ title: 'a' },
{ title: 'b' }
] }
]
}, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }]
})]);
}).then(() => {
return User.findAll({
include: [{
association: User.Tasks,
limit: 2,
order: [['title', 'ASC']],
separate: true,
as: 'tasks',
include: [
{
association: Task.SubTasks,
order: [['title', 'DESC']],
separate: true,
as: 'subtasks'
}
]
}],
order: [
['id', 'ASC']
await Support.dropTestSchemas(this.sequelize);
await this.sequelize.createSchema('work');
await User.sync({ force: true });
await Task.sync({ force: true });
await SubTask.sync({ force: true });
await Promise.all([User.create({
id: 1,
tasks: [
{ title: 'b', subtasks: [
{ title: 'c' },
{ title: 'a' }
] },
{ title: 'd' },
{ title: 'c', subtasks: [
{ title: 'b' },
{ title: 'a' },
{ title: 'c' }
] },
{ title: 'a', subtasks: [
{ title: 'c' },
{ title: 'a' },
{ title: 'b' }
] }
]
}, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }]
}), User.create({
id: 2,
tasks: [
{ title: 'a', subtasks: [
{ title: 'b' },
{ title: 'a' },
{ title: 'c' }
] },
{ title: 'c', subtasks: [
{ title: 'a' }
] },
{ title: 'b', subtasks: [
{ title: 'a' },
{ title: 'b' }
] }
]
}, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }]
})]);
const users = await User.findAll({
include: [{
association: User.Tasks,
limit: 2,
order: [['title', 'ASC']],
separate: true,
as: 'tasks',
include: [
{
association: Task.SubTasks,
order: [['title', 'DESC']],
separate: true,
as: 'subtasks'
}
]
}).then(users => {
expect(users[0].tasks.length).to.equal(2);
expect(users[0].tasks[0].title).to.equal('a');
expect(users[0].tasks[0].subtasks.length).to.equal(3);
expect(users[0].tasks[0].subtasks[0].title).to.equal('c');
expect(users[0].tasks[0].subtasks[1].title).to.equal('b');
expect(users[0].tasks[0].subtasks[2].title).to.equal('a');
expect(users[0].tasks[1].title).to.equal('b');
expect(users[0].tasks[1].subtasks.length).to.equal(2);
expect(users[0].tasks[1].subtasks[0].title).to.equal('c');
expect(users[0].tasks[1].subtasks[1].title).to.equal('a');
expect(users[1].tasks.length).to.equal(2);
expect(users[1].tasks[0].title).to.equal('a');
expect(users[1].tasks[0].subtasks.length).to.equal(3);
expect(users[1].tasks[0].subtasks[0].title).to.equal('c');
expect(users[1].tasks[0].subtasks[1].title).to.equal('b');
expect(users[1].tasks[0].subtasks[2].title).to.equal('a');
expect(users[1].tasks[1].title).to.equal('b');
expect(users[1].tasks[1].subtasks.length).to.equal(2);
expect(users[1].tasks[1].subtasks[0].title).to.equal('b');
expect(users[1].tasks[1].subtasks[1].title).to.equal('a');
return this.sequelize.dropSchema('work').then(() => {
return this.sequelize.showAllSchemas().then(schemas => {
if (dialect === 'postgres' || dialect === 'mssql' || schemas === 'mariadb') {
expect(schemas).to.be.empty;
}
});
});
});
}],
order: [
['id', 'ASC']
]
});
expect(users[0].tasks.length).to.equal(2);
expect(users[0].tasks[0].title).to.equal('a');
expect(users[0].tasks[0].subtasks.length).to.equal(3);
expect(users[0].tasks[0].subtasks[0].title).to.equal('c');
expect(users[0].tasks[0].subtasks[1].title).to.equal('b');
expect(users[0].tasks[0].subtasks[2].title).to.equal('a');
expect(users[0].tasks[1].title).to.equal('b');
expect(users[0].tasks[1].subtasks.length).to.equal(2);
expect(users[0].tasks[1].subtasks[0].title).to.equal('c');
expect(users[0].tasks[1].subtasks[1].title).to.equal('a');
expect(users[1].tasks.length).to.equal(2);
expect(users[1].tasks[0].title).to.equal('a');
expect(users[1].tasks[0].subtasks.length).to.equal(3);
expect(users[1].tasks[0].subtasks[0].title).to.equal('c');
expect(users[1].tasks[0].subtasks[1].title).to.equal('b');
expect(users[1].tasks[0].subtasks[2].title).to.equal('a');
expect(users[1].tasks[1].title).to.equal('b');
expect(users[1].tasks[1].subtasks.length).to.equal(2);
expect(users[1].tasks[1].subtasks[0].title).to.equal('b');
expect(users[1].tasks[1].subtasks[1].title).to.equal('a');
await this.sequelize.dropSchema('work');
const schemas = await this.sequelize.showAllSchemas();
if (dialect === 'postgres' || dialect === 'mssql' || schemas === 'mariadb') {
expect(schemas).to.be.empty;
}
});
});
}
......@@ -463,95 +458,82 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
});
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
let Article, Label, sequelize, article, label, t;
return Support.prepareTransactionTest(this.sequelize).then(_sequelize => {
sequelize = _sequelize;
Article = sequelize.define('Article', { 'title': DataTypes.STRING });
Label = sequelize.define('Label', { 'text': DataTypes.STRING });
Article.hasMany(Label);
return sequelize.sync({ force: true });
}).then(() => {
return Promise.all([
Article.create({ title: 'foo' }),
Label.create({ text: 'bar' })
]);
}).then(([_article, _label]) => {
article = _article;
label = _label;
return sequelize.transaction();
}).then(_t => {
t = _t;
return article.setLabels([label], { transaction: t });
}).then(() => {
return Article.findAll({ transaction: t });
}).then(articles => {
return articles[0].hasLabel(label).then(hasLabel => {
expect(hasLabel).to.be.false;
});
}).then(() => {
return Article.findAll({ transaction: t });
}).then(articles => {
return articles[0].hasLabel(label, { transaction: t }).then(hasLabel => {
expect(hasLabel).to.be.true;
return t.rollback();
});
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const Article = sequelize.define('Article', { 'title': DataTypes.STRING });
const Label = sequelize.define('Label', { 'text': DataTypes.STRING });
Article.hasMany(Label);
await sequelize.sync({ force: true });
const [article, label] = await Promise.all([
Article.create({ title: 'foo' }),
Label.create({ text: 'bar' })
]);
const t = await sequelize.transaction();
await article.setLabels([label], { transaction: t });
const articles0 = await Article.findAll({ transaction: t });
const hasLabel0 = await articles0[0].hasLabel(label);
expect(hasLabel0).to.be.false;
const articles = await Article.findAll({ transaction: t });
const hasLabel = await articles[0].hasLabel(label, { transaction: t });
expect(hasLabel).to.be.true;
await t.rollback();
});
}
it('does not have any labels assigned to it initially', function() {
return Promise.all([
it('does not have any labels assigned to it initially', async function() {
const [article, label1, label2] = await Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
]).then(([article, label1, label2]) => {
return Promise.all([
article.hasLabel(label1),
article.hasLabel(label2)
]);
}).then(([hasLabel1, hasLabel2]) => {
expect(hasLabel1).to.be.false;
expect(hasLabel2).to.be.false;
});
]);
const [hasLabel1, hasLabel2] = await Promise.all([
article.hasLabel(label1),
article.hasLabel(label2)
]);
expect(hasLabel1).to.be.false;
expect(hasLabel2).to.be.false;
});
it('answers true if the label has been assigned', function() {
return Promise.all([
it('answers true if the label has been assigned', async function() {
const [article, label1, label2] = await Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
]).then(([article, label1, label2]) => {
return article.addLabel(label1).then(() => {
return Promise.all([
article.hasLabel(label1),
article.hasLabel(label2)
]);
});
}).then(([hasLabel1, hasLabel2]) => {
expect(hasLabel1).to.be.true;
expect(hasLabel2).to.be.false;
});
]);
await article.addLabel(label1);
const [hasLabel1, hasLabel2] = await Promise.all([
article.hasLabel(label1),
article.hasLabel(label2)
]);
expect(hasLabel1).to.be.true;
expect(hasLabel2).to.be.false;
});
it('answers correctly if the label has been assigned when passing a primary key instead of an object', function() {
return Promise.all([
it('answers correctly if the label has been assigned when passing a primary key instead of an object', async function() {
const [article, label1, label2] = await Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
]).then(([article, label1, label2]) => {
return article.addLabel(label1).then(() => {
return Promise.all([
article.hasLabel(label1[this.Label.primaryKeyAttribute]),
article.hasLabel(label2[this.Label.primaryKeyAttribute])
]);
});
}).then(([hasLabel1, hasLabel2]) => {
expect(hasLabel1).to.be.true;
expect(hasLabel2).to.be.false;
});
]);
await article.addLabel(label1);
const [hasLabel1, hasLabel2] = await Promise.all([
article.hasLabel(label1[this.Label.primaryKeyAttribute]),
article.hasLabel(label2[this.Label.primaryKeyAttribute])
]);
expect(hasLabel1).to.be.true;
expect(hasLabel2).to.be.false;
});
});
......@@ -581,310 +563,249 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
});
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
const ctx = {};
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
ctx.sequelize = sequelize;
ctx.Article = sequelize.define('Article', { 'title': DataTypes.STRING });
ctx.Label = sequelize.define('Label', { 'text': DataTypes.STRING });
ctx.Article.hasMany(ctx.Label);
return ctx.sequelize.sync({ force: true });
}).then(() => {
return Promise.all([
ctx.Article.create({ title: 'foo' }),
ctx.Label.create({ text: 'bar' })
]);
}).then(([article, label]) => {
ctx.article = article;
ctx.label = label;
return ctx.sequelize.transaction();
}).then(t => {
ctx.t = t;
return ctx.article.setLabels([ctx.label], { transaction: t });
}).then(() => {
return ctx.Article.findAll({ transaction: ctx.t });
}).then(articles => {
return Promise.all([
articles[0].hasLabels([ctx.label]),
articles[0].hasLabels([ctx.label], { transaction: ctx.t })
]);
}).then(([hasLabel1, hasLabel2]) => {
expect(hasLabel1).to.be.false;
expect(hasLabel2).to.be.true;
return ctx.t.rollback();
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const Article = sequelize.define('Article', { 'title': DataTypes.STRING });
const Label = sequelize.define('Label', { 'text': DataTypes.STRING });
Article.hasMany(Label);
await sequelize.sync({ force: true });
const [article, label] = await Promise.all([
Article.create({ title: 'foo' }),
Label.create({ text: 'bar' })
]);
const t = await sequelize.transaction();
await article.setLabels([label], { transaction: t });
const articles = await Article.findAll({ transaction: t });
const [hasLabel1, hasLabel2] = await Promise.all([
articles[0].hasLabels([label]),
articles[0].hasLabels([label], { transaction: t })
]);
expect(hasLabel1).to.be.false;
expect(hasLabel2).to.be.true;
await t.rollback();
});
}
it('answers false if only some labels have been assigned', function() {
return Promise.all([
it('answers false if only some labels have been assigned', async function() {
const [article, label1, label2] = await Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
]).then(([article, label1, label2]) => {
return article.addLabel(label1).then(() => {
return article.hasLabels([label1, label2]);
});
}).then(result => {
expect(result).to.be.false;
});
]);
await article.addLabel(label1);
const result = await article.hasLabels([label1, label2]);
expect(result).to.be.false;
});
it('answers false if only some labels have been assigned when passing a primary key instead of an object', function() {
return Promise.all([
it('answers false if only some labels have been assigned when passing a primary key instead of an object', async function() {
const [article, label1, label2] = await Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
]).then(([article, label1, label2]) => {
return article.addLabel(label1).then(() => {
return article.hasLabels([
label1[this.Label.primaryKeyAttribute],
label2[this.Label.primaryKeyAttribute]
]).then(result => {
expect(result).to.be.false;
});
});
});
]);
await article.addLabel(label1);
const result = await article.hasLabels([
label1[this.Label.primaryKeyAttribute],
label2[this.Label.primaryKeyAttribute]
]);
expect(result).to.be.false;
});
it('answers true if all label have been assigned', function() {
return Promise.all([
it('answers true if all label have been assigned', async function() {
const [article, label1, label2] = await Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
]).then(([article, label1, label2]) => {
return article.setLabels([label1, label2]).then(() => {
return article.hasLabels([label1, label2]).then(result => {
expect(result).to.be.true;
});
});
});
]);
await article.setLabels([label1, label2]);
const result = await article.hasLabels([label1, label2]);
expect(result).to.be.true;
});
it('answers true if all label have been assigned when passing a primary key instead of an object', function() {
return Promise.all([
it('answers true if all label have been assigned when passing a primary key instead of an object', async function() {
const [article, label1, label2] = await Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
]).then(([article, label1, label2]) => {
return article.setLabels([label1, label2]).then(() => {
return article.hasLabels([
label1[this.Label.primaryKeyAttribute],
label2[this.Label.primaryKeyAttribute]
]).then(result => {
expect(result).to.be.true;
});
});
});
]);
await article.setLabels([label1, label2]);
const result = await article.hasLabels([
label1[this.Label.primaryKeyAttribute],
label2[this.Label.primaryKeyAttribute]
]);
expect(result).to.be.true;
});
});
describe('setAssociations', () => {
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
const ctx = {};
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
ctx.Article = sequelize.define('Article', { 'title': DataTypes.STRING });
ctx.Label = sequelize.define('Label', { 'text': DataTypes.STRING });
ctx.Article.hasMany(ctx.Label);
ctx.sequelize = sequelize;
return sequelize.sync({ force: true });
}).then(() => {
return Promise.all([
ctx.Article.create({ title: 'foo' }),
ctx.Label.create({ text: 'bar' }),
ctx.sequelize.transaction()
]);
}).then(([article, label, t]) => {
ctx.article = article;
ctx. t = t;
return article.setLabels([label], { transaction: t });
}).then(() => {
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id }, transaction: undefined });
}).then(labels => {
expect(labels.length).to.equal(0);
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id }, transaction: ctx.t });
}).then(labels => {
expect(labels.length).to.equal(1);
return ctx.t.rollback();
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const Article = sequelize.define('Article', { 'title': DataTypes.STRING });
const Label = sequelize.define('Label', { 'text': DataTypes.STRING });
Article.hasMany(Label);
await sequelize.sync({ force: true });
const [article, label, t] = await Promise.all([
Article.create({ title: 'foo' }),
Label.create({ text: 'bar' }),
sequelize.transaction()
]);
await article.setLabels([label], { transaction: t });
const labels0 = await Label.findAll({ where: { ArticleId: article.id }, transaction: undefined });
expect(labels0.length).to.equal(0);
const labels = await Label.findAll({ where: { ArticleId: article.id }, transaction: t });
expect(labels.length).to.equal(1);
await t.rollback();
});
}
it('clears associations when passing null to the set-method', function() {
it('clears associations when passing null to the set-method', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
Task = this.sequelize.define('Task', { title: DataTypes.STRING });
Task.hasMany(User);
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
}).then(([user, task]) => {
ctx.task = task;
return task.setUsers([user]);
}).then(() => {
return ctx.task.getUsers();
}).then(users => {
expect(users).to.have.length(1);
return ctx.task.setUsers(null);
}).then(() => {
return ctx.task.getUsers();
}).then(users => {
expect(users).to.have.length(0);
});
await this.sequelize.sync({ force: true });
const [user, task] = await Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
await task.setUsers([user]);
const users0 = await task.getUsers();
expect(users0).to.have.length(1);
await task.setUsers(null);
const users = await task.getUsers();
expect(users).to.have.length(0);
});
it('supports passing the primary key instead of an object', function() {
it('supports passing the primary key instead of an object', async function() {
const Article = this.sequelize.define('Article', { title: DataTypes.STRING }),
Label = this.sequelize.define('Label', { text: DataTypes.STRING });
Article.hasMany(Label);
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
Article.create({}),
Label.create({ text: 'label one' }),
Label.create({ text: 'label two' })
]);
}).then(([article, label1, label2]) => {
ctx.article = article;
ctx.label1 = label1;
ctx.label2 = label2;
return article.addLabel(label1.id);
}).then(() => {
return ctx.article.setLabels([ctx.label2.id]);
}).then(() => {
return ctx.article.getLabels();
}).then(labels => {
expect(labels).to.have.length(1);
expect(labels[0].text).to.equal('label two');
});
await this.sequelize.sync({ force: true });
const [article, label1, label2] = await Promise.all([
Article.create({}),
Label.create({ text: 'label one' }),
Label.create({ text: 'label two' })
]);
await article.addLabel(label1.id);
await article.setLabels([label2.id]);
const labels = await article.getLabels();
expect(labels).to.have.length(1);
expect(labels[0].text).to.equal('label two');
});
});
describe('addAssociations', () => {
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
const ctx = {};
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
ctx.Article = sequelize.define('Article', { 'title': DataTypes.STRING });
ctx.Label = sequelize.define('Label', { 'text': DataTypes.STRING });
ctx.Article.hasMany(ctx.Label);
ctx.sequelize = sequelize;
return sequelize.sync({ force: true });
}).then(() => {
return Promise.all([
ctx.Article.create({ title: 'foo' }),
ctx.Label.create({ text: 'bar' })
]);
}).then(([article, label]) => {
ctx.article = article;
ctx.label = label;
return ctx.sequelize.transaction();
}).then(t => {
ctx.t = t;
return ctx.article.addLabel(ctx.label, { transaction: ctx.t });
}).then(() => {
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id }, transaction: undefined });
}).then(labels => {
expect(labels.length).to.equal(0);
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id }, transaction: ctx.t });
}).then(labels => {
expect(labels.length).to.equal(1);
return ctx.t.rollback();
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const Article = sequelize.define('Article', { 'title': DataTypes.STRING });
const Label = sequelize.define('Label', { 'text': DataTypes.STRING });
Article.hasMany(Label);
await sequelize.sync({ force: true });
const [article, label] = await Promise.all([
Article.create({ title: 'foo' }),
Label.create({ text: 'bar' })
]);
const t = await sequelize.transaction();
await article.addLabel(label, { transaction: t });
const labels0 = await Label.findAll({ where: { ArticleId: article.id }, transaction: undefined });
expect(labels0.length).to.equal(0);
const labels = await Label.findAll({ where: { ArticleId: article.id }, transaction: t });
expect(labels.length).to.equal(1);
await t.rollback();
});
}
it('supports passing the primary key instead of an object', function() {
it('supports passing the primary key instead of an object', async function() {
const Article = this.sequelize.define('Article', { 'title': DataTypes.STRING }),
Label = this.sequelize.define('Label', { 'text': DataTypes.STRING });
Article.hasMany(Label);
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
Article.create({}),
Label.create({ text: 'label one' })
]);
}).then(([article, label]) => {
ctx.article = article;
return article.addLabel(label.id);
}).then(() => {
return ctx.article.getLabels();
}).then(labels => {
expect(labels[0].text).to.equal('label one'); // Make sure that we didn't modify one of the other attributes while building / saving a new instance
});
await this.sequelize.sync({ force: true });
const [article, label] = await Promise.all([
Article.create({}),
Label.create({ text: 'label one' })
]);
await article.addLabel(label.id);
const labels = await article.getLabels();
expect(labels[0].text).to.equal('label one'); // Make sure that we didn't modify one of the other attributes while building / saving a new instance
});
});
describe('addMultipleAssociations', () => {
it('adds associations without removing the current ones', function() {
it('adds associations without removing the current ones', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
Task = this.sequelize.define('Task', { title: DataTypes.STRING });
Task.hasMany(User);
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return User.bulkCreate([
{ username: 'foo ' },
{ username: 'bar ' },
{ username: 'baz ' }
]);
}).then(() => {
return Task.create({ title: 'task' });
}).then(task => {
ctx.task = task;
return User.findAll();
}).then(users => {
ctx.users = users;
return ctx.task.setUsers([users[0]]);
}).then(() => {
return ctx.task.addUsers([ctx.users[1], ctx.users[2]]);
}).then(() => {
return ctx.task.getUsers();
}).then(users => {
expect(users).to.have.length(3);
});
await this.sequelize.sync({ force: true });
await User.bulkCreate([
{ username: 'foo ' },
{ username: 'bar ' },
{ username: 'baz ' }
]);
const task = await Task.create({ title: 'task' });
const users0 = await User.findAll();
const users = users0;
await task.setUsers([users0[0]]);
await task.addUsers([users[1], users[2]]);
expect(await task.getUsers()).to.have.length(3);
});
it('handles decent sized bulk creates', function() {
it('handles decent sized bulk creates', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING, num: DataTypes.INTEGER, status: DataTypes.STRING }),
Task = this.sequelize.define('Task', { title: DataTypes.STRING });
Task.hasMany(User);
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
const users = _.range(1000).map(i => ({ username: `user${i}`, num: i, status: 'live' }));
return User.bulkCreate(users);
}).then(() => {
return Task.create({ title: 'task' });
}).then(task => {
ctx.task = task;
return User.findAll();
}).then(users=> {
expect(users).to.have.length(1000);
});
await this.sequelize.sync({ force: true });
const users0 = _.range(1000).map(i => ({ username: `user${i}`, num: i, status: 'live' }));
await User.bulkCreate(users0);
await Task.create({ title: 'task' });
const users = await User.findAll();
expect(users).to.have.length(1000);
});
});
it('clears associations when passing null to the set-method with omitNull set to true', function() {
it('clears associations when passing null to the set-method with omitNull set to true', async function() {
this.sequelize.options.omitNull = true;
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
......@@ -892,49 +813,38 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
Task.hasMany(User);
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' });
}).then(user => {
ctx.user = user;
return Task.create({ title: 'task' });
}).then(task => {
ctx.task = task;
return task.setUsers([ctx.user]);
}).then(() => {
return ctx.task.getUsers();
}).then(_users => {
expect(_users).to.have.length(1);
return ctx.task.setUsers(null);
}).then(() => {
return ctx.task.getUsers();
}).then(_users => {
try {
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await task.setUsers([user]);
const _users0 = await task.getUsers();
expect(_users0).to.have.length(1);
await task.setUsers(null);
const _users = await task.getUsers();
expect(_users).to.have.length(0);
}).finally(() => {
} finally {
this.sequelize.options.omitNull = false;
});
}
});
describe('createAssociations', () => {
it('creates a new associated object', function() {
it('creates a new associated object', async function() {
const Article = this.sequelize.define('Article', { 'title': DataTypes.STRING }),
Label = this.sequelize.define('Label', { 'text': DataTypes.STRING });
Article.hasMany(Label);
return this.sequelize.sync({ force: true }).then(() => {
return Article.create({ title: 'foo' });
}).then(article => {
return article.createLabel({ text: 'bar' }).then(() => article);
}).then(article => {
return Label.findAll({ where: { ArticleId: article.id } });
}).then(labels => {
expect(labels.length).to.equal(1);
});
await this.sequelize.sync({ force: true });
const article0 = await Article.create({ title: 'foo' });
await article0.createLabel({ text: 'bar' });
const article = article0;
const labels = await Label.findAll({ where: { ArticleId: article.id } });
expect(labels.length).to.equal(1);
});
it('creates the object with the association directly', function() {
it('creates the object with the association directly', async function() {
const spy = sinon.spy();
const Article = this.sequelize.define('Article', {
......@@ -947,53 +857,36 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
Article.hasMany(Label);
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return Article.create({ title: 'foo' });
}).then(article => {
ctx.article = article;
return article.createLabel({ text: 'bar' }, { logging: spy });
}).then(label => {
expect(spy.calledOnce).to.be.true;
expect(label.ArticleId).to.equal(ctx.article.id);
});
await this.sequelize.sync({ force: true });
const article = await Article.create({ title: 'foo' });
const label = await article.createLabel({ text: 'bar' }, { logging: spy });
expect(spy.calledOnce).to.be.true;
expect(label.ArticleId).to.equal(article.id);
});
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
const ctx = {};
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
ctx.sequelize = sequelize;
ctx.Article = sequelize.define('Article', { 'title': DataTypes.STRING });
ctx.Label = sequelize.define('Label', { 'text': DataTypes.STRING });
ctx.Article.hasMany(ctx.Label);
return sequelize.sync({ force: true });
}).then(() => {
return ctx.Article.create({ title: 'foo' });
}).then(article => {
ctx.article = article;
return ctx.sequelize.transaction();
}).then(t => {
ctx.t = t;
return ctx.article.createLabel({ text: 'bar' }, { transaction: ctx.t });
}).then(() => {
return ctx.Label.findAll();
}).then(labels => {
expect(labels.length).to.equal(0);
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id } });
}).then(labels => {
expect(labels.length).to.equal(0);
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id }, transaction: ctx.t });
}).then(labels => {
expect(labels.length).to.equal(1);
return ctx.t.rollback();
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const Article = sequelize.define('Article', { 'title': DataTypes.STRING });
const Label = sequelize.define('Label', { 'text': DataTypes.STRING });
Article.hasMany(Label);
await sequelize.sync({ force: true });
const article = await Article.create({ title: 'foo' });
const t = await sequelize.transaction();
await article.createLabel({ text: 'bar' }, { transaction: t });
const labels1 = await Label.findAll();
expect(labels1.length).to.equal(0);
const labels0 = await Label.findAll({ where: { ArticleId: article.id } });
expect(labels0.length).to.equal(0);
const labels = await Label.findAll({ where: { ArticleId: article.id }, transaction: t });
expect(labels.length).to.equal(1);
await t.rollback();
});
}
it('supports passing the field option', function() {
it('supports passing the field option', async function() {
const Article = this.sequelize.define('Article', {
'title': DataTypes.STRING
}),
......@@ -1003,41 +896,40 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
Article.hasMany(Label);
return this.sequelize.sync({ force: true }).then(() => {
return Article.create();
}).then(article => {
return article.createLabel({
text: 'yolo'
}, {
fields: ['text']
}).then(() => article);
}).then(article => {
return article.getLabels();
}).then(labels => {
expect(labels.length).to.be.ok;
await this.sequelize.sync({ force: true });
const article0 = await Article.create();
await article0.createLabel({
text: 'yolo'
}, {
fields: ['text']
});
const article = article0;
const labels = await article.getLabels();
expect(labels.length).to.be.ok;
});
});
describe('getting assocations with options', () => {
beforeEach(function() {
beforeEach(async function() {
this.User = this.sequelize.define('User', { username: DataTypes.STRING });
this.Task = this.sequelize.define('Task', { title: DataTypes.STRING, active: DataTypes.BOOLEAN });
this.User.hasMany(this.Task);
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.User.create({ username: 'John' }),
this.Task.create({ title: 'Get rich', active: true }),
this.Task.create({ title: 'Die trying', active: false })
]);
}).then(([john, task1, task2]) => {
return john.setTasks([task1, task2]);
});
await this.sequelize.sync({ force: true });
const [john, task1, task2] = await Promise.all([
this.User.create({ username: 'John' }),
this.Task.create({ title: 'Get rich', active: true }),
this.Task.create({ title: 'Die trying', active: false })
]);
return john.setTasks([task1, task2]);
});
it('should treat the where object of associations as a first class citizen', function() {
it('should treat the where object of associations as a first class citizen', async function() {
this.Article = this.sequelize.define('Article', {
'title': DataTypes.STRING
});
......@@ -1048,44 +940,36 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
this.Article.hasMany(this.Label);
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness', until: '2014-01-01 01:00:00' }),
this.Label.create({ text: 'Epicness', until: '2014-01-03 01:00:00' })
]);
}).then(([article, label1, label2]) => {
ctx.article = article;
return article.setLabels([label1, label2]);
}).then(() => {
return ctx.article.getLabels({ where: { until: { [Op.gt]: moment('2014-01-02').toDate() } } });
}).then(labels => {
expect(labels).to.be.instanceof(Array);
expect(labels).to.have.length(1);
expect(labels[0].text).to.equal('Epicness');
});
await this.sequelize.sync({ force: true });
const [article, label1, label2] = await Promise.all([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness', until: '2014-01-01 01:00:00' }),
this.Label.create({ text: 'Epicness', until: '2014-01-03 01:00:00' })
]);
await article.setLabels([label1, label2]);
const labels = await article.getLabels({ where: { until: { [Op.gt]: moment('2014-01-02').toDate() } } });
expect(labels).to.be.instanceof(Array);
expect(labels).to.have.length(1);
expect(labels[0].text).to.equal('Epicness');
});
it('gets all associated objects when no options are passed', function() {
return this.User.findOne({ where: { username: 'John' } }).then(john => {
return john.getTasks();
}).then(tasks => {
expect(tasks).to.have.length(2);
});
it('gets all associated objects when no options are passed', async function() {
const john = await this.User.findOne({ where: { username: 'John' } });
const tasks = await john.getTasks();
expect(tasks).to.have.length(2);
});
it('only get objects that fulfill the options', function() {
return this.User.findOne({ where: { username: 'John' } }).then(john => {
return john.getTasks({ where: { active: true }, limit: 10, order: [['id', 'DESC']] });
}).then(tasks => {
expect(tasks).to.have.length(1);
});
it('only get objects that fulfill the options', async function() {
const john = await this.User.findOne({ where: { username: 'John' } });
const tasks = await john.getTasks({ where: { active: true }, limit: 10, order: [['id', 'DESC']] });
expect(tasks).to.have.length(1);
});
});
describe('countAssociations', () => {
beforeEach(function() {
beforeEach(async function() {
this.User = this.sequelize.define('User', { username: DataTypes.STRING });
this.Task = this.sequelize.define('Task', { title: DataTypes.STRING, active: DataTypes.BOOLEAN });
......@@ -1093,31 +977,32 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
foreignKey: 'userId'
});
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.User.create({ username: 'John' }),
this.Task.create({ title: 'Get rich', active: true }),
this.Task.create({ title: 'Die trying', active: false })
]);
}).then(([john, task1, task2]) => {
this.user = john;
return john.setTasks([task1, task2]);
});
await this.sequelize.sync({ force: true });
const [john, task1, task2] = await Promise.all([
this.User.create({ username: 'John' }),
this.Task.create({ title: 'Get rich', active: true }),
this.Task.create({ title: 'Die trying', active: false })
]);
this.user = john;
return john.setTasks([task1, task2]);
});
it('should count all associations', function() {
return expect(this.user.countTasks({})).to.eventually.equal(2);
it('should count all associations', async function() {
await expect(this.user.countTasks({})).to.eventually.equal(2);
});
it('should count filtered associations', function() {
return expect(this.user.countTasks({
it('should count filtered associations', async function() {
await expect(this.user.countTasks({
where: {
active: true
}
})).to.eventually.equal(1);
});
it('should count scoped associations', function() {
it('should count scoped associations', async function() {
this.User.hasMany(this.Task, {
foreignKey: 'userId',
as: 'activeTasks',
......@@ -1126,201 +1011,188 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
}
});
return expect(this.user.countActiveTasks({})).to.eventually.equal(1);
await expect(this.user.countActiveTasks({})).to.eventually.equal(1);
});
});
describe('thisAssociations', () => {
it('should work with alias', function() {
it('should work with alias', async function() {
const Person = this.sequelize.define('Group', {});
Person.hasMany(Person, { as: 'Children' });
return this.sequelize.sync();
await this.sequelize.sync();
});
});
});
describe('foreign key constraints', () => {
describe('1:m', () => {
it('sets null by default', function() {
it('sets null by default', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
User.hasMany(Task);
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
}).then(([user, task]) => {
return user.setTasks([task]).then(() => {
return user.destroy().then(() => {
return task.reload();
});
});
}).then(task => {
expect(task.UserId).to.equal(null);
});
await this.sequelize.sync({ force: true });
const [user, task0] = await Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
await user.setTasks([task0]);
await user.destroy();
const task = await task0.reload();
expect(task.UserId).to.equal(null);
});
it('sets to CASCADE if allowNull: false', function() {
it('sets to CASCADE if allowNull: false', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
User.hasMany(Task, { foreignKey: { allowNull: false } }); // defaults to CASCADE
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task', UserId: user.id }).then(() => {
return user.destroy().then(() => {
return Task.findAll();
});
});
}).then(tasks => {
expect(tasks).to.be.empty;
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
await Task.create({ title: 'task', UserId: user.id });
await user.destroy();
const tasks = await Task.findAll();
expect(tasks).to.be.empty;
});
it('should be possible to remove all constraints', function() {
it('should be possible to remove all constraints', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
User.hasMany(Task, { constraints: false });
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
}).then(([user, task]) => {
ctx.user = user;
ctx.task = task;
return user.setTasks([task]);
}).then(() => {
return ctx.user.destroy();
}).then(() => {
return ctx.task.reload();
}).then(task => {
expect(task.UserId).to.equal(ctx.user.id);
});
await this.sequelize.sync({ force: true });
const [user, task0] = await Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
const task = task0;
await user.setTasks([task0]);
await user.destroy();
await task.reload();
expect(task.UserId).to.equal(user.id);
});
it('can cascade deletes', function() {
it('can cascade deletes', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
User.hasMany(Task, { onDelete: 'cascade' });
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
}).then(([user, task]) => {
ctx.user = user;
ctx.task = task;
return user.setTasks([task]);
}).then(() => {
return ctx.user.destroy();
}).then(() => {
return Task.findAll();
}).then(tasks => {
expect(tasks).to.have.length(0);
});
await this.sequelize.sync({ force: true });
const [user, task] = await Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
await user.setTasks([task]);
await user.destroy();
const tasks = await Task.findAll();
expect(tasks).to.have.length(0);
});
// NOTE: mssql does not support changing an autoincrement primary key
if (dialect !== 'mssql') {
it('can cascade updates', function() {
it('can cascade updates', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
User.hasMany(Task, { onUpdate: 'cascade' });
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
}).then(([user, task]) => {
return user.setTasks([task]).then(() => user);
}).then(user => {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
return user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id });
}).then(() => {
return Task.findAll();
}).then(tasks => {
expect(tasks).to.have.length(1);
expect(tasks[0].UserId).to.equal(999);
});
await this.sequelize.sync({ force: true });
const [user0, task] = await Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
await user0.setTasks([task]);
const user = user0;
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
await user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id });
const tasks = await Task.findAll();
expect(tasks).to.have.length(1);
expect(tasks[0].UserId).to.equal(999);
});
}
if (current.dialect.supports.constraints.restrict) {
it('can restrict deletes', function() {
it('can restrict deletes', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
User.hasMany(Task, { onDelete: 'restrict' });
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
}).then(([user, task]) => {
ctx.user = user;
ctx.task = task;
return user.setTasks([task]);
}).then(() => {
return ctx.user.destroy().catch(err => {
if (!(err instanceof Sequelize.ForeignKeyConstraintError)) throw err;
// Should fail due to FK violation
return Task.findAll();
});
}).then(tasks => {
expect(tasks).to.have.length(1);
});
let tasks;
await this.sequelize.sync({ force: true });
const [user, task] = await Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
await user.setTasks([task]);
try {
tasks = await user.destroy();
} catch (err) {
if (!(err instanceof Sequelize.ForeignKeyConstraintError))
throw err;
// Should fail due to FK violation
tasks = await Task.findAll();
}
expect(tasks).to.have.length(1);
});
it('can restrict updates', function() {
it('can restrict updates', async function() {
const Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
User = this.sequelize.define('User', { username: DataTypes.STRING });
User.hasMany(Task, { onUpdate: 'restrict' });
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
}).then(([user, task]) => {
return user.setTasks([task]).then(() => user);
}).then(user => {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
return user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id })
.catch(err => {
if (!(err instanceof Sequelize.ForeignKeyConstraintError)) throw err;
// Should fail due to FK violation
return Task.findAll();
});
}).then(tasks => {
expect(tasks).to.have.length(1);
});
let tasks;
await this.sequelize.sync({ force: true });
const [user0, task] = await Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
await user0.setTasks([task]);
const user = user0;
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
try {
tasks = await user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id });
} catch (err) {
if (!(err instanceof Sequelize.ForeignKeyConstraintError))
throw err;
// Should fail due to FK violation
tasks = await Task.findAll();
}
expect(tasks).to.have.length(1);
});
}
});
......@@ -1363,7 +1235,7 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
}
});
it('infers the keyType if none provided', function() {
it('infers the keyType if none provided', async function() {
const User = this.sequelize.define('User', {
id: { type: DataTypes.STRING, primaryKey: true },
username: DataTypes.STRING
......@@ -1374,9 +1246,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
User.hasMany(Task);
return this.sequelize.sync({ force: true }).then(() => {
expect(Task.rawAttributes.UserId.type instanceof DataTypes.STRING).to.be.ok;
});
await this.sequelize.sync({ force: true });
expect(Task.rawAttributes.UserId.type instanceof DataTypes.STRING).to.be.ok;
});
describe('allows the user to provide an attribute definition object as foreignKey', () => {
......@@ -1445,7 +1316,7 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
.throw('Naming collision between attribute \'user\' and association \'user\' on model user. To remedy this, change either foreignKey or as in your association definition');
});
it('should ignore group from ancestor on deep separated query', function() {
it('should ignore group from ancestor on deep separated query', async function() {
const User = this.sequelize.define('user', {
userId: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
username: Sequelize.STRING
......@@ -1462,29 +1333,26 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
Task.hasMany(Job, { foreignKey: 'taskId' });
User.hasMany(Task, { foreignKey: 'userId' });
return this.sequelize.sync({ force: true })
.then(() => {
return User.create({
username: 'John Doe',
tasks: [
{ title: 'Task #1', jobs: [{ title: 'Job #1' }, { title: 'Job #2' }] },
{ title: 'Task #2', jobs: [{ title: 'Job #3' }, { title: 'Job #4' }] }
]
}, { include: [{ model: Task, include: [Job] }] });
})
.then(() => {
return User.findAndCountAll({
attributes: ['userId'],
include: [
{ model: Task, separate: true, include: [{ model: Job, separate: true }] }
],
group: [['userId']]
});
})
.then(({ count, rows }) => {
expect(count.length).to.equal(1);
expect(rows[0].tasks[0].jobs.length).to.equal(2);
});
await this.sequelize.sync({ force: true });
await User.create({
username: 'John Doe',
tasks: [
{ title: 'Task #1', jobs: [{ title: 'Job #1' }, { title: 'Job #2' }] },
{ title: 'Task #2', jobs: [{ title: 'Job #3' }, { title: 'Job #4' }] }
]
}, { include: [{ model: Task, include: [Job] }] });
const { count, rows } = await User.findAndCountAll({
attributes: ['userId'],
include: [
{ model: Task, separate: true, include: [{ model: Job, separate: true }] }
],
group: [['userId']]
});
expect(count.length).to.equal(1);
expect(rows[0].tasks[0].jobs.length).to.equal(2);
});
});
......@@ -1505,49 +1373,39 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
return this.sequelize.sync({ force: true });
});
it('should use sourceKey', function() {
it('should use sourceKey', async function() {
const User = this.User,
Task = this.Task;
return User.create({ username: 'John', email: 'john@example.com' }).then(user => {
return Task.create({ title: 'Fix PR', userEmail: 'john@example.com' }).then(() => {
return user.getTasks().then(tasks => {
expect(tasks.length).to.equal(1);
expect(tasks[0].title).to.equal('Fix PR');
});
});
});
const user = await User.create({ username: 'John', email: 'john@example.com' });
await Task.create({ title: 'Fix PR', userEmail: 'john@example.com' });
const tasks = await user.getTasks();
expect(tasks.length).to.equal(1);
expect(tasks[0].title).to.equal('Fix PR');
});
it('should count related records', function() {
it('should count related records', async function() {
const User = this.User,
Task = this.Task;
return User.create({ username: 'John', email: 'john@example.com' }).then(user => {
return Task.create({ title: 'Fix PR', userEmail: 'john@example.com' }).then(() => {
return user.countTasks().then(tasksCount => {
expect(tasksCount).to.equal(1);
});
});
});
const user = await User.create({ username: 'John', email: 'john@example.com' });
await Task.create({ title: 'Fix PR', userEmail: 'john@example.com' });
const tasksCount = await user.countTasks();
expect(tasksCount).to.equal(1);
});
it('should set right field when add relative', function() {
it('should set right field when add relative', async function() {
const User = this.User,
Task = this.Task;
return User.create({ username: 'John', email: 'john@example.com' }).then(user => {
return Task.create({ title: 'Fix PR' }).then(task => {
return user.addTask(task).then(() => {
return user.hasTask(task.id).then(hasTask => {
expect(hasTask).to.be.true;
});
});
});
});
const user = await User.create({ username: 'John', email: 'john@example.com' });
const task = await Task.create({ title: 'Fix PR' });
await user.addTask(task);
const hasTask = await user.hasTask(task.id);
expect(hasTask).to.be.true;
});
it('should create with nested associated models', function() {
it('should create with nested associated models', async function() {
const User = this.User,
values = {
username: 'John',
......@@ -1555,27 +1413,22 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
tasks: [{ title: 'Fix new PR' }]
};
return User.create(values, { include: ['tasks'] })
.then(user => {
// Make sure tasks are defined for created user
expect(user).to.have.property('tasks');
expect(user.tasks).to.be.an('array');
expect(user.tasks).to.lengthOf(1);
expect(user.tasks[0].title).to.be.equal(values.tasks[0].title, 'task title is correct');
return User.findOne({ where: { email: values.email } });
})
.then(user =>
user.getTasks()
.then(tasks => {
// Make sure tasks relationship is successful
expect(tasks).to.be.an('array');
expect(tasks).to.lengthOf(1);
expect(tasks[0].title).to.be.equal(values.tasks[0].title, 'task title is correct');
}));
const user0 = await User.create(values, { include: ['tasks'] });
// Make sure tasks are defined for created user
expect(user0).to.have.property('tasks');
expect(user0.tasks).to.be.an('array');
expect(user0.tasks).to.lengthOf(1);
expect(user0.tasks[0].title).to.be.equal(values.tasks[0].title, 'task title is correct');
const user = await User.findOne({ where: { email: values.email } });
const tasks = await user.getTasks();
// Make sure tasks relationship is successful
expect(tasks).to.be.an('array');
expect(tasks).to.lengthOf(1);
expect(tasks[0].title).to.be.equal(values.tasks[0].title, 'task title is correct');
});
it('should create nested associations with symmetric getters/setters on FK', function() {
it('should create nested associations with symmetric getters/setters on FK', async function() {
// Dummy getter/setter to test they are symmetric
function toCustomFormat(string) {
return string && `FORMAT-${string}`;
......@@ -1626,20 +1479,18 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
id: 'sJn369d8Em',
children: [{ id: 'dgeQAQaW7A' }]
};
return this.sequelize.sync({ force: true })
.then(() => Parent.create(values, { include: { model: Child, as: 'children' } }))
.then(father => {
// Make sure tasks are defined for created user
expect(father.id).to.be.equal('sJn369d8Em');
expect(father.get('id', { raw: true })).to.be.equal('FORMAT-sJn369d8Em');
expect(father).to.have.property('children');
expect(father.children).to.be.an('array');
expect(father.children).to.lengthOf(1);
expect(father.children[0].parent).to.be.equal('sJn369d8Em');
expect(father.children[0].get('parent', { raw: true })).to.be.equal('FORMAT-sJn369d8Em');
});
await this.sequelize.sync({ force: true });
const father = await Parent.create(values, { include: { model: Child, as: 'children' } });
// Make sure tasks are defined for created user
expect(father.id).to.be.equal('sJn369d8Em');
expect(father.get('id', { raw: true })).to.be.equal('FORMAT-sJn369d8Em');
expect(father).to.have.property('children');
expect(father.children).to.be.an('array');
expect(father.children).to.lengthOf(1);
expect(father.children[0].parent).to.be.equal('sJn369d8Em');
expect(father.children[0].get('parent', { raw: true })).to.be.equal('FORMAT-sJn369d8Em');
});
});
......@@ -1660,27 +1511,27 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
return this.sequelize.sync({ force: true });
});
it('should use the specified sourceKey instead of the primary key', function() {
return this.User.create({ username: 'John', email: 'john@example.com' }).then(() =>
this.Task.bulkCreate([
{ title: 'Active Task', userEmail: 'john@example.com', taskStatus: 'Active' },
{ title: 'Inactive Task', userEmail: 'john@example.com', taskStatus: 'Inactive' }
])
).then(() =>
this.User.findOne({
include: [
{
model: this.Task,
where: { taskStatus: 'Active' }
}
],
where: { username: 'John' }
})
).then(user => {
expect(user).to.be.ok;
expect(user.Tasks.length).to.equal(1);
expect(user.Tasks[0].title).to.equal('Active Task');
it('should use the specified sourceKey instead of the primary key', async function() {
await this.User.create({ username: 'John', email: 'john@example.com' });
await this.Task.bulkCreate([
{ title: 'Active Task', userEmail: 'john@example.com', taskStatus: 'Active' },
{ title: 'Inactive Task', userEmail: 'john@example.com', taskStatus: 'Inactive' }
]);
const user = await this.User.findOne({
include: [
{
model: this.Task,
where: { taskStatus: 'Active' }
}
],
where: { username: 'John' }
});
expect(user).to.be.ok;
expect(user.Tasks.length).to.equal(1);
expect(user.Tasks[0].title).to.equal('Active Task');
});
});
......@@ -1700,44 +1551,44 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
});
});
it('should load with an alias', function() {
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
}).then(([individual, hat]) => {
return individual.addPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ model: this.Hat, as: 'personwearinghats' }]
});
}).then(individual => {
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghats.length).to.equal(1);
expect(individual.personwearinghats[0].name).to.equal('Baz');
it('should load with an alias', async function() {
await this.sequelize.sync({ force: true });
const [individual0, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
await individual0.addPersonwearinghat(hat);
const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ model: this.Hat, as: 'personwearinghats' }]
});
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghats.length).to.equal(1);
expect(individual.personwearinghats[0].name).to.equal('Baz');
});
it('should load all', function() {
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
}).then(([individual, hat]) => {
return individual.addPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ all: true }]
});
}).then(individual => {
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghats.length).to.equal(1);
expect(individual.personwearinghats[0].name).to.equal('Baz');
it('should load all', async function() {
await this.sequelize.sync({ force: true });
const [individual0, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
await individual0.addPersonwearinghat(hat);
const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ all: true }]
});
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghats.length).to.equal(1);
expect(individual.personwearinghats[0].name).to.equal('Baz');
});
});
});
......@@ -25,358 +25,276 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
describe('get', () => {
describe('multiple', () => {
it('should fetch associations for multiple instances', function() {
it('should fetch associations for multiple instances', async function() {
const User = this.sequelize.define('User', {}),
Player = this.sequelize.define('Player', {});
Player.User = Player.hasOne(User, { as: 'user' });
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([Player.create({
id: 1,
user: {}
}, {
include: [Player.User]
}), Player.create({
id: 2,
user: {}
}, {
include: [Player.User]
}), Player.create({
id: 3
})]);
}).then(players => {
return Player.User.get(players).then(result => {
expect(result[players[0].id].id).to.equal(players[0].user.id);
expect(result[players[1].id].id).to.equal(players[1].user.id);
expect(result[players[2].id]).to.equal(null);
});
});
await this.sequelize.sync({ force: true });
const players = await Promise.all([Player.create({
id: 1,
user: {}
}, {
include: [Player.User]
}), Player.create({
id: 2,
user: {}
}, {
include: [Player.User]
}), Player.create({
id: 3
})]);
const result = await Player.User.get(players);
expect(result[players[0].id].id).to.equal(players[0].user.id);
expect(result[players[1].id].id).to.equal(players[1].user.id);
expect(result[players[2].id]).to.equal(null);
});
});
});
describe('getAssociation', () => {
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.hasOne(User);
return sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(fakeUser => {
return User.create({ username: 'foo' }).then(user => {
return Group.create({ name: 'bar' }).then(group => {
return sequelize.transaction().then(t => {
return group.setUser(user, { transaction: t }).then(() => {
return Group.findAll().then(groups => {
return groups[0].getUser().then(associatedUser => {
expect(associatedUser).to.be.null;
return Group.findAll({ transaction: t }).then(groups => {
return groups[0].getUser({ transaction: t }).then(associatedUser => {
expect(associatedUser).not.to.be.null;
expect(associatedUser.id).to.equal(user.id);
expect(associatedUser.id).not.to.equal(fakeUser.id);
return t.rollback();
});
});
});
});
});
});
});
});
});
});
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.hasOne(User);
await sequelize.sync({ force: true });
const fakeUser = await User.create({ username: 'foo' });
const user = await User.create({ username: 'foo' });
const group = await Group.create({ name: 'bar' });
const t = await sequelize.transaction();
await group.setUser(user, { transaction: t });
const groups = await Group.findAll();
const associatedUser = await groups[0].getUser();
expect(associatedUser).to.be.null;
const groups0 = await Group.findAll({ transaction: t });
const associatedUser0 = await groups0[0].getUser({ transaction: t });
expect(associatedUser0).not.to.be.null;
expect(associatedUser0.id).to.equal(user.id);
expect(associatedUser0.id).not.to.equal(fakeUser.id);
await t.rollback();
});
}
it('should be able to handle a where object that\'s a first class citizen.', function() {
it('should be able to handle a where object that\'s a first class citizen.', async function() {
const User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING, status: Sequelize.STRING });
User.hasOne(Task);
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task', status: 'inactive' }).then(task => {
return user.setTaskXYZ(task).then(() => {
return user.getTaskXYZ({ where: { status: 'active' } }).then(task => {
expect(task).to.be.null;
});
});
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task', status: 'inactive' });
await user.setTaskXYZ(task);
const task0 = await user.getTaskXYZ({ where: { status: 'active' } });
expect(task0).to.be.null;
});
it('supports schemas', function() {
it('supports schemas', async function() {
const User = this.sequelize.define('User', { username: Support.Sequelize.STRING }).schema('admin'),
Group = this.sequelize.define('Group', { name: Support.Sequelize.STRING }).schema('admin');
Group.hasOne(User);
return Support.dropTestSchemas(this.sequelize).then(() => {
return this.sequelize.createSchema('admin');
}).then(() => {
return Group.sync({ force: true });
}).then(() => {
return User.sync({ force: true });
}).then(() => {
return Promise.all([
User.create({ username: 'foo' }),
User.create({ username: 'foo' }),
Group.create({ name: 'bar' })
]);
}).then(([fakeUser, user, group]) => {
return group.setUser(user).then(() => {
return Group.findAll().then(groups => {
return groups[0].getUser().then(associatedUser => {
expect(associatedUser).not.to.be.null;
expect(associatedUser.id).to.equal(user.id);
expect(associatedUser.id).not.to.equal(fakeUser.id);
});
});
});
}).then(() => {
return this.sequelize.dropSchema('admin').then(() => {
return this.sequelize.showAllSchemas().then(schemas => {
if (dialect === 'postgres' || dialect === 'mssql' || dialect === 'mariadb') {
expect(schemas).to.not.have.property('admin');
}
});
});
});
await Support.dropTestSchemas(this.sequelize);
await this.sequelize.createSchema('admin');
await Group.sync({ force: true });
await User.sync({ force: true });
const [fakeUser, user, group] = await Promise.all([
User.create({ username: 'foo' }),
User.create({ username: 'foo' }),
Group.create({ name: 'bar' })
]);
await group.setUser(user);
const groups = await Group.findAll();
const associatedUser = await groups[0].getUser();
expect(associatedUser).not.to.be.null;
expect(associatedUser.id).to.equal(user.id);
expect(associatedUser.id).not.to.equal(fakeUser.id);
await this.sequelize.dropSchema('admin');
const schemas = await this.sequelize.showAllSchemas();
if (dialect === 'postgres' || dialect === 'mssql' || dialect === 'mariadb') {
expect(schemas).to.not.have.property('admin');
}
});
});
describe('setAssociation', () => {
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.hasOne(User);
return sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Group.create({ name: 'bar' }).then(group => {
return sequelize.transaction().then(t => {
return group.setUser(user, { transaction: t }).then(() => {
return Group.findAll().then(groups => {
return groups[0].getUser().then(associatedUser => {
expect(associatedUser).to.be.null;
return t.rollback();
});
});
});
});
});
});
});
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const User = sequelize.define('User', { username: Support.Sequelize.STRING }),
Group = sequelize.define('Group', { name: Support.Sequelize.STRING });
Group.hasOne(User);
await sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
const group = await Group.create({ name: 'bar' });
const t = await sequelize.transaction();
await group.setUser(user, { transaction: t });
const groups = await Group.findAll();
const associatedUser = await groups[0].getUser();
expect(associatedUser).to.be.null;
await t.rollback();
});
}
it('can set an association with predefined primary keys', function() {
it('can set an association with predefined primary keys', async function() {
const User = this.sequelize.define('UserXYZZ', { userCoolIdTag: { type: Sequelize.INTEGER, primaryKey: true }, username: Sequelize.STRING }),
Task = this.sequelize.define('TaskXYZZ', { taskOrSomething: { type: Sequelize.INTEGER, primaryKey: true }, title: Sequelize.STRING });
User.hasOne(Task, { foreignKey: 'userCoolIdTag' });
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ userCoolIdTag: 1, username: 'foo' }).then(user => {
return Task.create({ taskOrSomething: 1, title: 'bar' }).then(task => {
return user.setTaskXYZZ(task).then(() => {
return user.getTaskXYZZ().then(task => {
expect(task).not.to.be.null;
return user.setTaskXYZZ(null).then(() => {
return user.getTaskXYZZ().then(_task => {
expect(_task).to.be.null;
});
});
});
});
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ userCoolIdTag: 1, username: 'foo' });
const task = await Task.create({ taskOrSomething: 1, title: 'bar' });
await user.setTaskXYZZ(task);
const task0 = await user.getTaskXYZZ();
expect(task0).not.to.be.null;
await user.setTaskXYZZ(null);
const _task = await user.getTaskXYZZ();
expect(_task).to.be.null;
});
it('clears the association if null is passed', function() {
it('clears the association if null is passed', async function() {
const User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING });
User.hasOne(Task);
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return user.setTaskXYZ(task).then(() => {
return user.getTaskXYZ().then(task => {
expect(task).not.to.equal(null);
return user.setTaskXYZ(null).then(() => {
return user.getTaskXYZ().then(task => {
expect(task).to.equal(null);
});
});
});
});
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await user.setTaskXYZ(task);
const task1 = await user.getTaskXYZ();
expect(task1).not.to.equal(null);
await user.setTaskXYZ(null);
const task0 = await user.getTaskXYZ();
expect(task0).to.equal(null);
});
it('should throw a ForeignKeyConstraintError if the associated record does not exist', function() {
it('should throw a ForeignKeyConstraintError if the associated record does not exist', async function() {
const User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING });
User.hasOne(Task);
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return expect(Task.create({ title: 'task', UserXYZId: 5 })).to.be.rejectedWith(Sequelize.ForeignKeyConstraintError).then(() => {
return Task.create({ title: 'task' }).then(task => {
return expect(Task.update({ title: 'taskUpdate', UserXYZId: 5 }, { where: { id: task.id } })).to.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
await expect(Task.create({ title: 'task', UserXYZId: 5 })).to.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
const task = await Task.create({ title: 'task' });
await expect(Task.update({ title: 'taskUpdate', UserXYZId: 5 }, { where: { id: task.id } })).to.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
});
it('supports passing the primary key instead of an object', function() {
it('supports passing the primary key instead of an object', async function() {
const User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING });
User.hasOne(Task);
return this.sequelize.sync({ force: true }).then(() => {
return User.create({}).then(user => {
return Task.create({ id: 19, title: 'task it!' }).then(task => {
return user.setTaskXYZ(task.id).then(() => {
return user.getTaskXYZ().then(task => {
expect(task.title).to.equal('task it!');
});
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({});
const task = await Task.create({ id: 19, title: 'task it!' });
await user.setTaskXYZ(task.id);
const task0 = await user.getTaskXYZ();
expect(task0.title).to.equal('task it!');
});
it('supports updating with a primary key instead of an object', function() {
it('supports updating with a primary key instead of an object', async function() {
const User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING });
User.hasOne(Task);
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
User.create({ id: 1, username: 'foo' }),
Task.create({ id: 20, title: 'bar' })
]);
})
.then(([user, task]) => {
return user.setTaskXYZ(task.id)
.then(() => user.getTaskXYZ())
.then(task => {
expect(task).not.to.be.null;
return Promise.all([
user,
Task.create({ id: 2, title: 'bar2' })
]);
});
})
.then(([user, task2]) => {
return user.setTaskXYZ(task2.id)
.then(() => user.getTaskXYZ())
.then(task => {
expect(task).not.to.be.null;
});
});
await this.sequelize.sync({ force: true });
const [user0, task1] = await Promise.all([
User.create({ id: 1, username: 'foo' }),
Task.create({ id: 20, title: 'bar' })
]);
await user0.setTaskXYZ(task1.id);
const task0 = await user0.getTaskXYZ();
expect(task0).not.to.be.null;
const [user, task2] = await Promise.all([
user0,
Task.create({ id: 2, title: 'bar2' })
]);
await user.setTaskXYZ(task2.id);
const task = await user.getTaskXYZ();
expect(task).not.to.be.null;
});
it('supports setting same association twice', function() {
it('supports setting same association twice', async function() {
const Home = this.sequelize.define('home', {}),
User = this.sequelize.define('user');
User.hasOne(Home);
const ctx = {};
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
Home.create(),
User.create()
]);
}).then(([home, user]) => {
ctx.home = home;
ctx.user = user;
return user.setHome(home);
}).then(() => {
return ctx.user.setHome(ctx.home);
}).then(() => {
return expect(ctx.user.getHome()).to.eventually.have.property('id', ctx.home.get('id'));
});
await this.sequelize.sync({ force: true });
const [home, user] = await Promise.all([
Home.create(),
User.create()
]);
await user.setHome(home);
await user.setHome(home);
await expect(user.getHome()).to.eventually.have.property('id', home.get('id'));
});
});
describe('createAssociation', () => {
it('creates an associated model instance', function() {
it('creates an associated model instance', async function() {
const User = this.sequelize.define('User', { username: Sequelize.STRING }),
Task = this.sequelize.define('Task', { title: Sequelize.STRING });
User.hasOne(Task);
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'bob' }).then(user => {
return user.createTask({ title: 'task' }).then(() => {
return user.getTask().then(task => {
expect(task).not.to.be.null;
expect(task.title).to.equal('task');
});
});
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'bob' });
await user.createTask({ title: 'task' });
const task = await user.getTask();
expect(task).not.to.be.null;
expect(task.title).to.equal('task');
});
if (current.dialect.supports.transactions) {
it('supports transactions', function() {
return Support.prepareTransactionTest(this.sequelize).then(sequelize => {
const User = sequelize.define('User', { username: Sequelize.STRING }),
Group = sequelize.define('Group', { name: Sequelize.STRING });
User.hasOne(Group);
return sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'bob' }).then(user => {
return sequelize.transaction().then(t => {
return user.createGroup({ name: 'testgroup' }, { transaction: t }).then(() => {
return User.findAll().then(users => {
return users[0].getGroup().then(group => {
expect(group).to.be.null;
return User.findAll({ transaction: t }).then(users => {
return users[0].getGroup({ transaction: t }).then(group => {
expect(group).to.be.not.null;
return t.rollback();
});
});
});
});
});
});
});
});
});
it('supports transactions', async function() {
const sequelize = await Support.prepareTransactionTest(this.sequelize);
const User = sequelize.define('User', { username: Sequelize.STRING }),
Group = sequelize.define('Group', { name: Sequelize.STRING });
User.hasOne(Group);
await sequelize.sync({ force: true });
const user = await User.create({ username: 'bob' });
const t = await sequelize.transaction();
await user.createGroup({ name: 'testgroup' }, { transaction: t });
const users = await User.findAll();
const group = await users[0].getGroup();
expect(group).to.be.null;
const users0 = await User.findAll({ transaction: t });
const group0 = await users0[0].getGroup({ transaction: t });
expect(group0).to.be.not.null;
await t.rollback();
});
}
......@@ -403,7 +321,7 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
expect(User.rawAttributes.AccountId.field).to.equal('AccountId');
});
it('should support specifying the field of a foreign key', function() {
it('should support specifying the field of a foreign key', async function() {
const User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING, gender: Sequelize.STRING }),
Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING, status: Sequelize.STRING });
......@@ -416,223 +334,176 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
expect(User.rawAttributes.taskId).to.exist;
expect(User.rawAttributes.taskId.field).to.equal('task_id');
return Task.sync({ force: true }).then(() => {
// Can't use Promise.all cause of foreign key references
return User.sync({ force: true });
}).then(() => {
return Promise.all([
User.create({ username: 'foo', gender: 'male' }),
Task.create({ title: 'task', status: 'inactive' })
]);
}).then(([user, task]) => {
return task.setUserXYZ(user).then(() => {
return task.getUserXYZ();
});
}).then(user => {
// the sql query should correctly look at task_id instead of taskId
expect(user).to.not.be.null;
return Task.findOne({
where: { title: 'task' },
include: [User]
});
}).then(task => {
expect(task.UserXYZ).to.exist;
await Task.sync({ force: true });
await User.sync({ force: true });
const [user0, task0] = await Promise.all([
User.create({ username: 'foo', gender: 'male' }),
Task.create({ title: 'task', status: 'inactive' })
]);
await task0.setUserXYZ(user0);
const user = await task0.getUserXYZ();
// the sql query should correctly look at task_id instead of taskId
expect(user).to.not.be.null;
const task = await Task.findOne({
where: { title: 'task' },
include: [User]
});
expect(task.UserXYZ).to.exist;
});
});
describe('foreign key constraints', () => {
it('are enabled by default', function() {
it('are enabled by default', async function() {
const Task = this.sequelize.define('Task', { title: Sequelize.STRING }),
User = this.sequelize.define('User', { username: Sequelize.STRING });
User.hasOne(Task); // defaults to set NULL
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return user.setTask(task).then(() => {
return user.destroy().then(() => {
return task.reload().then(() => {
expect(task.UserId).to.equal(null);
});
});
});
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await user.setTask(task);
await user.destroy();
await task.reload();
expect(task.UserId).to.equal(null);
});
it('sets to CASCADE if allowNull: false', function() {
it('sets to CASCADE if allowNull: false', async function() {
const Task = this.sequelize.define('Task', { title: Sequelize.STRING }),
User = this.sequelize.define('User', { username: Sequelize.STRING });
User.hasOne(Task, { foreignKey: { allowNull: false } }); // defaults to CASCADE
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task', UserId: user.id }).then(() => {
return user.destroy().then(() => {
return Task.findAll();
});
});
}).then(tasks => {
expect(tasks).to.be.empty;
});
});
await this.sequelize.sync({ force: true });
const user = await User.create({ username: 'foo' });
await Task.create({ title: 'task', UserId: user.id });
await user.destroy();
const tasks = await Task.findAll();
expect(tasks).to.be.empty;
});
it('should be possible to disable them', function() {
it('should be possible to disable them', async function() {
const Task = this.sequelize.define('Task', { title: Sequelize.STRING }),
User = this.sequelize.define('User', { username: Sequelize.STRING });
User.hasOne(Task, { constraints: false });
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return user.setTask(task).then(() => {
return user.destroy().then(() => {
return task.reload().then(() => {
expect(task.UserId).to.equal(user.id);
});
});
});
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await user.setTask(task);
await user.destroy();
await task.reload();
expect(task.UserId).to.equal(user.id);
});
it('can cascade deletes', function() {
it('can cascade deletes', async function() {
const Task = this.sequelize.define('Task', { title: Sequelize.STRING }),
User = this.sequelize.define('User', { username: Sequelize.STRING });
User.hasOne(Task, { onDelete: 'cascade' });
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return user.setTask(task).then(() => {
return user.destroy().then(() => {
return Task.findAll().then(tasks => {
expect(tasks).to.have.length(0);
});
});
});
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await user.setTask(task);
await user.destroy();
const tasks = await Task.findAll();
expect(tasks).to.have.length(0);
});
it('works when cascading a delete with hooks but there is no associate (i.e. "has zero")', function() {
it('works when cascading a delete with hooks but there is no associate (i.e. "has zero")', async function() {
const Task = this.sequelize.define('Task', { title: Sequelize.STRING }),
User = this.sequelize.define('User', { username: Sequelize.STRING });
User.hasOne(Task, { onDelete: 'cascade', hooks: true });
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return user.destroy();
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ username: 'foo' });
await user.destroy();
});
// NOTE: mssql does not support changing an autoincrement primary key
if (Support.getTestDialect() !== 'mssql') {
it('can cascade updates', function() {
it('can cascade updates', async function() {
const Task = this.sequelize.define('Task', { title: Sequelize.STRING }),
User = this.sequelize.define('User', { username: Sequelize.STRING });
User.hasOne(Task, { onUpdate: 'cascade' });
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return user.setTask(task).then(() => {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
return user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id }).then(() => {
return Task.findAll().then(tasks => {
expect(tasks).to.have.length(1);
expect(tasks[0].UserId).to.equal(999);
});
});
});
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await user.setTask(task);
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
await user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id });
const tasks = await Task.findAll();
expect(tasks).to.have.length(1);
expect(tasks[0].UserId).to.equal(999);
});
}
if (current.dialect.supports.constraints.restrict) {
it('can restrict deletes', function() {
it('can restrict deletes', async function() {
const Task = this.sequelize.define('Task', { title: Sequelize.STRING }),
User = this.sequelize.define('User', { username: Sequelize.STRING });
User.hasOne(Task, { onDelete: 'restrict' });
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return user.setTask(task).then(() => {
return expect(user.destroy()).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError).then(() => {
return Task.findAll().then(tasks => {
expect(tasks).to.have.length(1);
});
});
});
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await user.setTask(task);
await expect(user.destroy()).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
const tasks = await Task.findAll();
expect(tasks).to.have.length(1);
});
it('can restrict updates', function() {
it('can restrict updates', async function() {
const Task = this.sequelize.define('Task', { title: Sequelize.STRING }),
User = this.sequelize.define('User', { username: Sequelize.STRING });
User.hasOne(Task, { onUpdate: 'restrict' });
return User.sync({ force: true }).then(() => {
return Task.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(user => {
return Task.create({ title: 'task' }).then(task => {
return user.setTask(task).then(() => {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
return expect(
user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id })
).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError).then(() => {
// Should fail due to FK restriction
return Task.findAll().then(tasks => {
expect(tasks).to.have.length(1);
});
});
});
});
});
});
});
await User.sync({ force: true });
await Task.sync({ force: true });
const user = await User.create({ username: 'foo' });
const task = await Task.create({ title: 'task' });
await user.setTask(task);
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
const tableName = user.sequelize.getQueryInterface().queryGenerator.addSchema(user.constructor);
await expect(
user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id })
).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
// Should fail due to FK restriction
const tasks = await Task.findAll();
expect(tasks).to.have.length(1);
});
}
......@@ -640,7 +511,7 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
});
describe('association column', () => {
it('has correct type for non-id primary keys with non-integer type', function() {
it('has correct type for non-id primary keys with non-integer type', async function() {
const User = this.sequelize.define('UserPKBT', {
username: {
type: Sequelize.STRING
......@@ -656,12 +527,11 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
Group.hasOne(User);
return this.sequelize.sync({ force: true }).then(() => {
expect(User.rawAttributes.GroupPKBTName.type).to.an.instanceof(Sequelize.STRING);
});
await this.sequelize.sync({ force: true });
expect(User.rawAttributes.GroupPKBTName.type).to.an.instanceof(Sequelize.STRING);
});
it('should support a non-primary key as the association column on a target with custom primary key', function() {
it('should support a non-primary key as the association column on a target with custom primary key', async function() {
const User = this.sequelize.define('User', {
user_name: {
unique: true,
......@@ -676,22 +546,16 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
User.hasOne(Task, { foreignKey: 'username', sourceKey: 'user_name' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ user_name: 'bob' }).then(newUser => {
return Task.create({ title: 'some task' }).then(newTask => {
return newUser.setTask(newTask).then(() => {
return User.findOne({ where: { user_name: 'bob' } }).then(foundUser => {
return foundUser.getTask().then(foundTask => {
expect(foundTask.title).to.equal('some task');
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const newUser = await User.create({ user_name: 'bob' });
const newTask = await Task.create({ title: 'some task' });
await newUser.setTask(newTask);
const foundUser = await User.findOne({ where: { user_name: 'bob' } });
const foundTask = await foundUser.getTask();
expect(foundTask.title).to.equal('some task');
});
it('should support a non-primary unique key as the association column', function() {
it('should support a non-primary unique key as the association column', async function() {
const User = this.sequelize.define('User', {
username: {
type: Sequelize.STRING,
......@@ -706,22 +570,16 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
User.hasOne(Task, { foreignKey: 'username', sourceKey: 'username' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'bob' }).then(newUser => {
return Task.create({ title: 'some task' }).then(newTask => {
return newUser.setTask(newTask).then(() => {
return User.findOne({ where: { username: 'bob' } }).then(foundUser => {
return foundUser.getTask().then(foundTask => {
expect(foundTask.title).to.equal('some task');
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const newUser = await User.create({ username: 'bob' });
const newTask = await Task.create({ title: 'some task' });
await newUser.setTask(newTask);
const foundUser = await User.findOne({ where: { username: 'bob' } });
const foundTask = await foundUser.getTask();
expect(foundTask.title).to.equal('some task');
});
it('should support a non-primary unique key as the association column with a field option', function() {
it('should support a non-primary unique key as the association column with a field option', async function() {
const User = this.sequelize.define('User', {
username: {
type: Sequelize.STRING,
......@@ -737,37 +595,30 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
User.hasOne(Task, { foreignKey: 'username', sourceKey: 'username' });
return this.sequelize.sync({ force: true }).then(() => {
return User.create({ username: 'bob' }).then(newUser => {
return Task.create({ title: 'some task' }).then(newTask => {
return newUser.setTask(newTask).then(() => {
return User.findOne({ where: { username: 'bob' } }).then(foundUser => {
return foundUser.getTask().then(foundTask => {
expect(foundTask.title).to.equal('some task');
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
const newUser = await User.create({ username: 'bob' });
const newTask = await Task.create({ title: 'some task' });
await newUser.setTask(newTask);
const foundUser = await User.findOne({ where: { username: 'bob' } });
const foundTask = await foundUser.getTask();
expect(foundTask.title).to.equal('some task');
});
});
describe('Association options', () => {
it('can specify data type for autogenerated relational keys', function() {
it('can specify data type for autogenerated relational keys', async function() {
const User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }),
dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT, Sequelize.STRING],
Tasks = {};
return Promise.all(dataTypes.map(dataType => {
await Promise.all(dataTypes.map(async dataType => {
const tableName = `TaskXYZ_${dataType.key}`;
Tasks[dataType] = this.sequelize.define(tableName, { title: Sequelize.STRING });
User.hasOne(Tasks[dataType], { foreignKey: 'userId', keyType: dataType, constraints: false });
return Tasks[dataType].sync({ force: true }).then(() => {
expect(Tasks[dataType].rawAttributes.userId.type).to.be.an.instanceof(dataType);
});
await Tasks[dataType].sync({ force: true });
expect(Tasks[dataType].rawAttributes.userId.type).to.be.an.instanceof(dataType);
}));
});
......@@ -893,53 +744,53 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
});
});
it('should load with an alias', function() {
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
}).then(([individual, hat]) => {
return individual.setPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ model: this.Hat, as: 'personwearinghat' }]
});
}).then(individual => {
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
}).then(() => {
return this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{
model: this.Hat,
as: { singular: 'personwearinghat' }
}]
});
}).then(individual => {
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
it('should load with an alias', async function() {
await this.sequelize.sync({ force: true });
const [individual1, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
await individual1.setPersonwearinghat(hat);
const individual0 = await this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ model: this.Hat, as: 'personwearinghat' }]
});
expect(individual0.name).to.equal('Foo Bar');
expect(individual0.personwearinghat.name).to.equal('Baz');
const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{
model: this.Hat,
as: { singular: 'personwearinghat' }
}]
});
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
});
it('should load all', function() {
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
}).then(([individual, hat]) => {
return individual.setPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ all: true }]
});
}).then(individual => {
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
it('should load all', async function() {
await this.sequelize.sync({ force: true });
const [individual0, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' })
]);
await individual0.setPersonwearinghat(hat);
const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' },
include: [{ all: true }]
});
expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz');
});
});
});
......@@ -6,7 +6,7 @@ const chai = require('chai'),
DataTypes = require('../../../lib/data-types');
describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
it('can filter through belongsTo', function() {
it('can filter through belongsTo', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
Project = this.sequelize.define('Project', { title: DataTypes.STRING });
......@@ -17,55 +17,54 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
Task.belongsTo(Project);
Project.hasMany(Task);
return this.sequelize.sync({ force: true }).then(() => {
return User.bulkCreate([{
username: 'leia'
}, {
username: 'vader'
}]).then(() => {
return Project.bulkCreate([{
UserId: 1,
title: 'republic'
}, {
UserId: 2,
title: 'empire'
}]).then(() => {
return Task.bulkCreate([{
ProjectId: 1,
title: 'fight empire'
}, {
ProjectId: 1,
title: 'stablish republic'
}, {
ProjectId: 2,
title: 'destroy rebel alliance'
}, {
ProjectId: 2,
title: 'rule everything'
}]).then(() => {
return Task.findAll({
include: [
{
model: Project,
include: [
{ model: User, where: { username: 'leia' } }
],
required: true
}
]
}).then(tasks => {
expect(tasks.length).to.be.equal(2);
expect(tasks[0].title).to.be.equal('fight empire');
expect(tasks[1].title).to.be.equal('stablish republic');
});
});
});
});
await this.sequelize.sync({ force: true });
await User.bulkCreate([{
username: 'leia'
}, {
username: 'vader'
}]);
await Project.bulkCreate([{
UserId: 1,
title: 'republic'
}, {
UserId: 2,
title: 'empire'
}]);
await Task.bulkCreate([{
ProjectId: 1,
title: 'fight empire'
}, {
ProjectId: 1,
title: 'stablish republic'
}, {
ProjectId: 2,
title: 'destroy rebel alliance'
}, {
ProjectId: 2,
title: 'rule everything'
}]);
const tasks = await Task.findAll({
include: [
{
model: Project,
include: [
{ model: User, where: { username: 'leia' } }
],
required: true
}
]
});
expect(tasks.length).to.be.equal(2);
expect(tasks[0].title).to.be.equal('fight empire');
expect(tasks[1].title).to.be.equal('stablish republic');
});
it('avoids duplicated tables in query', function() {
it('avoids duplicated tables in query', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
Project = this.sequelize.define('Project', { title: DataTypes.STRING });
......@@ -76,57 +75,57 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
Task.belongsTo(Project);
Project.hasMany(Task);
return this.sequelize.sync({ force: true }).then(() => {
return User.bulkCreate([{
username: 'leia'
}, {
username: 'vader'
}]).then(() => {
return Project.bulkCreate([{
UserId: 1,
title: 'republic'
}, {
UserId: 2,
title: 'empire'
}]).then(() => {
return Task.bulkCreate([{
ProjectId: 1,
title: 'fight empire'
}, {
ProjectId: 1,
title: 'stablish republic'
}, {
ProjectId: 2,
title: 'destroy rebel alliance'
}, {
ProjectId: 2,
title: 'rule everything'
}]).then(() => {
return Task.findAll({
include: [
{
model: Project,
include: [
{ model: User, where: {
username: 'leia',
id: 1
} }
],
required: true
}
]
}).then(tasks => {
expect(tasks.length).to.be.equal(2);
expect(tasks[0].title).to.be.equal('fight empire');
expect(tasks[1].title).to.be.equal('stablish republic');
});
});
});
});
await this.sequelize.sync({ force: true });
await User.bulkCreate([{
username: 'leia'
}, {
username: 'vader'
}]);
await Project.bulkCreate([{
UserId: 1,
title: 'republic'
}, {
UserId: 2,
title: 'empire'
}]);
await Task.bulkCreate([{
ProjectId: 1,
title: 'fight empire'
}, {
ProjectId: 1,
title: 'stablish republic'
}, {
ProjectId: 2,
title: 'destroy rebel alliance'
}, {
ProjectId: 2,
title: 'rule everything'
}]);
const tasks = await Task.findAll({
include: [
{
model: Project,
include: [
{ model: User, where: {
username: 'leia',
id: 1
} }
],
required: true
}
]
});
expect(tasks.length).to.be.equal(2);
expect(tasks[0].title).to.be.equal('fight empire');
expect(tasks[1].title).to.be.equal('stablish republic');
});
it('can filter through hasMany', function() {
it('can filter through hasMany', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
Task = this.sequelize.define('Task', { title: DataTypes.STRING }),
Project = this.sequelize.define('Project', { title: DataTypes.STRING });
......@@ -137,92 +136,87 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
Task.belongsTo(Project);
Project.hasMany(Task);
return this.sequelize.sync({ force: true }).then(() => {
return User.bulkCreate([{
username: 'leia'
}, {
username: 'vader'
}]).then(() => {
return Project.bulkCreate([{
UserId: 1,
title: 'republic'
}, {
UserId: 2,
title: 'empire'
}]).then(() => {
return Task.bulkCreate([{
ProjectId: 1,
title: 'fight empire'
}, {
ProjectId: 1,
title: 'stablish republic'
}, {
ProjectId: 2,
title: 'destroy rebel alliance'
}, {
ProjectId: 2,
title: 'rule everything'
}]).then(() => {
return User.findAll({
include: [
{
model: Project,
include: [
{ model: Task, where: { title: 'fight empire' } }
],
required: true
}
]
}).then(users => {
expect(users.length).to.be.equal(1);
expect(users[0].username).to.be.equal('leia');
});
});
});
});
await this.sequelize.sync({ force: true });
await User.bulkCreate([{
username: 'leia'
}, {
username: 'vader'
}]);
await Project.bulkCreate([{
UserId: 1,
title: 'republic'
}, {
UserId: 2,
title: 'empire'
}]);
await Task.bulkCreate([{
ProjectId: 1,
title: 'fight empire'
}, {
ProjectId: 1,
title: 'stablish republic'
}, {
ProjectId: 2,
title: 'destroy rebel alliance'
}, {
ProjectId: 2,
title: 'rule everything'
}]);
const users = await User.findAll({
include: [
{
model: Project,
include: [
{ model: Task, where: { title: 'fight empire' } }
],
required: true
}
]
});
expect(users.length).to.be.equal(1);
expect(users[0].username).to.be.equal('leia');
});
it('can filter through hasMany connector', function() {
it('can filter through hasMany connector', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }),
Project = this.sequelize.define('Project', { title: DataTypes.STRING });
Project.belongsToMany(User, { through: 'user_project' });
User.belongsToMany(Project, { through: 'user_project' });
return this.sequelize.sync({ force: true }).then(() => {
return User.bulkCreate([{
username: 'leia'
}, {
username: 'vader'
}]).then(() => {
return Project.bulkCreate([{
title: 'republic'
}, {
title: 'empire'
}]).then(() => {
return User.findByPk(1).then(user => {
return Project.findByPk(1).then(project => {
return user.setProjects([project]).then(() => {
return User.findByPk(2).then(user => {
return Project.findByPk(2).then(project => {
return user.setProjects([project]).then(() => {
return User.findAll({
include: [
{ model: Project, where: { title: 'republic' } }
]
}).then(users => {
expect(users.length).to.be.equal(1);
expect(users[0].username).to.be.equal('leia');
});
});
});
});
});
});
});
});
});
await this.sequelize.sync({ force: true });
await User.bulkCreate([{
username: 'leia'
}, {
username: 'vader'
}]);
await Project.bulkCreate([{
title: 'republic'
}, {
title: 'empire'
}]);
const user = await User.findByPk(1);
const project = await Project.findByPk(1);
await user.setProjects([project]);
const user0 = await User.findByPk(2);
const project0 = await Project.findByPk(2);
await user0.setProjects([project0]);
const users = await User.findAll({
include: [
{ model: Project, where: { title: 'republic' } }
]
});
expect(users.length).to.be.equal(1);
expect(users[0].username).to.be.equal('leia');
});
});
......@@ -96,164 +96,158 @@ describe(Support.getTestDialectTeaser('associations'), () => {
});
describe('1:1', () => {
it('should create, find and include associations with scope values', function() {
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([this.Post.create(), this.Comment.create({
title: 'I am a comment'
}), this.Comment.create({
title: 'I am a main comment',
isMain: true
})]);
}).then(([post]) => {
this.post = post;
return post.createComment({
title: 'I am a post comment'
});
}).then(comment => {
expect(comment.get('commentable')).to.equal('post');
expect(comment.get('isMain')).to.be.false;
return this.Post.scope('withMainComment').findByPk(this.post.get('id'));
}).then(post => {
expect(post.mainComment).to.be.null;
return post.createMainComment({
title: 'I am a main post comment'
});
}).then(mainComment => {
this.mainComment = mainComment;
expect(mainComment.get('commentable')).to.equal('post');
expect(mainComment.get('isMain')).to.be.true;
return this.Post.scope('withMainComment').findByPk(this.post.id);
}).then(post => {
expect(post.mainComment.get('id')).to.equal(this.mainComment.get('id'));
return post.getMainComment();
}).then(mainComment => {
expect(mainComment.get('commentable')).to.equal('post');
expect(mainComment.get('isMain')).to.be.true;
return this.Comment.create({
title: 'I am a future main comment'
});
}).then(comment => {
return this.post.setMainComment(comment);
}).then(() => {
return this.post.getMainComment();
}).then(mainComment => {
expect(mainComment.get('commentable')).to.equal('post');
expect(mainComment.get('isMain')).to.be.true;
expect(mainComment.get('title')).to.equal('I am a future main comment');
it('should create, find and include associations with scope values', async function() {
await this.sequelize.sync({ force: true });
const [post1] = await Promise.all([this.Post.create(), this.Comment.create({
title: 'I am a comment'
}), this.Comment.create({
title: 'I am a main comment',
isMain: true
})]);
this.post = post1;
const comment0 = await post1.createComment({
title: 'I am a post comment'
});
expect(comment0.get('commentable')).to.equal('post');
expect(comment0.get('isMain')).to.be.false;
const post0 = await this.Post.scope('withMainComment').findByPk(this.post.get('id'));
expect(post0.mainComment).to.be.null;
const mainComment1 = await post0.createMainComment({
title: 'I am a main post comment'
});
this.mainComment = mainComment1;
expect(mainComment1.get('commentable')).to.equal('post');
expect(mainComment1.get('isMain')).to.be.true;
const post = await this.Post.scope('withMainComment').findByPk(this.post.id);
expect(post.mainComment.get('id')).to.equal(this.mainComment.get('id'));
const mainComment0 = await post.getMainComment();
expect(mainComment0.get('commentable')).to.equal('post');
expect(mainComment0.get('isMain')).to.be.true;
const comment = await this.Comment.create({
title: 'I am a future main comment'
});
await this.post.setMainComment(comment);
const mainComment = await this.post.getMainComment();
expect(mainComment.get('commentable')).to.equal('post');
expect(mainComment.get('isMain')).to.be.true;
expect(mainComment.get('title')).to.equal('I am a future main comment');
});
it('should create included association with scope values', function() {
return this.sequelize.sync({ force: true }).then(() => {
return this.Post.create({
mainComment: {
title: 'I am a main comment created with a post'
}
}, {
include: [{ model: this.Comment, as: 'mainComment' }]
});
}).then(post => {
expect(post.mainComment.get('commentable')).to.equal('post');
expect(post.mainComment.get('isMain')).to.be.true;
return this.Post.scope('withMainComment').findByPk(post.id);
}).then(post => {
expect(post.mainComment.get('commentable')).to.equal('post');
expect(post.mainComment.get('isMain')).to.be.true;
it('should create included association with scope values', async function() {
await this.sequelize.sync({ force: true });
const post0 = await this.Post.create({
mainComment: {
title: 'I am a main comment created with a post'
}
}, {
include: [{ model: this.Comment, as: 'mainComment' }]
});
expect(post0.mainComment.get('commentable')).to.equal('post');
expect(post0.mainComment.get('isMain')).to.be.true;
const post = await this.Post.scope('withMainComment').findByPk(post0.id);
expect(post.mainComment.get('commentable')).to.equal('post');
expect(post.mainComment.get('isMain')).to.be.true;
});
});
describe('1:M', () => {
it('should create, find and include associations with scope values', function() {
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
this.Post.create(),
this.Image.create(),
this.Question.create(),
this.Comment.create({
title: 'I am a image comment'
}),
this.Comment.create({
title: 'I am a question comment'
})
]);
}).then(([post, image, question, commentA, commentB]) => {
this.post = post;
this.image = image;
this.question = question;
return Promise.all([post.createComment({
title: 'I am a post comment'
}), image.addComment(commentA), question.setComments([commentB])]);
}).then(() => {
return this.Comment.findAll();
}).then(comments => {
comments.forEach(comment => {
expect(comment.get('commentable')).to.be.ok;
});
expect(comments.map(comment => {
return comment.get('commentable');
}).sort()).to.deep.equal(['image', 'post', 'question']);
}).then(() => {
return Promise.all([
this.post.getComments(),
this.image.getComments(),
this.question.getComments()
]);
}).then(([postComments, imageComments, questionComments]) => {
expect(postComments.length).to.equal(1);
expect(postComments[0].get('title')).to.equal('I am a post comment');
expect(imageComments.length).to.equal(1);
expect(imageComments[0].get('title')).to.equal('I am a image comment');
expect(questionComments.length).to.equal(1);
expect(questionComments[0].get('title')).to.equal('I am a question comment');
return [postComments[0], imageComments[0], questionComments[0]];
}).then(([postComment, imageComment, questionComment]) => {
return Promise.all([postComment.getItem(), imageComment.getItem(), questionComment.getItem()]);
}).then(([post, image, question]) => {
expect(post).to.be.instanceof(this.Post);
expect(image).to.be.instanceof(this.Image);
expect(question).to.be.instanceof(this.Question);
}).then(() => {
return Promise.all([this.Post.findOne({
include: [this.Comment]
}), this.Image.findOne({
include: [this.Comment]
}), this.Question.findOne({
include: [this.Comment]
})]);
}).then(([post, image, question]) => {
expect(post.comments.length).to.equal(1);
expect(post.comments[0].get('title')).to.equal('I am a post comment');
expect(image.comments.length).to.equal(1);
expect(image.comments[0].get('title')).to.equal('I am a image comment');
expect(question.comments.length).to.equal(1);
expect(question.comments[0].get('title')).to.equal('I am a question comment');
it('should create, find and include associations with scope values', async function() {
await this.sequelize.sync({ force: true });
const [post1, image1, question1, commentA, commentB] = await Promise.all([
this.Post.create(),
this.Image.create(),
this.Question.create(),
this.Comment.create({
title: 'I am a image comment'
}),
this.Comment.create({
title: 'I am a question comment'
})
]);
this.post = post1;
this.image = image1;
this.question = question1;
await Promise.all([post1.createComment({
title: 'I am a post comment'
}), image1.addComment(commentA), question1.setComments([commentB])]);
const comments = await this.Comment.findAll();
comments.forEach(comment => {
expect(comment.get('commentable')).to.be.ok;
});
expect(comments.map(comment => {
return comment.get('commentable');
}).sort()).to.deep.equal(['image', 'post', 'question']);
const [postComments, imageComments, questionComments] = await Promise.all([
this.post.getComments(),
this.image.getComments(),
this.question.getComments()
]);
expect(postComments.length).to.equal(1);
expect(postComments[0].get('title')).to.equal('I am a post comment');
expect(imageComments.length).to.equal(1);
expect(imageComments[0].get('title')).to.equal('I am a image comment');
expect(questionComments.length).to.equal(1);
expect(questionComments[0].get('title')).to.equal('I am a question comment');
const [postComment, imageComment, questionComment] = [postComments[0], imageComments[0], questionComments[0]];
const [post0, image0, question0] = await Promise.all([postComment.getItem(), imageComment.getItem(), questionComment.getItem()]);
expect(post0).to.be.instanceof(this.Post);
expect(image0).to.be.instanceof(this.Image);
expect(question0).to.be.instanceof(this.Question);
const [post, image, question] = await Promise.all([this.Post.findOne({
include: [this.Comment]
}), this.Image.findOne({
include: [this.Comment]
}), this.Question.findOne({
include: [this.Comment]
})]);
expect(post.comments.length).to.equal(1);
expect(post.comments[0].get('title')).to.equal('I am a post comment');
expect(image.comments.length).to.equal(1);
expect(image.comments[0].get('title')).to.equal('I am a image comment');
expect(question.comments.length).to.equal(1);
expect(question.comments[0].get('title')).to.equal('I am a question comment');
});
it('should make the same query if called multiple time (#4470)', function() {
it('should make the same query if called multiple time (#4470)', async function() {
const logs = [];
const logging = function(log) {
//removing 'executing(<uuid> || 'default'}) :' from logs
logs.push(log.substring(log.indexOf(':') + 1));
};
return this.sequelize.sync({ force: true }).then(() => {
return this.Post.create();
}).then(post => {
return post.createComment({
title: 'I am a post comment'
});
}).then(() => {
return this.Post.scope('withComments').findAll({
logging
});
}).then(() => {
return this.Post.scope('withComments').findAll({
logging
});
}).then(() => {
expect(logs[0]).to.equal(logs[1]);
await this.sequelize.sync({ force: true });
const post = await this.Post.create();
await post.createComment({
title: 'I am a post comment'
});
await this.Post.scope('withComments').findAll({
logging
});
await this.Post.scope('withComments').findAll({
logging
});
expect(logs[0]).to.equal(logs[1]);
});
it('should created included association with scope values', async function() {
await this.sequelize.sync({ force: true });
......@@ -275,34 +269,34 @@ describe(Support.getTestDialectTeaser('associations'), () => {
expect(comment.get('commentable')).to.equal('post');
}
});
it('should include associations with operator scope values', function() {
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([this.Post.create(), this.Comment.create({
title: 'I am a blue comment',
type: 'blue'
}), this.Comment.create({
title: 'I am a red comment',
type: 'red'
}), this.Comment.create({
title: 'I am a green comment',
type: 'green'
})]);
}).then(([post, commentA, commentB, commentC]) => {
this.post = post;
return post.addComments([commentA, commentB, commentC]);
}).then(() => {
return this.Post.findByPk(this.post.id, {
include: [{
model: this.Comment,
as: 'coloredComments'
}]
});
}).then(post => {
expect(post.coloredComments.length).to.equal(2);
for (const comment of post.coloredComments) {
expect(comment.type).to.match(/blue|green/);
}
it('should include associations with operator scope values', async function() {
await this.sequelize.sync({ force: true });
const [post0, commentA, commentB, commentC] = await Promise.all([this.Post.create(), this.Comment.create({
title: 'I am a blue comment',
type: 'blue'
}), this.Comment.create({
title: 'I am a red comment',
type: 'red'
}), this.Comment.create({
title: 'I am a green comment',
type: 'green'
})]);
this.post = post0;
await post0.addComments([commentA, commentB, commentC]);
const post = await this.Post.findByPk(this.post.id, {
include: [{
model: this.Comment,
as: 'coloredComments'
}]
});
expect(post.coloredComments.length).to.equal(2);
for (const comment of post.coloredComments) {
expect(comment.type).to.match(/blue|green/);
}
});
});
......@@ -321,96 +315,95 @@ describe(Support.getTestDialectTeaser('associations'), () => {
this.Post.belongsToMany(this.Tag, { as: 'tags', through: this.PostTag, scope: { type: 'tag' } });
});
it('should create, find and include associations with scope values', function() {
return Promise.all([this.Post.sync({ force: true }), this.Tag.sync({ force: true })]).then(() => {
return this.PostTag.sync({ force: true });
}).then(() => {
return Promise.all([
this.Post.create(),
this.Post.create(),
this.Post.create(),
this.Tag.create({ type: 'category' }),
this.Tag.create({ type: 'category' }),
this.Tag.create({ type: 'tag' }),
this.Tag.create({ type: 'tag' })
]);
}).then(([postA, postB, postC, categoryA, categoryB, tagA, tagB]) => {
this.postA = postA;
this.postB = postB;
this.postC = postC;
return Promise.all([
postA.addCategory(categoryA),
postB.setCategories([categoryB]),
postC.createCategory(),
postA.createTag(),
postB.addTag(tagA),
postC.setTags([tagB])
]);
}).then(() => {
return Promise.all([
this.postA.getCategories(),
this.postA.getTags(),
this.postB.getCategories(),
this.postB.getTags(),
this.postC.getCategories(),
this.postC.getTags()
]);
}).then(([postACategories, postATags, postBCategories, postBTags, postCCategories, postCTags]) => {
expect(postACategories.length).to.equal(1);
expect(postATags.length).to.equal(1);
expect(postBCategories.length).to.equal(1);
expect(postBTags.length).to.equal(1);
expect(postCCategories.length).to.equal(1);
expect(postCTags.length).to.equal(1);
expect(postACategories[0].get('type')).to.equal('category');
expect(postATags[0].get('type')).to.equal('tag');
expect(postBCategories[0].get('type')).to.equal('category');
expect(postBTags[0].get('type')).to.equal('tag');
expect(postCCategories[0].get('type')).to.equal('category');
expect(postCTags[0].get('type')).to.equal('tag');
}).then(() => {
return Promise.all([this.Post.findOne({
where: {
id: this.postA.get('id')
},
include: [
{ model: this.Tag, as: 'tags' },
{ model: this.Tag, as: 'categories' }
]
}), this.Post.findOne({
where: {
id: this.postB.get('id')
},
include: [
{ model: this.Tag, as: 'tags' },
{ model: this.Tag, as: 'categories' }
]
}), this.Post.findOne({
where: {
id: this.postC.get('id')
},
include: [
{ model: this.Tag, as: 'tags' },
{ model: this.Tag, as: 'categories' }
]
})]);
}).then(([postA, postB, postC]) => {
expect(postA.get('categories').length).to.equal(1);
expect(postA.get('tags').length).to.equal(1);
expect(postB.get('categories').length).to.equal(1);
expect(postB.get('tags').length).to.equal(1);
expect(postC.get('categories').length).to.equal(1);
expect(postC.get('tags').length).to.equal(1);
expect(postA.get('categories')[0].get('type')).to.equal('category');
expect(postA.get('tags')[0].get('type')).to.equal('tag');
expect(postB.get('categories')[0].get('type')).to.equal('category');
expect(postB.get('tags')[0].get('type')).to.equal('tag');
expect(postC.get('categories')[0].get('type')).to.equal('category');
expect(postC.get('tags')[0].get('type')).to.equal('tag');
});
it('should create, find and include associations with scope values', async function() {
await Promise.all([this.Post.sync({ force: true }), this.Tag.sync({ force: true })]);
await this.PostTag.sync({ force: true });
const [postA0, postB0, postC0, categoryA, categoryB, tagA, tagB] = await Promise.all([
this.Post.create(),
this.Post.create(),
this.Post.create(),
this.Tag.create({ type: 'category' }),
this.Tag.create({ type: 'category' }),
this.Tag.create({ type: 'tag' }),
this.Tag.create({ type: 'tag' })
]);
this.postA = postA0;
this.postB = postB0;
this.postC = postC0;
await Promise.all([
postA0.addCategory(categoryA),
postB0.setCategories([categoryB]),
postC0.createCategory(),
postA0.createTag(),
postB0.addTag(tagA),
postC0.setTags([tagB])
]);
const [postACategories, postATags, postBCategories, postBTags, postCCategories, postCTags] = await Promise.all([
this.postA.getCategories(),
this.postA.getTags(),
this.postB.getCategories(),
this.postB.getTags(),
this.postC.getCategories(),
this.postC.getTags()
]);
expect(postACategories.length).to.equal(1);
expect(postATags.length).to.equal(1);
expect(postBCategories.length).to.equal(1);
expect(postBTags.length).to.equal(1);
expect(postCCategories.length).to.equal(1);
expect(postCTags.length).to.equal(1);
expect(postACategories[0].get('type')).to.equal('category');
expect(postATags[0].get('type')).to.equal('tag');
expect(postBCategories[0].get('type')).to.equal('category');
expect(postBTags[0].get('type')).to.equal('tag');
expect(postCCategories[0].get('type')).to.equal('category');
expect(postCTags[0].get('type')).to.equal('tag');
const [postA, postB, postC] = await Promise.all([this.Post.findOne({
where: {
id: this.postA.get('id')
},
include: [
{ model: this.Tag, as: 'tags' },
{ model: this.Tag, as: 'categories' }
]
}), this.Post.findOne({
where: {
id: this.postB.get('id')
},
include: [
{ model: this.Tag, as: 'tags' },
{ model: this.Tag, as: 'categories' }
]
}), this.Post.findOne({
where: {
id: this.postC.get('id')
},
include: [
{ model: this.Tag, as: 'tags' },
{ model: this.Tag, as: 'categories' }
]
})]);
expect(postA.get('categories').length).to.equal(1);
expect(postA.get('tags').length).to.equal(1);
expect(postB.get('categories').length).to.equal(1);
expect(postB.get('tags').length).to.equal(1);
expect(postC.get('categories').length).to.equal(1);
expect(postC.get('tags').length).to.equal(1);
expect(postA.get('categories')[0].get('type')).to.equal('category');
expect(postA.get('tags')[0].get('type')).to.equal('tag');
expect(postB.get('categories')[0].get('type')).to.equal('category');
expect(postB.get('tags')[0].get('type')).to.equal('tag');
expect(postC.get('categories')[0].get('type')).to.equal('category');
expect(postC.get('tags')[0].get('type')).to.equal('tag');
});
});
......@@ -502,80 +495,80 @@ describe(Support.getTestDialectTeaser('associations'), () => {
});
});
it('should create, find and include associations with scope values', function() {
return Promise.all([
it('should create, find and include associations with scope values', async function() {
await Promise.all([
this.Post.sync({ force: true }),
this.Image.sync({ force: true }),
this.Question.sync({ force: true }),
this.Tag.sync({ force: true })
]).then(() => {
return this.ItemTag.sync({ force: true });
}).then(() => {
return Promise.all([
this.Post.create(),
this.Image.create(),
this.Question.create(),
this.Tag.create({ name: 'tagA' }),
this.Tag.create({ name: 'tagB' }),
this.Tag.create({ name: 'tagC' })
]);
}).then(([post, image, question, tagA, tagB, tagC]) => {
this.post = post;
this.image = image;
this.question = question;
return Promise.all([post.setTags([tagA]).then(() => {
return Promise.all([post.createTag({ name: 'postTag' }), post.addTag(tagB)]);
}), image.setTags([tagB]).then(() => {
return Promise.all([image.createTag({ name: 'imageTag' }), image.addTag(tagC)]);
}), question.setTags([tagC]).then(() => {
return Promise.all([question.createTag({ name: 'questionTag' }), question.addTag(tagA)]);
})]);
}).then(() => {
return Promise.all([this.post.getTags(), this.image.getTags(), this.question.getTags()]).then(([postTags, imageTags, questionTags]) => {
expect(postTags.length).to.equal(3);
expect(imageTags.length).to.equal(3);
expect(questionTags.length).to.equal(3);
expect(postTags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['postTag', 'tagA', 'tagB']);
expect(imageTags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['imageTag', 'tagB', 'tagC']);
expect(questionTags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['questionTag', 'tagA', 'tagC']);
}).then(() => {
return Promise.all([this.Post.findOne({
where: {},
include: [this.Tag]
}), this.Image.findOne({
where: {},
include: [this.Tag]
}), this.Question.findOne({
where: {},
include: [this.Tag]
})]).then(([post, image, question]) => {
expect(post.tags.length).to.equal(3);
expect(image.tags.length).to.equal(3);
expect(question.tags.length).to.equal(3);
expect(post.tags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['postTag', 'tagA', 'tagB']);
expect(image.tags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['imageTag', 'tagB', 'tagC']);
expect(question.tags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['questionTag', 'tagA', 'tagC']);
});
});
});
]);
await this.ItemTag.sync({ force: true });
const [post0, image0, question0, tagA, tagB, tagC] = await Promise.all([
this.Post.create(),
this.Image.create(),
this.Question.create(),
this.Tag.create({ name: 'tagA' }),
this.Tag.create({ name: 'tagB' }),
this.Tag.create({ name: 'tagC' })
]);
this.post = post0;
this.image = image0;
this.question = question0;
await Promise.all([post0.setTags([tagA]).then(async () => {
return Promise.all([post0.createTag({ name: 'postTag' }), post0.addTag(tagB)]);
}), image0.setTags([tagB]).then(async () => {
return Promise.all([image0.createTag({ name: 'imageTag' }), image0.addTag(tagC)]);
}), question0.setTags([tagC]).then(async () => {
return Promise.all([question0.createTag({ name: 'questionTag' }), question0.addTag(tagA)]);
})]);
const [postTags, imageTags, questionTags] = await Promise.all([this.post.getTags(), this.image.getTags(), this.question.getTags()]);
expect(postTags.length).to.equal(3);
expect(imageTags.length).to.equal(3);
expect(questionTags.length).to.equal(3);
expect(postTags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['postTag', 'tagA', 'tagB']);
expect(imageTags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['imageTag', 'tagB', 'tagC']);
expect(questionTags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['questionTag', 'tagA', 'tagC']);
const [post, image, question] = await Promise.all([this.Post.findOne({
where: {},
include: [this.Tag]
}), this.Image.findOne({
where: {},
include: [this.Tag]
}), this.Question.findOne({
where: {},
include: [this.Tag]
})]);
expect(post.tags.length).to.equal(3);
expect(image.tags.length).to.equal(3);
expect(question.tags.length).to.equal(3);
expect(post.tags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['postTag', 'tagA', 'tagB']);
expect(image.tags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['imageTag', 'tagB', 'tagC']);
expect(question.tags.map(tag => {
return tag.name;
}).sort()).to.deep.equal(['questionTag', 'tagA', 'tagC']);
});
});
});
......
......@@ -6,7 +6,7 @@ const chai = require('chai'),
DataTypes = require('../../../lib/data-types');
describe(Support.getTestDialectTeaser('Self'), () => {
it('supports freezeTableName', function() {
it('supports freezeTableName', async function() {
const Group = this.sequelize.define('Group', {}, {
tableName: 'user_group',
timestamps: false,
......@@ -15,35 +15,35 @@ describe(Support.getTestDialectTeaser('Self'), () => {
});
Group.belongsTo(Group, { as: 'Parent', foreignKey: 'parent_id' });
return Group.sync({ force: true }).then(() => {
return Group.findAll({
include: [{
model: Group,
as: 'Parent'
}]
});
await Group.sync({ force: true });
await Group.findAll({
include: [{
model: Group,
as: 'Parent'
}]
});
});
it('can handle 1:m associations', function() {
it('can handle 1:m associations', async function() {
const Person = this.sequelize.define('Person', { name: DataTypes.STRING });
Person.hasMany(Person, { as: 'Children', foreignKey: 'parent_id' });
expect(Person.rawAttributes.parent_id).to.be.ok;
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
Person.create({ name: 'Mary' }),
Person.create({ name: 'John' }),
Person.create({ name: 'Chris' })
]);
}).then(([mary, john, chris]) => {
return mary.setChildren([john, chris]);
});
await this.sequelize.sync({ force: true });
const [mary, john, chris] = await Promise.all([
Person.create({ name: 'Mary' }),
Person.create({ name: 'John' }),
Person.create({ name: 'Chris' })
]);
await mary.setChildren([john, chris]);
});
it('can handle n:m associations', function() {
it('can handle n:m associations', async function() {
const Person = this.sequelize.define('Person', { name: DataTypes.STRING });
Person.belongsToMany(Person, { as: 'Parents', through: 'Family', foreignKey: 'ChildId', otherKey: 'PersonId' });
......@@ -58,24 +58,21 @@ describe(Support.getTestDialectTeaser('Self'), () => {
expect(foreignIdentifiers).to.have.members(['PersonId', 'ChildId']);
expect(rawAttributes).to.have.members(['createdAt', 'updatedAt', 'PersonId', 'ChildId']);
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
Person.create({ name: 'Mary' }),
Person.create({ name: 'John' }),
Person.create({ name: 'Chris' })
]).then(([mary, john, chris]) => {
return mary.setParents([john]).then(() => {
return chris.addParent(john);
}).then(() => {
return john.getChilds();
}).then(children => {
expect(children.map(v => v.id)).to.have.members([mary.id, chris.id]);
});
});
});
await this.sequelize.sync({ force: true });
const [mary, john, chris] = await Promise.all([
Person.create({ name: 'Mary' }),
Person.create({ name: 'John' }),
Person.create({ name: 'Chris' })
]);
await mary.setParents([john]);
await chris.addParent(john);
const children = await john.getChilds();
expect(children.map(v => v.id)).to.have.members([mary.id, chris.id]);
});
it('can handle n:m associations with pre-defined through table', function() {
it('can handle n:m associations with pre-defined through table', async function() {
const Person = this.sequelize.define('Person', { name: DataTypes.STRING });
const Family = this.sequelize.define('Family', {
preexisting_child: {
......@@ -101,47 +98,49 @@ describe(Support.getTestDialectTeaser('Self'), () => {
expect(rawAttributes).to.have.members(['preexisting_parent', 'preexisting_child']);
let count = 0;
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
Person.create({ name: 'Mary' }),
Person.create({ name: 'John' }),
Person.create({ name: 'Chris' })
]);
}).then(([mary, john, chris]) => {
this.mary = mary;
this.chris = chris;
this.john = john;
return mary.setParents([john], {
logging(sql) {
if (sql.match(/INSERT/)) {
count++;
expect(sql).to.have.string('preexisting_child');
expect(sql).to.have.string('preexisting_parent');
}
}
});
}).then(() => {
return this.mary.addParent(this.chris, {
logging(sql) {
if (sql.match(/INSERT/)) {
count++;
expect(sql).to.have.string('preexisting_child');
expect(sql).to.have.string('preexisting_parent');
}
await this.sequelize.sync({ force: true });
const [mary, john, chris] = await Promise.all([
Person.create({ name: 'Mary' }),
Person.create({ name: 'John' }),
Person.create({ name: 'Chris' })
]);
this.mary = mary;
this.chris = chris;
this.john = john;
await mary.setParents([john], {
logging(sql) {
if (sql.match(/INSERT/)) {
count++;
expect(sql).to.have.string('preexisting_child');
expect(sql).to.have.string('preexisting_parent');
}
});
}).then(() => {
return this.john.getChildren({
logging(sql) {
}
});
await this.mary.addParent(this.chris, {
logging(sql) {
if (sql.match(/INSERT/)) {
count++;
const whereClause = sql.split('FROM')[1]; // look only in the whereClause
expect(whereClause).to.have.string('preexisting_child');
expect(whereClause).to.have.string('preexisting_parent');
expect(sql).to.have.string('preexisting_child');
expect(sql).to.have.string('preexisting_parent');
}
});
}).then(children => {
expect(count).to.be.equal(3);
expect(children.map(v => v.id)).to.have.members([this.mary.id]);
}
});
const children = await this.john.getChildren({
logging(sql) {
count++;
const whereClause = sql.split('FROM')[1];
// look only in the whereClause
expect(whereClause).to.have.string('preexisting_child');
expect(whereClause).to.have.string('preexisting_parent');
}
});
expect(count).to.be.equal(3);
expect(children.map(v => v.id)).to.have.members([this.mary.id]);
});
});
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!