Merge branch 'release/2.10.3' into production
This commit is contained in:
commit
c0cc347aa7
|
@ -16,6 +16,6 @@ Also install the appropriated connector, for example for mongodb:
|
|||
|
||||
npm install loopback-connector-mongodb
|
||||
|
||||
See [StrongLoop Suite Documentation](http://docs.strongloop.com/) for up-to-date list of connectors supported.
|
||||
See [StrongLoop Documentation](http://docs.strongloop.com/) for more information.
|
||||
|
||||
|
||||
|
|
|
@ -9,24 +9,31 @@ var defineCachedRelations = utils.defineCachedRelations;
|
|||
* @returns {*}
|
||||
*/
|
||||
function normalizeInclude(include) {
|
||||
var newInclude;
|
||||
if (typeof include === 'string') {
|
||||
return [include];
|
||||
} else if (isPlainObject(include)) {
|
||||
// Build an array of key/value pairs
|
||||
var newInclude = [];
|
||||
newInclude = [];
|
||||
var rel = include.rel || include.relation;
|
||||
var obj = {};
|
||||
if (typeof rel === 'string') {
|
||||
var obj = {};
|
||||
obj[rel] = new IncludeScope(include.scope);
|
||||
newInclude.push(obj);
|
||||
} else {
|
||||
for (var key in include) {
|
||||
var obj = {};
|
||||
obj[key] = include[key];
|
||||
newInclude.push(obj);
|
||||
}
|
||||
}
|
||||
return newInclude;
|
||||
} else if (Array.isArray(include)) {
|
||||
newInclude = [];
|
||||
for (var i = 0, n = include.length; i < n; i++) {
|
||||
var subIncludes = normalizeInclude(include[i]);
|
||||
newInclude = newInclude.concat(subIncludes);
|
||||
}
|
||||
return newInclude;
|
||||
} else {
|
||||
return include;
|
||||
}
|
||||
|
|
32
lib/model.js
32
lib/model.js
|
@ -53,7 +53,7 @@ function ModelBaseClass(data, options) {
|
|||
ModelBaseClass.prototype._initProperties = function (data, options) {
|
||||
var self = this;
|
||||
var ctor = this.constructor;
|
||||
|
||||
|
||||
if(data instanceof ctor) {
|
||||
// Convert the data to be plain object to avoid pollutions
|
||||
data = data.toObject(false);
|
||||
|
@ -73,10 +73,6 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
strict = ctor.definition.settings.strict;
|
||||
}
|
||||
|
||||
if (options.persisted !== undefined) {
|
||||
this.__persisted = options.persisted === true;
|
||||
}
|
||||
|
||||
if (ctor.hideInternalProperties) {
|
||||
// Object.defineProperty() is expensive. We only try to make the internal
|
||||
// properties hidden (non-enumerable) if the model class has the
|
||||
|
@ -110,6 +106,13 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
enumerable: false,
|
||||
configurable: true,
|
||||
value: strict
|
||||
},
|
||||
|
||||
__persisted: {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: false
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -117,6 +120,11 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
this.__data = {};
|
||||
this.__dataSource = options.dataSource;
|
||||
this.__strict = strict;
|
||||
this.__persisted = false;
|
||||
}
|
||||
|
||||
if (options.persisted !== undefined) {
|
||||
this.__persisted = options.persisted === true;
|
||||
}
|
||||
|
||||
if (data.__cachedRelations) {
|
||||
|
@ -124,6 +132,13 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
}
|
||||
|
||||
var keys = Object.keys(data);
|
||||
|
||||
if (Array.isArray(options.fields)) {
|
||||
keys = keys.filter(function(k) {
|
||||
return (options.fields.indexOf(k) != -1);
|
||||
});
|
||||
}
|
||||
|
||||
var size = keys.length;
|
||||
var p, propVal;
|
||||
for (var k = 0; k < size; k++) {
|
||||
|
@ -169,6 +184,13 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
}
|
||||
|
||||
keys = Object.keys(properties);
|
||||
|
||||
if (Array.isArray(options.fields)) {
|
||||
keys = keys.filter(function(k) {
|
||||
return (options.fields.indexOf(k) != -1);
|
||||
});
|
||||
}
|
||||
|
||||
size = keys.length;
|
||||
|
||||
for (k = 0; k < size; k++) {
|
||||
|
|
|
@ -1417,7 +1417,7 @@ RelationDefinition.hasOne = function (modelFrom, modelTo, params) {
|
|||
params = params || {};
|
||||
modelTo = lookupModelTo(modelFrom, modelTo, params);
|
||||
|
||||
var pk = modelTo.dataSource.idName(modelTo.modelName) || 'id';
|
||||
var pk = modelFrom.dataSource.idName(modelFrom.modelName) || 'id';
|
||||
var relationName = params.as || i8n.camelize(modelTo.modelName, true);
|
||||
|
||||
var fk = params.foreignKey || i8n.camelize(modelFrom.modelName + '_id', true);
|
||||
|
@ -2748,4 +2748,4 @@ ReferencesMany.prototype.remove = function (acInst, cb) {
|
|||
} else {
|
||||
process.nextTick(function() { cb(null, ids); });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "loopback-datasource-juggler",
|
||||
"version": "2.10.2",
|
||||
"version": "2.10.3",
|
||||
"description": "LoopBack DataSoure Juggler",
|
||||
"keywords": [
|
||||
"StrongLoop",
|
||||
|
|
|
@ -35,4 +35,18 @@ describe('defaults', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore defaults with limited fields', function (done) {
|
||||
Server.create({ host: 'localhost', port: 8080 }, function(err, s) {
|
||||
should.not.exist(err);
|
||||
s.port.should.equal(8080);
|
||||
Server.find({ fields: ['host'] }, function (err, servers) {
|
||||
servers[0].host.should.equal('localhost');
|
||||
servers[0].should.have.property('host');
|
||||
servers[0].should.not.have.property('port');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -256,6 +256,45 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch User - Posts AND Passports in relation syntax',
|
||||
function(done) {
|
||||
User.find({include: [
|
||||
{relation: 'posts', scope: {
|
||||
where: {title: 'Post A'}
|
||||
}},
|
||||
'passports'
|
||||
]}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
users.length.should.be.ok;
|
||||
users.forEach(function(user) {
|
||||
// The relation should be promoted as the 'owner' property
|
||||
user.should.have.property('posts');
|
||||
user.should.have.property('passports');
|
||||
|
||||
var userObj = user.toJSON();
|
||||
userObj.should.have.property('posts');
|
||||
userObj.should.have.property('passports');
|
||||
userObj.posts.should.be.an.instanceOf(Array);
|
||||
userObj.passports.should.be.an.instanceOf(Array);
|
||||
|
||||
// The __cachedRelations should be removed from json output
|
||||
userObj.should.not.have.property('__cachedRelations');
|
||||
|
||||
user.__cachedRelations.should.have.property('posts');
|
||||
user.__cachedRelations.should.have.property('passports');
|
||||
user.__cachedRelations.posts.forEach(function(p) {
|
||||
p.userId.should.equal(user.id);
|
||||
p.title.should.be.equal('Post A');
|
||||
});
|
||||
user.__cachedRelations.passports.forEach(function(pp) {
|
||||
pp.ownerId.should.equal(user.id);
|
||||
});
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not fetch User - AccessTokens', function (done) {
|
||||
User.find({include: ['accesstokens']}, function (err, users) {
|
||||
should.not.exist(err);
|
||||
|
|
|
@ -902,6 +902,130 @@ describe('relations', function () {
|
|||
|
||||
});
|
||||
|
||||
describe('polymorphic hasOne with non standard ids', function () {
|
||||
before(function (done) {
|
||||
db = getSchema();
|
||||
Picture = db.define('Picture', {name: String});
|
||||
Author = db.define('Author', {
|
||||
username: {type: String, id: true},
|
||||
name: String
|
||||
});
|
||||
Reader = db.define('Reader', {
|
||||
username: {type: String, id: true},
|
||||
name: String
|
||||
});
|
||||
|
||||
db.automigrate(function () {
|
||||
Picture.destroyAll(function () {
|
||||
Author.destroyAll(function () {
|
||||
Reader.destroyAll(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can be declared with non standard foreign key', function (done) {
|
||||
Author.hasOne(Picture, {
|
||||
as: 'avatar',
|
||||
polymorphic: {
|
||||
foreignKey: 'oid',
|
||||
discriminator: 'type'
|
||||
}
|
||||
});
|
||||
Reader.hasOne(Picture, {
|
||||
as: 'mugshot',
|
||||
polymorphic: {
|
||||
foreignKey: 'oid',
|
||||
discriminator: 'type'
|
||||
}
|
||||
});
|
||||
Picture.belongsTo('owner', {
|
||||
idName: 'username',
|
||||
polymorphic: {
|
||||
idType: String,
|
||||
foreignKey: 'oid',
|
||||
discriminator: 'type'
|
||||
}
|
||||
});
|
||||
db.automigrate(done);
|
||||
});
|
||||
|
||||
it('should create polymorphic relation - author', function (done) {
|
||||
Author.create({name: 'Author 1' }, function (err, author) {
|
||||
author.avatar.create({ name: 'Avatar' }, function (err, p) {
|
||||
should.not.exist(err);
|
||||
should.exist(p);
|
||||
p.oid.should.equal(author.username);
|
||||
p.type.should.equal('Author');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should create polymorphic relation - reader', function (done) {
|
||||
Reader.create({name: 'Reader 1' }, function (err, reader) {
|
||||
reader.mugshot.create({ name: 'Mugshot' }, function (err, p) {
|
||||
should.not.exist(err);
|
||||
should.exist(p);
|
||||
p.oid.should.equal(reader.username);
|
||||
p.type.should.equal('Reader');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should find polymorphic relation - author', function (done) {
|
||||
Author.findOne(function (err, author) {
|
||||
author.avatar(function (err, p) {
|
||||
should.not.exist(err);
|
||||
|
||||
var avatar = author.avatar();
|
||||
avatar.should.equal(p);
|
||||
|
||||
p.name.should.equal('Avatar');
|
||||
p.oid.should.eql(author.username);
|
||||
p.type.should.equal('Author');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should find polymorphic relation - reader', function (done) {
|
||||
Reader.findOne(function (err, reader) {
|
||||
reader.mugshot(function (err, p) {
|
||||
should.not.exist(err);
|
||||
p.name.should.equal('Mugshot');
|
||||
p.oid.should.eql(reader.username);
|
||||
p.type.should.equal('Reader');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should find inverse polymorphic relation - author', function (done) {
|
||||
Picture.findOne({ where: { name: 'Avatar' } }, function (err, p) {
|
||||
p.owner(function (err, owner) {
|
||||
should.not.exist(err);
|
||||
owner.should.be.instanceof(Author);
|
||||
owner.name.should.equal('Author 1');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should find inverse polymorphic relation - reader', function (done) {
|
||||
Picture.findOne({ where: { name: 'Mugshot' } }, function (err, p) {
|
||||
p.owner(function (err, owner) {
|
||||
should.not.exist(err);
|
||||
owner.should.be.instanceof(Reader);
|
||||
owner.name.should.equal('Reader 1');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('polymorphic hasMany', function () {
|
||||
before(function (done) {
|
||||
db = getSchema();
|
||||
|
@ -1622,7 +1746,93 @@ describe('relations', function () {
|
|||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('hasOne with non standard id', function () {
|
||||
var Supplier, Account;
|
||||
var supplierId, accountId;
|
||||
|
||||
before(function () {
|
||||
db = getSchema();
|
||||
Supplier = db.define('Supplier', {
|
||||
sid: {
|
||||
type: String,
|
||||
id: true
|
||||
},
|
||||
name: String
|
||||
});
|
||||
Account = db.define('Account', {
|
||||
accid: {
|
||||
type: String,
|
||||
id: true,
|
||||
generated: false
|
||||
},
|
||||
supplierName: String
|
||||
});
|
||||
});
|
||||
|
||||
it('can be declared with non standard foreignKey', function () {
|
||||
Supplier.hasOne(Account, {
|
||||
properties: {name: 'supplierName'},
|
||||
foreignKey: 'sid'
|
||||
});
|
||||
Object.keys((new Account()).toObject()).should.include('sid');
|
||||
(new Supplier()).account.should.be.an.instanceOf(Function);
|
||||
});
|
||||
|
||||
it('can be used to query data', function (done) {
|
||||
db.automigrate(function () {
|
||||
Supplier.create({name: 'Supplier 1'}, function (e, supplier) {
|
||||
supplierId = supplier.sid;
|
||||
should.not.exist(e);
|
||||
should.exist(supplier);
|
||||
supplier.account.create({accid: 'a01'}, function (err, account) {
|
||||
supplier.account(function (e, act) {
|
||||
accountId = act.accid;
|
||||
should.not.exist(e);
|
||||
should.exist(act);
|
||||
act.should.be.an.instanceOf(Account);
|
||||
supplier.account().accid.should.equal(act.accid);
|
||||
act.supplierName.should.equal(supplier.name);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should destroy the related item on scope', function(done) {
|
||||
Supplier.findById(supplierId, function(e, supplier) {
|
||||
should.not.exist(e);
|
||||
should.exist(supplier);
|
||||
supplier.account.destroy(function(err) {
|
||||
should.not.exist(e);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should get the related item on scope - verify', function(done) {
|
||||
Supplier.findById(supplierId, function(e, supplier) {
|
||||
should.not.exist(e);
|
||||
should.exist(supplier);
|
||||
supplier.account(function(err, act) {
|
||||
should.not.exist(e);
|
||||
should.not.exist(act);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should have deleted related item', function(done) {
|
||||
Supplier.findById(supplierId, function (e, supplier) {
|
||||
should.not.exist(e);
|
||||
should.exist(supplier);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('hasAndBelongsToMany', function () {
|
||||
var Article, TagName, ArticleTag;
|
||||
it('can be declared', function (done) {
|
||||
|
|
Loading…
Reference in New Issue