Permalink
Browse files

Merge pull request #32 from racker/change_numItems_validator

Make numItems work more like isOptional validator
  • Loading branch information...
2 parents 4adae3d + 9f87f32 commit dade79caa8d78f428258d07a58590c409ba6adb8 @Kami Kami committed May 7, 2013
Showing with 114 additions and 44 deletions.
  1. +25 −0 lib/util.js
  2. +29 −0 lib/validators.js
  3. +44 −42 lib/valve.js
  4. +1 −1 package.json
  5. +15 −1 tests/test-valve.js
View
@@ -42,5 +42,30 @@ function merge(a, b) {
}
+/**
+ * A "better" typeof-like function that can distinguish between array and null
+ * objects. NOTE: This is a function, not an operator like "typeof".
+ *
+ * @private
+ * @param {value} value an object.
+ * @return {String} 'array' or 'null'.
+ */
+function typeOf(value) {
+ var t = typeof(value);
+ if (t === 'object') {
+ if (value) {
+ if (value instanceof Array) {
+ t = 'array';
+ }
+ }
+ else {
+ t = 'null';
+ }
+ }
+ return t;
+}
+
+
exports.trim = trim;
exports.merge = merge;
+exports.typeOf = typeOf;
View
@@ -1,5 +1,7 @@
var check = require('validator').check;
+var utils = require('./util');
+
exports.isPort = function(value, baton) {
value = parseInt(value, 10);
@@ -34,3 +36,30 @@ exports.isHostname = function(value) {
return true;
};
+
+/**
+ * Verify that the provided array or object has between min and max number of
+ * elements.
+ * @param {Object} value Object or array to validate.
+ * @param {Number} min Minimum number of elements.
+ * @param {Number} max Maximum number of elements.
+ */
+exports.numItems = function(value, min, max) {
+ var len, type = utils.typeOf(value);
+
+ if (type === 'array') {
+ len = value.length;
+ }
+ else if (type === 'object') {
+ len = Object.keys(value).length;
+ }
+ else {
+ throw new Error('value must either be a array or an object');
+ }
+
+ if (len < min || len > max) {
+ throw new Error('Object needs to have between ' + min + ' and ' + max + ' items');
+ }
+
+ return value;
+};
View
@@ -60,6 +60,7 @@ var async = require('async'),
sanitize = require('validator').sanitize,
check = require('validator').check,
validators = require('./validators'),
+ utils = require('./util'),
net = require('net'),
ipv6 = require('ipv6').v6,
ipv4 = require('ipv6').v4,
@@ -139,30 +140,6 @@ function chainHelp(chain) {
}
-/**
- * A "better" typeof-like function that can distinguish between array and null
- * objects. NOTE: This is a function, not an operator like "typeof".
- *
- * @private
- * @param {value} value an object.
- * @return {String} 'array' or 'null'.
- */
-function typeOf(value) {
- var t = typeof(value);
- if (t === 'object') {
- if (value) {
- if (value instanceof Array) {
- t = 'array';
- }
- }
- else {
- t = 'null';
- }
- }
- return t;
-}
-
-
/**
* Normalize an IP address. Expands "::" notation in IPv6 addresses and
* zero-prefixes each component number (see ipv6.canonical_form()).
@@ -213,12 +190,14 @@ var Chain = function() {
if (! (this instanceof Chain)) {
return new Chain();
}
+
this.validators = [];
this.target = null;
this.isOptional = false;
this.isImmutable = false;
this.isUpdateRequired = false;
this._validatorCount = 0;
+ this._numItemsValidator = null;
};
@@ -1171,7 +1150,7 @@ Chain.prototype.notIn = function(values, caseSensitive) {
this._pushValidator({
name: 'notIn',
func: function(value, baton, callback) {
- var type = typeOf(value), keys, key, i;
+ var type = utils.typeOf(value), keys, key, i;
if (type === 'string' || type === 'number') {
keys = [value];
@@ -1332,7 +1311,6 @@ Chain.prototype.len = function(min, max) {
return this;
};
-
/**
* Verify that the provided array or object has between min and max number of
* elements.
@@ -1350,21 +1328,16 @@ Chain.prototype.numItems = function(min, max) {
max = Infinity;
}
- v.func = function(value, baton, callback) {
- var len;
-
- if (value instanceof Array) {
- len = value.length;
- }
- else {
- len = Object.keys(value).length;
- }
+ if (this._numItemsValidator) {
+ throw new Error('Chain can only have a single numItems validator');
+ }
- if (len < min || len > max) {
- callback('Object needs to have between ' + min + ' and ' + max + ' items');
- return;
- }
+ this._numItemsValidator = {
+ 'min': min,
+ 'max': max
+ }
+ v.func = function(value, baton, callback) {
callback(null, value);
};
@@ -1640,7 +1613,7 @@ Chain.prototype.isString = function() {
this._pushValidator({
name: 'isString',
func: function(value, baton, callback) {
- if (typeOf(value) !== 'string') {
+ if (utils.typeOf(value) !== 'string') {
callback('Not a string');
} else {
callback(null, value);
@@ -1824,10 +1797,19 @@ Chain.prototype.isArray = function(chain) {
this._pushValidator({
name: 'isArray',
func: function(value, baton, callback) {
- if (typeOf(value) !== 'array') {
+ if (utils.typeOf(value) !== 'array') {
callback('Not an array');
return;
}
+
+ try {
+ self._validateNumItems(value);
+ }
+ catch (e) {
+ callback(e.message);
+ return;
+ }
+
async.map(value,
function(item, itercb) {
checkChain(item, chain, baton, itercb);
@@ -1883,15 +1865,26 @@ Chain.prototype.isHash = function(keyChain, valueChain) {
func: function(value, baton, callback) {
var key,
kvpairs = [];
- if (typeOf(value) !== 'object') {
+
+ if (utils.typeOf(value) !== 'object') {
callback('Not a hash');
return;
}
+
+ try {
+ self._validateNumItems(value);
+ }
+ catch (e) {
+ callback(e.message);
+ return;
+ }
+
for (key in value) {
if (value.hasOwnProperty(key)) {
kvpairs.push([key, value[key]]);
}
}
+
async.reduce(kvpairs, {}, iter(baton), callback);
},
help: 'Hash [' + chainHelp(keyChain).join(',') + ':' +
@@ -1900,6 +1893,15 @@ Chain.prototype.isHash = function(keyChain, valueChain) {
return this;
};
+Chain.prototype._validateNumItems = function(value) {
+ if (!this._numItemsValidator) {
+ return;
+ }
+
+ validators.numItems(value, this._numItemsValidator.min,
+ this._numItemsValidator.max);
+};
+
/**
* Adds a validator to the chain that reassigns the value for the
View
@@ -12,7 +12,7 @@
],
"name": "swiz",
"description": "Serialization and Validation Framework for objects in RESTful APIs",
- "version": "0.4.55",
+ "version": "0.4.56",
"homepage": "https://github.com/racker/node-swiz",
"repository": {
"type": "git",
View
@@ -124,7 +124,7 @@ var badExampleNode1 = {
exports['test_validate_numItems'] = function(test, assert) {
- var v1, v2, v3;
+ var v1, v2, v3, thrown = false;
v1 = new V({
a: C().isArray(C().isInt()).numItems(1, 5)
@@ -138,6 +138,20 @@ exports['test_validate_numItems'] = function(test, assert) {
a: C().isArray(C().isInt()).numItems(2)
});
+ try {
+ new V({
+ a: C().isArray(C().isInt()).numItems(2).numItems(2)
+ });
+ }
+ catch (e) {
+ thrown = true;
+ assert.match(e.message, /single numItems validator/i);
+ }
+
+ if (!thrown) {
+ assert.fail('numItems added multiple times, but exception wasnt thrown');
+ }
+
// Negative test cases (array)
v1.check({'a': [1]}, function(err, cleaned) {
assert.ifError(err);

0 comments on commit dade79c

Please sign in to comment.