Skip to content

Commit

Permalink
Merge branch 'pr-19' - PR \#19
Browse files Browse the repository at this point in the history
  • Loading branch information
scottwrobinson committed Dec 14, 2015
2 parents 07e6f7a + 7b2da6a commit a2e71dd
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ The `default` option supports both values and no-argument functions (like `Date.
- `match`: A regex string that should match the value *(optional)*
- `validate`: A 1-argument function that returns `false` if the value is invalid *(optional)*
- `unique`: A boolean value indicating if a 'unique' index should be set *(optional)*
- `required`: A boolean value indicating if a key value is required *(optional)*

To reference another document, just use its class name as the type.

Expand Down
6 changes: 6 additions & 0 deletions lib/base-document.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var _ = require('lodash');
var DB = require('./clients').getClient;
var isSupportedType = require('./validate').isSupportedType;
var isValidType = require('./validate').isValidType;
var isEmptyValue = require('./validate').isEmptyValue;
var isInChoices = require('./validate').isInChoices;
var isArray = require('./validate').isArray;
var isDocument = require('./validate').isDocument;
Expand Down Expand Up @@ -139,6 +140,11 @@ class BaseDocument {
' should be ' + typeName + ', got ' + valueName);
}

if (that._schema[key].required && isEmptyValue(value)) {
throw new Error('Key ' + that.collectionName() + '.' + key +
' is required' + ', but got ' + value);
}

if (that._schema[key].match && isString(value) && !that._schema[key].match.test(value)) {
throw new Error('Value assigned to ' + that.collectionName() + '.' + key +
' does not match the regex/string ' + that._schema[key].match.toString() + '. Value was ' + value);
Expand Down
8 changes: 7 additions & 1 deletion lib/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ var isInChoices = function(choices, choice) {
return choices.indexOf(choice) > -1;
};

var isEmptyValue = function(value) {
return typeof value === 'undefined' || (!(typeof value === 'number' || value instanceof Date || typeof value === 'boolean')
&& (0 === Object.keys(value).length));
};

exports.isString = isString;
exports.isNumber = isNumber;
exports.isBoolean = isBoolean;
Expand All @@ -136,4 +141,5 @@ exports.isNativeId = isNativeId;
exports.isSupportedType = isSupportedType;
exports.isType = isType;
exports.isValidType = isValidType;
exports.isInChoices = isInChoices;
exports.isInChoices = isInChoices;
exports.isEmptyValue = isEmptyValue;
342 changes: 342 additions & 0 deletions test/document.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,348 @@ describe('Document', function() {
});
});

describe('required', function() {
it('should accept empty value that is not reqired', function(done) {

class Person extends Document {
constructor() {
super();

this.name = {
type: String,
required: false
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create({
name: ''
});

person.save().then(function() {
validateId(person);
expect(person.name).to.be.equal('');
}).then(done, done);
});

it('should accept value that is not undefined', function(done) {

class Person extends Document {
constructor() {
super();

this.name = {
type: String,
required: true
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create({
name: 'Scott'
});

person.save().then(function() {
validateId(person);
expect(person.name).to.be.equal('Scott');
}).then(done, done);
});

it('should accept an empty value if default is specified', function(done) {

class Person extends Document {
constructor() {
super();

this.name = {
type: String,
required: true,
default: 'Scott'
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create();

person.save().then(function() {
validateId(person);
expect(person.name).to.be.equal('Scott');
}).then(done, done);
});

it('should accept boolean value', function(done) {

class Person extends Document {
constructor() {
super();

this.isSingle = {
type: Boolean,
required: true
};
this.isMerried = {
type: Boolean,
required: true
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create({
isMerried: true,
isSingle: false
});

person.save().then(function() {
validateId(person);
expect(person.isMerried).to.be.true;
expect(person.isSingle).to.be.false;
}).then(done, done);
});

it('should accept date value', function(done) {

class Person extends Document {
constructor() {
super();

this.birthDate = {
type: Date,
required: true
};
}

static collectionName() {
return 'people';
}
}

var myBirthDate = new Date();

var person = Person.create({
birthDate: myBirthDate
});

person.save().then(function(savedPerson) {
validateId(person);
expect(savedPerson.birthDate).to.equal(myBirthDate);
}).then(done, done);
});

it('should accept any number value', function(done) {

class Person extends Document {
constructor() {
super();

this.age = {
type: Number,
required: true
};
this.level = {
type: Number,
required: true
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create({
age: 21,
level: 0
});

person.save().then(function(savedPerson) {
validateId(person);
expect(savedPerson.age).to.equal(21);
expect(savedPerson.level).to.equal(0);
}).then(done, done);
});

it('should reject value that is undefined', function(done) {

class Person extends Document {
constructor() {
super();

this.name = {
type: String,
required: true
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create();

person.save().then(function() {
fail(null, Error, 'Expected error, but got none.');
}).catch(function(error) {
expectError(error);
}).then(done, done);
});

it('should reject value if specified default empty value', function(done) {

class Person extends Document {
constructor() {
super();

this.name = {
type: String,
required: true,
default: ''
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create();

person.save().then(function() {
fail(null, Error, 'Expected error, but got none.');
}).catch(function(error) {
expectError(error);
}).then(done, done);
});

it('should reject value that is null', function(done) {

class Person extends Document {
constructor() {
super();

this.name = {
type: Object,
required: true
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create({
name: null
});

person.save().then(function() {
fail(null, Error, 'Expected error, but got none.');
}).catch(function(error) {
expectError(error);
}).then(done, done);
});

it('should reject value that is an empty array', function(done) {

class Person extends Document {
constructor() {
super();

this.names = {
type: Array,
required: true
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create({
names: []
});

person.save().then(function() {
fail(null, Error, 'Expected error, but got none.');
}).catch(function(error) {
expectError(error);
}).then(done, done);
});

it('should reject value that is an empty string', function(done) {

class Person extends Document {
constructor() {
super();

this.name = {
type: String,
required: true
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create({
name: ''
});

person.save().then(function() {
fail(null, Error, 'Expected error, but got none.');
}).catch(function(error) {
expectError(error);
}).then(done, done);
});

it('should reject value that is an empty object', function(done) {

class Person extends Document {
constructor() {
super();

this.names = {
type: Object,
required: true
};
}

static collectionName() {
return 'people';
}
}

var person = Person.create({
names: {}
});

person.save().then(function() {
fail(null, Error, 'Expected error, but got none.');
}).catch(function(error) {
expectError(error);
}).then(done, done);
});
});

describe('hooks', function() {
it('should call all pre and post functions', function(done) {

Expand Down

0 comments on commit a2e71dd

Please sign in to comment.