waterline-postgresql
Version:
PostgreSQL Adapter for Sails and Waterline
182 lines (145 loc) • 4.18 kB
JavaScript
/**
* Helper functions
*/
var _ = require('lodash');
// Module Exports
var utils = module.exports = {};
/**
* Safe hasOwnProperty
*/
utils.object = {};
/**
* Safer helper for hasOwnProperty checks
*
* @param {Object} obj
* @param {String} prop
* @return {Boolean}
* @api public
*/
var hop = Object.prototype.hasOwnProperty;
utils.object.hasOwnProperty = function(obj, prop) {
return hop.call(obj, prop);
};
/**
* Escape Name
*
* Wraps a name in quotes to allow reserved
* words as table or column names such as user.
*
*
* NOTE: do not use this method to escape strings in a general-purpose way.
* This is intended only to escape schema object (e.g. table and column) names.
* Check out utils.escapeString() for other purposes. No harm in taking a
* peek at https://dev.mysql.com/doc/refman/5.7/en/identifiers.html .
*/
utils.escapeName = function escapeName(name, escapeCharacter, schemaName) {
var regex = new RegExp(escapeCharacter, 'g');
var replacementString = '' + escapeCharacter + escapeCharacter;
var replacementDot = '\.';
if (schemaName && schemaName[name]) {
return utils.escapeName(schemaName[name], escapeCharacter) + '.' +
utils.escapeName(name, escapeCharacter);
}
return '' + escapeCharacter + name.replace(regex, replacementString).replace(/\./g, replacementDot) + escapeCharacter;
};
/**
* Populate alias. Create the alias for an association
*
* @param {string} alias
*
* @returns {string}
*/
utils.populationAlias = function (alias) {
return '__' + alias;
};
/**
* Map Attributes
*
* Takes a js object and creates arrays used for parameterized
* queries in postgres.
*/
utils.mapAttributes = function(data, options) {
var keys = [], // Column Names
values = [], // Column Values
params = [], // Param Index, ex: $1, $2
i = 1;
// Flag whether to use parameterized queries or not
var parameterized = options && utils.object.hasOwnProperty(options, 'parameterized') ? options.parameterized : true;
// Get the escape character
var escapeCharacter = options && utils.object.hasOwnProperty(options, 'escapeCharacter') ? options.escapeCharacter : '"';
// Determine if we should escape the inserted characters
var escapeInserts = options && utils.object.hasOwnProperty(options, 'escapeInserts') ? options.escapeInserts : false;
Object.keys(data).forEach(function(key) {
var k = escapeInserts ? (options.escapeCharacter + key + options.escapeCharacter) : key;
keys.push(k);
var value = utils.prepareValue(data[key]);
values.push(value);
if(parameterized) {
params.push('$' + i);
}
else {
if(value === null || value === undefined) {
params.push('null');
}
else {
params.push(value);
}
}
i++;
});
return({ keys: keys, values: values, params: params });
};
/**
* Prepare values
*
* Transform a JS date to SQL date and functions
* to strings.
*/
utils.prepareValue = function(value) {
// Cast dates to SQL
if (_.isDate(value)) {
value = utils.toSqlDate(value);
}
// Cast functions to strings
if (_.isFunction(value)) {
value = value.toString();
}
// Store Arrays as strings
if (Array.isArray(value)) {
value = JSON.stringify(value);
}
// Store Buffers as hex strings (for BYTEA)
if (Buffer.isBuffer(value)) {
value = '\\x' + value.toString('hex');
}
return value;
};
/**
* Escape Strings
*/
utils.escapeString = function(value, forLike) {
if(!_.isString(value)) return value;
value = value.replace(/[_%\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
switch(s) {
case "\0": return "\\0";
case "\n": return "\\n";
case "\r": return "\\r";
case "\b": return "\\b";
case "\t": return "\\t";
case "\x1a": return "\\Z";
case "%": return forLike ? "\\%" : "%";
case "_": return forLike ? "\\_" : "_";
default: return "\\"+s;
}
});
return value;
};
/**
* JS Date to UTC Timestamp
*
* Dates should be stored in Postgres with UTC timestamps
* and then converted to local time on the client.
*/
utils.toSqlDate = function(date) {
return date.toUTCString();
};