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

Commit 1c96744f by Jan Aagaard Meier

Merge pull request #2746 from x-warrior/master

Resolving multiple hasMany cascades which weren't working in some cases
2 parents 8ea99e8a 0bbf8de9
Showing with 315 additions and 1 deletions
...@@ -604,7 +604,12 @@ module.exports = (function() { ...@@ -604,7 +604,12 @@ module.exports = (function() {
dao[cascades[i]]().success(function(tasks) { dao[cascades[i]]().success(function(tasks) {
if (tasks === null || tasks.length < 1) { if (tasks === null || tasks.length < 1) {
if (i >= cascades.length) {
return resolve(); return resolve();
} else {
tick++;
return iterate(null, tick);
}
} }
tasks = Array.isArray(tasks) ? tasks : [tasks]; tasks = Array.isArray(tasks) ? tasks : [tasks];
......
...@@ -6,7 +6,8 @@ var chai = require('chai') ...@@ -6,7 +6,8 @@ var chai = require('chai')
, DataTypes = require(__dirname + '/../lib/data-types') , DataTypes = require(__dirname + '/../lib/data-types')
, _ = require('lodash') , _ = require('lodash')
, Sequelize = Support.Sequelize , Sequelize = Support.Sequelize
, sinon = require('sinon'); , sinon = require('sinon')
, dialect = Support.getTestDialect();
chai.config.includeStack = true; chai.config.includeStack = true;
...@@ -5331,6 +5332,314 @@ describe(Support.getTestDialectTeaser('Hooks'), function() { ...@@ -5331,6 +5332,314 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
}); });
}); });
}); });
// NOTE: Reenable when FK constraints create table query is fixed when using hooks
if (dialect !== "mssql") {
describe('multiple 1:M', function () {
describe('cascade', function() {
beforeEach(function() {
var self = this;
this.Projects = this.sequelize.define('Project', {
title: DataTypes.STRING
});
this.Tasks = this.sequelize.define('Task', {
title: DataTypes.STRING
});
this.MiniTasks = this.sequelize.define('MiniTask', {
mini_title: DataTypes.STRING
});
this.Projects.hasMany(this.Tasks, {onDelete: 'cascade', hooks: true});
this.Projects.hasMany(this.MiniTasks, {onDelete: 'cascade', hooks: true});
this.Tasks.belongsTo(this.Projects, {hooks: true});
this.Tasks.hasMany(this.MiniTasks, {onDelete: 'cascade', hooks: true});
this.MiniTasks.belongsTo(this.Projects, {hooks: true});
this.MiniTasks.belongsTo(this.Tasks, {hooks: true});
return this.sequelize.sync({force: true});
});
describe('#remove', function() {
it('with no errors', function() {
var self = this
, beforeProject = false
, afterProject = false
, beforeTask = false
, afterTask = false
, beforeMiniTask = false
, afterMiniTask = false;
this.Projects.beforeCreate(function(project, options, fn) {
beforeProject = true;
fn();
});
this.Projects.afterCreate(function(project, options, fn) {
afterProject = true;
fn();
});
this.Tasks.beforeDestroy(function(task, options, fn) {
beforeTask = true;
fn();
});
this.Tasks.afterDestroy(function(task, options, fn) {
afterTask = true;
fn();
});
this.MiniTasks.beforeDestroy(function(minitask, options, fn) {
beforeMiniTask = true;
fn();
});
this.MiniTasks.afterDestroy(function(minitask, options, fn) {
afterMiniTask = true;
fn();
});
return this.sequelize.Promise.all([
this.Projects.create({title: 'New Project'}),
this.MiniTasks.create({mini_title: 'New MiniTask'})
]).bind(this).spread(function(project, minitask) {
return project.addMiniTask(minitask);
}).then(function(project) {
return project.destroy();
}).then(function() {
expect(beforeProject).to.be.true;
expect(afterProject).to.be.true;
expect(beforeTask).to.be.false;
expect(afterTask).to.be.false;
expect(beforeMiniTask).to.be.true;
expect(afterMiniTask).to.be.true;
});
});
it('with errors', function() {
var self = this
, beforeProject = false
, afterProject = false
, beforeTask = false
, afterTask = false
, beforeMiniTask = false
, afterMiniTask = false;
this.Projects.beforeCreate(function(project, options, fn) {
beforeProject = true;
fn();
});
this.Projects.afterCreate(function(project, options, fn) {
afterProject = true;
fn();
});
this.Tasks.beforeDestroy(function(task, options, fn) {
beforeTask = true;
fn();
});
this.Tasks.afterDestroy(function(task, options, fn) {
afterTask = true;
fn();
});
this.MiniTasks.beforeDestroy(function(minitask, options, fn) {
beforeMiniTask = true;
fn(new Error('Whoops!'));
});
this.MiniTasks.afterDestroy(function(minitask, options, fn) {
afterMiniTask = true;
fn();
});
return this.sequelize.Promise.all([
this.Projects.create({title: 'New Project'}),
this.MiniTasks.create({mini_title: 'New MiniTask'})
]).bind(this).spread(function(project, minitask) {
return project.addMiniTask(minitask);
}).then(function(project) {
return project.destroy();
}).catch(function() {
expect(beforeProject).to.be.true;
expect(afterProject).to.be.true;
expect(beforeTask).to.be.false;
expect(afterTask).to.be.false;
expect(beforeMiniTask).to.be.true;
expect(afterMiniTask).to.be.false;
});
});
});
});
});
describe('multiple 1:M sequential hooks', function () {
describe('cascade', function() {
beforeEach(function() {
var self = this;
this.Projects = this.sequelize.define('Project', {
title: DataTypes.STRING
});
this.Tasks = this.sequelize.define('Task', {
title: DataTypes.STRING
});
this.MiniTasks = this.sequelize.define('MiniTask', {
mini_title: DataTypes.STRING
});
this.Projects.hasMany(this.Tasks, {onDelete: 'cascade', hooks: true});
this.Projects.hasMany(this.MiniTasks, {onDelete: 'cascade', hooks: true});
this.Tasks.belongsTo(this.Projects, {hooks: true});
this.Tasks.hasMany(this.MiniTasks, {onDelete: 'cascade', hooks: true});
this.MiniTasks.belongsTo(this.Projects, {hooks: true});
this.MiniTasks.belongsTo(this.Tasks, {hooks: true});
return this.sequelize.sync({force: true});
});
describe('#remove', function() {
it('with no errors', function() {
var self = this
, beforeProject = false
, afterProject = false
, beforeTask = false
, afterTask = false
, beforeMiniTask = false
, afterMiniTask = false;
this.Projects.beforeCreate(function(project, options, fn) {
beforeProject = true;
fn();
});
this.Projects.afterCreate(function(project, options, fn) {
afterProject = true;
fn();
});
this.Tasks.beforeDestroy(function(task, options, fn) {
beforeTask = true;
fn();
});
this.Tasks.afterDestroy(function(task, options, fn) {
afterTask = true;
fn();
});
this.MiniTasks.beforeDestroy(function(minitask, options, fn) {
beforeMiniTask = true;
fn();
});
this.MiniTasks.afterDestroy(function(minitask, options, fn) {
afterMiniTask = true;
fn();
});
return this.sequelize.Promise.all([
this.Projects.create({title: 'New Project'}),
this.Tasks.create({title: 'New Task'}),
this.MiniTasks.create({mini_title: 'New MiniTask'})
]).bind(this).spread(function(project, task, minitask) {
return this.sequelize.Promise.all([
task.addMiniTask(minitask),
project.addTask(task)
]).return(project);
}).then(function(project) {
return project.destroy();
}).then(function() {
expect(beforeProject).to.be.true;
expect(afterProject).to.be.true;
expect(beforeTask).to.be.true;
expect(afterTask).to.be.true;
expect(beforeMiniTask).to.be.true;
expect(afterMiniTask).to.be.true;
});
});
it('with errors', function() {
var self = this
, beforeProject = false
, afterProject = false
, beforeTask = false
, afterTask = false
, beforeMiniTask = false
, afterMiniTask = false;
this.Projects.beforeCreate(function(project, options, fn) {
beforeProject = true;
fn();
});
this.Projects.afterCreate(function(project, options, fn) {
afterProject = true;
fn();
});
this.Tasks.beforeDestroy(function(task, options, fn) {
beforeTask = true;
fn(new Error('Whoops!'));
fn();
});
this.Tasks.afterDestroy(function(task, options, fn) {
afterTask = true;
fn();
});
this.MiniTasks.beforeDestroy(function(minitask, options, fn) {
beforeMiniTask = true;
});
this.MiniTasks.afterDestroy(function(minitask, options, fn) {
afterMiniTask = true;
fn();
});
return this.sequelize.Promise.all([
this.Projects.create({title: 'New Project'}),
this.Tasks.create({title: 'New Task'}),
this.MiniTasks.create({mini_title: 'New MiniTask'})
]).bind(this).spread(function(project, task, minitask) {
return this.sequelize.Promise.all([
task.addMiniTask(minitask),
project.addTask(task)
]).return(project);
}).then(function(project) {
return project.destroy();
}).catch(function() {
expect(beforeProject).to.be.true;
expect(afterProject).to.be.true;
expect(beforeTask).to.be.true;
expect(afterTask).to.be.false;
expect(beforeMiniTask).to.be.false;
expect(afterMiniTask).to.be.false;
});
});
});
});
});
}
}); });
describe('passing DAO instances', function() { describe('passing DAO instances', function() {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!