Merge pull request #30 from strongloop/ds-url
Support datasource/connector configuration using URL string
This commit is contained in:
commit
37ced0111e
|
@ -4,6 +4,7 @@
|
|||
var ModelBuilder = require('./model-builder.js').ModelBuilder;
|
||||
var ModelDefinition = require('./model-definition.js');
|
||||
var jutil = require('./jutil');
|
||||
var utils = require('./utils');
|
||||
var ModelBaseClass = require('./model.js');
|
||||
var DataAccessObject = require('./dao.js');
|
||||
var List = require('./list.js');
|
||||
|
@ -31,7 +32,7 @@ var slice = Array.prototype.slice;
|
|||
* All classes in single dataSource shares same connector type and
|
||||
* one database connection
|
||||
*
|
||||
* @param {String} name - type of dataSource connector (mysql, mongoose, sequelize, redis)
|
||||
* @param {String} name - type of dataSource connector (mysql, mongoose, oracle, redis)
|
||||
* @param {Object} settings - any database-specific settings which we need to
|
||||
* establish connection (of course it depends on specific connector)
|
||||
*
|
||||
|
@ -55,7 +56,24 @@ function DataSource(name, settings) {
|
|||
if (!(this instanceof DataSource)) {
|
||||
return new DataSource(name, settings);
|
||||
}
|
||||
ModelBuilder.call(this, arguments);
|
||||
|
||||
// Check if the settings object is passed as the first argument
|
||||
if (typeof name === 'object' && settings === undefined) {
|
||||
settings = name;
|
||||
name = undefined;
|
||||
}
|
||||
|
||||
// Check if the first argument is a URL
|
||||
if(typeof name === 'string' && name.indexOf('://') !== -1 ) {
|
||||
name = utils.parseSettings(name);
|
||||
}
|
||||
|
||||
// Check if the settings is in the form of URL string
|
||||
if(typeof settings === 'string' && settings.indexOf('://') !== -1 ) {
|
||||
settings = utils.parseSettings(settings);
|
||||
}
|
||||
|
||||
ModelBuilder.call(this, name, settings);
|
||||
|
||||
// operation metadata
|
||||
// Initialize it before calling setup as the connector might register operations
|
||||
|
@ -70,7 +88,7 @@ function DataSource(name, settings) {
|
|||
|
||||
// DataAccessObject - connector defined or supply the default
|
||||
this.DataAccessObject = (connector && connector.DataAccessObject) ? connector.DataAccessObject : this.constructor.DataAccessObject;
|
||||
this.DataAccessObject.call(this, arguments);
|
||||
this.DataAccessObject.apply(this, arguments);
|
||||
|
||||
|
||||
// define DataAccessObject methods
|
||||
|
@ -164,7 +182,7 @@ DataSource.prototype.setup = function(name, settings) {
|
|||
settings = name;
|
||||
name = undefined;
|
||||
}
|
||||
|
||||
|
||||
if(typeof settings === 'object') {
|
||||
if(settings.initialize) {
|
||||
connector = settings;
|
||||
|
@ -176,7 +194,6 @@ DataSource.prototype.setup = function(name, settings) {
|
|||
}
|
||||
|
||||
// just save everything we get
|
||||
this.name = name;
|
||||
this.settings = settings || {};
|
||||
|
||||
// Check the debug env settings
|
||||
|
@ -190,14 +207,16 @@ DataSource.prototype.setup = function(name, settings) {
|
|||
this.connected = false;
|
||||
this.connecting = false;
|
||||
|
||||
if(typeof connector === 'string') {
|
||||
name = connector;
|
||||
connector = undefined;
|
||||
}
|
||||
name = name || (connector && connector.name);
|
||||
this.name = name;
|
||||
|
||||
if (name && !connector) {
|
||||
// and initialize dataSource using connector
|
||||
// this is only one initialization entry point of connector
|
||||
// this module should define `connector` member of `this` (dataSource)
|
||||
if (typeof name === 'object') {
|
||||
connector = name;
|
||||
this.name = connector.name;
|
||||
} else if (name.match(/^\//)) {
|
||||
// The connector has not been resolved
|
||||
if (name.match(/^\//)) {
|
||||
// try absolute path
|
||||
connector = require(name);
|
||||
} else if (existsSync(__dirname + '/connectors/' + name + '.js')) {
|
||||
|
@ -216,10 +235,6 @@ DataSource.prototype.setup = function(name, settings) {
|
|||
}
|
||||
}
|
||||
|
||||
if('string' === typeof connector) {
|
||||
connector = require(connector);
|
||||
}
|
||||
|
||||
if (connector) {
|
||||
var postInit = function postInit(err, result) {
|
||||
|
||||
|
|
31
lib/utils.js
31
lib/utils.js
|
@ -2,6 +2,7 @@ exports.safeRequire = safeRequire;
|
|||
exports.fieldsToArray = fieldsToArray;
|
||||
exports.selectFields = selectFields;
|
||||
exports.removeUndefined = removeUndefined;
|
||||
exports.parseSettings = parseSettings;
|
||||
|
||||
var traverse = require('traverse');
|
||||
|
||||
|
@ -87,3 +88,33 @@ function removeUndefined(query) {
|
|||
return x;
|
||||
});
|
||||
}
|
||||
|
||||
var url = require('url');
|
||||
var qs = require('qs');
|
||||
|
||||
/**
|
||||
* Parse a URL into a settings object
|
||||
* @param {String} urlStr The URL for connector settings
|
||||
* @returns {Object} The settings object
|
||||
*/
|
||||
function parseSettings(urlStr) {
|
||||
if(!urlStr) {
|
||||
return {};
|
||||
}
|
||||
var uri = url.parse(urlStr, false);
|
||||
var settings = {};
|
||||
settings.connector = uri.protocol && uri.protocol.split(':')[0]; // Remove the trailing :
|
||||
settings.host = settings.hostname = uri.hostname;
|
||||
settings.port = uri.port && Number(uri.port); // port is a string
|
||||
settings.user = settings.username = uri.auth && uri.auth.split(':')[0]; // <username>:<password>
|
||||
settings.password = uri.auth && uri.auth.split(':')[1];
|
||||
settings.database = uri.pathname && uri.pathname.split('/')[1]; // remove the leading /
|
||||
settings.url = urlStr;
|
||||
if(uri.query) {
|
||||
var params = qs.parse(uri.query);
|
||||
for(var p in params) {
|
||||
settings[p] = params[p];
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
|
11
package.json
11
package.json
|
@ -2,7 +2,13 @@
|
|||
"name": "loopback-datasource-juggler",
|
||||
"version": "1.0.0",
|
||||
"description": "LoopBack DataSoure Juggler",
|
||||
"keywords": [ "StrongLoop", "LoopBack", "DataSource", "Juggler", "ORM" ],
|
||||
"keywords": [
|
||||
"StrongLoop",
|
||||
"LoopBack",
|
||||
"DataSource",
|
||||
"Juggler",
|
||||
"ORM"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/strongloop/loopback-datasource-juggler"
|
||||
|
@ -26,7 +32,8 @@
|
|||
"dependencies": {
|
||||
"async": "~0.2.9",
|
||||
"inflection": "~1.2.6",
|
||||
"traverse": "~0.6.5"
|
||||
"traverse": "~0.6.5",
|
||||
"qs": "~0.6.5"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
|
|
@ -466,3 +466,25 @@ describe('Load models from json', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('DataSource constructor', function(){
|
||||
it('Takes url as the settings', function() {
|
||||
var ds = new DataSource('memory://localhost/mydb?x=1');
|
||||
assert.equal(ds.connector.name, 'memory');
|
||||
});
|
||||
|
||||
it('Takes connector name', function() {
|
||||
var ds = new DataSource('memory');
|
||||
assert.equal(ds.connector.name, 'memory');
|
||||
});
|
||||
|
||||
it('Takes settings object', function() {
|
||||
var ds = new DataSource({connector: 'memory'});
|
||||
assert.equal(ds.connector.name, 'memory');
|
||||
});
|
||||
|
||||
it('Takes settings object and name', function() {
|
||||
var ds = new DataSource('x', {connector: 'memory'});
|
||||
assert.equal(ds.connector.name, 'memory');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -47,4 +47,67 @@ describe('util.removeUndefined', function(){
|
|||
should.equal(removeUndefined('x'), 'x');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('util.parseSettings', function(){
|
||||
it('Parse a full url into a settings object', function() {
|
||||
var url = 'mongodb://x:y@localhost:27017/mydb?w=2';
|
||||
var settings = utils.parseSettings(url);
|
||||
should.equal(settings.hostname, 'localhost');
|
||||
should.equal(settings.port, 27017);
|
||||
should.equal(settings.host, 'localhost');
|
||||
should.equal(settings.user, 'x');
|
||||
should.equal(settings.password, 'y');
|
||||
should.equal(settings.database, 'mydb');
|
||||
should.equal(settings.connector, 'mongodb');
|
||||
should.equal(settings.w, '2');
|
||||
should.equal(settings.url, 'mongodb://x:y@localhost:27017/mydb?w=2');
|
||||
|
||||
});
|
||||
|
||||
it('Parse a url without auth into a settings object', function() {
|
||||
var url = 'mongodb://localhost:27017/mydb/abc?w=2';
|
||||
var settings = utils.parseSettings(url);
|
||||
should.equal(settings.hostname, 'localhost');
|
||||
should.equal(settings.port, 27017);
|
||||
should.equal(settings.host, 'localhost');
|
||||
should.equal(settings.user, undefined);
|
||||
should.equal(settings.password, undefined);
|
||||
should.equal(settings.database, 'mydb');
|
||||
should.equal(settings.connector, 'mongodb');
|
||||
should.equal(settings.w, '2');
|
||||
should.equal(settings.url, 'mongodb://localhost:27017/mydb/abc?w=2');
|
||||
|
||||
});
|
||||
|
||||
it('Parse a url with complex query into a settings object', function() {
|
||||
var url = 'mysql://127.0.0.1:3306/mydb?x[a]=1&x[b]=2&engine=InnoDB';
|
||||
var settings = utils.parseSettings(url);
|
||||
should.equal(settings.hostname, '127.0.0.1');
|
||||
should.equal(settings.port, 3306);
|
||||
should.equal(settings.host, '127.0.0.1');
|
||||
should.equal(settings.user, undefined);
|
||||
should.equal(settings.password, undefined);
|
||||
should.equal(settings.database, 'mydb');
|
||||
should.equal(settings.connector, 'mysql');
|
||||
should.equal(settings.x.a, '1');
|
||||
should.equal(settings.x.b, '2');
|
||||
should.equal(settings.engine, 'InnoDB');
|
||||
should.equal(settings.url, 'mysql://127.0.0.1:3306/mydb?x[a]=1&x[b]=2&engine=InnoDB');
|
||||
|
||||
});
|
||||
|
||||
it('Parse a url without auth into a settings object', function() {
|
||||
var url = 'memory://?x=1';
|
||||
var settings = utils.parseSettings(url);
|
||||
should.equal(settings.hostname, '');
|
||||
should.equal(settings.user, undefined);
|
||||
should.equal(settings.password, undefined);
|
||||
should.equal(settings.database, undefined);
|
||||
should.equal(settings.connector, 'memory');
|
||||
should.equal(settings.x, '1');
|
||||
should.equal(settings.url, 'memory://?x=1');
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue