Support datasource/connector configuration using URL string
This commit is contained in:
parent
f164ed6919
commit
f3011216b5
|
@ -4,6 +4,7 @@
|
||||||
var ModelBuilder = require('./model-builder.js').ModelBuilder;
|
var ModelBuilder = require('./model-builder.js').ModelBuilder;
|
||||||
var ModelDefinition = require('./model-definition.js');
|
var ModelDefinition = require('./model-definition.js');
|
||||||
var jutil = require('./jutil');
|
var jutil = require('./jutil');
|
||||||
|
var utils = require('./utils');
|
||||||
var ModelBaseClass = require('./model.js');
|
var ModelBaseClass = require('./model.js');
|
||||||
var DataAccessObject = require('./dao.js');
|
var DataAccessObject = require('./dao.js');
|
||||||
var List = require('./list.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
|
* All classes in single dataSource shares same connector type and
|
||||||
* one database connection
|
* 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
|
* @param {Object} settings - any database-specific settings which we need to
|
||||||
* establish connection (of course it depends on specific connector)
|
* establish connection (of course it depends on specific connector)
|
||||||
*
|
*
|
||||||
|
@ -55,7 +56,24 @@ function DataSource(name, settings) {
|
||||||
if (!(this instanceof DataSource)) {
|
if (!(this instanceof DataSource)) {
|
||||||
return new DataSource(name, settings);
|
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
|
// operation metadata
|
||||||
// Initialize it before calling setup as the connector might register operations
|
// 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
|
// DataAccessObject - connector defined or supply the default
|
||||||
this.DataAccessObject = (connector && connector.DataAccessObject) ? connector.DataAccessObject : this.constructor.DataAccessObject;
|
this.DataAccessObject = (connector && connector.DataAccessObject) ? connector.DataAccessObject : this.constructor.DataAccessObject;
|
||||||
this.DataAccessObject.call(this, arguments);
|
this.DataAccessObject.apply(this, arguments);
|
||||||
|
|
||||||
|
|
||||||
// define DataAccessObject methods
|
// define DataAccessObject methods
|
||||||
|
@ -176,7 +194,6 @@ DataSource.prototype.setup = function(name, settings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// just save everything we get
|
// just save everything we get
|
||||||
this.name = name;
|
|
||||||
this.settings = settings || {};
|
this.settings = settings || {};
|
||||||
|
|
||||||
// Check the debug env settings
|
// Check the debug env settings
|
||||||
|
@ -190,14 +207,16 @@ DataSource.prototype.setup = function(name, settings) {
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
this.connecting = false;
|
this.connecting = false;
|
||||||
|
|
||||||
|
if(typeof connector === 'string') {
|
||||||
|
name = connector;
|
||||||
|
connector = undefined;
|
||||||
|
}
|
||||||
|
name = name || (connector && connector.name);
|
||||||
|
this.name = name;
|
||||||
|
|
||||||
if (name && !connector) {
|
if (name && !connector) {
|
||||||
// and initialize dataSource using connector
|
// The connector has not been resolved
|
||||||
// this is only one initialization entry point of connector
|
if (name.match(/^\//)) {
|
||||||
// this module should define `connector` member of `this` (dataSource)
|
|
||||||
if (typeof name === 'object') {
|
|
||||||
connector = name;
|
|
||||||
this.name = connector.name;
|
|
||||||
} else if (name.match(/^\//)) {
|
|
||||||
// try absolute path
|
// try absolute path
|
||||||
connector = require(name);
|
connector = require(name);
|
||||||
} else if (existsSync(__dirname + '/connectors/' + name + '.js')) {
|
} 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) {
|
if (connector) {
|
||||||
var postInit = function postInit(err, result) {
|
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.fieldsToArray = fieldsToArray;
|
||||||
exports.selectFields = selectFields;
|
exports.selectFields = selectFields;
|
||||||
exports.removeUndefined = removeUndefined;
|
exports.removeUndefined = removeUndefined;
|
||||||
|
exports.parseSettings = parseSettings;
|
||||||
|
|
||||||
var traverse = require('traverse');
|
var traverse = require('traverse');
|
||||||
|
|
||||||
|
@ -87,3 +88,33 @@ function removeUndefined(query) {
|
||||||
return x;
|
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",
|
"name": "loopback-datasource-juggler",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "LoopBack DataSoure Juggler",
|
"description": "LoopBack DataSoure Juggler",
|
||||||
"keywords": [ "StrongLoop", "LoopBack", "DataSource", "Juggler", "ORM" ],
|
"keywords": [
|
||||||
|
"StrongLoop",
|
||||||
|
"LoopBack",
|
||||||
|
"DataSource",
|
||||||
|
"Juggler",
|
||||||
|
"ORM"
|
||||||
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/strongloop/loopback-datasource-juggler"
|
"url": "https://github.com/strongloop/loopback-datasource-juggler"
|
||||||
|
@ -26,7 +32,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "~0.2.9",
|
"async": "~0.2.9",
|
||||||
"inflection": "~1.2.6",
|
"inflection": "~1.2.6",
|
||||||
"traverse": "~0.6.5"
|
"traverse": "~0.6.5",
|
||||||
|
"qs": "~0.6.5"
|
||||||
},
|
},
|
||||||
"license": "MIT"
|
"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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -48,3 +48,66 @@ describe('util.removeUndefined', function(){
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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