Merge branch 'release/2.10.3' into production

This commit is contained in:
Raymond Feng 2014-11-04 22:11:55 -08:00
commit c0cc347aa7
8 changed files with 305 additions and 13 deletions

View File

@ -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.

View File

@ -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;
}

View File

@ -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++) {

View File

@ -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); });
}
};
};

View File

@ -1,6 +1,6 @@
{
"name": "loopback-datasource-juggler",
"version": "2.10.2",
"version": "2.10.3",
"description": "LoopBack DataSoure Juggler",
"keywords": [
"StrongLoop",

View File

@ -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();
});
});
});
});

View File

@ -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);

View File

@ -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) {