Skip to content

Commit

Permalink
Define remote methods via model settings/config
Browse files Browse the repository at this point in the history
Process `settings.methods` and `config.methods` as a key-value map
where the key is the method name and the value is an object describing
the method in the format expected by strong-remoting.

Example: a static method `Model.create`

    "methods": {
      "create": {
        "isStatic": true,
        "accepts": {
           "arg": "data", "type": "Car",
           "http": { "source": "body" }
        },
        "returns": { "arg": "data", "type": "Car", "root": true }
      }
    }

This patch is based on the code proposed by @mrfelton in strongloop#1163.
  • Loading branch information
Miroslav Bajtoš committed May 7, 2015
1 parent ce26141 commit f93b69e
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ app.model = function(Model, config) {
Model = registry.createModel(modelConfig);

// delete config options already applied
['relations', 'base', 'acls', 'hidden'].forEach(function(prop) {
['relations', 'base', 'acls', 'hidden', 'methods'].forEach(function(prop) {
delete config[prop];
if (config.options) delete config.options[prop];
});
Expand Down
26 changes: 26 additions & 0 deletions lib/registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ Registry.prototype.createModel = function(name, properties, options) {
var model = BaseModel.extend(name, properties, options);
model.registry = this;

this._defineRemoteMethods(model, options.methods);

// try to attach
try {
this.autoAttachModel(model);
Expand Down Expand Up @@ -247,6 +249,30 @@ Registry.prototype.configureModel = function(ModelCtor, config) {
'Use `null` or `false` to mark models not attached to any data source.',
modelName);
}

// Remote methods
this._defineRemoteMethods(ModelCtor, config.methods);
};

Registry.prototype._defineRemoteMethods = function(ModelCtor, methods) {
if (!methods) return;
if (typeof methods !== 'object') {
console.warn('Ignoring non-object "methods" setting of "%s".',
ModelCtor.modelName);
return;
}

Object.keys(methods).forEach(function(key) {
var meta = methods[key];
if (typeof meta.isStatic !== 'boolean') {
console.warn('Remoting metadata for "%s.%s" is missing "isStatic" ' +
'flag, the method is registered as an instance method.',
ModelCtor.modelName,
key);
console.warn('This behaviour may change in the next major version.');
}
ModelCtor.remoteMethod(key, meta);
});
};

/**
Expand Down
50 changes: 50 additions & 0 deletions test/loopback.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,30 @@ describe('loopback', function() {
.to.throw(Error, new RegExp('Model not found: ' + uniqueModelName));
});
});

it('configures remote methods', function() {
var TestModel = loopback.createModel(uniqueModelName, {}, {
methods: {
staticMethod: {
isStatic: true,
http: { path: '/static' }
},
instanceMethod: {
isStatic: false,
http: { path: '/instance' }
}
}
});

var methodNames = TestModel.sharedClass.methods().map(function(m) {
return m.stringName.replace(/^[^.]+\./, ''); // drop the class name
});

expect(methodNames).to.include.members([
'staticMethod',
'prototype.instanceMethod'
]);
});
});

describe('loopback.createModel(config)', function() {
Expand Down Expand Up @@ -449,6 +473,32 @@ describe('loopback', function() {
// configureModel MUST NOT change Model's base class
expect(model.settings.base.name).to.equal(baseName);
});

it('configures remote methods', function() {
var TestModel = loopback.createModel(uniqueModelName);
loopback.configureModel(TestModel, {
dataSource: null,
methods: {
staticMethod: {
isStatic: true,
http: { path: '/static' }
},
instanceMethod: {
isStatic: false,
http: { path: '/instance' }
}
}
});

var methodNames = TestModel.sharedClass.methods().map(function(m) {
return m.stringName.replace(/^[^.]+\./, ''); // drop the class name
});

expect(methodNames).to.include.members([
'staticMethod',
'prototype.instanceMethod'
]);
});
});

describe('loopback object', function() {
Expand Down

0 comments on commit f93b69e

Please sign in to comment.