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

Commit 30145e0f by Mick Hansen

Merge pull request #3847 from johngiudici/unique-error-custom-message

Add support for unique constraint custom error message
2 parents bebad6e2 4fe70b41
# Next # Next
- [FIXED] Fix `Promise#nodeify()` and `Promise#done()` not passing CLS context - [FIXED] Fix `Promise#nodeify()` and `Promise#done()` not passing CLS context
- [ADDED] Unique constraints may now include custom error messages
# 3.2.0 # 3.2.0
- [FEATURE] Add support for new option `targetKey` in a belongs-to relationship for situations where the target key is not the id field. - [FEATURE] Add support for new option `targetKey` in a belongs-to relationship for situations where the target key is not the id field.
......
...@@ -414,6 +414,19 @@ AbstractQuery.prototype.findTableNameInAttribute = function(attribute) { ...@@ -414,6 +414,19 @@ AbstractQuery.prototype.findTableNameInAttribute = function(attribute) {
} }
}; };
AbstractQuery.prototype.getUniqueConstraintErrorMessage = function(field) {
var message = field + ' must be unique';
var self = this;
Object.keys(self.model.uniqueKeys).forEach(function(key) {
if (self.model.uniqueKeys[key].fields.indexOf(field.replace(/"/g, '')) >= 0) {
if (self.model.uniqueKeys[key].hasOwnProperty('msg')) {
message = self.model.uniqueKeys[key].msg;
}
}
});
return message;
};
AbstractQuery.prototype.isRawQuery = function () { AbstractQuery.prototype.isRawQuery = function () {
return this.options.type === QueryTypes.RAW; return this.options.type === QueryTypes.RAW;
}; };
......
...@@ -185,9 +185,11 @@ Query.prototype.formatError = function (err) { ...@@ -185,9 +185,11 @@ Query.prototype.formatError = function (err) {
} }
var errors = []; var errors = [];
var self = this;
Utils._.forOwn(fields, function(value, field) { Utils._.forOwn(fields, function(value, field) {
errors.push(new sequelizeErrors.ValidationErrorItem( errors.push(new sequelizeErrors.ValidationErrorItem(
field + ' must be unique', 'unique violation', field, value)); self.getUniqueConstraintErrorMessage(field),
'unique violation', field, value));
}); });
return new sequelizeErrors.UniqueConstraintError({ return new sequelizeErrors.UniqueConstraintError({
......
...@@ -123,9 +123,11 @@ Query.prototype.formatError = function (err) { ...@@ -123,9 +123,11 @@ Query.prototype.formatError = function (err) {
} }
var errors = []; var errors = [];
var self = this;
Utils._.forOwn(fields, function(value, field) { Utils._.forOwn(fields, function(value, field) {
errors.push(new sequelizeErrors.ValidationErrorItem( errors.push(new sequelizeErrors.ValidationErrorItem(
field + ' must be unique', 'unique violation', field, value)); self.getUniqueConstraintErrorMessage(field),
'unique violation', field, value));
}); });
return new sequelizeErrors.UniqueConstraintError({ return new sequelizeErrors.UniqueConstraintError({
......
...@@ -134,10 +134,11 @@ Query.prototype.run = function(sql) { ...@@ -134,10 +134,11 @@ Query.prototype.run = function(sql) {
if (rows[0] && rows[0].sequelize_caught_exception !== undefined) { if (rows[0] && rows[0].sequelize_caught_exception !== undefined) {
if (rows[0].sequelize_caught_exception !== null) { if (rows[0].sequelize_caught_exception !== null) {
throw new self.formatError({ var err = self.formatError({
code: '23505', code: '23505',
detail: rows[0].sequelize_caught_exception detail: rows[0].sequelize_caught_exception
}); });
throw err;
} else { } else {
rows = rows.map(function (row) { rows = rows.map(function (row) {
delete row.sequelize_caught_exception; delete row.sequelize_caught_exception;
...@@ -343,7 +344,8 @@ Query.prototype.formatError = function (err) { ...@@ -343,7 +344,8 @@ Query.prototype.formatError = function (err) {
, index , index
, fields , fields
, errors , errors
, message; , message
, self = this;
var code = err.code || err.sqlState var code = err.code || err.sqlState
, errMessage = err.message || err.messagePrimary , errMessage = err.message || err.messagePrimary
...@@ -374,7 +376,8 @@ Query.prototype.formatError = function (err) { ...@@ -374,7 +376,8 @@ Query.prototype.formatError = function (err) {
Utils._.forOwn(fields, function(value, field) { Utils._.forOwn(fields, function(value, field) {
errors.push(new sequelizeErrors.ValidationErrorItem( errors.push(new sequelizeErrors.ValidationErrorItem(
field + ' must be unique', 'unique violation', field, value)); self.getUniqueConstraintErrorMessage(field),
'unique violation', field, value));
}); });
if (this.model && this.model.uniqueKeys) { if (this.model && this.model.uniqueKeys) {
......
...@@ -215,7 +215,8 @@ Query.prototype.formatError = function (err) { ...@@ -215,7 +215,8 @@ Query.prototype.formatError = function (err) {
fields.forEach(function(field) { fields.forEach(function(field) {
errors.push(new sequelizeErrors.ValidationErrorItem( errors.push(new sequelizeErrors.ValidationErrorItem(
field + ' must be unique', 'unique violation', field, self.instance && self.instance[field])); self.getUniqueConstraintErrorMessage(field),
'unique violation', field, self.instance && self.instance[field]));
}); });
if (this.model) { if (this.model) {
......
...@@ -1866,6 +1866,7 @@ Model.prototype.bulkCreate = function(records, options) { ...@@ -1866,6 +1866,7 @@ Model.prototype.bulkCreate = function(records, options) {
} }
// Insert all records at once // Insert all records at once
options.model = self;
return self.QueryInterface.bulkInsert(self.getTableName(options), records, options, attributes).then(function (results) { return self.QueryInterface.bulkInsert(self.getTableName(options), records, options, attributes).then(function (results) {
if (Array.isArray(results)) { if (Array.isArray(results)) {
results.forEach(function (result, i) { results.forEach(function (result, i) {
......
...@@ -79,7 +79,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), function() { ...@@ -79,7 +79,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), function() {
}); });
}); });
it('should enforce a unque constraint', function() { it('should enforce a unique constraint', function() {
var Model = this.sequelize.define('model', { var Model = this.sequelize.define('model', {
uniqueName: { type: Sequelize.STRING, unique: true } uniqueName: { type: Sequelize.STRING, unique: true }
}); });
...@@ -103,6 +103,34 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), function() { ...@@ -103,6 +103,34 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), function() {
expect(err.errors[0].message).to.include('must be unique'); expect(err.errors[0].message).to.include('must be unique');
}); });
}); });
it('should allow a custom unique constraint error message', function() {
var Model = this.sequelize.define('model', {
uniqueName: {
type: Sequelize.STRING,
unique: { msg: 'custom unique error message' }
}
});
var records = [
{ uniqueName: 'unique name one' },
{ uniqueName: 'unique name two' }
];
return Model.sync({ force: true })
.then(function() {
return Model.create(records[0]);
}).then(function(instance) {
expect(instance).to.be.ok;
return Model.create(records[1]);
}).then(function(instance) {
expect(instance).to.be.ok;
return expect(Model.update(records[0], { where: { id: instance.id } })).to.be.rejected;
}).then(function(err) {
expect(err).to.be.an.instanceOf(Error);
expect(err.errors).to.have.length(1);
expect(err.errors[0].path).to.include('uniqueName');
expect(err.errors[0].message).to.equal('custom unique error message');
});
});
}); });
describe('#create', function() { describe('#create', function() {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!