From e1ec152c78f3ee6cd0f0e46d1b9171c4036bea8e Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 18 Dec 2013 16:13:41 -0800 Subject: [PATCH 1/2] Add models to LDL options 1. Use 'models' to specify the dependencies to other models 2. The 'models' property is an object, such as: { Model1: 'Model1', Model2: Model2 } 3. The model classes will be injected into the newly defined class as static properties using the keys from the models option. --- lib/datasource.js | 16 ++++------------ lib/model-builder.js | 23 +++++++++++++++++++++-- test/loopback-dl.test.js | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/lib/datasource.js b/lib/datasource.js index dc03afd9..a667e4c3 100644 --- a/lib/datasource.js +++ b/lib/datasource.js @@ -363,18 +363,10 @@ DataSource.prototype.defineRelations = function(modelClass, relations) { for (var rn in relations) { var r = relations[rn]; assert(DataSource.relationTypes.indexOf(r.type) !== -1, "Invalid relation type: " + r.type); - var targetModel = isModelClass(r.model) ? r.model : this.getModel(r.model); - if (!targetModel) { - // The target model doesn't exist, let create a place holder for it - targetModel = this.define(r.model, {}, {unresolved: true}); - } + var targetModel = isModelClass(r.model) ? r.model : this.getModel(r.model, true); var throughModel = null; if (r.through) { - throughModel = isModelClass(r.through) ? r.through : this.getModel(r.through); - if (!throughModel) { - // The through model doesn't exist, let create a place holder for it - throughModel = this.define(r.through, {}, {unresolved: true}); - } + throughModel = isModelClass(r.through) ? r.through : this.getModel(r.through, true); } if (!isModelDataSourceAttached(targetModel) || (throughModel && !isModelDataSourceAttached(throughModel))) { // Create a listener to defer the relation set up @@ -533,8 +525,8 @@ DataSource.prototype.mixin = function (ModelCtor) { }); }; -DataSource.prototype.getModel = function(name) { - return this.modelBuilder.getModel(name); +DataSource.prototype.getModel = function(name, forceCreate) { + return this.modelBuilder.getModel(name, forceCreate); }; DataSource.prototype.getModelDefinition = function(name) { diff --git a/lib/model-builder.js b/lib/model-builder.js index dcbb3a99..59a62a17 100644 --- a/lib/model-builder.js +++ b/lib/model-builder.js @@ -56,8 +56,19 @@ function isModelClass(cls) { return cls.prototype instanceof DefaultModelBaseClass; } -ModelBuilder.prototype.getModel = function(name) { - return this.models[name]; +/** + * Get a model by name + * @param {String} name The model name + * @param {Boolean} forceCreate Indicate if a stub should be created for the + * given name if a model doesn't exist + * @returns {*} The model class + */ +ModelBuilder.prototype.getModel = function(name, forceCreate) { + var model = this.models[name]; + if(!model && forceCreate) { + model = this.define(name, {}, {unresolved: true}); + } + return model; }; ModelBuilder.prototype.getModelDefinition = function(name) { @@ -185,6 +196,14 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett ModelClass[i] = ModelBaseClass[i]; } } + + // Load and inject the model classes + if(settings.models) { + Object.keys(settings.models).forEach(function(m) { + var model = settings.models[m]; + ModelClass[m] = typeof model === 'string' ? modelBuilder.getModel(model, true) : model; + }); + } ModelClass.getter = {}; ModelClass.setter = {}; diff --git a/test/loopback-dl.test.js b/test/loopback-dl.test.js index bb3c6457..a6225b59 100644 --- a/test/loopback-dl.test.js +++ b/test/loopback-dl.test.js @@ -906,3 +906,39 @@ describe('Injected methods from connectors', function(){ }); }); + + +describe('ModelBuilder options.models', function(){ + it('should inject model classes from models', function() { + var builder = new ModelBuilder(); + var M1 = builder.define('M1'); + var M2 = builder.define('M2', {}, {models: { + 'M1': M1 + }}); + + assert.equal(M2.M1, M1, 'M1 should be injected to M2'); + }); + + it('should inject model classes by name in the models', function() { + var builder = new ModelBuilder(); + var M1 = builder.define('M1'); + var M2 = builder.define('M2', {}, {models: { + 'M1': 'M1' + }}); + + assert.equal(M2.M1, M1, 'M1 should be injected to M2'); + }); + + it('should inject model classes by name in the models before the class is defined', + function() { + var builder = new ModelBuilder(); + var M2 = builder.define('M2', {}, {models: { + 'M1': 'M1' + }}); + assert(M2.M1, 'M1 should be injected to M2'); + assert(M2.M1.settings.unresolved, 'M1 is still a proxy'); + var M1 = builder.define('M1'); + assert.equal(M2.M1, M1, 'M1 should be injected to M2'); + }); + +}); \ No newline at end of file From c9e133d7bc9ba9c6a412a9bd425beb50431a96f3 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 18 Dec 2013 17:14:54 -0800 Subject: [PATCH 2/2] Add a EOL --- test/loopback-dl.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/loopback-dl.test.js b/test/loopback-dl.test.js index a6225b59..f4214df5 100644 --- a/test/loopback-dl.test.js +++ b/test/loopback-dl.test.js @@ -941,4 +941,5 @@ describe('ModelBuilder options.models', function(){ assert.equal(M2.M1, M1, 'M1 should be injected to M2'); }); -}); \ No newline at end of file +}); +