Skip to content

Commit cec173e

Browse files
committed
Merge pull request #4 from angelxmoreno/development
v1.0.0 is ready
2 parents 448c8a7 + e66b838 commit cec173e

File tree

5 files changed

+180
-7
lines changed

5 files changed

+180
-7
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ build/Release
2525
# Dependency directory
2626
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
2727
node_modules
28+
test/database.sqlite

README.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ errors: ...
6060

6161
#### sequelize.validateIsUnique(`table field`, `optional error message`)
6262

63-
When using `sequelize.validateIsUnique()` the first parameter must the the field to do the check on. Notice that `isUnique: sequelize.validateIsUnique('email')` is going to check for the `email` field on the table with the value of `User.email`. Based on the previous example, the query it performed was something like this ( depending on your database):
64-
```sql
65-
SELECT count(*) AS `count` FROM `users` AS `User` WHERE `User`.`email` = 'bob2@jones.com');
63+
When using `sequelize.validateIsUnique()` the first parameter must the the field to do the check on. For example, `isUnique: sequelize.validateIsUnique('email')`. In order for the validation to pass for an existing instance, the primary keys for that instance will be used to exclude values for that instance. Based on the previous example, the query it performed was something like this ( depending on your database):
64+
```
65+
SELECT count(*) AS `count` FROM `users` AS `User` WHERE `User`.`email` = 'jdoe@example.com' AND `User `.`id` IS NOT NULL;
6666
```
6767

6868
The second parameter allows you to define a custom error message. The default error message is: `'{{field}} must be unique'`. Using our previous example we could do something like this:
@@ -84,11 +84,14 @@ var User = sequelize.define('User', {
8484
## Branch Strategy
8585
The master branch will be the stable branch. Please submit your PRs against the development branch. Once tests are created for v1.0.0 I will be moving development to master.
8686

87-
## Issues
88-
If you discover a bug, please create a ticket on Github. https://github.com/angelxmoreno/sequelize-isunique-validator/issues
87+
## Testing
88+
```
89+
npm test
90+
```
8991

90-
### Kown Issues
91-
There aren't any tests! I will be writing tests after further testing, oh and after I finish learning how to test, obviously :stuck_out_tongue_winking_eye:
92+
## Issues
93+
If you discover a bug, please create a ticket on Github.
94+
[https://github.com/angelxmoreno/sequelize-isunique-validator/issues](https://github.com/angelxmoreno/sequelize-isunique-validator/issues)
9295

9396
## Contribution
9497
Pull requests are always welcomed. This is my first module contributed to the NodeJS ecosystem. I'm sure there are a few things that could be improved. Please point them out, provide feedback and suggestions. I am all ears!

lib/index.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* global module */
2+
3+
'use strict';
4+
var validateIsUnique = function (col, msg) {
5+
var conditions = {where: {}};
6+
msg = (!msg) ? col + ' must be unique' : msg;
7+
return function (value, next) {
8+
var self = this;
9+
this.Model.describe().then(function (schema) {
10+
conditions.where[col] = value;
11+
Object.keys(schema).filter(function (field) {
12+
return schema[field].primaryKey;
13+
}).forEach(function (pk) {
14+
conditions.where[pk] = {$ne: self[pk]};
15+
});
16+
}).then(function () {
17+
return self.Model.count(conditions).then(function (found) {
18+
return (found !== 0) ? next(msg) : next();
19+
});
20+
}).catch(next);
21+
};
22+
};
23+
24+
module.exports = function (Sequelize) {
25+
Sequelize = !Sequelize ? require('sequelize') : Sequelize;
26+
Sequelize.prototype.validateIsUnique = validateIsUnique;
27+
return Sequelize;
28+
};

package.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "sequelize-isunique-validator",
3+
"version": "1.0.0",
4+
"description": "A Sequelize plugin to add isUnique validation to models",
5+
"main": "./lib/",
6+
"scripts": {
7+
"test": "mocha"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/angelxmoreno/sequelize-isunique-validator.git"
12+
},
13+
"keywords": [
14+
"Sequelize",
15+
"validation",
16+
"models"
17+
],
18+
"author": {
19+
"name": "Agel S. Moreno",
20+
"email": "angelxmoreno@gmail.com",
21+
"url": "https://angelxmoreno.github.io/"
22+
},
23+
"license": "MIT",
24+
"bugs": {
25+
"url": "https://github.com/angelxmoreno/sequelize-isunique-validator/issues"
26+
},
27+
"homepage": "https://github.com/angelxmoreno/sequelize-isunique-validator#readme",
28+
"dependencies": {
29+
"sqlite3": "^3.1.0"
30+
},
31+
"peerDependencies": {
32+
"sequelize": "2.0.0 - 3.x.x"
33+
}
34+
}

test/isuniqueValidatorSpec.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/* global require */
2+
3+
var expect = require('chai').expect;
4+
var Sequelize = require('sequelize');
5+
require('../lib')(Sequelize);
6+
var db = new Sequelize('database', 'username', 'password', {
7+
dialect: 'sqlite',
8+
storage: './test/database.sqlite',
9+
logging: false
10+
});
11+
var UserModel;
12+
var isuniqueUsernameMsg = 'Please choose a different username';
13+
var dataset = {
14+
user1: {
15+
name: 'John Doe',
16+
email: 'jdoe@example.com',
17+
username: 'jdoe'
18+
},
19+
user2: {
20+
name: 'Jane Doe',
21+
email: 'jdoe@example.com',
22+
username: 'jdoe1'
23+
},
24+
user3: {
25+
name: 'Jack Does',
26+
email: 'jackdoes@example.com',
27+
username: 'jdoe'
28+
}
29+
};
30+
var initModel = function (done) {
31+
UserModel = db.define('UserModel', {
32+
name: Sequelize.STRING,
33+
email: {
34+
type: Sequelize.STRING,
35+
validate: {
36+
isUnique: db.validateIsUnique('email')
37+
}
38+
},
39+
username: {
40+
type: Sequelize.STRING,
41+
validate: {
42+
isUnique: db.validateIsUnique('username', isuniqueUsernameMsg)
43+
}
44+
}
45+
});
46+
47+
UserModel.sync({force: true}).then(function () {
48+
done();
49+
}).catch(done);
50+
};
51+
52+
describe('Is Unique Validator', function () {
53+
before('Creating db instance', function (done) {
54+
return initModel(done);
55+
});
56+
57+
describe('#init()', function () {
58+
it('should add the `validateIsUnique` function to the sequelize object', function () {
59+
expect(db.validateIsUnique).to.be.a('function');
60+
});
61+
});
62+
63+
describe('usage', function () {
64+
it('should work ok when no duplicate fields are found', function (done) {
65+
UserModel.create(dataset.user1).then(function (user) {
66+
expect(user.name).to.equal(dataset.user1.name);
67+
expect(user.email).to.equal(dataset.user1.email);
68+
expect(user.username).to.equal(dataset.user1.username);
69+
done();
70+
}).catch(done);
71+
});
72+
73+
it('should use the default error message when no message string is given', function (done) {
74+
UserModel.create(dataset.user2).then(function (user) {
75+
expect(user).to.be.null;
76+
}).catch(function (err) {
77+
expect(err.message).to.equal('Validation error: email must be unique');
78+
}).finally(function () {
79+
done();
80+
});
81+
});
82+
83+
it('should use the provided error message when a message string is given', function (done) {
84+
UserModel.create(dataset.user3).then(function (user) {
85+
expect(user).to.be.null;
86+
}).catch(function (err) {
87+
expect(err.message).to.equal('Validation error: ' + isuniqueUsernameMsg);
88+
}).finally(function () {
89+
done();
90+
});
91+
});
92+
93+
it('should allow an instance to be saved when it is the only row holding the unique value', function (done) {
94+
UserModel.findOne({
95+
where: {
96+
email: dataset.user1.email
97+
}
98+
}).then(function (user) {
99+
user.name += ' II';
100+
user.validate().then(function(err){
101+
expect(err).to.be.a('undefined');
102+
done();
103+
});
104+
}).catch(done);
105+
});
106+
});
107+
});

0 commit comments

Comments
 (0)