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

Commit 5f4a5637 by Mick Hansen

Merge pull request #2605 from mbroadst/restrict-support

only enable RESTRICT fk constraint tests for supporting dialects
2 parents d5cef99f 8a12e05d
...@@ -11,6 +11,9 @@ AbstractDialect.prototype.supports = { ...@@ -11,6 +11,9 @@ AbstractDialect.prototype.supports = {
'VALUES ()': false, 'VALUES ()': false,
'LIMIT ON UPDATE': false, 'LIMIT ON UPDATE': false,
schemas: false, schemas: false,
constraints: {
restrict: true
},
index: { index: {
collate: true, collate: true,
length: false, length: false,
......
...@@ -6,6 +6,7 @@ var chai = require('chai') ...@@ -6,6 +6,7 @@ var chai = require('chai')
, Sequelize = require('../../index') , Sequelize = require('../../index')
, Promise = Sequelize.Promise , Promise = Sequelize.Promise
, assert = require('assert') , assert = require('assert')
, current = Support.sequelize;
chai.config.includeStack = true chai.config.includeStack = true
...@@ -428,67 +429,70 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -428,67 +429,70 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
it("can restrict deletes", function(done) { if (current.dialect.supports.constraints.restrict) {
var self = this it("can restrict deletes", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING }) var self = this
, User = this.sequelize.define('User', { username: DataTypes.STRING }) var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING })
Task.belongsTo(User, {onDelete: 'restrict'}) Task.belongsTo(User, {onDelete: 'restrict'})
this.sequelize.sync({ force: true }).success(function() { this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() { task.setUser(user).success(function() {
// Should fail due to FK restriction // Should fail due to FK restriction
user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function(err) { user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function(err) {
expect(err).to.be.ok; expect(err).to.be.ok;
Task.findAll().success(function(tasks) { Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1) expect(tasks).to.have.length(1)
done() done()
})
}) })
}) });
}); })
}) })
}) })
}) })
})
it("can cascade updates", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING })
Task.belongsTo(User, {onUpdate: 'cascade'}) it("can restrict updates", function(done) {
var self = this
this.sequelize.sync({ force: true }).success(function() { var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
User.create({ username: 'foo' }).success(function(user) { , User = this.sequelize.define('User', { username: DataTypes.STRING })
Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() {
// Changing the id of a DAO requires a little dance since Task.belongsTo(User, {onUpdate: 'restrict'})
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.Model) this.sequelize.sync({ force: true }).success(function() {
user.QueryInterface.update(user, tableName, {id: 999}, user.id) User.create({ username: 'foo' }).success(function(user) {
.success(function() { Task.create({ title: 'task' }).success(function(task) {
Task.findAll().success(function(tasks) { task.setUser(user).success(function() {
expect(tasks).to.have.length(1)
expect(tasks[0].UserId).to.equal(999) // Changing the id of a DAO requires a little dance since
done() // the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.Model)
user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.catch(self.sequelize.ForeignKeyConstraintError, function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1)
done()
})
}) })
}) })
}) })
}) })
}) })
}) })
})
it("can restrict updates", function(done) { }
var self = this
it("can cascade updates", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING }) var 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: 'cascade'})
this.sequelize.sync({ force: true }).success(function() { this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
...@@ -501,10 +505,10 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -501,10 +505,10 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() {
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.Model) var tableName = user.QueryInterface.QueryGenerator.addSchema(user.Model)
user.QueryInterface.update(user, tableName, {id: 999}, user.id) user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.catch(self.sequelize.ForeignKeyConstraintError, function() { .success(function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) { Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1) expect(tasks).to.have.length(1)
expect(tasks[0].UserId).to.equal(999)
done() done()
}) })
}) })
...@@ -513,6 +517,7 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -513,6 +517,7 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
}) })
}) })
describe("Association column", function() { describe("Association column", function() {
......
...@@ -9,7 +9,8 @@ var chai = require('chai') ...@@ -9,7 +9,8 @@ var chai = require('chai')
, _ = require('lodash') , _ = require('lodash')
, moment = require('moment') , moment = require('moment')
, sinon = require('sinon') , sinon = require('sinon')
, Promise = Sequelize.Promise; , Promise = Sequelize.Promise
, current = Support.sequelize;
chai.config.includeStack = true; chai.config.includeStack = true;
...@@ -2252,32 +2253,6 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -2252,32 +2253,6 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}); });
}); });
it("can restrict deletes", function() {
var self = this;
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING });
User.hasMany(Task, {onDelete: 'restrict'});
return this.sequelize.sync({ force: true }).bind({}).then(function() {
return Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' }),
]);
}).spread(function (user, task) {
this.user = user;
this.task = task;
return user.setTasks([task]);
}).then(function() {
return this.user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function () {
// Should fail due to FK violation
return Task.findAll();
});
}).then(function(tasks) {
expect(tasks).to.have.length(1);
});
});
it("can cascade updates", function() { it("can cascade updates", function() {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING }) var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING }); , User = this.sequelize.define('User', { username: DataTypes.STRING });
...@@ -2306,35 +2281,65 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -2306,35 +2281,65 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}); });
}); });
it("can restrict updates", function() { if (current.dialect.supports.constraints.restrict) {
var self = this; it("can restrict deletes", function() {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING }) var self = this;
, User = this.sequelize.define('User', { username: DataTypes.STRING }); var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING });
User.hasMany(Task, {onUpdate: 'restrict'}); User.hasMany(Task, {onDelete: 'restrict'});
return this.sequelize.sync({ force: true }).then(function() { return this.sequelize.sync({ force: true }).bind({}).then(function() {
return Promise.all([ return Promise.all([
User.create({ username: 'foo' }), User.create({ username: 'foo' }),
Task.create({ title: 'task' }) Task.create({ title: 'task' }),
]); ]);
}).spread(function (user, task) { }).spread(function (user, task) {
return user.setTasks([task]).return(user); this.user = user;
}).then(function(user) { this.task = task;
// Changing the id of a DAO requires a little dance since return user.setTasks([task]);
// the `UPDATE` query generated by `save()` uses `id` in the }).then(function() {
// `WHERE` clause return this.user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function () {
// Should fail due to FK violation
return Task.findAll();
});
}).then(function(tasks) {
expect(tasks).to.have.length(1);
});
});
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.Model); it("can restrict updates", function() {
return user.QueryInterface.update(user, tableName, {id: 999}, user.id) var self = this;
.catch(self.sequelize.ForeignKeyConstraintError, function() { var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
// Should fail due to FK violation , User = this.sequelize.define('User', { username: DataTypes.STRING });
return Task.findAll();
User.hasMany(Task, {onUpdate: 'restrict'});
return this.sequelize.sync({ force: true }).then(function() {
return Promise.all([
User.create({ username: 'foo' }),
Task.create({ title: 'task' })
]);
}).spread(function (user, task) {
return user.setTasks([task]).return(user);
}).then(function(user) {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.Model);
return user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.catch(self.sequelize.ForeignKeyConstraintError, function() {
// Should fail due to FK violation
return Task.findAll();
});
}).then(function(tasks) {
expect(tasks).to.have.length(1);
}); });
}).then(function(tasks) {
expect(tasks).to.have.length(1);
}); });
});
}
}); });
describe('n:m', function () { describe('n:m', function () {
...@@ -2382,75 +2387,79 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -2382,75 +2387,79 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}); });
}); });
it("can restrict deletes both ways", function () { if (current.dialect.supports.constraints.restrict) {
var self = this
, spy = sinon.spy();
this.User.hasMany(this.Task, { onDelete: 'RESTRICT'}); it("can restrict deletes both ways", function () {
this.Task.hasMany(this.User, { onDelete: 'RESTRICT'}); var self = this
, spy = sinon.spy();
return this.sequelize.sync({ force: true }).bind({}).then(function() { this.User.hasMany(this.Task, { onDelete: 'RESTRICT'});
return Promise.all([ this.Task.hasMany(this.User, { onDelete: 'RESTRICT'});
self.User.create({ id: 67, username: 'foo' }),
self.Task.create({ id: 52, title: 'task' }), return this.sequelize.sync({ force: true }).bind({}).then(function() {
self.User.create({ id: 89, username: 'bar' }), return Promise.all([
self.Task.create({ id: 42, title: 'kast' }), self.User.create({ id: 67, username: 'foo' }),
]); self.Task.create({ id: 52, title: 'task' }),
}).spread(function (user1, task1, user2, task2) { self.User.create({ id: 89, username: 'bar' }),
this.user1 = user1; self.Task.create({ id: 42, title: 'kast' }),
this.task1 = task1; ]);
this.user2 = user2; }).spread(function (user1, task1, user2, task2) {
this.task2 = task2; this.user1 = user1;
return Promise.all([ this.task1 = task1;
user1.setTasks([task1]), this.user2 = user2;
task2.setUsers([user2]) this.task2 = task2;
]); return Promise.all([
}).then(function () { user1.setTasks([task1]),
return Promise.all([ task2.setUsers([user2])
this.user1.destroy().catch(self.sequelize.ForeignKeyConstraintError, spy), // Fails because of RESTRICT constraint ]);
this.task2.destroy().catch(self.sequelize.ForeignKeyConstraintError, spy) }).then(function () {
]); return Promise.all([
}).then(function () { this.user1.destroy().catch(self.sequelize.ForeignKeyConstraintError, spy), // Fails because of RESTRICT constraint
expect(spy).to.have.been.calledTwice; this.task2.destroy().catch(self.sequelize.ForeignKeyConstraintError, spy)
]);
}).then(function () {
expect(spy).to.have.been.calledTwice;
});
}); });
});
it("can cascade and restrict deletes", function () { it("can cascade and restrict deletes", function () {
var spy = sinon.spy() var spy = sinon.spy()
, self = this; , self = this;
self.User.hasMany(self.Task, { onDelete: 'RESTRICT'}); self.User.hasMany(self.Task, { onDelete: 'RESTRICT'});
self.Task.hasMany(self.User); // Implicit CASCADE self.Task.hasMany(self.User); // Implicit CASCADE
return this.sequelize.sync({ force: true }).bind({}).then(function() { return this.sequelize.sync({ force: true }).bind({}).then(function() {
return Promise.all([ return Promise.all([
self.User.create({ id: 67, username: 'foo' }), self.User.create({ id: 67, username: 'foo' }),
self.Task.create({ id: 52, title: 'task' }), self.Task.create({ id: 52, title: 'task' }),
self.User.create({ id: 89, username: 'bar' }), self.User.create({ id: 89, username: 'bar' }),
self.Task.create({ id: 42, title: 'kast' }), self.Task.create({ id: 42, title: 'kast' }),
]); ]);
}).spread(function (user1, task1, user2, task2) { }).spread(function (user1, task1, user2, task2) {
this.user1 = user1; this.user1 = user1;
this.task1 = task1; this.task1 = task1;
this.user2 = user2; this.user2 = user2;
this.task2 = task2; this.task2 = task2;
return Promise.all([ return Promise.all([
user1.setTasks([task1]), user1.setTasks([task1]),
task2.setUsers([user2]) task2.setUsers([user2])
]); ]);
}).then(function () { }).then(function () {
return Promise.all([ return Promise.all([
this.user1.destroy().catch(self.sequelize.ForeignKeyConstraintError, spy), // Fails because of RESTRICT constraint this.user1.destroy().catch(self.sequelize.ForeignKeyConstraintError, spy), // Fails because of RESTRICT constraint
this.task2.destroy() this.task2.destroy()
]); ]);
}).then(function () { }).then(function () {
expect(spy).to.have.been.calledOnce; expect(spy).to.have.been.calledOnce;
return self.sequelize.model('tasksusers').findAll({ where: { taskId: this.task2.id }}); return self.sequelize.model('tasksusers').findAll({ where: { taskId: this.task2.id }});
}).then(function(usertasks) { }).then(function(usertasks) {
// This should not exist because deletes cascade // This should not exist because deletes cascade
expect(usertasks).to.have.length(0); expect(usertasks).to.have.length(0);
});
}); });
});
}
it("should be possible to remove all constraints", function () { it("should be possible to remove all constraints", function () {
var self = this; var self = this;
......
...@@ -4,6 +4,7 @@ var chai = require('chai') ...@@ -4,6 +4,7 @@ var chai = require('chai')
, Support = require(__dirname + '/../support') , Support = require(__dirname + '/../support')
, Sequelize = require('../../index') , Sequelize = require('../../index')
, Promise = Sequelize.Promise , Promise = Sequelize.Promise
, current = Support.sequelize;
chai.config.includeStack = true chai.config.includeStack = true
...@@ -386,32 +387,6 @@ describe(Support.getTestDialectTeaser("HasOne"), function() { ...@@ -386,32 +387,6 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
it("can restrict deletes", function(done) {
var self = this
var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING })
User.hasOne(Task, {onDelete: 'restrict'})
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1)
done()
})
})
})
})
})
})
})
})
it("can cascade updates", function(done) { it("can cascade updates", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING }) , User = this.sequelize.define('User', { username: Sequelize.STRING })
...@@ -444,30 +419,59 @@ describe(Support.getTestDialectTeaser("HasOne"), function() { ...@@ -444,30 +419,59 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
it("can restrict updates", function(done) { if (current.dialect.supports.constraints.restrict) {
var self = this
var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING })
User.hasOne(Task, {onUpdate: 'restrict'}) it("can restrict deletes", function(done) {
var self = this
var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING })
User.sync({ force: true }).success(function() { User.hasOne(Task, {onDelete: 'restrict'})
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
// Changing the id of a DAO requires a little dance since User.sync({ force: true }).success(function() {
// the `UPDATE` query generated by `save()` uses `id` in the Task.sync({ force: true }).success(function() {
// `WHERE` clause User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1)
done()
})
})
})
})
})
})
})
})
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.Model) it("can restrict updates", function(done) {
user.QueryInterface.update(user, tableName, {id: 999}, user.id) var self = this
.catch(self.sequelize.ForeignKeyConstraintError, function() { var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
// Should fail due to FK restriction , User = this.sequelize.define('User', { username: Sequelize.STRING })
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1) User.hasOne(Task, {onUpdate: 'restrict'})
done()
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.Model)
user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.catch(self.sequelize.ForeignKeyConstraintError, function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1)
done()
})
}) })
}) })
}) })
...@@ -475,7 +479,8 @@ describe(Support.getTestDialectTeaser("HasOne"), function() { ...@@ -475,7 +479,8 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}) })
})
}
}) })
......
...@@ -244,7 +244,7 @@ describe(Support.getTestDialectTeaser("QueryInterface"), function () { ...@@ -244,7 +244,7 @@ describe(Support.getTestDialectTeaser("QueryInterface"), function () {
references: 'level', references: 'level',
referenceKey: 'id', referenceKey: 'id',
onUpdate: 'cascade', onUpdate: 'cascade',
onDelete: 'restrict' onDelete: 'set null'
}); });
}); });
}); });
...@@ -292,7 +292,7 @@ describe(Support.getTestDialectTeaser("QueryInterface"), function () { ...@@ -292,7 +292,7 @@ describe(Support.getTestDialectTeaser("QueryInterface"), function () {
references: 'users', references: 'users',
referenceKey: 'id', referenceKey: 'id',
onUpdate: 'cascade', onUpdate: 'cascade',
onDelete: 'restrict' onDelete: 'set null'
}, },
}) })
}) })
...@@ -308,7 +308,7 @@ describe(Support.getTestDialectTeaser("QueryInterface"), function () { ...@@ -308,7 +308,7 @@ describe(Support.getTestDialectTeaser("QueryInterface"), function () {
if (dialect === "postgres" || dialect === "postgres-native") { if (dialect === "postgres" || dialect === "postgres-native") {
expect(keys).to.have.length(6) expect(keys).to.have.length(6)
expect(keys2).to.have.length(7) expect(keys2).to.have.length(7)
expect(keys3).to.have.length(8) expect(keys3).to.have.length(7)
} else if (dialect === "sqlite") { } else if (dialect === "sqlite") {
expect(keys).to.have.length(8) expect(keys).to.have.length(8)
} else if (dialect === "mysql") { } else if (dialect === "mysql") {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!