exports.safeRequire = safeRequire; exports.fieldsToArray = fieldsToArray; exports.selectFields = selectFields; exports.removeUndefined = removeUndefined; exports.parseSettings = parseSettings; exports.mergeSettings = mergeSettings; var traverse = require('traverse'); function safeRequire(module) { 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); } } function fieldsToArray(fields, properties) { 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); }); } } return result; } function selectFields(fields) { // map function return function (obj) { var result = {}; var key; for (var i = 0; i < fields.length; i++) { key = fields[i]; result[key] = obj[key]; } return result; }; } /** * Remove undefined values from the queury object * @param query * @returns {exports.map|*} */ function removeUndefined(query) { 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(); } 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) { 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]; // : 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; } /** * 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); src.forEach(function (e, i) { if (typeof target[i] === 'undefined') { dst[i] = e; } else { if (target.indexOf(e) === -1) { dst.push(e); } } }); } 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 { dst[key] = mergeSettings(target[key], src[key]) } } }); } return dst; }