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

Commit c013246b by Andy Edwards Committed by GitHub

test: asyncify integration/associations (#12227)

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