Merge branch 'release/2.2.1' into production

This commit is contained in:
Raymond Feng 2014-08-04 15:36:03 -07:00
commit 5a4d78ffc8
7 changed files with 106 additions and 17 deletions

View File

@ -393,7 +393,7 @@ DataSource.prototype.defineRelations = function (modelClass, relations) {
// Create a function for the closure in the loop
var createListener = function (name, relation, targetModel, throughModel) {
if (!isModelDataSourceAttached(targetModel)) {
targetModel.once('dataSourceAttached', function (model) {
targetModel.once('dataAccessConfigured', function (model) {
// Check if the through model doesn't exist or resolved
if (!throughModel || isModelDataSourceAttached(throughModel)) {
// The target model is resolved
@ -410,7 +410,7 @@ DataSource.prototype.defineRelations = function (modelClass, relations) {
}
if (throughModel && !isModelDataSourceAttached(throughModel)) {
// Set up a listener to the through model
throughModel.once('dataSourceAttached', function (model) {
throughModel.once('dataAccessConfigured', function (model) {
if (isModelDataSourceAttached(targetModel)) {
// The target model is resolved
var params = traverse(relations).clone();
@ -479,9 +479,15 @@ DataSource.prototype.setupDataAccess = function (modelClass, settings) {
// add data access objects
this.mixin(modelClass);
// define relations from LDL (options.relations)
var relations = settings.relationships || settings.relations;
this.defineRelations(modelClass, relations);
// Emit the dataAccessConfigured event to indicate all the methods for data
// access have been mixed into the model class
modelClass.emit('dataAccessConfigured', modelClass);
// define scopes from LDL (options.relations)
var scopes = settings.scopes || {};
this.defineScopes(modelClass, scopes);

View File

@ -110,7 +110,10 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
var args = slice.call(arguments);
var pluralName = (settings && settings.plural) ||
inflection.pluralize(className);
var httpOptions = (settings && settings.http) || {};
var pathName = httpOptions.path || pluralName;
if (!className) {
throw new Error('Class name required');
}
@ -188,7 +191,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
hiddenProperty(ModelClass, 'dataSource', modelBuilder); // Keep for back-compatibility
hiddenProperty(ModelClass, 'pluralModelName', pluralName);
hiddenProperty(ModelClass, 'relations', {});
hiddenProperty(ModelClass, 'http', { path: '/' + pluralName });
hiddenProperty(ModelClass, 'http', { path: '/' + pathName });
hiddenProperty(ModelClass, 'base', ModelBaseClass);
// inherit ModelBaseClass static methods

View File

@ -70,11 +70,7 @@ function extendScopeMethods(definition, scopeMethods, ext) {
return relationMethod.apply(relation, arguments);
};
if (relationMethod.shared) {
method.shared = true;
method.accepts = relationMethod.accepts;
method.returns = relationMethod.returns;
method.http = relationMethod.http;
method.description = relationMethod.description;
sharedMethod(definition, key, method, relationMethod);
}
customMethods.push(key);
}
@ -573,15 +569,19 @@ function scopeMethod(definition, methodName) {
var relationMethod = relationClass.prototype[methodName];
if (relationMethod.shared) {
method.shared = true;
method.accepts = relationMethod.accepts;
method.returns = relationMethod.returns;
method.http = relationMethod.http;
method.description = relationMethod.description;
sharedMethod(definition, methodName, method, relationMethod);
}
return method;
}
function sharedMethod(definition, methodName, method, relationMethod) {
method.shared = true;
method.accepts = relationMethod.accepts;
method.returns = relationMethod.returns;
method.http = relationMethod.http;
method.description = relationMethod.description;
};
/**
* Find a related item by foreign key
* @param {*} fkId The foreign key
@ -1295,6 +1295,15 @@ RelationDefinition.hasOne = function (modelFrom, modelTo, params) {
return relationMethod;
}
});
// FIXME: [rfeng] Wrap the property into a function for remoting
// so that it can be accessed as /api/<model>/<id>/<hasOneRelationName>
// For example, /api/orders/1/customer
var fn = function() {
var f = this[relationName];
f.apply(this, arguments);
};
modelFrom.prototype['__get__' + relationName] = fn;
};
/**

View File

@ -248,9 +248,15 @@ function mergeQuery(base, update) {
}
}
// Overwrite inclusion
// Merge inclusion
if (update.include) {
base.include = update.include;
if (!base.include) {
base.include = update.include;
} else {
var saved = base.include;
base.include = {};
base.include[update.include] = [saved];
}
}
if (update.collect) {
base.collect = update.collect;

View File

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

View File

@ -350,6 +350,34 @@ describe('DataSource define model', function () {
});
it('should emit events during attach', function() {
var ds = new DataSource('memory');
var modelBuilder = new ModelBuilder();
var User = modelBuilder.define('User', {
name: String
});
var seq = 0;
var dataAccessConfigured = -1;
var dataSourceAttached = -1;
User.on('dataAccessConfigured', function (model) {
dataAccessConfigured = seq++;
assert(User.create);
assert(User.hasMany);
});
User.on('dataSourceAttached', function (model) {
assert(User.dataSource instanceof DataSource);
dataSourceAttached = seq++;
});
ds.attach(User);
assert.equal(dataAccessConfigured, 0);
assert.equal(dataSourceAttached, 1);
});
it('should not take unknown properties in strict mode', function (done) {
var ds = new DataSource('memory');
@ -548,6 +576,15 @@ describe('DataSource define model', function () {
done();
});
it('should allow an explicit remoting path', function () {
var ds = new DataSource('memory');
var User = ds.define('User', {name: String, bio: String}, {
http: { path: 'accounts' }
});
User.http.path.should.equal('/accounts');
});
});

View File

@ -276,6 +276,34 @@ describe('relations', function () {
}
});
it('should allow to use include syntax on related data', function (done) {
var Address = db.define('Address', {name: String});
Patient.belongsTo(Address);
Physician.create(function (err, physician) {
physician.patients.create({name: 'a'}, function (err, patient) {
Address.create({name: 'z'}, function (err, address) {
patient.address(address);
patient.save(function() {
verify(physician);
});
});
});
});
function verify(physician) {
physician.patients({include: 'address'}, function (err, ch) {
should.not.exist(err);
should.exist(ch);
ch.should.have.lengthOf(1);
ch[0].addressId.should.equal(1);
var address = ch[0].address();
should.exist(address);
address.should.be.an.instanceof(Address);
address.name.should.equal('z');
done();
});
}
});
it('should set targetClass on scope property', function() {
should.equal(Physician.prototype.patients._targetClass, 'Patient');
});