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

Commit 2bc77fac by Jarkko Mönkkönen

Prefer index name when mapping unique constraint errors

When using migrations to create indexes instead of sync or when unique
index name has fields with underscores (was problem at least with
postgres implementation) then it was not possible to set custom error
message, because mapping the error thrown from database always failed.
Fixed by using indexName always for mapping the error if possible.
1 parent a64c0371
...@@ -162,13 +162,22 @@ module.exports = (function() { ...@@ -162,13 +162,22 @@ module.exports = (function() {
uniqueConstraintMapping: { uniqueConstraintMapping: {
code: '23505', code: '23505',
map: function(str) { map: function(str) {
var match = str.match(/duplicate key value violates unique constraint "(.*?)_key"/); var match = str.match(/duplicate key value violates unique constraint "(.*?)"/);
if (match === null || match.length < 2) { if (match === null || match.length < 2) {
return false; return false;
} }
var indexName = match[1];
var fields = [];
match = indexName.match(/(.*?)_key/);
if (!!match && match.length > 1) {
fields = match[1].split('_').splice(1);
}
return { return {
fields: match[1].split('_').splice(1) indexName: indexName,
fields: fields
}; };
} }
}, },
......
...@@ -614,15 +614,19 @@ module.exports = (function() { ...@@ -614,15 +614,19 @@ module.exports = (function() {
if (index !== false) { if (index !== false) {
var fields = index.fields.filter(function(f) { return f !== self.Model.tableName; }); var fields = index.fields.filter(function(f) { return f !== self.Model.tableName; });
Utils._.each(self.__options.uniqueKeys, function(uniqueKey) { Utils._.each(self.__options.uniqueKeys, function(uniqueKey) {
if (!!uniqueKey.msg && (Utils._.isEqual(uniqueKey.fields, fields)) || uniqueKey.name === index.indexName) { if (!!uniqueKey.msg) {
err = new self.sequelize.UniqueConstraintError({ if (uniqueKey.name === index.indexName) {
message: uniqueKey.msg, fields = _.clone(uniqueKey.fields);
fields: fields, }
index: index.indexName, if (Utils._.isEqual(uniqueKey.fields, fields)) {
parent: err.parent err = new self.sequelize.UniqueConstraintError({
}); message: uniqueKey.msg,
fields: fields,
index: index.indexName,
parent: err.parent
});
}
} }
}); });
} }
......
...@@ -342,7 +342,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -342,7 +342,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
} }
}); });
}); });
}); })
it('allows us to customize the error message for unique constraint', function(done) { it('allows us to customize the error message for unique constraint', function(done) {
var self = this var self = this
...@@ -363,6 +363,40 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -363,6 +363,40 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}) })
}) })
// If you use migrations to create unique indexes that have explicit names and/or contain fields
// that have underscore in their name. Then sequelize must use the index name to map the custom message to the error thrown from db.
it('allows us to map the customized error message with unique constraint name', function(done) {
// Fake migration style index creation with explicit index definition
var self = this
, User = this.sequelize.define('UserWithUniqueUsername', {
user_id: { type: Sequelize.INTEGER},
email: { type: Sequelize.STRING}
}, {
indexes: [
{
name: 'user_and_email_index',
msg: 'User and email must be unique',
unique: true,
method: 'BTREE',
fields: ['user_id', {attribute:'email', collate: dialect === 'sqlite' ? 'RTRIM' : 'en_US', order: 'DESC', length: 5}]
}]
});
User.sync({ force: true }).success(function() {
// Redefine the model to use the index in database and override error message
User = self.sequelize.define('UserWithUniqueUsername', {
user_id: { type: Sequelize.INTEGER, unique: { name: 'user_and_email_index', msg: 'User and email must be unique' }},
email: { type: Sequelize.STRING, unique: 'user_and_email_index'}
});
User.create({user_id: 1, email: 'tobi@tobi.me'}).success(function() {
User.create({user_id: 1, email: 'tobi@tobi.me'}).catch(self.sequelize.UniqueConstraintError, function(err) {
expect(err.message).to.equal('User and email must be unique')
done()
})
})
})
})
it('should allow the user to specify indexes in options', function () { it('should allow the user to specify indexes in options', function () {
var Model = this.sequelize.define('model', { var Model = this.sequelize.define('model', {
fieldA: Sequelize.STRING, fieldA: Sequelize.STRING,
...@@ -707,14 +741,14 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -707,14 +741,14 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
sequelize.transaction().then(function(t) { sequelize.transaction().then(function(t) {
User.create({ username: 'foo' }, { transaction: t }).success(function() { User.create({ username: 'foo' }, { transaction: t }).success(function() {
User.findOrInitialize({ User.findOrInitialize({
where: {username: 'foo'} where: {username: 'foo'}
}).spread(function(user1) { }).spread(function(user1) {
User.findOrInitialize({ User.findOrInitialize({
where: {username: 'foo'}, where: {username: 'foo'},
transaction: t transaction: t
}).spread(function(user2) { }).spread(function(user2) {
User.findOrInitialize({ User.findOrInitialize({
where: {username: 'foo'}, where: {username: 'foo'},
defaults: { foo: 'asd' }, defaults: { foo: 'asd' },
transaction: t transaction: t
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!