Make sure own properties are copied by toObject for non-strict mode

See https://github.com/strongloop/loopback/issues/162
This commit is contained in:
Raymond Feng 2014-01-30 11:51:34 -08:00
parent 38e31b3033
commit ee5b351398
2 changed files with 63 additions and 4 deletions

View File

@ -199,16 +199,20 @@ ModelBaseClass.toString = function () {
/**
* Convert instance to Object
*
* @param {Boolean} onlySchema - restrict properties to dataSource only, default false
* @param {Boolean} onlySchema - restrict properties to dataSource only, default true
* when onlySchema == true, only properties defined in dataSource returned,
* otherwise all enumerable properties returned
* @returns {Object} - canonical object representation (no getters and setters)
*/
ModelBaseClass.prototype.toObject = function (onlySchema) {
if(onlySchema === undefined) {
onlySchema = true;
}
var data = {};
var self = this;
var schemaLess = this.constructor.definition.settings.strict === false || !onlySchema;
var strict = this.constructor.definition.settings.strict;
var schemaLess = strict === false || !onlySchema;
this.constructor.forEachProperty(function (propertyName) {
if (self[propertyName] instanceof List) {
data[propertyName] = self[propertyName].toObject(!schemaLess);
@ -223,10 +227,25 @@ ModelBaseClass.prototype.toObject = function (onlySchema) {
}
});
var val = null;
if (schemaLess) {
for (var propertyName in self.__data) {
// Find its own properties which can be set via myModel.myProperty = 'myValue'.
// If the property is not declared in the model definition, no setter will be
// triggered to add it to __data
for (var propertyName in self) {
if(self.hasOwnProperty(propertyName) && (!data.hasOwnProperty(propertyName))) {
val = self[propertyName];
if (val !== undefined && val !== null && val.toObject) {
data[propertyName] = val.toObject(!schemaLess);
} else {
data[propertyName] = val;
}
}
}
// Now continue to check __data
for (propertyName in self.__data) {
if (!data.hasOwnProperty(propertyName)) {
var val = self.hasOwnProperty(propertyName) ? self[propertyName] : self.__data[propertyName];
val = self.hasOwnProperty(propertyName) ? self[propertyName] : self.__data[propertyName];
if (val !== undefined && val !== null && val.toObject) {
data[propertyName] = val.toObject(!schemaLess);
} else {

View File

@ -54,6 +54,26 @@ describe('ModelBuilder define model', function () {
done(null, User);
});
it('should ignore non-predefined properties in strict mode', function (done) {
var modelBuilder = new ModelBuilder();
var User = modelBuilder.define('User', {name: String, bio: String}, {strict: true});
var user = new User({name: 'Joe'});
user.age = 10;
user.bio = 'me';
assert(user.name === 'Joe');
assert(user.bio === 'me');
assert(user.toObject().age === undefined);
assert(user.toObject(true).age === undefined);
assert(user.toObject(false).age === 10);
assert(user.toObject().bio === 'me');
assert(user.toObject(true).bio === 'me');
assert(user.toObject(false).bio === 'me');
done(null, User);
});
it('should throw when unknown properties are used if strict=throw', function (done) {
var modelBuilder = new ModelBuilder();
@ -83,6 +103,26 @@ describe('ModelBuilder define model', function () {
done(null, User);
});
it('should take non-predefined properties in non-strict mode', function (done) {
var modelBuilder = new ModelBuilder();
var User = modelBuilder.define('User', {name: String, bio: String}, {strict: false});
var user = new User({name: 'Joe'});
user.age = 10;
user.bio = 'me';
assert(user.name === 'Joe');
assert(user.bio === 'me');
assert(user.toObject().age === 10);
assert(user.toObject(false).age === 10);
assert(user.toObject(true).age === 10);
assert(user.toObject().bio === 'me');
assert(user.toObject(true).bio === 'me');
assert(user.toObject(false).bio === 'me');
done(null, User);
});
it('should use false as the default value for strict', function (done) {
var modelBuilder = new ModelBuilder();