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

Commit 8a12e05d by Matt Broadstone

only enable RESTRICT fk constraint tests for supporting dialects

MSSQL doesn't support a RESTRICT fk constraint, so we need a way
to conditionally disable these tests. This change adds an extra
section to dialect.supports indicating support for RESTRICT
constraints. Also changed some cases where RESTRICT wasn't being
explicitly tested but used to test the ability to simply use
constraints (query-interface.test.js)
1 parent d5cef99f
...@@ -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,6 +429,7 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -428,6 +429,7 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
if (current.dialect.supports.constraints.restrict) {
it("can restrict deletes", function(done) { it("can restrict deletes", function(done) {
var self = this var self = this
var Task = this.sequelize.define('Task', { title: DataTypes.STRING }) var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
...@@ -453,11 +455,12 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -453,11 +455,12 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
it("can cascade updates", function(done) { it("can restrict updates", function(done) {
var self = this
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: 'cascade'}) Task.belongsTo(User, {onUpdate: '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) {
...@@ -470,10 +473,10 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -470,10 +473,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)
.success(function() { .catch(self.sequelize.ForeignKeyConstraintError, 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()
}) })
}) })
...@@ -483,12 +486,13 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -483,12 +486,13 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
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,57 +2253,58 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -2252,57 +2253,58 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}); });
}); });
it("can restrict deletes", function() { it("can cascade updates", function() {
var self = this;
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 });
User.hasMany(Task, {onDelete: 'restrict'}); User.hasMany(Task, {onUpdate: 'cascade'});
return this.sequelize.sync({ force: true }).bind({}).then(function() { return this.sequelize.sync({ force: true }).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) {
this.user = user; return user.setTasks([task]).return(user);
this.task = task; }).then(function(user) {
return user.setTasks([task]); // 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);
}).then(function() { }).then(function() {
return this.user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function () {
// Should fail due to FK violation
return Task.findAll(); return Task.findAll();
});
}).then(function(tasks) { }).then(function(tasks) {
expect(tasks).to.have.length(1); expect(tasks).to.have.length(1);
expect(tasks[0].UserId).to.equal(999);
}); });
}); });
it("can cascade updates", function() { if (current.dialect.supports.constraints.restrict) {
it("can restrict deletes", function() {
var self = this;
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 });
User.hasMany(Task, {onUpdate: 'cascade'}); 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
// `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.Model);
return user.QueryInterface.update(user, tableName, {id: 999}, user.id);
}).then(function() { }).then(function() {
return this.user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function () {
// Should fail due to FK violation
return Task.findAll(); return Task.findAll();
});
}).then(function(tasks) { }).then(function(tasks) {
expect(tasks).to.have.length(1); expect(tasks).to.have.length(1);
expect(tasks[0].UserId).to.equal(999);
}); });
}); });
...@@ -2335,6 +2337,9 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -2335,6 +2337,9 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
expect(tasks).to.have.length(1); expect(tasks).to.have.length(1);
}); });
}); });
}
}); });
describe('n:m', function () { describe('n:m', function () {
...@@ -2382,6 +2387,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -2382,6 +2387,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}); });
}); });
if (current.dialect.supports.constraints.restrict) {
it("can restrict deletes both ways", function () { it("can restrict deletes both ways", function () {
var self = this var self = this
, spy = sinon.spy(); , spy = sinon.spy();
...@@ -2452,6 +2459,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -2452,6 +2459,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}); });
}); });
}
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,22 +387,28 @@ describe(Support.getTestDialectTeaser("HasOne"), function() { ...@@ -386,22 +387,28 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
it("can restrict deletes", function(done) { it("can cascade updates", function(done) {
var self = this
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 })
User.hasOne(Task, {onDelete: 'restrict'}) User.hasOne(Task, {onUpdate: 'cascade'})
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() { Task.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) {
user.setTask(task).success(function() { user.setTask(task).success(function() {
user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function() {
// Should fail due to FK restriction // 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)
.success(function() {
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()
}) })
}) })
...@@ -412,28 +419,24 @@ describe(Support.getTestDialectTeaser("HasOne"), function() { ...@@ -412,28 +419,24 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
it("can cascade updates", function(done) { if (current.dialect.supports.constraints.restrict) {
it("can restrict deletes", function(done) {
var self = this
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 })
User.hasOne(Task, {onUpdate: 'cascade'}) User.hasOne(Task, {onDelete: 'restrict'})
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() { Task.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) {
user.setTask(task).success(function() { user.setTask(task).success(function() {
user.destroy().catch(self.sequelize.ForeignKeyConstraintError, function() {
// Changing the id of a DAO requires a little dance since // Should fail due to FK restriction
// 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)
.success(function() {
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()
}) })
}) })
...@@ -477,6 +480,8 @@ describe(Support.getTestDialectTeaser("HasOne"), function() { ...@@ -477,6 +480,8 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}
}) })
describe("Association column", function() { describe("Association column", 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!