Merge branch 'master' of https://github.com/strongloop/loopback-data
This commit is contained in:
commit
3190298aac
22
lib/dao.js
22
lib/dao.js
|
@ -85,7 +85,7 @@ DataAccessObject.create = function (data, callback) {
|
|||
data = {};
|
||||
}
|
||||
|
||||
if (data instanceof Array) {
|
||||
if (Array.isArray(data)) {
|
||||
var instances = [];
|
||||
var errors = Array(data.length);
|
||||
var gotError = false;
|
||||
|
@ -117,7 +117,7 @@ DataAccessObject.create = function (data, callback) {
|
|||
|
||||
var obj;
|
||||
// if we come from save
|
||||
if (data instanceof Model && !data.id) {
|
||||
if (data instanceof Model && !getIdValue(this, data)) {
|
||||
obj = data;
|
||||
} else {
|
||||
obj = new Model(data);
|
||||
|
@ -182,6 +182,16 @@ function stillConnecting(dataSource, obj, args) {
|
|||
return true;
|
||||
};
|
||||
|
||||
function getIdValue(m, data) {
|
||||
return data && data[m.dataSource.idName(m.modelName)];
|
||||
}
|
||||
|
||||
function setIdValue(m, data, value) {
|
||||
if(data) {
|
||||
data[m.dataSource.idName(m.modelName)] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update or insert
|
||||
*/
|
||||
|
@ -189,7 +199,7 @@ DataAccessObject.upsert = DataAccessObject.updateOrCreate = function upsert(data
|
|||
if (stillConnecting(this.dataSource, this, arguments)) return;
|
||||
|
||||
var Model = this;
|
||||
if (!data.id) return this.create(data, callback);
|
||||
if (!getIdValue(this, data)) return this.create(data, callback);
|
||||
if (this.dataSource.connector.updateOrCreate) {
|
||||
var inst = new Model(data);
|
||||
this.dataSource.connector.updateOrCreate(Model.modelName, inst.toObject(true), function (err, data) {
|
||||
|
@ -203,7 +213,7 @@ DataAccessObject.upsert = DataAccessObject.updateOrCreate = function upsert(data
|
|||
callback(err, obj);
|
||||
});
|
||||
} else {
|
||||
this.findById(data.id, function (err, inst) {
|
||||
this.findById(getIdValue(this, data), function (err, inst) {
|
||||
if (err) return callback(err);
|
||||
if (inst) {
|
||||
inst.updateAttributes(data, callback);
|
||||
|
@ -276,8 +286,8 @@ DataAccessObject.findById = function find(id, cb) {
|
|||
this.dataSource.connector.find(this.modelName, id, function (err, data) {
|
||||
var obj = null;
|
||||
if (data) {
|
||||
if (!data.id) {
|
||||
data.id = id;
|
||||
if (!getIdValue(this, data)) {
|
||||
setIdValue(this, data, id);
|
||||
}
|
||||
obj = new this();
|
||||
obj._initProperties(data, false);
|
||||
|
|
|
@ -132,6 +132,7 @@ DataSource.prototype._setupConnector = function () {
|
|||
// Set up the dataSource if the connector doesn't do so
|
||||
this.connector.dataSource = this;
|
||||
}
|
||||
var dataSource = this;
|
||||
this.connector.log = function (query, start) {
|
||||
dataSource.log(query, start);
|
||||
};
|
||||
|
|
|
@ -7,7 +7,6 @@ var ModelBaseClass = require('./model.js');
|
|||
var List = require('./list.js');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var GeoPoint = require('./geo').GeoPoint;
|
||||
|
||||
/**
|
||||
* Export public API
|
||||
|
@ -21,36 +20,6 @@ exports.Schema = exports.ModelBuilder = ModelBuilder;
|
|||
*/
|
||||
var slice = Array.prototype.slice;
|
||||
|
||||
/**
|
||||
* Schema types
|
||||
*/
|
||||
ModelBuilder.Text = function Text() {}; // Text type
|
||||
ModelBuilder.JSON = function JSON() {}; // JSON Object
|
||||
ModelBuilder.Any = function Any() {}; // Any Type
|
||||
|
||||
ModelBuilder.schemaTypes = {};
|
||||
ModelBuilder.registerType = function (type, names) {
|
||||
names = names || [];
|
||||
names = names.concat([type.name]);
|
||||
for (var n = 0; n < names.length; n++) {
|
||||
this.schemaTypes[names[n].toLowerCase()] = type;
|
||||
}
|
||||
};
|
||||
|
||||
ModelBuilder.registerType(ModelBuilder.Text);
|
||||
ModelBuilder.registerType(ModelBuilder.JSON);
|
||||
ModelBuilder.registerType(ModelBuilder.Any);
|
||||
|
||||
ModelBuilder.registerType(String);
|
||||
ModelBuilder.registerType(Number);
|
||||
ModelBuilder.registerType(Boolean);
|
||||
ModelBuilder.registerType(Date);
|
||||
ModelBuilder.registerType(Buffer, ['Binary']);
|
||||
ModelBuilder.registerType(Array);
|
||||
ModelBuilder.registerType(GeoPoint);
|
||||
ModelBuilder.registerType(Object);
|
||||
|
||||
|
||||
/**
|
||||
* ModelBuilder - Data Model Definition
|
||||
*/
|
||||
|
@ -62,6 +31,8 @@ function ModelBuilder() {
|
|||
|
||||
util.inherits(ModelBuilder, EventEmitter);
|
||||
|
||||
// Set up types
|
||||
require('./types')(ModelBuilder);
|
||||
|
||||
/**
|
||||
* Define class
|
||||
|
@ -221,7 +192,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
if(!DataType) {
|
||||
throw new Error('Invalid type for property ' + attr);
|
||||
}
|
||||
if (DataType instanceof Array) {
|
||||
if (Array.isArray(DataType)) {
|
||||
DataType = List;
|
||||
} else if (DataType.name === 'Date') {
|
||||
var OrigDate = Date;
|
||||
|
@ -261,6 +232,8 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
if(DataType === List) {
|
||||
this.__data[attr] = DataType(value, properties[attr].type, this.__data);
|
||||
} else {
|
||||
// Assume the type constructor handles Constructor() call
|
||||
// If not, we should call new DataType(value).valueOf();
|
||||
this.__data[attr] = DataType(value);
|
||||
}
|
||||
}
|
||||
|
|
33
lib/model.js
33
lib/model.js
|
@ -34,12 +34,7 @@ ModelBaseClass.prototype._initProperties = function (data, applySetters) {
|
|||
var self = this;
|
||||
var ctor = this.constructor;
|
||||
|
||||
var ds = {
|
||||
properties: ctor.properties,
|
||||
setters: ctor.settings
|
||||
};
|
||||
|
||||
var properties = ds.properties;
|
||||
var properties = ctor.properties;
|
||||
data = data || {};
|
||||
|
||||
Object.defineProperty(this, '__cachedRelations', {
|
||||
|
@ -67,18 +62,29 @@ ModelBaseClass.prototype._initProperties = function (data, applySetters) {
|
|||
this.__cachedRelations = data['__cachedRelations'];
|
||||
}
|
||||
|
||||
// Check if the strict option is set to false for the model
|
||||
var strict = ctor.settings.strict;
|
||||
|
||||
for (var i in data) {
|
||||
if (i in properties) {
|
||||
this.__data[i] = this.__dataWas[i] = data[i];
|
||||
} else if (i in ctor.relations) {
|
||||
this.__data[ctor.relations[i].keyFrom] = this.__dataWas[i] = data[i][ctor.relations[i].keyTo];
|
||||
this.__cachedRelations[i] = data[i];
|
||||
} else {
|
||||
if(strict === false) {
|
||||
this.__data[i] = this.__dataWas[i] = data[i];
|
||||
} else if(strict === 'throw') {
|
||||
throw new Error('Unknown property: ' + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (applySetters === true) {
|
||||
Object.keys(data).forEach(function (attr) {
|
||||
self[attr] = data[attr];
|
||||
if((attr in properties) || (attr in ctor.relations) || strict === false) {
|
||||
self[attr] = data[attr];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -170,12 +176,13 @@ ModelBaseClass.prototype.toObject = function (onlySchema) {
|
|||
var properties = ds.properties;
|
||||
var self = this;
|
||||
|
||||
var schemaless = this.constructor.settings.strict === false || !onlySchema;
|
||||
this.constructor.forEachProperty(function (attr) {
|
||||
if (self[attr] instanceof List) {
|
||||
data[attr] = self[attr].toObject(onlySchema);
|
||||
data[attr] = self[attr].toObject(!schemaless);
|
||||
} else if (self.__data.hasOwnProperty(attr)) {
|
||||
if(self[attr] !== undefined && self[attr]!== null && self[attr].toObject) {
|
||||
data[attr] = self[attr].toObject(onlySchema);
|
||||
data[attr] = self[attr].toObject(!schemaless);
|
||||
} else {
|
||||
data[attr] = self[attr];
|
||||
}
|
||||
|
@ -184,10 +191,14 @@ ModelBaseClass.prototype.toObject = function (onlySchema) {
|
|||
}
|
||||
});
|
||||
|
||||
if (!onlySchema) {
|
||||
if (schemaless) {
|
||||
Object.keys(self).forEach(function (attr) {
|
||||
if (!data.hasOwnProperty(attr)) {
|
||||
data[attr] = this[attr];
|
||||
if(self[attr] !== undefined && self[attr]!== null && self[attr].toObject) {
|
||||
data[attr] = self[attr].toObject(!schemaless);
|
||||
} else {
|
||||
data[attr] = self[attr];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
module.exports = function (Types) {
|
||||
|
||||
var List = require('./list.js');
|
||||
var GeoPoint = require('./geo').GeoPoint;
|
||||
|
||||
/**
|
||||
* Schema types
|
||||
*/
|
||||
Types.Text = function Text(value) {
|
||||
if (!(this instanceof Text)) {
|
||||
return new Text(value);
|
||||
}
|
||||
this.value = value;
|
||||
}; // Text type
|
||||
|
||||
Types.Text.prototype.toObject = Types.Text.prototype.toJSON = function () {
|
||||
return this.value;
|
||||
};
|
||||
|
||||
Types.JSON = function JSON() {
|
||||
if (!(this instanceof JSON)) {
|
||||
return new JSON(value);
|
||||
}
|
||||
this.value = value;
|
||||
}; // JSON Object
|
||||
Types.JSON.prototype.toObject = Types.JSON.prototype.toJSON = function () {
|
||||
return this.value;
|
||||
};
|
||||
|
||||
Types.Any = function Any() {
|
||||
if (!(this instanceof Any)) {
|
||||
return new Any(value);
|
||||
}
|
||||
this.value = value;
|
||||
}; // Any Type
|
||||
Types.Any.prototype.toObject = Types.Any.prototype.toJSON = function () {
|
||||
return this.value;
|
||||
};
|
||||
|
||||
Types.schemaTypes = {};
|
||||
Types.registerType = function (type, names) {
|
||||
names = names || [];
|
||||
names = names.concat([type.name]);
|
||||
for (var n = 0; n < names.length; n++) {
|
||||
this.schemaTypes[names[n].toLowerCase()] = type;
|
||||
}
|
||||
};
|
||||
|
||||
Types.registerType(Types.Text);
|
||||
Types.registerType(Types.JSON);
|
||||
Types.registerType(Types.Any);
|
||||
|
||||
Types.registerType(String);
|
||||
Types.registerType(Number);
|
||||
Types.registerType(Boolean);
|
||||
Types.registerType(Date);
|
||||
Types.registerType(Buffer, ['Binary']);
|
||||
Types.registerType(Array);
|
||||
Types.registerType(GeoPoint);
|
||||
Types.registerType(Object);
|
||||
}
|
|
@ -39,6 +39,43 @@ describe('ModelBuilder define model', function () {
|
|||
done(null, User);
|
||||
});
|
||||
|
||||
it('should not take unknown properties in strict mode', function (done) {
|
||||
var modelBuilder = new ModelBuilder();
|
||||
|
||||
// simplier way to describe model
|
||||
var User = modelBuilder.define('User', {name: String, bio: String}, {strict: true});
|
||||
|
||||
var user = new User({name: 'Joe', age: 20});
|
||||
// console.log(user);
|
||||
|
||||
User.modelName.should.equal('User');
|
||||
user.should.be.a('object');
|
||||
// console.log(user);
|
||||
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 be able to define open models', function (done) {
|
||||
var modelBuilder = new ModelBuilder();
|
||||
|
||||
// simplier way to describe model
|
||||
var User = modelBuilder.define('User', {}, {strict: false});
|
||||
|
||||
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 be able to define nesting models', function (done) {
|
||||
var modelBuilder = new ModelBuilder();
|
||||
|
|
Loading…
Reference in New Issue