Skip to content

Commit da09876

Browse files
authored
Merge pull request #2401 from strongloop/compat_flag_cleanup
[SEMVER-MAJOR] Discard sugar method for model creation
2 parents a6f8ec6 + 832e2c3 commit da09876

File tree

11 files changed

+152
-183
lines changed

11 files changed

+152
-183
lines changed

3.0-RELEASE-NOTES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,12 @@ module:
194194
195195
See also [loopback#2564](https://github.com/strongloop/loopback/pull/2564)
196196
and the official [documentation](https://docs.strongloop.com/display/APIC/Using+current+context)
197+
198+
## Remove sugar for creating models
199+
200+
`app.model(modelName, settings)`, a sugar for creating non-existing model, is
201+
now removed in favor of promoting use of:
202+
- `app.registry.createModel(modelName, properties, options)` to create new model
203+
- `app.model(modelCtor, config)` to update existing model and attach it to app
204+
205+
Please see [related code change](https://github.com/strongloop/loopback/pull/2401) here.

example/colors/app.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ var schema = {
1414
name: String,
1515
};
1616

17-
var Color = app.model('color', schema);
18-
19-
app.dataSource('db', { adapter: 'memory' }).attach(Color);
17+
app.dataSource('db', { connector: 'memory' });
18+
var Color = app.registry.createModel('color', schema);
19+
app.model(Color, { dataSource: 'db' });
2020

2121
Color.create({ name: 'red' });
2222
Color.create({ name: 'green' });

example/replication/app.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
var loopback = require('../../');
77
var app = loopback();
8-
var db = app.dataSource('db', { connector: loopback.Memory });
9-
var Color = app.model('color', { dataSource: 'db', options: { trackChanges: true }});
10-
var Color2 = app.model('color2', { dataSource: 'db', options: { trackChanges: true }});
8+
var db = app.dataSource('db', { connector: 'memory' });
9+
var Color = app.registry.createModel('color', {}, { trackChanges: true });
10+
app.model(Color, { dataSource: 'db' });
11+
var Color2 = app.registry.createModel('color2', {}, { trackChanges: true });
12+
app.model(Color2, { dataSource: 'db' });
1113
var target = Color2;
1214
var source = Color;
1315
var SPEED = process.env.SPEED || 100;

lib/application.js

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ app.disuse = function(route) {
101101
* app.model(User, { dataSource: 'db' });
102102
*```
103103
*
104-
* @param {Object|String} Model The model to attach.
104+
* @param {Object} Model The model to attach.
105105
* @options {Object} config The model's configuration.
106106
* @property {String|DataSource} dataSource The `DataSource` to which to attach the model.
107107
* @property {Boolean} [public] Whether the model should be exposed via REST API.
@@ -114,29 +114,15 @@ app.model = function(Model, config) {
114114
var isPublic = true;
115115
var registry = this.registry;
116116

117+
if (typeof Model === 'string') {
118+
var msg = 'app.model(modelName, settings) is no longer supported. ' +
119+
'Use app.registry.createModel(modelName, definition) and ' +
120+
'app.model(ModelCtor, config) instead.';
121+
throw new Error(msg);
122+
}
123+
117124
if (arguments.length > 1) {
118125
config = config || {};
119-
if (typeof Model === 'string') {
120-
// create & attach the model - backwards compatibility
121-
122-
// create config for loopback.modelFromConfig
123-
var modelConfig = extend({}, config);
124-
modelConfig.options = extend({}, config.options);
125-
modelConfig.name = Model;
126-
127-
// modeller does not understand `dataSource` option
128-
delete modelConfig.dataSource;
129-
130-
Model = registry.createModel(modelConfig);
131-
132-
// delete config options already applied
133-
['relations', 'base', 'acls', 'hidden', 'methods'].forEach(function(prop) {
134-
delete config[prop];
135-
if (config.options) delete config.options[prop];
136-
});
137-
delete config.properties;
138-
}
139-
140126
configureModel(Model, config, this);
141127
isPublic = config.public !== false;
142128
} else {
@@ -186,7 +172,7 @@ app.model = function(Model, config) {
186172
* });
187173
* ```
188174
*
189-
* 2. Use `app.model` to access a model by name.
175+
* 2. Use `app.models` to access a model by name.
190176
* `app.models` has properties for all defined models.
191177
*
192178
* The following example illustrates accessing the `Product` and `CustomerReceipt` models
@@ -201,8 +187,10 @@ app.model = function(Model, config) {
201187
* }
202188
* });
203189
*
204-
* app.model('product', {dataSource: 'db'});
205-
* app.model('customer-receipt', {dataSource: 'db'});
190+
* var productModel = app.registry.createModel('product');
191+
* app.model(productModel, {dataSource: 'db'});
192+
* var customerReceiptModel = app.registry.createModel('customer-receipt');
193+
* app.model(customerReceiptModel, {dataSource: 'db'});
206194
*
207195
* // available based on the given name
208196
* var Product = app.models.Product;

test/acl.test.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -393,20 +393,18 @@ describe('security ACLs', function() {
393393
});
394394

395395
describe('access check', function() {
396-
var app;
397-
before(function() {
398-
app = loopback();
399-
app.set('remoting', { errorHandler: { debug: true, log: false }});
400-
app.use(loopback.rest());
401-
app.enableAuth();
402-
app.dataSource('test', { connector: 'memory' });
403-
});
404-
405396
it('should occur before other remote hooks', function(done) {
406-
var MyTestModel = app.model('MyTestModel', { base: 'PersistedModel', dataSource: 'test' });
397+
var app = loopback();
398+
var MyTestModel = app.registry.createModel('MyTestModel');
407399
var checkAccessCalled = false;
408400
var beforeHookCalled = false;
409401

402+
app.use(loopback.rest());
403+
app.set('remoting', { errorHandler: { debug: true, log: false }});
404+
app.enableAuth();
405+
app.dataSource('test', { connector: 'memory' });
406+
app.model(MyTestModel, { dataSource: 'test' });
407+
410408
// fake / spy on the checkAccess method
411409
MyTestModel.checkAccess = function() {
412410
var cb = arguments[arguments.length - 1];

test/app.test.js

Lines changed: 21 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -611,11 +611,12 @@ describe('app', function() {
611611
});
612612

613613
describe('app.model(Model)', function() {
614-
var app, db;
614+
var app, db, MyTestModel;
615615
beforeEach(function() {
616616
app = loopback();
617617
app.set('remoting', { errorHandler: { debug: true, log: false }});
618618
db = loopback.createDataSource({ connector: loopback.Memory });
619+
MyTestModel = app.registry.createModel('MyTestModel');
619620
});
620621

621622
it('Expose a `Model` to remote clients', function() {
@@ -626,7 +627,7 @@ describe('app', function() {
626627
expect(app.models()).to.eql([Color]);
627628
});
628629

629-
it('uses singlar name as app.remoteObjects() key', function() {
630+
it('uses singular name as app.remoteObjects() key', function() {
630631
var Color = PersistedModel.extend('color', { name: String });
631632
app.model(Color);
632633
Color.attachTo(db);
@@ -689,76 +690,26 @@ describe('app', function() {
689690
});
690691
});
691692

692-
it('accepts null dataSource', function() {
693-
app.model('MyTestModel', { dataSource: null });
694-
});
695-
696-
it('accepts false dataSource', function() {
697-
app.model('MyTestModel', { dataSource: false });
693+
it('accepts null dataSource', function(done) {
694+
app.model(MyTestModel, { dataSource: null });
695+
expect(MyTestModel.dataSource).to.eql(null);
696+
done();
698697
});
699698

700-
it('should not require dataSource', function() {
701-
app.model('MyTestModel', {});
702-
});
703-
});
704-
705-
describe('app.model(name, config)', function() {
706-
var app;
707-
708-
beforeEach(function() {
709-
app = loopback();
710-
app.dataSource('db', {
711-
connector: 'memory',
712-
});
699+
it('accepts false dataSource', function(done) {
700+
app.model(MyTestModel, { dataSource: false });
701+
expect(MyTestModel.getDataSource()).to.eql(null);
702+
done();
713703
});
714704

715-
it('Sugar for defining a fully built model', function() {
716-
app.model('foo', {
717-
dataSource: 'db',
718-
});
719-
720-
var Foo = app.models.foo;
721-
var f = new Foo();
722-
723-
assert(f instanceof app.registry.getModel('Model'));
705+
it('does not require dataSource', function(done) {
706+
app.model(MyTestModel);
707+
done();
724708
});
725709

726-
it('interprets extra first-level keys as options', function() {
727-
app.model('foo', {
728-
dataSource: 'db',
729-
base: 'User',
730-
});
731-
732-
expect(app.models.foo.definition.settings.base).to.equal('User');
733-
});
734-
735-
it('prefers config.options.key over config.key', function() {
736-
app.model('foo', {
737-
dataSource: 'db',
738-
base: 'User',
739-
options: {
740-
base: 'Application',
741-
},
742-
});
743-
744-
expect(app.models.foo.definition.settings.base).to.equal('Application');
745-
});
746-
747-
it('honors config.public options', function() {
748-
app.model('foo', {
749-
dataSource: 'db',
750-
public: false,
751-
});
752-
expect(app.models.foo.app).to.equal(app);
753-
expect(app.models.foo.shared).to.equal(false);
754-
});
755-
756-
it('defaults config.public to be true', function() {
757-
app.model('foo', {
758-
dataSource: 'db',
759-
});
760-
expect(app.models.foo.app).to.equal(app);
761-
expect(app.models.foo.shared).to.equal(true);
710+
it('throws error if model typeof string is passed', function() {
711+
var fn = function() { app.model('MyTestModel'); };
712+
expect(fn).to.throw(/app(\.model|\.registry)/);
762713
});
763714
});
764715

@@ -772,15 +723,17 @@ describe('app', function() {
772723
}
773724

774725
assert(!previousModel || !previousModel.dataSource);
775-
app.model('TestModel', { dataSource: 'db' });
726+
var TestModel = app.registry.createModel('TestModel');
727+
app.model(TestModel, { dataSource: 'db' });
776728
expect(app.models.TestModel.dataSource).to.equal(app.dataSources.db);
777729
});
778730
});
779731

780732
describe('app.models', function() {
781733
it('is unique per app instance', function() {
782734
app.dataSource('db', { connector: 'memory' });
783-
var Color = app.model('Color', { dataSource: 'db' });
735+
var Color = app.registry.createModel('Color');
736+
app.model(Color, { dataSource: 'db' });
784737
expect(app.models.Color).to.equal(Color);
785738
var anotherApp = loopback();
786739
expect(anotherApp.models.Color).to.equal(undefined);

test/change-stream.test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ describe('PersistedModel.createChangeStream()', function() {
99
var test = this;
1010
var app = loopback({ localRegistry: true });
1111
var ds = app.dataSource('ds', { connector: 'memory' });
12-
this.Score = app.model('Score', {
12+
var Score = app.registry.createModel('Score');
13+
this.Score = app.model(Score, {
1314
dataSource: 'ds',
1415
changeDataSource: false, // use only local observers
1516
});

test/integration.test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ describe('loopback application', function() {
4040
loopback.ACL.attachTo(db);
4141
loopback.User.hasMany(loopback.AccessToken, { as: 'accessTokens' });
4242

43-
var Streamer = app.model('Streamer', { dataSource: 'db' });
43+
var Streamer = app.registry.createModel('Streamer');
44+
app.model(Streamer, { dataSource: 'db' });
4445
Streamer.read = function(req, res, cb) {
4546
var body = new Buffer(0);
4647
req.on('data', function(chunk) {

test/registries.test.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,17 @@ describe('Registry', function() {
2626
var dsFoo = appFoo.dataSource('dsFoo', { connector: 'memory' });
2727
var dsBar = appFoo.dataSource('dsBar', { connector: 'memory' });
2828

29-
var FooModel = appFoo.model(modelName, settings);
30-
var FooSubModel = appFoo.model(subModelName, settings);
31-
var BarModel = appBar.model(modelName, settings);
32-
var BarSubModel = appBar.model(subModelName, settings);
29+
var FooModel = appFoo.registry.createModel(modelName, {}, settings);
30+
appFoo.model(FooModel, { dataSource: dsFoo });
3331

34-
FooModel.attachTo(dsFoo);
35-
FooSubModel.attachTo(dsFoo);
36-
BarModel.attachTo(dsBar);
37-
BarSubModel.attachTo(dsBar);
32+
var FooSubModel = appFoo.registry.createModel(subModelName, {}, settings);
33+
appFoo.model(FooSubModel, { dataSource: dsFoo });
34+
35+
var BarModel = appBar.registry.createModel(modelName, {}, settings);
36+
appBar.model(BarModel, { dataSource: dsBar });
37+
38+
var BarSubModel = appBar.registry.createModel(subModelName, {}, settings);
39+
appBar.model(BarSubModel, { dataSource: dsBar });
3840

3941
FooModel.hasMany(FooSubModel);
4042
BarModel.hasMany(BarSubModel);

0 commit comments

Comments
 (0)