Merge pull request #6 from strongloop/strict-mode

Set strict to false by default for non-relational data sources
This commit is contained in:
Raymond Feng 2013-08-27 16:37:45 -07:00
commit 8674e67416
6 changed files with 161 additions and 22 deletions

View File

@ -59,7 +59,8 @@ DataAccessObject._forDB = function (data) {
} }
var res = {}; var res = {};
Object.keys(data).forEach(function (propName) { Object.keys(data).forEach(function (propName) {
if (this.whatTypeName(propName) === 'JSON' || data[propName] instanceof Array) { var type = this.whatTypeName(propName);
if (type === 'JSON' || type === 'Any' || type === 'Object' || data[propName] instanceof Array) {
res[propName] = JSON.stringify(data[propName]); res[propName] = JSON.stringify(data[propName]);
} else { } else {
res[propName] = data[propName]; res[propName] = data[propName];

View File

@ -319,6 +319,16 @@ DataSource.prototype.createModel = DataSource.prototype.define = function define
properties = properties || {}; properties = properties || {};
settings = settings || {}; settings = settings || {};
if(this.isRelational()) {
// Set the strict mode to be true for relational DBs by default
if(settings.strict === undefined || settings.strict === null) {
settings.strict = true;
}
if(settings.strict === false) {
settings.strict = 'throw';
}
}
var NewClass = ModelBuilder.prototype.define.call(this, className, properties, settings); var NewClass = ModelBuilder.prototype.define.call(this, className, properties, settings);
// add data access objects // add data access objects

View File

@ -94,6 +94,11 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
properties = properties || {}; properties = properties || {};
settings = settings || {}; settings = settings || {};
// Set the strict mode to be false by default
if(settings.strict === undefined || settings.strict === null) {
settings.strict = false;
}
this.buildSchema(className, properties); this.buildSchema(className, properties);
// every class can receive hash of data as optional param // every class can receive hash of data as optional param

View File

@ -163,8 +163,13 @@ ModelBaseClass.defineProperty = function (prop, params) {
ModelBaseClass.whatTypeName = function (propName) { ModelBaseClass.whatTypeName = function (propName) {
var prop = this.properties[propName]; var prop = this.properties[propName];
if (!prop || !prop.type) { if(!prop) {
throw new Error('Undefined type for ' + this.modelName + ':' + propName); // The property is not part of the definition
return null;
}
if (!prop.type) {
throw new Error('Type not defined for property ' + this.modelName + '.' + propName);
// return null;
} }
return prop.type.name; return prop.type.name;
}; };

View File

@ -320,12 +320,12 @@ function seed(done) {
var beatles = [ var beatles = [
{ {
name: 'John Lennon', name: 'John Lennon',
mail: 'john@b3atl3s.co.uk', email: 'john@b3atl3s.co.uk',
role: 'lead', role: 'lead',
order: 2 order: 2
}, { }, {
name: 'Paul McCartney', name: 'Paul McCartney',
mail: 'paul@b3atl3s.co.uk', email: 'paul@b3atl3s.co.uk',
role: 'lead', role: 'lead',
order: 1 order: 1
}, },

View File

@ -11,7 +11,6 @@ describe('ModelBuilder define model', function () {
it('should be able to define plain models', function (done) { it('should be able to define plain models', function (done) {
var modelBuilder = new ModelBuilder(); var modelBuilder = new ModelBuilder();
// simplier way to describe model
var User = modelBuilder.define('User', { var User = modelBuilder.define('User', {
name: String, name: String,
bio: ModelBuilder.Text, bio: ModelBuilder.Text,
@ -29,7 +28,6 @@ describe('ModelBuilder define model', function () {
modelBuilder.definitions.should.be.a('object').and.have.property('User'); modelBuilder.definitions.should.be.a('object').and.have.property('User');
var user = new User({name: 'Joe', age: 20}); var user = new User({name: 'Joe', age: 20});
// console.log(user);
User.modelName.should.equal('User'); User.modelName.should.equal('User');
user.should.be.a('object').and.have.property('name', 'Joe'); user.should.be.a('object').and.have.property('name', 'Joe');
@ -42,15 +40,12 @@ describe('ModelBuilder define model', function () {
it('should not take unknown properties in strict mode', function (done) { it('should not take unknown properties in strict mode', function (done) {
var modelBuilder = new ModelBuilder(); var modelBuilder = new ModelBuilder();
// simplier way to describe model
var User = modelBuilder.define('User', {name: String, bio: String}, {strict: true}); var User = modelBuilder.define('User', {name: String, bio: String}, {strict: true});
var user = new User({name: 'Joe', age: 20}); var user = new User({name: 'Joe', age: 20});
// console.log(user);
User.modelName.should.equal('User'); User.modelName.should.equal('User');
user.should.be.a('object'); user.should.be.a('object');
// console.log(user);
assert(user.name === 'Joe'); assert(user.name === 'Joe');
assert(user.age === undefined); assert(user.age === undefined);
assert(user.toObject().age === undefined); assert(user.toObject().age === undefined);
@ -59,14 +54,41 @@ describe('ModelBuilder define model', function () {
done(null, User); done(null, User);
}); });
it('should throw when unknown properties are used if strict=throw', function (done) {
var modelBuilder = new ModelBuilder();
var User = modelBuilder.define('User', {name: String, bio: String}, {strict: 'throw'});
try {
var user = new User({name: 'Joe', age: 20});
assert(false, 'The code should have thrown an error');
} catch(e) {
assert(true, 'The code is expected to throw an error');
}
done(null, User);
});
it('should be able to define open models', function (done) { it('should be able to define open models', function (done) {
var modelBuilder = new ModelBuilder(); var modelBuilder = new ModelBuilder();
// simplier way to describe model
var User = modelBuilder.define('User', {}, {strict: false}); var User = modelBuilder.define('User', {}, {strict: false});
var user = new User({name: 'Joe', age: 20}); var user = new User({name: 'Joe', age: 20});
// console.log(user);
User.modelName.should.equal('User');
user.should.be.a('object').and.have.property('name', 'Joe');
user.should.have.property('name', 'Joe');
user.should.have.property('age', 20);
user.should.not.have.property('bio');
done(null, User);
});
it('should use false as the default value for strict', function (done) {
var modelBuilder = new ModelBuilder();
var User = modelBuilder.define('User', {});
var user = new User({name: 'Joe', age: 20});
User.modelName.should.equal('User'); User.modelName.should.equal('User');
user.should.be.a('object').and.have.property('name', 'Joe'); user.should.be.a('object').and.have.property('name', 'Joe');
@ -115,7 +137,6 @@ describe('ModelBuilder define model', function () {
emails: [{label: 'work', email: 'xyz@sample.com'}], emails: [{label: 'work', email: 'xyz@sample.com'}],
friends: ['Mary', 'John'] friends: ['Mary', 'John']
}); });
// console.log(user);
User.modelName.should.equal('User'); User.modelName.should.equal('User');
user.should.be.a('object').and.have.property('name', 'Joe'); user.should.be.a('object').and.have.property('name', 'Joe');
@ -149,13 +170,13 @@ describe('DataSource define model', function () {
title: { type: String, length: 255 }, title: { type: String, length: 255 },
content: { type: DataSource.Text }, content: { type: DataSource.Text },
date: { type: Date, default: function () { date: { type: Date, default: function () {
return new Date; return new Date();
} }, } },
timestamp: { type: Number, default: Date.now }, timestamp: { type: Number, default: Date.now },
published: { type: Boolean, default: false, index: true } published: { type: Boolean, default: false, index: true }
}); });
// simplier way to describe model // simpler way to describe model
var User = ds.define('User', { var User = ds.define('User', {
name: String, name: String,
bio: DataSource.Text, bio: DataSource.Text,
@ -164,15 +185,17 @@ describe('DataSource define model', function () {
age: Number age: Number
}); });
var Group = ds.define('Group', {name: String}); var Group = ds.define('Group', {group: String});
User.mixin(Group);
// define any custom method // define any custom method
User.prototype.getNameAndAge = function () { User.prototype.getNameAndAge = function () {
return this.name + ', ' + this.age; return this.name + ', ' + this.age;
}; };
var user = new User({name: 'Joe'}); var user = new User({name: 'Joe', group: 'G1'});
// console.log(user); assert.equal(user.name, 'Joe');
assert.equal(user.group, 'G1');
// setup relationships // setup relationships
User.hasMany(Post, {as: 'posts', foreignKey: 'userId'}); User.hasMany(Post, {as: 'posts', foreignKey: 'userId'});
@ -183,7 +206,6 @@ describe('DataSource define model', function () {
var user2 = new User({name: 'Smith'}); var user2 = new User({name: 'Smith'});
user2.save(function (err) { user2.save(function (err) {
// console.log(user2);
var post = user2.posts.build({title: 'Hello world'}); var post = user2.posts.build({title: 'Hello world'});
post.save(function (err, data) { post.save(function (err, data) {
// console.log(err ? err : data); // console.log(err ? err : data);
@ -199,9 +221,7 @@ describe('DataSource define model', function () {
console.log(err); console.log(err);
return; return;
} }
// console.log(data);
var post = data.posts.build({title: 'My Post'}); var post = data.posts.build({title: 'My Post'});
// console.log(post);
}); });
User.create({name: 'Ray'}, function (err, data) { User.create({name: 'Ray'}, function (err, data) {
@ -244,6 +264,104 @@ describe('DataSource define model', function () {
}); });
}); });
it('should not take unknown properties in strict mode', function (done) {
var ds = new DataSource('memory');
var User = ds.define('User', {name: String, bio: String}, {strict: true});
User.create({name: 'Joe', age: 20}, function (err, user) {
User.modelName.should.equal('User');
user.should.be.a('object');
assert(user.name === 'Joe');
assert(user.age === undefined);
assert(user.toObject().age === undefined);
assert(user.toObject(true).age === undefined);
assert(user.bio === undefined);
done(null, User);
});
});
it('should throw when unknown properties are used if strict=throw', function (done) {
var ds = new DataSource('memory');
var User = ds.define('User', {name: String, bio: String}, {strict: 'throw'});
try {
var user = new User({name: 'Joe', age: 20});
assert(false, 'The code should have thrown an error');
} catch(e) {
assert(true, 'The code is expected to throw an error');
}
done(null, User);
});
it('should be able to define open models', function (done) {
var ds = new DataSource('memory');
var User = ds.define('User', {}, {strict: false});
User.create({name: 'Joe', age: 20}, function (err, user) {
User.modelName.should.equal('User');
user.should.be.a('object').and.have.property('name', 'Joe');
user.should.have.property('name', 'Joe');
user.should.have.property('age', 20);
user.should.not.have.property('bio');
done(null, User);
});
});
it('should use false as the default value for strict', function (done) {
var ds = new DataSource('memory');
var User = ds.define('User', {});
User.create({name: 'Joe', age: 20}, function (err, user) {
User.modelName.should.equal('User');
user.should.be.a('object').and.have.property('name', 'Joe');
user.should.have.property('name', 'Joe');
user.should.have.property('age', 20);
user.should.not.have.property('bio');
done(null, User);
});
});
it('should use true as the default value for strict for relational DBs', function (done) {
var ds = new DataSource('memory');
ds.connector.relational = true; // HACK
var User = ds.define('User', {name: String, bio: String}, {strict: true});
var user = new User({name: 'Joe', age: 20});
User.modelName.should.equal('User');
user.should.be.a('object');
assert(user.name === 'Joe');
assert(user.age === undefined);
assert(user.toObject().age === undefined);
assert(user.toObject(true).age === undefined);
assert(user.bio === undefined);
done(null, User);
});
it('should throw when unknown properties are used if strict=false for relational DBs', function (done) {
var ds = new DataSource('memory');
ds.connector.relational = true; // HACK
var User = ds.define('User', {name: String, bio: String}, {strict: 'throw'});
try {
var user = new User({name: 'Joe', age: 20});
assert(false, 'The code should have thrown an error');
} catch(e) {
assert(true, 'The code is expected to throw an error');
}
done(null, User);
});
}); });
@ -286,7 +404,7 @@ describe('Load models from json', function () {
models.should.have.property('Customer'); models.should.have.property('Customer');
for (var s in models) { for (var s in models) {
var m = models[s]; var m = models[s];
// console.log(m.modelName, new m()); assert(new m());
} }
}); });
}); });