app: implement `connector()` and `connectors`

Allow browserified applications to explicitly register connectors
to use in data-sources via `app.connector(name, exportsFromRequire)`.

Include built-in connectors like `Memory` and `Remote` in the registry.

Modify `dataSourcesFromConfig()` to resolve the connector via
`app.connectors` first and only then fall back to auto-require
the connector module.
This commit is contained in:
Miroslav Bajtoš 2014-05-28 15:02:55 +02:00
parent 7508337d56
commit 94ec5c294a
3 changed files with 83 additions and 5 deletions

View File

@ -196,9 +196,30 @@ app.models = function () {
app.dataSource = function (name, config) { app.dataSource = function (name, config) {
this.dataSources[name] = this.dataSources[name] =
this.dataSources[classify(name)] = this.dataSources[classify(name)] =
this.dataSources[camelize(name)] = dataSourcesFromConfig(config); this.dataSources[camelize(name)] =
dataSourcesFromConfig(config, this.connectors);
} }
/**
* Register a connector.
*
* When a new data-source is being added via `app.dataSource`, the connector
* name is looked up in the registered connectors first.
*
* Connectors are required to be explicitly registered only for applications
* using browserify, because browserify does not support dynamic require,
* which is used by LoopBack to automatically load the connector module.
*
* @param {String} name Name of the connector, e.g. 'mysql'.
* @param {Object} connector Connector object as returned
* by `require('loopback-connector-{name}')`.
*/
app.connector = function(name, connector) {
this.connectors[name] =
this.connectors[classify(name)] =
this.connectors[camelize(name)] = connector;
};
/** /**
* Get all remote objects. * Get all remote objects.
* @returns {Object} [Remote objects](http://apidocs.strongloop.com/strong-remoting/#remoteobjectsoptions). * @returns {Object} [Remote objects](http://apidocs.strongloop.com/strong-remoting/#remoteobjectsoptions).
@ -523,17 +544,22 @@ function camelize(str) {
return stringUtils.camelize(str); return stringUtils.camelize(str);
} }
function dataSourcesFromConfig(config) { function dataSourcesFromConfig(config, connectorRegistry) {
var connectorPath; var connectorPath;
assert(typeof config === 'object', assert(typeof config === 'object',
'cannont create data source without config object'); 'cannont create data source without config object');
if(typeof config.connector === 'string') { if(typeof config.connector === 'string') {
connectorPath = path.join(__dirname, 'connectors', config.connector+'.js'); var name = config.connector;
if (connectorRegistry[name]) {
config.connector = connectorRegistry[name];
} else {
connectorPath = path.join(__dirname, 'connectors', name + '.js');
if(fs.existsSync(connectorPath)) { if (fs.existsSync(connectorPath)) {
config.connector = require(connectorPath); config.connector = require(connectorPath);
}
} }
} }

View File

@ -79,6 +79,15 @@ function createApplication() {
// Create a new instance of datasources registry per each app instance // Create a new instance of datasources registry per each app instance
app.datasources = app.dataSources = {}; app.datasources = app.dataSources = {};
// Create a new instance of connector registry per each app instance
app.connectors = {};
// Register built-in connectors. It's important to keep this code
// hand-written, so that all require() calls are static
// and thus browserify can process them (include connectors in the bundle)
app.connector('memory', loopback.Memory);
app.connector('remote', loopback.Remote);
return app; return app;
} }

View File

@ -128,6 +128,14 @@ describe('app', function() {
}); });
}); });
describe('app.dataSource', function() {
it('looks up the connector in `app.connectors`', function() {
app.connector('custom', loopback.Memory);
app.dataSource('custom', { connector: 'custom' });
expect(app.dataSources.custom.name).to.equal(loopback.Memory.name);
});
});
describe('app.boot([options])', function () { describe('app.boot([options])', function () {
beforeEach(function () { beforeEach(function () {
app.boot({ app.boot({
@ -502,4 +510,39 @@ describe('app', function() {
}); });
}); });
}); });
describe('app.connectors', function() {
it('is unique per app instance', function() {
app.connectors.foo = 'bar';
var anotherApp = loopback();
expect(anotherApp.connectors.foo).to.equal(undefined);
});
it('includes Remote connector', function() {
expect(app.connectors.remote).to.equal(loopback.Remote);
});
it('includes Memory connector', function() {
expect(app.connectors.memory).to.equal(loopback.Memory);
});
});
describe('app.connector', function() {
// any connector will do
it('adds the connector to the registry', function() {
app.connector('foo-bar', loopback.Memory);
expect(app.connectors['foo-bar']).to.equal(loopback.Memory);
});
it('adds a classified alias', function() {
app.connector('foo-bar', loopback.Memory);
expect(app.connectors.FooBar).to.equal(loopback.Memory);
});
it('adds a camelized alias', function() {
app.connector('FOO-BAR', loopback.Memory);
console.log(app.connectors);
expect(app.connectors.FOOBAR).to.equal(loopback.Memory);
});
});
}); });