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

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;
return Task.create({ id: 1, userId: 1 }); const task0 = await Task.create({ id: 1, userId: 1 });
}).then(task => { expect(task0.getOwner).to.be.ok;
expect(task.getOwner).to.be.ok;
return Promise.all([ const [user, task] = await Promise.all([
User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'assignments' }] }), User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'assignments' }] }),
Task.findOne({ where: { id: 1 }, include: [{ model: User, as: 'owner' }] }) Task.findOne({ where: { id: 1 }, include: [{ model: User, as: 'owner' }] })
]); ]);
}).then(([user, task]) => {
expect(user.assignments).to.be.ok; expect(user.assignments).to.be.ok;
expect(task.owner).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;
return Task.create({ id: 1, userId: 1 }); const task0 = await Task.create({ id: 1, userId: 1 });
}).then(task => { expect(task0.getOWNER).to.be.ok;
expect(task.getOWNER).to.be.ok;
return Promise.all([ const [user, task] = await Promise.all([
User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'ASSIGNMENTS' }] }), User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'ASSIGNMENTS' }] }),
Task.findOne({ where: { id: 1 }, include: [{ model: User, as: 'OWNER' }] }) Task.findOne({ where: { id: 1 }, include: [{ model: User, as: 'OWNER' }] })
]); ]);
}).then(([user, task]) => {
expect(user.ASSIGNMENTS).to.be.ok; expect(user.ASSIGNMENTS).to.be.ok;
expect(task.OWNER).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(() => {
return User.findOne({ where: { id: 1 }, include: [{ model: Task, as: 'taskz' }] });
}).then(user => {
expect(user.taskz).to.be.ok; 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(() => {
return User.findOne({ where: { id: 1 }, include: [Task] });
}).then(user => {
expect(user.assignments).to.be.ok; expect(user.assignments).to.be.ok;
}); });
});
}); });
This diff could not be displayed because it is too large.
...@@ -27,14 +27,15 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -27,14 +27,15 @@ 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({
const tasks = await Promise.all([Task.create({
id: 1, id: 1,
user: { id: 1 } user: { id: 1 }
}, { }, {
...@@ -47,109 +48,87 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -47,109 +48,87 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
}), Task.create({ }), Task.create({
id: 3 id: 3
})]); })]);
}).then(tasks => {
return Task.User.get(tasks).then(result => { const result = await Task.User.get(tasks);
expect(result[tasks[0].id].id).to.equal(tasks[0].user.id); expect(result[tasks[0].id].id).to.equal(tasks[0].user.id);
expect(result[tasks[1].id].id).to.equal(tasks[1].user.id); expect(result[tasks[1].id].id).to.equal(tasks[1].user.id);
expect(result[tasks[2].id]).to.be.undefined; 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' } });
});
}).then(user => {
expect(user).to.be.null; 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(() => {
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]) => {
return task.setUserXYZ(user).then(() => { await task.setUserXYZ(user0);
return task.getUserXYZ(); const user = await task.getUserXYZ();
});
}).then(user => {
expect(user).to.be.ok; expect(user).to.be.ok;
return this.sequelize.dropSchema('archive').then(() => { await this.sequelize.dropSchema('archive');
return this.sequelize.showAllSchemas().then(schemas => { const schemas = await this.sequelize.showAllSchemas();
if (dialect === 'postgres' || dialect === 'mssql' || dialect === 'mariadb') { if (dialect === 'postgres' || dialect === 'mssql' || dialect === 'mariadb') {
expect(schemas).to.not.have.property('archive'); 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 => {
return Task.create({}).then(task => {
return task.setUserXYZ(user).then(() => {
return task.getUserXYZ();
});
});
}).then(user => {
expect(user).to.be.ok; expect(user).to.be.ok;
return this.sequelize.dropSchema('archive');
}); await 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({
const post = await Post.create({
title: 'Post title' title: 'Post title'
}).then(post => { });
return Comment.create({
const comment = await Comment.create({
text: 'OLD VALUE' text: 'OLD VALUE'
}).then(comment => { });
comment.text = 'UPDATED VALUE'; comment.text = 'UPDATED VALUE';
return comment.setPost(post).then(() => { await comment.setPost(post);
expect(comment.text).to.equal('UPDATED VALUE'); 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,8 +298,8 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -360,8 +298,8 @@ 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 });
...@@ -370,8 +308,6 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -370,8 +308,6 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
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() {
const Home = this.sequelize.define('home', {}); const Home = this.sequelize.define('home', {});
...@@ -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 // the sql query should correctly look at account_id instead of AccountId
expect(user.Account).to.exist; 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,16 +466,15 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -542,16 +466,15 @@ 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
.then(() => mail.setRecipients([1])) await mail.setRecipients([1]);
)
.then(() => Entry.findAndCountAll({ const result = await Entry.findAndCountAll({
offset: 0, offset: 0,
limit: 10, limit: 10,
order: [['id', 'DESC']], order: [['id', 'DESC']],
...@@ -572,7 +495,8 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -572,7 +495,8 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
required: true required: true
} }
] ]
})).then(result => { });
expect(result.count).to.equal(2); expect(result.count).to.equal(2);
expect(result.rows[0].get({ plain: true })).to.deep.equal( expect(result.rows[0].get({ plain: true })).to.deep.equal(
{ {
...@@ -593,179 +517,141 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -593,179 +517,141 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
); );
}); });
}); });
});
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();
await task.reload();
expect(task.UserId).to.equal(null); 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);
const tasks = await Task.findAll();
expect(tasks).to.have.length(1); 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(
await expect(
user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id }) user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id })
).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError).then(() => { ).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
// Should fail due to FK restriction // Should fail due to FK restriction
return Task.findAll().then(tasks => { const tasks = await Task.findAll();
expect(tasks).to.have.length(1); 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,15 +772,14 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -893,15 +772,14 @@ 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',
...@@ -909,10 +787,9 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -909,10 +787,9 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
}); });
}); });
}); });
});
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,12 +800,11 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -923,12 +800,11 @@ 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);
}); });
}); });
});
describe('allows the user to provide an attribute definition object as foreignKey', () => { describe('allows the user to provide an attribute definition object as foreignKey', () => {
it('works with a column that hasnt been defined before', function() { it('works with a column that hasnt been defined before', function() {
...@@ -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([
const [individual1, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }), this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' }) this.Hat.create({ name: 'Baz' })
]); ]);
}).then(([individual, hat]) => {
return individual.setPersonwearinghat(hat); await individual1.setPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({ const individual0 = await this.Individual.findOne({
where: { name: 'Foo Bar' }, where: { name: 'Foo Bar' },
include: [{ model: this.Hat, as: 'personwearinghat' }] include: [{ model: this.Hat, as: 'personwearinghat' }]
}); });
}).then(individual => {
expect(individual.name).to.equal('Foo Bar'); expect(individual0.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz'); expect(individual0.personwearinghat.name).to.equal('Baz');
}).then(() => {
return this.Individual.findOne({ const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' }, where: { name: 'Foo Bar' },
include: [{ include: [{
model: this.Hat, model: this.Hat,
as: { singular: 'personwearinghat' } as: { singular: 'personwearinghat' }
}] }]
}); });
}).then(individual => {
expect(individual.name).to.equal('Foo Bar'); expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz'); 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([
const [individual0, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }), this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' }) this.Hat.create({ name: 'Baz' })
]); ]);
}).then(([individual, hat]) => {
return individual.setPersonwearinghat(hat); await individual0.setPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({ const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' }, where: { name: 'Foo Bar' },
include: [{ all: true }] include: [{ all: true }]
}); });
}).then(individual => {
expect(individual.name).to.equal('Foo Bar'); expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz'); expect(individual.personwearinghat.name).to.equal('Baz');
}); });
}); });
});
}); });
...@@ -27,15 +27,16 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -27,15 +27,16 @@ 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({
const user0 = await User.create({
username: 'John', username: 'John',
Tasks: [{ Tasks: [{
title: 'Get rich', active: true title: 'Get rich', active: true
...@@ -43,13 +44,15 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -43,13 +44,15 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
}, { }, {
include: [Task] include: [Task]
}); });
}).then(user => {
return Promise.all([ await Promise.all([
user.get('Tasks')[0].createSubtask({ title: 'Make a startup', active: false }), user0.get('Tasks')[0].createSubtask({ title: 'Make a startup', active: false }),
user.get('Tasks')[0].createSubtask({ title: 'Engage rock stars', active: true }) user0.get('Tasks')[0].createSubtask({ title: 'Engage rock stars', active: true })
]).then(() => user); ]);
}).then(user => {
return expect(user.countTasks({ const user = user0;
await expect(user.countTasks({
attributes: [Task.primaryKeyField, 'title'], attributes: [Task.primaryKeyField, 'title'],
include: [{ include: [{
attributes: [], attributes: [],
...@@ -62,19 +65,19 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -62,19 +65,19 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
})).to.eventually.equal(1); })).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({
const users = await Promise.all([User.create({
id: 1, id: 1,
tasks: [ tasks: [
{}, {},
...@@ -93,16 +96,14 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -93,16 +96,14 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
}), User.create({ }), User.create({
id: 3 id: 3
})]); })]);
}).then(users => {
return User.Tasks.get(users).then(result => { const result = await User.Tasks.get(users);
expect(result[users[0].id].length).to.equal(3); expect(result[users[0].id].length).to.equal(3);
expect(result[users[1].id].length).to.equal(1); expect(result[users[1].id].length).to.equal(1);
expect(result[users[2].id].length).to.equal(0); 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,8 +111,9 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -110,8 +111,9 @@ 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({
const users = await Promise.all([User.create({
tasks: [ tasks: [
{ title: 'b' }, { title: 'b' },
{ title: 'd' }, { title: 'd' },
...@@ -129,13 +131,14 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -129,13 +131,14 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
}, { }, {
include: [User.Tasks] include: [User.Tasks]
})]); })]);
}).then(users => {
return User.Tasks.get(users, { const result = await User.Tasks.get(users, {
limit: 2, limit: 2,
order: [ order: [
['title', 'ASC'] ['title', 'ASC']
] ]
}).then(result => { });
expect(result[users[0].id].length).to.equal(2); 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].title).to.equal('a');
expect(result[users[0].id][1].title).to.equal('b'); expect(result[users[0].id][1].title).to.equal('b');
...@@ -144,10 +147,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -144,10 +147,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
expect(result[users[1].id][0].title).to.equal('a'); expect(result[users[1].id][0].title).to.equal('a');
expect(result[users[1].id][1].title).to.equal('b'); 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,8 +160,9 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -159,8 +160,9 @@ 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({
await Promise.all([User.create({
id: 1, id: 1,
tasks: [ tasks: [
{ title: 'b', subtasks: [ { title: 'b', subtasks: [
...@@ -200,8 +202,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -200,8 +202,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
}, { }, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }] include: [{ association: User.Tasks, include: [Task.SubTasks] }]
})]); })]);
}).then(() => {
return User.findAll({ const users = await User.findAll({
include: [{ include: [{
association: User.Tasks, association: User.Tasks,
limit: 2, limit: 2,
...@@ -220,7 +222,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -220,7 +222,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
order: [ order: [
['id', 'ASC'] ['id', 'ASC']
] ]
}).then(users => { });
expect(users[0].tasks.length).to.equal(2); expect(users[0].tasks.length).to.equal(2);
expect(users[0].tasks[0].title).to.equal('a'); expect(users[0].tasks[0].title).to.equal('a');
...@@ -246,10 +249,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -246,10 +249,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
expect(users[1].tasks[1].subtasks[0].title).to.equal('b'); expect(users[1].tasks[1].subtasks[0].title).to.equal('b');
expect(users[1].tasks[1].subtasks[1].title).to.equal('a'); 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,8 +264,9 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -263,8 +264,9 @@ 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({
const users = await Promise.all([User.create({
tasks: [ tasks: [
{ title: 'b', category: {} }, { title: 'b', category: {} },
{ title: 'd', category: {} }, { title: 'd', category: {} },
...@@ -282,14 +284,15 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -282,14 +284,15 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
}, { }, {
include: [{ association: User.Tasks, include: [Task.Category] }] include: [{ association: User.Tasks, include: [Task.Category] }]
})]); })]);
}).then(users => {
return User.Tasks.get(users, { const result = await User.Tasks.get(users, {
limit: 2, limit: 2,
order: [ order: [
['title', 'ASC'] ['title', 'ASC']
], ],
include: [Task.Category] include: [Task.Category]
}).then(result => { });
expect(result[users[0].id].length).to.equal(2); 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].title).to.equal('a');
expect(result[users[0].id][0].category).to.be.ok; expect(result[users[0].id][0].category).to.be.ok;
...@@ -302,10 +305,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -302,10 +305,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
expect(result[users[1].id][1].title).to.equal('b'); expect(result[users[1].id][1].title).to.equal('b');
expect(result[users[1].id][1].category).to.be.ok; 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,16 +318,13 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -317,16 +318,13 @@ 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 });
}).then(() => {
return Promise.all([User.create({
id: 1, id: 1,
tasks: [ tasks: [
{ title: 'b', subtasks: [ { title: 'b', subtasks: [
...@@ -366,8 +364,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -366,8 +364,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
}, { }, {
include: [{ association: User.Tasks, include: [Task.SubTasks] }] include: [{ association: User.Tasks, include: [Task.SubTasks] }]
})]); })]);
}).then(() => {
return User.findAll({ const users = await User.findAll({
include: [{ include: [{
association: User.Tasks, association: User.Tasks,
limit: 2, limit: 2,
...@@ -386,7 +384,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -386,7 +384,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
order: [ order: [
['id', 'ASC'] ['id', 'ASC']
] ]
}).then(users => { });
expect(users[0].tasks.length).to.equal(2); expect(users[0].tasks.length).to.equal(2);
expect(users[0].tasks[0].title).to.equal('a'); expect(users[0].tasks[0].title).to.equal('a');
...@@ -411,17 +410,13 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -411,17 +410,13 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
expect(users[1].tasks[1].subtasks.length).to.equal(2); 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[0].title).to.equal('b');
expect(users[1].tasks[1].subtasks[1].title).to.equal('a'); expect(users[1].tasks[1].subtasks[1].title).to.equal('a');
return this.sequelize.dropSchema('work').then(() => { await this.sequelize.dropSchema('work');
return this.sequelize.showAllSchemas().then(schemas => { const schemas = await this.sequelize.showAllSchemas();
if (dialect === 'postgres' || dialect === 'mssql' || schemas === 'mariadb') { if (dialect === 'postgres' || dialect === 'mssql' || schemas === 'mariadb') {
expect(schemas).to.be.empty; expect(schemas).to.be.empty;
} }
}); });
}); });
});
});
});
});
} }
}); });
...@@ -463,97 +458,84 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -463,97 +458,84 @@ 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);
return sequelize.sync({ force: true }); await sequelize.sync({ force: true });
}).then(() => {
return Promise.all([ const [article, label] = await Promise.all([
Article.create({ title: 'foo' }), Article.create({ title: 'foo' }),
Label.create({ text: 'bar' }) Label.create({ text: 'bar' })
]); ]);
}).then(([_article, _label]) => {
article = _article; const t = await sequelize.transaction();
label = _label; await article.setLabels([label], { transaction: t });
return sequelize.transaction(); const articles0 = await Article.findAll({ transaction: t });
}).then(_t => { const hasLabel0 = await articles0[0].hasLabel(label);
t = _t; expect(hasLabel0).to.be.false;
return article.setLabels([label], { transaction: t }); const articles = await Article.findAll({ transaction: t });
}).then(() => { const hasLabel = await articles[0].hasLabel(label, { transaction: t });
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; expect(hasLabel).to.be.true;
return t.rollback(); await 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([
const [hasLabel1, hasLabel2] = await Promise.all([
article.hasLabel(label1), article.hasLabel(label1),
article.hasLabel(label2) article.hasLabel(label2)
]); ]);
}).then(([hasLabel1, hasLabel2]) => {
expect(hasLabel1).to.be.false; expect(hasLabel1).to.be.false;
expect(hasLabel2).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);
const [hasLabel1, hasLabel2] = await Promise.all([
article.hasLabel(label1), article.hasLabel(label1),
article.hasLabel(label2) article.hasLabel(label2)
]); ]);
});
}).then(([hasLabel1, hasLabel2]) => {
expect(hasLabel1).to.be.true; expect(hasLabel1).to.be.true;
expect(hasLabel2).to.be.false; 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);
const [hasLabel1, hasLabel2] = await Promise.all([
article.hasLabel(label1[this.Label.primaryKeyAttribute]), article.hasLabel(label1[this.Label.primaryKeyAttribute]),
article.hasLabel(label2[this.Label.primaryKeyAttribute]) article.hasLabel(label2[this.Label.primaryKeyAttribute])
]); ]);
});
}).then(([hasLabel1, hasLabel2]) => {
expect(hasLabel1).to.be.true; expect(hasLabel1).to.be.true;
expect(hasLabel2).to.be.false; expect(hasLabel2).to.be.false;
}); });
}); });
});
describe('hasAssociations', () => { describe('hasAssociations', () => {
beforeEach(function() { beforeEach(function() {
...@@ -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' })
]); ]);
}).then(([article, label]) => {
ctx.article = article; const t = await sequelize.transaction();
ctx.label = label; await article.setLabels([label], { transaction: t });
return ctx.sequelize.transaction(); const articles = await Article.findAll({ transaction: t });
}).then(t => {
ctx.t = t; const [hasLabel1, hasLabel2] = await Promise.all([
return ctx.article.setLabels([ctx.label], { transaction: t }); articles[0].hasLabels([label]),
}).then(() => { articles[0].hasLabels([label], { transaction: t })
return ctx.Article.findAll({ transaction: ctx.t });
}).then(articles => {
return Promise.all([
articles[0].hasLabels([ctx.label]),
articles[0].hasLabels([ctx.label], { transaction: ctx.t })
]); ]);
}).then(([hasLabel1, hasLabel2]) => {
expect(hasLabel1).to.be.false; expect(hasLabel1).to.be.false;
expect(hasLabel2).to.be.true; expect(hasLabel2).to.be.true;
return ctx.t.rollback(); await 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);
const result = await article.hasLabels([
label1[this.Label.primaryKeyAttribute], label1[this.Label.primaryKeyAttribute],
label2[this.Label.primaryKeyAttribute] label2[this.Label.primaryKeyAttribute]
]).then(result => { ]);
expect(result).to.be.false; 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]);
const result = await article.hasLabels([label1, label2]);
expect(result).to.be.true; 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]);
const result = await article.hasLabels([
label1[this.Label.primaryKeyAttribute], label1[this.Label.primaryKeyAttribute],
label2[this.Label.primaryKeyAttribute] label2[this.Label.primaryKeyAttribute]
]).then(result => { ]);
expect(result).to.be.true; 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()
]); ]);
}).then(([article, label, t]) => {
ctx.article = article; await article.setLabels([label], { transaction: t });
ctx. t = t; const labels0 = await Label.findAll({ where: { ArticleId: article.id }, transaction: undefined });
return article.setLabels([label], { transaction: t }); expect(labels0.length).to.equal(0);
}).then(() => {
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id }, transaction: undefined }); const labels = await Label.findAll({ where: { ArticleId: article.id }, transaction: t });
}).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); expect(labels.length).to.equal(1);
return ctx.t.rollback(); await t.rollback();
});
}); });
} }
it('clears associations when passing null to the set-method', function() { it('clears associations when passing null to the set-method', async function() {
const User = this.sequelize.define('User', { username: DataTypes.STRING }), 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();
return ctx.task.setUsers(null);
}).then(() => {
return ctx.task.getUsers();
}).then(users => {
expect(users).to.have.length(0); 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);
}).then(() => {
return ctx.article.setLabels([ctx.label2.id]);
}).then(() => {
return ctx.article.getLabels();
}).then(labels => {
expect(labels).to.have.length(1); expect(labels).to.have.length(1);
expect(labels[0].text).to.equal('label two'); 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' })
]); ]);
}).then(([article, label]) => {
ctx.article = article; const t = await sequelize.transaction();
ctx.label = label; await article.addLabel(label, { transaction: t });
return ctx.sequelize.transaction(); const labels0 = await Label.findAll({ where: { ArticleId: article.id }, transaction: undefined });
}).then(t => { expect(labels0.length).to.equal(0);
ctx.t = t;
return ctx.article.addLabel(ctx.label, { transaction: ctx.t }); const labels = await Label.findAll({ where: { ArticleId: article.id }, transaction: t });
}).then(() => {
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id }, transaction: undefined });
}).then(labels => {
expect(labels.length).to.equal(0);
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id }, transaction: ctx.t });
}).then(labels => {
expect(labels.length).to.equal(1); expect(labels.length).to.equal(1);
return ctx.t.rollback(); await t.rollback();
});
}); });
} }
it('supports passing the primary key instead of an object', function() { it('supports passing the primary key instead of an object', async function() {
const Article = this.sequelize.define('Article', { 'title': DataTypes.STRING }), 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(() => {
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 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]]); it('handles decent sized bulk creates', async function() {
}).then(() => {
return ctx.task.getUsers();
}).then(users => {
expect(users).to.have.length(3);
});
});
it('handles decent sized bulk creates', 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' });
}).then(task => {
ctx.task = task;
return User.findAll();
}).then(users=> {
expect(users).to.have.length(1000); expect(users).to.have.length(1000);
}); });
}); });
}); it('clears associations when passing null to the set-method with omitNull set to true', async function() {
it('clears associations when passing null to the set-method with omitNull set to true', 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 } });
}).then(labels => {
expect(labels.length).to.equal(1); 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 => {
ctx.article = article;
return article.createLabel({ text: 'bar' }, { logging: spy });
}).then(label => {
expect(spy.calledOnce).to.be.true; expect(spy.calledOnce).to.be.true;
expect(label.ArticleId).to.equal(ctx.article.id); expect(label.ArticleId).to.equal(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;
return ctx.article.createLabel({ text: 'bar' }, { transaction: ctx.t });
}).then(() => {
return ctx.Label.findAll();
}).then(labels => {
expect(labels.length).to.equal(0);
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id } });
}).then(labels => {
expect(labels.length).to.equal(0);
return ctx.Label.findAll({ where: { ArticleId: ctx.article.id }, transaction: ctx.t });
}).then(labels => {
expect(labels.length).to.equal(1); expect(labels.length).to.equal(1);
return ctx.t.rollback(); await 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([
const [john, task1, task2] = await Promise.all([
this.User.create({ username: 'John' }), this.User.create({ username: 'John' }),
this.Task.create({ title: 'Get rich', active: true }), this.Task.create({ title: 'Get rich', active: true }),
this.Task.create({ title: 'Die trying', active: false }) 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(() => {
return ctx.article.getLabels({ where: { until: { [Op.gt]: moment('2014-01-02').toDate() } } });
}).then(labels => {
expect(labels).to.be.instanceof(Array); expect(labels).to.be.instanceof(Array);
expect(labels).to.have.length(1); expect(labels).to.have.length(1);
expect(labels[0].text).to.equal('Epicness'); 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([
const [john, task1, task2] = await Promise.all([
this.User.create({ username: 'John' }), this.User.create({ username: 'John' }),
this.Task.create({ title: 'Get rich', active: true }), this.Task.create({ title: 'Get rich', active: true }),
this.Task.create({ title: 'Die trying', active: false }) this.Task.create({ title: 'Die trying', active: false })
]); ]);
}).then(([john, task1, task2]) => {
this.user = john; this.user = john;
return john.setTasks([task1, task2]); 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,202 +1011,189 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -1126,202 +1011,189 @@ 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([
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]) => {
return user.setTasks([task]).then(() => { await user.setTasks([task0]);
return user.destroy().then(() => { await user.destroy();
return task.reload(); const task = await task0.reload();
});
});
}).then(task => {
expect(task.UserId).to.equal(null); 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();
});
}).then(tasks => {
expect(tasks).to.be.empty; 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(() => {
return ctx.user.destroy();
}).then(() => {
return Task.findAll();
}).then(tasks => {
expect(tasks).to.have.length(0); 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([
const [user0, task] = await Promise.all([
User.create({ username: 'foo' }), User.create({ username: 'foo' }),
Task.create({ title: 'task' }) Task.create({ title: 'task' })
]); ]);
}).then(([user, task]) => {
return user.setTasks([task]).then(() => user); await user0.setTasks([task]);
}).then(user => { const user = user0;
// 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);
}); });
});
} }
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([
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;
return user.setTasks([task]); try {
}).then(() => { tasks = await user.destroy();
return ctx.user.destroy().catch(err => { } catch (err) {
if (!(err instanceof Sequelize.ForeignKeyConstraintError)) throw err; if (!(err instanceof Sequelize.ForeignKeyConstraintError))
throw err;
// Should fail due to FK violation // Should fail due to FK violation
return Task.findAll(); tasks = await Task.findAll();
}); }
}).then(tasks => {
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 });
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 });
const [user0, task] = await Promise.all([
User.create({ username: 'foo' }), User.create({ username: 'foo' }),
Task.create({ title: 'task' }) Task.create({ title: 'task' })
]); ]);
}).then(([user, task]) => {
return user.setTasks([task]).then(() => user); await user0.setTasks([task]);
}).then(user => { const user = user0;
// 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 })
.catch(err => { try {
if (!(err instanceof Sequelize.ForeignKeyConstraintError)) throw err; tasks = await user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id });
} catch (err) {
if (!(err instanceof Sequelize.ForeignKeyConstraintError))
throw err;
// Should fail due to FK violation // Should fail due to FK violation
return Task.findAll(); tasks = await Task.findAll();
}); }
}).then(tasks => {
expect(tasks).to.have.length(1); 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,10 +1246,9 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -1374,10 +1246,9 @@ 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', () => {
it('works with a column that hasnt been defined before', function() { it('works with a column that hasnt been defined before', function() {
...@@ -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,31 +1333,28 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -1462,31 +1333,28 @@ 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']]
}); });
})
.then(({ count, rows }) => {
expect(count.length).to.equal(1); expect(count.length).to.equal(1);
expect(rows[0].tasks[0].jobs.length).to.equal(2); expect(rows[0].tasks[0].jobs.length).to.equal(2);
}); });
}); });
});
describe('sourceKey', () => { describe('sourceKey', () => {
beforeEach(function() { beforeEach(function() {
...@@ -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(user).to.have.property('tasks'); expect(user0).to.have.property('tasks');
expect(user.tasks).to.be.an('array'); expect(user0.tasks).to.be.an('array');
expect(user.tasks).to.lengthOf(1); expect(user0.tasks).to.lengthOf(1);
expect(user.tasks[0].title).to.be.equal(values.tasks[0].title, 'task title is correct'); expect(user0.tasks[0].title).to.be.equal(values.tasks[0].title, 'task title is correct');
return User.findOne({ where: { email: values.email } }); const user = await User.findOne({ where: { email: values.email } });
}) const tasks = await user.getTasks();
.then(user =>
user.getTasks()
.then(tasks => {
// Make sure tasks relationship is successful // Make sure tasks relationship is successful
expect(tasks).to.be.an('array'); expect(tasks).to.be.an('array');
expect(tasks).to.lengthOf(1); expect(tasks).to.lengthOf(1);
expect(tasks[0].title).to.be.equal(values.tasks[0].title, 'task title is correct'); 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,9 +1479,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -1626,9 +1479,8 @@ 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');
...@@ -1641,7 +1493,6 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -1641,7 +1493,6 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
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');
}); });
}); });
});
describe('sourceKey with where clause in include', () => { describe('sourceKey with where clause in include', () => {
beforeEach(function() { beforeEach(function() {
...@@ -1660,14 +1511,15 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -1660,14 +1511,15 @@ 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([
await this.Task.bulkCreate([
{ title: 'Active Task', userEmail: 'john@example.com', taskStatus: 'Active' }, { title: 'Active Task', userEmail: 'john@example.com', taskStatus: 'Active' },
{ title: 'Inactive Task', userEmail: 'john@example.com', taskStatus: 'Inactive' } { title: 'Inactive Task', userEmail: 'john@example.com', taskStatus: 'Inactive' }
]) ]);
).then(() =>
this.User.findOne({ const user = await this.User.findOne({
include: [ include: [
{ {
model: this.Task, model: this.Task,
...@@ -1675,14 +1527,13 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -1675,14 +1527,13 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
} }
], ],
where: { username: 'John' } where: { username: 'John' }
}) });
).then(user => {
expect(user).to.be.ok; expect(user).to.be.ok;
expect(user.Tasks.length).to.equal(1); expect(user.Tasks.length).to.equal(1);
expect(user.Tasks[0].title).to.equal('Active Task'); expect(user.Tasks[0].title).to.equal('Active Task');
}); });
}); });
});
describe('Eager loading', () => { describe('Eager loading', () => {
beforeEach(function() { beforeEach(function() {
...@@ -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([
const [individual0, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }), this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' }) this.Hat.create({ name: 'Baz' })
]); ]);
}).then(([individual, hat]) => {
return individual.addPersonwearinghat(hat); await individual0.addPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({ const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' }, where: { name: 'Foo Bar' },
include: [{ model: this.Hat, as: 'personwearinghats' }] include: [{ model: this.Hat, as: 'personwearinghats' }]
}); });
}).then(individual => {
expect(individual.name).to.equal('Foo Bar'); expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghats.length).to.equal(1); expect(individual.personwearinghats.length).to.equal(1);
expect(individual.personwearinghats[0].name).to.equal('Baz'); 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([
const [individual0, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }), this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' }) this.Hat.create({ name: 'Baz' })
]); ]);
}).then(([individual, hat]) => {
return individual.addPersonwearinghat(hat); await individual0.addPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({ const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' }, where: { name: 'Foo Bar' },
include: [{ all: true }] include: [{ all: true }]
}); });
}).then(individual => {
expect(individual.name).to.equal('Foo Bar'); expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghats.length).to.equal(1); expect(individual.personwearinghats.length).to.equal(1);
expect(individual.personwearinghats[0].name).to.equal('Baz'); expect(individual.personwearinghats[0].name).to.equal('Baz');
}); });
}); });
});
}); });
...@@ -25,14 +25,15 @@ describe(Support.getTestDialectTeaser('HasOne'), () => { ...@@ -25,14 +25,15 @@ 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({
const players = await Promise.all([Player.create({
id: 1, id: 1,
user: {} user: {}
}, { }, {
...@@ -45,338 +46,255 @@ describe(Support.getTestDialectTeaser('HasOne'), () => { ...@@ -45,338 +46,255 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
}), Player.create({ }), Player.create({
id: 3 id: 3
})]); })]);
}).then(players => {
return Player.User.get(players).then(result => { const result = await Player.User.get(players);
expect(result[players[0].id].id).to.equal(players[0].user.id); expect(result[players[0].id].id).to.equal(players[0].user.id);
expect(result[players[1].id].id).to.equal(players[1].user.id); expect(result[players[1].id].id).to.equal(players[1].user.id);
expect(result[players[2].id]).to.equal(null); 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(() => {
return Promise.all([
User.create({ username: 'foo' }), User.create({ username: 'foo' }),
User.create({ username: 'foo' }), User.create({ username: 'foo' }),
Group.create({ name: 'bar' }) Group.create({ name: 'bar' })
]); ]);
}).then(([fakeUser, user, group]) => {
return group.setUser(user).then(() => { await group.setUser(user);
return Group.findAll().then(groups => { const groups = await Group.findAll();
return groups[0].getUser().then(associatedUser => { const associatedUser = await groups[0].getUser();
expect(associatedUser).not.to.be.null; expect(associatedUser).not.to.be.null;
expect(associatedUser.id).to.equal(user.id); expect(associatedUser.id).to.equal(user.id);
expect(associatedUser.id).not.to.equal(fakeUser.id); expect(associatedUser.id).not.to.equal(fakeUser.id);
}); await this.sequelize.dropSchema('admin');
}); const schemas = await this.sequelize.showAllSchemas();
});
}).then(() => {
return this.sequelize.dropSchema('admin').then(() => {
return this.sequelize.showAllSchemas().then(schemas => {
if (dialect === 'postgres' || dialect === 'mssql' || dialect === 'mariadb') { if (dialect === 'postgres' || dialect === 'mssql' || dialect === 'mariadb') {
expect(schemas).to.not.have.property('admin'); 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([
const [user0, task1] = await Promise.all([
User.create({ id: 1, username: 'foo' }), User.create({ id: 1, username: 'foo' }),
Task.create({ id: 20, title: 'bar' }) Task.create({ id: 20, title: 'bar' })
]); ]);
})
.then(([user, task]) => { await user0.setTaskXYZ(task1.id);
return user.setTaskXYZ(task.id) const task0 = await user0.getTaskXYZ();
.then(() => user.getTaskXYZ()) expect(task0).not.to.be.null;
.then(task => {
expect(task).not.to.be.null; const [user, task2] = await Promise.all([
return Promise.all([ user0,
user,
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)
.then(() => user.getTaskXYZ())
.then(task => {
expect(task).not.to.be.null; 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,231 +334,184 @@ describe(Support.getTestDialectTeaser('HasOne'), () => { ...@@ -416,231 +334,184 @@ 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]) => {
return task.setUserXYZ(user).then(() => { await task0.setUserXYZ(user0);
return task.getUserXYZ(); const user = await task0.getUserXYZ();
});
}).then(user => {
// the sql query should correctly look at task_id instead of taskId // the sql query should correctly look at task_id instead of taskId
expect(user).to.not.be.null; expect(user).to.not.be.null;
return Task.findOne({
const task = await Task.findOne({
where: { title: 'task' }, where: { title: 'task' },
include: [User] 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();
await task.reload();
expect(task.UserId).to.equal(null); 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();
});
}).then(tasks => {
expect(tasks).to.be.empty; 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(
await expect(
user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id }) user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id })
).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError).then(() => { ).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
// Should fail due to FK restriction // Should fail due to FK restriction
return Task.findAll().then(tasks => { const tasks = await Task.findAll();
expect(tasks).to.have.length(1); expect(tasks).to.have.length(1);
}); });
});
});
});
});
});
});
});
} }
}); });
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([
const [individual1, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }), this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' }) this.Hat.create({ name: 'Baz' })
]); ]);
}).then(([individual, hat]) => {
return individual.setPersonwearinghat(hat); await individual1.setPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({ const individual0 = await this.Individual.findOne({
where: { name: 'Foo Bar' }, where: { name: 'Foo Bar' },
include: [{ model: this.Hat, as: 'personwearinghat' }] include: [{ model: this.Hat, as: 'personwearinghat' }]
}); });
}).then(individual => {
expect(individual.name).to.equal('Foo Bar'); expect(individual0.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz'); expect(individual0.personwearinghat.name).to.equal('Baz');
}).then(() => {
return this.Individual.findOne({ const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' }, where: { name: 'Foo Bar' },
include: [{ include: [{
model: this.Hat, model: this.Hat,
as: { singular: 'personwearinghat' } as: { singular: 'personwearinghat' }
}] }]
}); });
}).then(individual => {
expect(individual.name).to.equal('Foo Bar'); expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz'); 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([
const [individual0, hat] = await Promise.all([
this.Individual.create({ name: 'Foo Bar' }), this.Individual.create({ name: 'Foo Bar' }),
this.Hat.create({ name: 'Baz' }) this.Hat.create({ name: 'Baz' })
]); ]);
}).then(([individual, hat]) => {
return individual.setPersonwearinghat(hat); await individual0.setPersonwearinghat(hat);
}).then(() => {
return this.Individual.findOne({ const individual = await this.Individual.findOne({
where: { name: 'Foo Bar' }, where: { name: 'Foo Bar' },
include: [{ all: true }] include: [{ all: true }]
}); });
}).then(individual => {
expect(individual.name).to.equal('Foo Bar'); expect(individual.name).to.equal('Foo Bar');
expect(individual.personwearinghat.name).to.equal('Baz'); 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,20 +17,23 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => { ...@@ -17,20 +17,23 @@ 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([{
await User.bulkCreate([{
username: 'leia' username: 'leia'
}, { }, {
username: 'vader' username: 'vader'
}]).then(() => { }]);
return Project.bulkCreate([{
await Project.bulkCreate([{
UserId: 1, UserId: 1,
title: 'republic' title: 'republic'
}, { }, {
UserId: 2, UserId: 2,
title: 'empire' title: 'empire'
}]).then(() => { }]);
return Task.bulkCreate([{
await Task.bulkCreate([{
ProjectId: 1, ProjectId: 1,
title: 'fight empire' title: 'fight empire'
}, { }, {
...@@ -42,8 +45,9 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => { ...@@ -42,8 +45,9 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
}, { }, {
ProjectId: 2, ProjectId: 2,
title: 'rule everything' title: 'rule everything'
}]).then(() => { }]);
return Task.findAll({
const tasks = await Task.findAll({
include: [ include: [
{ {
model: Project, model: Project,
...@@ -53,19 +57,14 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => { ...@@ -53,19 +57,14 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
required: true required: true
} }
] ]
}).then(tasks => { });
expect(tasks.length).to.be.equal(2); expect(tasks.length).to.be.equal(2);
expect(tasks[0].title).to.be.equal('fight empire'); expect(tasks[0].title).to.be.equal('fight empire');
expect(tasks[1].title).to.be.equal('stablish republic'); 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,20 +75,23 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => { ...@@ -76,20 +75,23 @@ 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([{
await User.bulkCreate([{
username: 'leia' username: 'leia'
}, { }, {
username: 'vader' username: 'vader'
}]).then(() => { }]);
return Project.bulkCreate([{
await Project.bulkCreate([{
UserId: 1, UserId: 1,
title: 'republic' title: 'republic'
}, { }, {
UserId: 2, UserId: 2,
title: 'empire' title: 'empire'
}]).then(() => { }]);
return Task.bulkCreate([{
await Task.bulkCreate([{
ProjectId: 1, ProjectId: 1,
title: 'fight empire' title: 'fight empire'
}, { }, {
...@@ -101,8 +103,9 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => { ...@@ -101,8 +103,9 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
}, { }, {
ProjectId: 2, ProjectId: 2,
title: 'rule everything' title: 'rule everything'
}]).then(() => { }]);
return Task.findAll({
const tasks = await Task.findAll({
include: [ include: [
{ {
model: Project, model: Project,
...@@ -115,18 +118,14 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => { ...@@ -115,18 +118,14 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
required: true required: true
} }
] ]
}).then(tasks => { });
expect(tasks.length).to.be.equal(2); expect(tasks.length).to.be.equal(2);
expect(tasks[0].title).to.be.equal('fight empire'); expect(tasks[0].title).to.be.equal('fight empire');
expect(tasks[1].title).to.be.equal('stablish republic'); 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,20 +136,23 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => { ...@@ -137,20 +136,23 @@ 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([{
await User.bulkCreate([{
username: 'leia' username: 'leia'
}, { }, {
username: 'vader' username: 'vader'
}]).then(() => { }]);
return Project.bulkCreate([{
await Project.bulkCreate([{
UserId: 1, UserId: 1,
title: 'republic' title: 'republic'
}, { }, {
UserId: 2, UserId: 2,
title: 'empire' title: 'empire'
}]).then(() => { }]);
return Task.bulkCreate([{
await Task.bulkCreate([{
ProjectId: 1, ProjectId: 1,
title: 'fight empire' title: 'fight empire'
}, { }, {
...@@ -162,8 +164,9 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => { ...@@ -162,8 +164,9 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
}, { }, {
ProjectId: 2, ProjectId: 2,
title: 'rule everything' title: 'rule everything'
}]).then(() => { }]);
return User.findAll({
const users = await User.findAll({
include: [ include: [
{ {
model: Project, model: Project,
...@@ -173,56 +176,47 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => { ...@@ -173,56 +176,47 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), () => {
required: true required: true
} }
] ]
}).then(users => { });
expect(users.length).to.be.equal(1); expect(users.length).to.be.equal(1);
expect(users[0].username).to.be.equal('leia'); 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([{
await User.bulkCreate([{
username: 'leia' username: 'leia'
}, { }, {
username: 'vader' username: 'vader'
}]).then(() => { }]);
return Project.bulkCreate([{
await Project.bulkCreate([{
title: 'republic' title: 'republic'
}, { }, {
title: 'empire' title: 'empire'
}]).then(() => { }]);
return User.findByPk(1).then(user => {
return Project.findByPk(1).then(project => { const user = await User.findByPk(1);
return user.setProjects([project]).then(() => { const project = await Project.findByPk(1);
return User.findByPk(2).then(user => { await user.setProjects([project]);
return Project.findByPk(2).then(project => { const user0 = await User.findByPk(2);
return user.setProjects([project]).then(() => { const project0 = await Project.findByPk(2);
return User.findAll({ await user0.setProjects([project0]);
const users = await User.findAll({
include: [ include: [
{ model: Project, where: { title: 'republic' } } { model: Project, where: { title: 'republic' } }
] ]
}).then(users => { });
expect(users.length).to.be.equal(1); expect(users.length).to.be.equal(1);
expect(users[0].username).to.be.equal('leia'); expect(users[0].username).to.be.equal('leia');
}); });
});
});
});
});
});
});
});
});
});
});
}); });
...@@ -96,76 +96,74 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -96,76 +96,74 @@ 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({
const [post1] = await Promise.all([this.Post.create(), this.Comment.create({
title: 'I am a comment' title: 'I am a comment'
}), this.Comment.create({ }), this.Comment.create({
title: 'I am a main comment', title: 'I am a main comment',
isMain: true isMain: true
})]); })]);
}).then(([post]) => {
this.post = post; this.post = post1;
return post.createComment({
const comment0 = await post1.createComment({
title: 'I am a post comment' title: 'I am a post comment'
}); });
}).then(comment => {
expect(comment.get('commentable')).to.equal('post'); expect(comment0.get('commentable')).to.equal('post');
expect(comment.get('isMain')).to.be.false; expect(comment0.get('isMain')).to.be.false;
return this.Post.scope('withMainComment').findByPk(this.post.get('id')); const post0 = await this.Post.scope('withMainComment').findByPk(this.post.get('id'));
}).then(post => { expect(post0.mainComment).to.be.null;
expect(post.mainComment).to.be.null;
return post.createMainComment({ const mainComment1 = await post0.createMainComment({
title: 'I am a main post comment' title: 'I am a main post comment'
}); });
}).then(mainComment => {
this.mainComment = mainComment; this.mainComment = mainComment1;
expect(mainComment.get('commentable')).to.equal('post'); expect(mainComment1.get('commentable')).to.equal('post');
expect(mainComment.get('isMain')).to.be.true; expect(mainComment1.get('isMain')).to.be.true;
return this.Post.scope('withMainComment').findByPk(this.post.id); const post = await this.Post.scope('withMainComment').findByPk(this.post.id);
}).then(post => {
expect(post.mainComment.get('id')).to.equal(this.mainComment.get('id')); expect(post.mainComment.get('id')).to.equal(this.mainComment.get('id'));
return post.getMainComment(); const mainComment0 = await post.getMainComment();
}).then(mainComment => { expect(mainComment0.get('commentable')).to.equal('post');
expect(mainComment.get('commentable')).to.equal('post'); expect(mainComment0.get('isMain')).to.be.true;
expect(mainComment.get('isMain')).to.be.true;
return this.Comment.create({ const comment = await this.Comment.create({
title: 'I am a future main comment' title: 'I am a future main comment'
}); });
}).then(comment => {
return this.post.setMainComment(comment); await this.post.setMainComment(comment);
}).then(() => { const mainComment = await this.post.getMainComment();
return this.post.getMainComment();
}).then(mainComment => {
expect(mainComment.get('commentable')).to.equal('post'); expect(mainComment.get('commentable')).to.equal('post');
expect(mainComment.get('isMain')).to.be.true; expect(mainComment.get('isMain')).to.be.true;
expect(mainComment.get('title')).to.equal('I am a future main comment'); expect(mainComment.get('title')).to.equal('I am a future main comment');
}); });
}); it('should create included association with scope values', async function() {
it('should create included association with scope values', function() { await this.sequelize.sync({ force: true });
return this.sequelize.sync({ force: true }).then(() => {
return this.Post.create({ const post0 = await this.Post.create({
mainComment: { mainComment: {
title: 'I am a main comment created with a post' 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(post0.mainComment.get('commentable')).to.equal('post');
expect(post.mainComment.get('isMain')).to.be.true; expect(post0.mainComment.get('isMain')).to.be.true;
return this.Post.scope('withMainComment').findByPk(post.id); const post = await this.Post.scope('withMainComment').findByPk(post0.id);
}).then(post => {
expect(post.mainComment.get('commentable')).to.equal('post'); expect(post.mainComment.get('commentable')).to.equal('post');
expect(post.mainComment.get('isMain')).to.be.true; 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([
const [post1, image1, question1, commentA, commentB] = await Promise.all([
this.Post.create(), this.Post.create(),
this.Image.create(), this.Image.create(),
this.Question.create(), this.Question.create(),
...@@ -176,29 +174,29 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -176,29 +174,29 @@ describe(Support.getTestDialectTeaser('associations'), () => {
title: 'I am a question comment' title: 'I am a question comment'
}) })
]); ]);
}).then(([post, image, question, commentA, commentB]) => {
this.post = post; this.post = post1;
this.image = image; this.image = image1;
this.question = question; this.question = question1;
return Promise.all([post.createComment({
await Promise.all([post1.createComment({
title: 'I am a post comment' title: 'I am a post comment'
}), image.addComment(commentA), question.setComments([commentB])]); }), image1.addComment(commentA), question1.setComments([commentB])]);
}).then(() => {
return this.Comment.findAll(); const comments = await this.Comment.findAll();
}).then(comments => {
comments.forEach(comment => { comments.forEach(comment => {
expect(comment.get('commentable')).to.be.ok; expect(comment.get('commentable')).to.be.ok;
}); });
expect(comments.map(comment => { expect(comments.map(comment => {
return comment.get('commentable'); return comment.get('commentable');
}).sort()).to.deep.equal(['image', 'post', 'question']); }).sort()).to.deep.equal(['image', 'post', 'question']);
}).then(() => {
return Promise.all([ const [postComments, imageComments, questionComments] = await Promise.all([
this.post.getComments(), this.post.getComments(),
this.image.getComments(), this.image.getComments(),
this.question.getComments() this.question.getComments()
]); ]);
}).then(([postComments, imageComments, questionComments]) => {
expect(postComments.length).to.equal(1); expect(postComments.length).to.equal(1);
expect(postComments[0].get('title')).to.equal('I am a post comment'); expect(postComments[0].get('title')).to.equal('I am a post comment');
expect(imageComments.length).to.equal(1); expect(imageComments.length).to.equal(1);
...@@ -206,22 +204,20 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -206,22 +204,20 @@ describe(Support.getTestDialectTeaser('associations'), () => {
expect(questionComments.length).to.equal(1); expect(questionComments.length).to.equal(1);
expect(questionComments[0].get('title')).to.equal('I am a question comment'); expect(questionComments[0].get('title')).to.equal('I am a question comment');
return [postComments[0], imageComments[0], questionComments[0]]; const [postComment, imageComment, questionComment] = [postComments[0], imageComments[0], questionComments[0]];
}).then(([postComment, imageComment, questionComment]) => { const [post0, image0, question0] = await Promise.all([postComment.getItem(), imageComment.getItem(), questionComment.getItem()]);
return Promise.all([postComment.getItem(), imageComment.getItem(), questionComment.getItem()]); expect(post0).to.be.instanceof(this.Post);
}).then(([post, image, question]) => { expect(image0).to.be.instanceof(this.Image);
expect(post).to.be.instanceof(this.Post); expect(question0).to.be.instanceof(this.Question);
expect(image).to.be.instanceof(this.Image);
expect(question).to.be.instanceof(this.Question); const [post, image, question] = await Promise.all([this.Post.findOne({
}).then(() => {
return Promise.all([this.Post.findOne({
include: [this.Comment] include: [this.Comment]
}), this.Image.findOne({ }), this.Image.findOne({
include: [this.Comment] include: [this.Comment]
}), this.Question.findOne({ }), this.Question.findOne({
include: [this.Comment] include: [this.Comment]
})]); })]);
}).then(([post, image, question]) => {
expect(post.comments.length).to.equal(1); expect(post.comments.length).to.equal(1);
expect(post.comments[0].get('title')).to.equal('I am a post comment'); expect(post.comments[0].get('title')).to.equal('I am a post comment');
expect(image.comments.length).to.equal(1); expect(image.comments.length).to.equal(1);
...@@ -229,32 +225,30 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -229,32 +225,30 @@ describe(Support.getTestDialectTeaser('associations'), () => {
expect(question.comments.length).to.equal(1); expect(question.comments.length).to.equal(1);
expect(question.comments[0].get('title')).to.equal('I am a question comment'); expect(question.comments[0].get('title')).to.equal('I am a question comment');
}); });
}); it('should make the same query if called multiple time (#4470)', async function() {
it('should make the same query if called multiple time (#4470)', 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 });
let post = await this.Post.create({ let post = await this.Post.create({
...@@ -275,9 +269,10 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -275,9 +269,10 @@ 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({
const [post0, commentA, commentB, commentC] = await Promise.all([this.Post.create(), this.Comment.create({
title: 'I am a blue comment', title: 'I am a blue comment',
type: 'blue' type: 'blue'
}), this.Comment.create({ }), this.Comment.create({
...@@ -287,24 +282,23 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -287,24 +282,23 @@ describe(Support.getTestDialectTeaser('associations'), () => {
title: 'I am a green comment', title: 'I am a green comment',
type: 'green' type: 'green'
})]); })]);
}).then(([post, commentA, commentB, commentC]) => {
this.post = post; this.post = post0;
return post.addComments([commentA, commentB, commentC]); await post0.addComments([commentA, commentB, commentC]);
}).then(() => {
return this.Post.findByPk(this.post.id, { const post = await this.Post.findByPk(this.post.id, {
include: [{ include: [{
model: this.Comment, model: this.Comment,
as: 'coloredComments' as: 'coloredComments'
}] }]
}); });
}).then(post => {
expect(post.coloredComments.length).to.equal(2); expect(post.coloredComments.length).to.equal(2);
for (const comment of post.coloredComments) { for (const comment of post.coloredComments) {
expect(comment.type).to.match(/blue|green/); expect(comment.type).to.match(/blue|green/);
} }
}); });
}); });
});
if (Support.getTestDialect() !== 'sqlite') { if (Support.getTestDialect() !== 'sqlite') {
describe('N:M', () => { describe('N:M', () => {
...@@ -321,11 +315,11 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -321,11 +315,11 @@ 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(),
...@@ -334,21 +328,21 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -334,21 +328,21 @@ describe(Support.getTestDialectTeaser('associations'), () => {
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(),
...@@ -356,7 +350,7 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -356,7 +350,7 @@ describe(Support.getTestDialectTeaser('associations'), () => {
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);
...@@ -370,8 +364,8 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -370,8 +364,8 @@ describe(Support.getTestDialectTeaser('associations'), () => {
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')
}, },
...@@ -396,7 +390,7 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -396,7 +390,7 @@ describe(Support.getTestDialectTeaser('associations'), () => {
{ 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);
...@@ -412,7 +406,6 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -412,7 +406,6 @@ describe(Support.getTestDialectTeaser('associations'), () => {
expect(postC.get('tags')[0].get('type')).to.equal('tag'); expect(postC.get('tags')[0].get('type')).to.equal('tag');
}); });
}); });
});
describe('on the through model', () => { describe('on the through model', () => {
beforeEach(function() { beforeEach(function() {
...@@ -502,16 +495,17 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -502,16 +495,17 @@ 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([
const [post0, image0, question0, tagA, tagB, tagC] = await Promise.all([
this.Post.create(), this.Post.create(),
this.Image.create(), this.Image.create(),
this.Question.create(), this.Question.create(),
...@@ -519,19 +513,20 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -519,19 +513,20 @@ describe(Support.getTestDialectTeaser('associations'), () => {
this.Tag.create({ name: 'tagB' }), this.Tag.create({ name: 'tagB' }),
this.Tag.create({ name: 'tagC' }) this.Tag.create({ name: 'tagC' })
]); ]);
}).then(([post, image, question, tagA, tagB, tagC]) => {
this.post = post; this.post = post0;
this.image = image; this.image = image0;
this.question = question; this.question = question0;
return Promise.all([post.setTags([tagA]).then(() => {
return Promise.all([post.createTag({ name: 'postTag' }), post.addTag(tagB)]); await Promise.all([post0.setTags([tagA]).then(async () => {
}), image.setTags([tagB]).then(() => { return Promise.all([post0.createTag({ name: 'postTag' }), post0.addTag(tagB)]);
return Promise.all([image.createTag({ name: 'imageTag' }), image.addTag(tagC)]); }), image0.setTags([tagB]).then(async () => {
}), question.setTags([tagC]).then(() => { return Promise.all([image0.createTag({ name: 'imageTag' }), image0.addTag(tagC)]);
return Promise.all([question.createTag({ name: 'questionTag' }), question.addTag(tagA)]); }), question0.setTags([tagC]).then(async () => {
return Promise.all([question0.createTag({ name: 'questionTag' }), question0.addTag(tagA)]);
})]); })]);
}).then(() => {
return Promise.all([this.post.getTags(), this.image.getTags(), this.question.getTags()]).then(([postTags, imageTags, questionTags]) => { const [postTags, imageTags, questionTags] = await Promise.all([this.post.getTags(), this.image.getTags(), this.question.getTags()]);
expect(postTags.length).to.equal(3); expect(postTags.length).to.equal(3);
expect(imageTags.length).to.equal(3); expect(imageTags.length).to.equal(3);
expect(questionTags.length).to.equal(3); expect(questionTags.length).to.equal(3);
...@@ -547,8 +542,8 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -547,8 +542,8 @@ describe(Support.getTestDialectTeaser('associations'), () => {
expect(questionTags.map(tag => { expect(questionTags.map(tag => {
return tag.name; return tag.name;
}).sort()).to.deep.equal(['questionTag', 'tagA', 'tagC']); }).sort()).to.deep.equal(['questionTag', 'tagA', 'tagC']);
}).then(() => {
return Promise.all([this.Post.findOne({ const [post, image, question] = await Promise.all([this.Post.findOne({
where: {}, where: {},
include: [this.Tag] include: [this.Tag]
}), this.Image.findOne({ }), this.Image.findOne({
...@@ -557,7 +552,8 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -557,7 +552,8 @@ describe(Support.getTestDialectTeaser('associations'), () => {
}), this.Question.findOne({ }), this.Question.findOne({
where: {}, where: {},
include: [this.Tag] include: [this.Tag]
})]).then(([post, image, question]) => { })]);
expect(post.tags.length).to.equal(3); expect(post.tags.length).to.equal(3);
expect(image.tags.length).to.equal(3); expect(image.tags.length).to.equal(3);
expect(question.tags.length).to.equal(3); expect(question.tags.length).to.equal(3);
...@@ -576,9 +572,6 @@ describe(Support.getTestDialectTeaser('associations'), () => { ...@@ -576,9 +572,6 @@ describe(Support.getTestDialectTeaser('associations'), () => {
}); });
}); });
}); });
});
});
});
} }
}); });
}); });
...@@ -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({
await Group.findAll({
include: [{ include: [{
model: Group, model: Group,
as: 'Parent' 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([
const [mary, john, chris] = await Promise.all([
Person.create({ name: 'Mary' }), Person.create({ name: 'Mary' }),
Person.create({ name: 'John' }), Person.create({ name: 'John' }),
Person.create({ name: 'Chris' }) 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([
const [mary, john, chris] = await Promise.all([
Person.create({ name: 'Mary' }), Person.create({ name: 'Mary' }),
Person.create({ name: 'John' }), Person.create({ name: 'John' }),
Person.create({ name: 'Chris' }) Person.create({ name: 'Chris' })
]).then(([mary, john, chris]) => { ]);
return mary.setParents([john]).then(() => {
return chris.addParent(john); await mary.setParents([john]);
}).then(() => { await chris.addParent(john);
return john.getChilds(); const children = await john.getChilds();
}).then(children => {
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,17 +98,19 @@ describe(Support.getTestDialectTeaser('Self'), () => { ...@@ -101,17 +98,19 @@ 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([
const [mary, john, chris] = await Promise.all([
Person.create({ name: 'Mary' }), Person.create({ name: 'Mary' }),
Person.create({ name: 'John' }), Person.create({ name: 'John' }),
Person.create({ name: 'Chris' }) Person.create({ name: 'Chris' })
]); ]);
}).then(([mary, john, chris]) => {
this.mary = mary; this.mary = mary;
this.chris = chris; this.chris = chris;
this.john = john; this.john = john;
return mary.setParents([john], {
await mary.setParents([john], {
logging(sql) { logging(sql) {
if (sql.match(/INSERT/)) { if (sql.match(/INSERT/)) {
count++; count++;
...@@ -120,8 +119,8 @@ describe(Support.getTestDialectTeaser('Self'), () => { ...@@ -120,8 +119,8 @@ describe(Support.getTestDialectTeaser('Self'), () => {
} }
} }
}); });
}).then(() => {
return this.mary.addParent(this.chris, { await this.mary.addParent(this.chris, {
logging(sql) { logging(sql) {
if (sql.match(/INSERT/)) { if (sql.match(/INSERT/)) {
count++; count++;
...@@ -130,18 +129,18 @@ describe(Support.getTestDialectTeaser('Self'), () => { ...@@ -130,18 +129,18 @@ describe(Support.getTestDialectTeaser('Self'), () => {
} }
} }
}); });
}).then(() => {
return this.john.getChildren({ const children = await this.john.getChildren({
logging(sql) { logging(sql) {
count++; count++;
const whereClause = sql.split('FROM')[1]; // look only in the whereClause const whereClause = sql.split('FROM')[1];
// look only in the whereClause
expect(whereClause).to.have.string('preexisting_child'); expect(whereClause).to.have.string('preexisting_child');
expect(whereClause).to.have.string('preexisting_parent'); expect(whereClause).to.have.string('preexisting_parent');
} }
}); });
}).then(children => {
expect(count).to.be.equal(3); expect(count).to.be.equal(3);
expect(children.map(v => v.id)).to.have.members([this.mary.id]); 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!