loopback-datasource-juggler/lib/utils.js

244 lines
5.9 KiB
JavaScript
Raw Normal View History

2012-01-30 19:37:14 +00:00
exports.safeRequire = safeRequire;
exports.fieldsToArray = fieldsToArray;
exports.selectFields = selectFields;
exports.removeUndefined = removeUndefined;
exports.parseSettings = parseSettings;
2013-12-06 23:52:39 +00:00
exports.mergeSettings = mergeSettings;
exports.isPlainObject = isPlainObject;
exports.defineCachedRelations = defineCachedRelations;
exports.sortObjectsByIds = sortObjectsByIds;
var traverse = require('traverse');
2012-01-30 19:37:14 +00:00
function safeRequire(module) {
2014-01-24 17:09:53 +00:00
try {
return require(module);
} catch (e) {
console.log('Run "npm install loopback-datasource-juggler ' + module
+ '" command to use loopback-datasource-juggler using ' + module
+ ' database engine');
process.exit(1);
}
2012-01-30 19:37:14 +00:00
}
function fieldsToArray(fields, properties) {
2014-01-24 17:09:53 +00:00
if (!fields) return;
// include all properties by default
var result = properties;
if (typeof fields === 'string') {
return [fields];
}
if (Array.isArray(fields) && fields.length > 0) {
// No empty array, including all the fields
return fields;
}
if ('object' === typeof fields) {
// { field1: boolean, field2: boolean ... }
var included = [];
var excluded = [];
var keys = Object.keys(fields);
if (!keys.length) return;
keys.forEach(function (k) {
if (fields[k]) {
included.push(k);
} else if ((k in fields) && !fields[k]) {
excluded.push(k);
}
});
if (included.length > 0) {
result = included;
} else if (excluded.length > 0) {
excluded.forEach(function (e) {
var index = result.indexOf(e);
result.splice(index, 1);
});
}
2014-01-24 17:09:53 +00:00
}
return result;
}
function selectFields(fields) {
// map function
return function (obj) {
var result = {};
var key;
2014-01-24 17:09:53 +00:00
for (var i = 0; i < fields.length; i++) {
key = fields[i];
2014-01-24 17:09:53 +00:00
result[key] = obj[key];
}
return result;
};
}
/**
* Remove undefined values from the queury object
* @param query
* @returns {exports.map|*}
*/
function removeUndefined(query) {
2014-01-24 17:09:53 +00:00
if (typeof query !== 'object' || query === null) {
return query;
}
// WARNING: [rfeng] Use map() will cause mongodb to produce invalid BSON
// as traverse doesn't transform the ObjectId correctly
return traverse(query).forEach(function (x) {
if (x === undefined) {
this.remove();
}
2014-01-24 17:09:53 +00:00
if (!Array.isArray(x) && (typeof x === 'object' && x !== null
&& x.constructor !== Object)) {
// This object is not a plain object
this.update(x, true); // Stop navigating into this object
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) {
2014-01-24 17:09:53 +00:00
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];
}
2014-01-24 17:09:53 +00:00
}
return settings;
}
2013-12-06 23:52:39 +00:00
/**
* Merge model settings
*
* Folked from https://github.com/nrf110/deepmerge/blob/master/index.js
*
* The original function tries to merge array items if they are objects
*
* @param {Object} target The target settings object
* @param {Object} src The source settings object
* @returns {Object} The merged settings object
*/
function mergeSettings(target, src) {
var array = Array.isArray(src);
var dst = array && [] || {};
if (array) {
target = target || [];
dst = dst.concat(target);
2013-12-17 01:14:56 +00:00
src.forEach(function (e) {
if (dst.indexOf(e) === -1) {
dst.push(e);
2013-12-06 23:52:39 +00:00
}
});
} else {
if (target && typeof target === 'object') {
Object.keys(target).forEach(function (key) {
dst[key] = target[key];
});
}
Object.keys(src).forEach(function (key) {
if (typeof src[key] !== 'object' || !src[key]) {
dst[key] = src[key];
}
else {
if (!target[key]) {
dst[key] = src[key]
} else {
2013-12-17 01:14:56 +00:00
dst[key] = mergeSettings(target[key], src[key]);
2013-12-06 23:52:39 +00:00
}
}
});
}
return dst;
}
/**
* Define an non-enumerable __cachedRelations property
* @param {Object} obj The obj to receive the __cachedRelations
*/
function defineCachedRelations(obj) {
if (!obj.__cachedRelations) {
Object.defineProperty(obj, '__cachedRelations', {
writable: true,
enumerable: false,
configurable: true,
value: {}
});
}
}
/**
* Check if the argument is plain object
* @param {*) obj The obj value
* @returns {boolean}
*/
function isPlainObject(obj) {
return (typeof obj === 'object') && (obj !== null)
&& (obj.constructor === Object);
}
function sortObjectsByIds(idName, ids, objects, strict) {
ids = ids.map(function(id) {
return (typeof id === 'object') ? String(id) : id;
});
var indexOf = function(x) {
var isObj = (typeof x[idName] === 'object'); // ObjectID
var id = isObj ? String(x[idName]) : x[idName];
return ids.indexOf(id);
};
var heading = [];
var tailing = [];
objects.forEach(function(x) {
if (typeof x === 'object') {
var idx = indexOf(x);
if (strict && idx === -1) return;
idx === -1 ? tailing.push(x) : heading.push(x);
}
});
heading.sort(function(x, y) {
var a = indexOf(x);
var b = indexOf(y);
if (a === -1 || b === -1) return 1; // last
if (a === b) return 0;
if (a > b) return 1;
if (a < b) return -1;
});
return heading.concat(tailing);
};