From af125c50cc0e474604d747b718d2282941471ed5 Mon Sep 17 00:00:00 2001 From: "maxim.sharai" Date: Sun, 7 Jan 2018 23:34:59 +0300 Subject: [PATCH] Fix duplicate definition of a remote model type Before this commit, when a remote model had relations, the model was registered an additional time per each relation. As a result, the following warnings were printed to the console Warning: overriding remoting type $MODEL_NAME This commit fixes registration of models with strong-remoting to avoid those warnings. --- lib/remote-connector.js | 12 ++++-- package.json | 1 + test/models-define-type.test.js | 74 +++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 test/models-define-type.test.js diff --git a/lib/remote-connector.js b/lib/remote-connector.js index d33c2f8..d96134d 100644 --- a/lib/remote-connector.js +++ b/lib/remote-connector.js @@ -62,8 +62,8 @@ RemoteConnector.initialize = function(dataSource, callback) { }; RemoteConnector.prototype.define = function(definition) { - var Model = definition.model; - var remotes = this.remotes; + const Model = definition.model; + const remotes = this.remotes; assert(Model.sharedClass, 'cannot attach ' + @@ -73,17 +73,23 @@ RemoteConnector.prototype.define = function(definition) { jutil.mixin(Model, RelationMixin); jutil.mixin(Model, InclusionMixin); remotes.addClass(Model.sharedClass); + this.resolve(Model); + this.setupRemotingTypeFor(Model); }; RemoteConnector.prototype.resolve = function(Model) { - var remotes = this.remotes; + const remotes = this.remotes; Model.sharedClass.methods().forEach(function(remoteMethod) { if (remoteMethod.name !== 'Change' && remoteMethod.name !== 'Checkpoint') { createProxyMethod(Model, remotes, remoteMethod); } }); +}; + +RemoteConnector.prototype.setupRemotingTypeFor = function(Model) { + const remotes = this.remotes; // setup a remoting type converter for this model remotes.defineObjectType(Model.modelName, function(data) { diff --git a/package.json b/package.json index d11a83c..44c7dc5 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "grunt-mocha-test": "^0.12.7", "loopback": "^3.0.0", "mocha": "^3.0.2", + "sinon": "^4.1.3", "strong-task-emitter": "^0.0.7" }, "optionalDependencies": {} diff --git a/test/models-define-type.test.js b/test/models-define-type.test.js new file mode 100644 index 0000000..c15328e --- /dev/null +++ b/test/models-define-type.test.js @@ -0,0 +1,74 @@ +// Copyright IBM Corp. 2016. All Rights Reserved. +// Node module: loopback-connector-remote +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const helper = require('./helper'); +const loopback = require('loopback'); +const sinon = require('sinon'); + +const relation = require('loopback-datasource-juggler/lib/relation-definition'); +const RelationTypes = relation.RelationTypes; + +describe('Models Define Type Tests', function() { + let serverApp, clientApp, remoteDs, defineObjectTypeSpy, ChildModel; + + beforeEach('create remote datasource', () => { + serverApp = helper.createRestAppAndListen(); + clientApp = loopback({localRegistry: true}); + remoteDs = helper.createRemoteDataSource(clientApp, serverApp); + }); + + beforeEach('spy remote connector', () => { + defineObjectTypeSpy = sinon.spy(remoteDs.connector.remotes, + 'defineObjectType'); + }); + + afterEach('restore remote connector', () => { + defineObjectTypeSpy.restore(); + }); + + it('should define a type of a remote model only once (no relations)', () => { + const RemoteModel = clientApp.registry.createModel({ + name: 'RemoteModel', + }); + clientApp.model(RemoteModel, {dataSource: remoteDs}); + + sinon.assert.calledOnce(defineObjectTypeSpy.withArgs( + RemoteModel.modelName)); + }); + + describe('when a child model is created', () => { + beforeEach('create a child model', () => { + ChildModel = clientApp.registry.createModel({ + name: 'ChildModel', + }); + clientApp.model(ChildModel, {dataSource: remoteDs}); + }); + + Object.getOwnPropertyNames(RelationTypes).forEach((relationKey) => { + const relation = RelationTypes[relationKey]; + + it('should define a type of a remote model only once (' + relation + ')', + () => { + const RemoteModel = clientApp.registry.createModel({ + name: 'RemoteModel' + relation, + relations: { + children: { + type: relation, + model: 'ChildModel', + }, + }, + }); + clientApp.model(RemoteModel, {dataSource: remoteDs}); + + sinon.assert.calledOnce(defineObjectTypeSpy.withArgs( + RemoteModel.modelName)); + sinon.assert.calledOnce(defineObjectTypeSpy.withArgs( + ChildModel.modelName)); + }); + }); + }); +});