Merge pull request #110 from strongloop/feature/multi-column-unique-validation

validations: support multi-key unique constraint
This commit is contained in:
Miroslav Bajtoš 2014-05-15 09:31:55 +02:00
commit 1f2d012842
2 changed files with 55 additions and 0 deletions

View File

@ -197,9 +197,19 @@ Validatable.validateAsync = getConfigurator('custom', {async: true});
* - Oracle * - Oracle
* - MongoDB * - MongoDB
* *
* ```
* // The login must be unique across all User instances.
* User.validatesUniquenessOf('login');
*
* // Assuming SiteUser.belongsTo(Site)
* // The login must be unique within each Site.
* SiteUser.validateUniquenessOf('login', { scopedTo: ['siteId'] });
* ```
* @param {String} propertyName Property name to validate. * @param {String} propertyName Property name to validate.
* @options {Object} Options * @options {Object} Options
* @property {RegExp} with Regular expression to validate format. * @property {RegExp} with Regular expression to validate format.
* @property {Array.<String>} scopedTo List of properties defining the scope.
* @property {String} message Optional error message if property is not valid. Default error message: "is not unique". * @property {String} message Optional error message if property is not valid. Default error message: "is not unique".
*/ */
Validatable.validatesUniquenessOf = getConfigurator('uniqueness', {async: true}); Validatable.validatesUniquenessOf = getConfigurator('uniqueness', {async: true});
@ -297,6 +307,15 @@ function validateCustom(attr, conf, err, done) {
function validateUniqueness(attr, conf, err, done) { function validateUniqueness(attr, conf, err, done) {
var cond = {where: {}}; var cond = {where: {}};
cond.where[attr] = this[attr]; cond.where[attr] = this[attr];
if (conf && conf.scopedTo) {
conf.scopedTo.forEach(function(k) {
var val = this[k];
if (val !== undefined)
cond.where[k] = this[k];
}, this);
}
this.constructor.find(cond, function (error, found) { this.constructor.find(cond, function (error, found) {
if (error) { if (error) {
return err(); return err();

View File

@ -1,5 +1,6 @@
// This test written in mocha+should.js // This test written in mocha+should.js
var should = require('./init.js'); var should = require('./init.js');
var async = require('async');
var j = require('../'), db, User; var j = require('../'), db, User;
var ValidationError = j.ValidationError; var ValidationError = j.ValidationError;
@ -172,6 +173,41 @@ describe('validations', function () {
})).should.not.be.ok; })).should.not.be.ok;
}); });
it('should support multi-key constraint', function(done) {
var EMAIL = 'user@xample.com';
var SiteUser = db.define('SiteUser', {
siteId: String,
email: String
});
SiteUser.validatesUniquenessOf('email', { scopedTo: ['siteId'] });
async.waterfall([
function automigrate(next) {
db.automigrate(next);
},
function createSite1User(next) {
SiteUser.create(
{ siteId: 1, email: EMAIL },
next);
},
function createSite2User(user1, next) {
SiteUser.create(
{ siteId: 2, email: EMAIL },
next);
},
function validateDuplicateUser(user2, next) {
var user3 = new SiteUser({ siteId: 1, email: EMAIL });
user3.isValid(function(valid) {
valid.should.be.false;
next();
});
}
], function(err) {
if (err && err.name == 'ValidationError') {
console.error('ValidationError:', err.details.messages);
}
done(err);
});
});
}); });
describe('format', function () { describe('format', function () {