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

Commit 10314423 by Dr. Evil

Proper ExcludeConstraintError details handling

Error constructor is now being exposed to the global Sequelize object
Some tests for the error are added as well
1 parent dc181e2d
...@@ -344,43 +344,19 @@ module.exports = (function() { ...@@ -344,43 +344,19 @@ module.exports = (function() {
break; break;
case '23P01': case '23P01':
// there are multiple different formats of error messages for this error code
// this regex should check at least two
match = errDetail.match(/Key \((.*?)\)=\((.*?)\)/); match = errDetail.match(/Key \((.*?)\)=\((.*?)\)/);
if (match) { fields = Utils._.zipObject(match[1].split(', '), match[2].split(', '));
fields = Utils._.zipObject(match[1].split(', '), match[2].split(', ')); message = 'Exclusion constraint error';
errors = [];
message = 'Validation error';
Utils._.forOwn(fields, function(value, field) { return new sequelizeErrors.ExclusionConstraintError({
errors.push(new sequelizeErrors.ValidationErrorItem( message: message,
field + ' must be unique', 'unique violation', field, value)); constraint: err.constraint,
}); fields: fields,
table: err.table,
if (this.callee && this.callee.__options && this.callee.__options.uniqueKeys) { parent: err
Utils._.forOwn(this.callee.__options.uniqueKeys, function(constraint) { });
if (Utils._.isEqual(constraint.fields, Object.keys(fields)) && !!constraint.msg) {
message = constraint.msg;
return false;
}
});
}
return new sequelizeErrors.ExclusionConstraintError({
message: message,
errors: errors,
parent: err,
fields: fields
});
} else {
return new sequelizeErrors.ExclusionConstraintError({
message: errMessage,
parent: err
});
}
break;
default: default:
return new sequelizeErrors.DatabaseError(err); return new sequelizeErrors.DatabaseError(err);
} }
......
...@@ -157,10 +157,9 @@ error.ExclusionConstraintError = function (options) { ...@@ -157,10 +157,9 @@ error.ExclusionConstraintError = function (options) {
this.name = 'SequelizeExclusionConstraintError'; this.name = 'SequelizeExclusionConstraintError';
this.message = options.message; this.message = options.message;
this.constraint = options.constraint;
this.fields = options.fields; this.fields = options.fields;
this.table = options.table; this.table = options.table;
this.value = options.value;
this.index = options.index;
}; };
util.inherits(error.ExclusionConstraintError, error.DatabaseError); util.inherits(error.ExclusionConstraintError, error.DatabaseError);
......
...@@ -321,6 +321,13 @@ module.exports = (function() { ...@@ -321,6 +321,13 @@ module.exports = (function() {
sequelizeErrors.UniqueConstraintError; sequelizeErrors.UniqueConstraintError;
/** /**
* Thrown when an exclusion constraint is violated in the database
* @see {Errors#ExclusionConstraintError}
*/
Sequelize.prototype.ExclusionConstraintError = Sequelize.ExclusionConstraintError =
sequelizeErrors.ExclusionConstraintError;
/**
* Thrown when a foreign key constraint is violated in the database * Thrown when a foreign key constraint is violated in the database
* @see {Errors#ForeignKeyConstraintError} * @see {Errors#ForeignKeyConstraintError}
*/ */
......
'use strict';
var chai = require('chai')
, sinon = require('sinon')
, expect = chai.expect
, DataTypes = require(__dirname + '/../../../../lib/data-types')
, Support = require(__dirname + '/../../support')
, Sequelize = Support.Sequelize
, dialect = Support.getTestDialect()
, Promise = Sequelize.Promise
, _ = require('lodash');
chai.config.includeStack = true;
if (dialect.match(/^postgres/)) {
var constraintName = 'overlap_period';
beforeEach(function () {
var self = this;
this.Booking = self.sequelize.define('Booking', {
roomNo: DataTypes.INTEGER,
period: DataTypes.RANGE(DataTypes.DATE)
});
return self.Booking
.sync({ force: true })
.then(function () {
return self.sequelize.query('ALTER TABLE "' + self.Booking.tableName + '" ADD CONSTRAINT ' + constraintName +
' EXCLUDE USING gist ("roomNo" WITH =, period WITH &&)');
});
});
describe('[POSTGRES Specific] ExclusionConstraintError', function () {
it('should contain error specific properties', function () {
var errDetails = {
message: 'Exclusion constraint error',
constraint: 'constraint_name',
fields: { 'field1': 1, 'field2': [123, 321] },
table: 'table_name',
parent: new Error('Test error')
};
var err = new Sequelize.ExclusionConstraintError(errDetails);
_.each(errDetails, function (value, key) {
expect(value).to.be.deep.equal(err[key]);
});
});
it('should throw ExclusionConstraintError when "period" value overlaps existing', function () {
var Booking = this.Booking;
return Booking
.create({
roomNo: 1,
guestName: 'Incognito Visitor',
period: [new Date(2015, 0, 1), new Date(2015, 0, 3)]
})
.then(function () {
return Booking
.create({
roomNo: 1,
guestName: 'Frequent Visitor',
period: [new Date(2015, 0, 2), new Date(2015, 0, 5)]
})
.done(function (err) {
expect(!!err).to.be.ok;
expect(err instanceof Sequelize.ExclusionConstraintError).to.be.ok;
});
});
});
});
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!