safe-squel
Version:
(safe version) SQL query string builder
1,560 lines (1,269 loc) • 127 kB
JavaScript
;(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.squel = factory();
}
}(this, function() {
'use strict';
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var escape = require('sql-escape-string');
// append to string if non-empty
function _pad(str, pad) {
return str.length ? str + pad : str;
}
// Extend given object's with other objects' properties, overriding existing ones if necessary
function _extend(dst) {
for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
sources[_key - 1] = arguments[_key];
}
if (dst && sources) {
var _loop = function _loop(src) {
if ((typeof src === 'undefined' ? 'undefined' : _typeof(src)) === 'object') {
Object.getOwnPropertyNames(src).forEach(function (key) {
dst[key] = src[key];
});
}
};
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = sources[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var src = _step.value;
_loop(src);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
return dst;
};
// get whether object is a plain object
function _isPlainObject(obj) {
return obj && obj.constructor.prototype === Object.prototype;
};
// get whether object is an array
function _isArray(obj) {
return obj && obj.constructor.prototype === Array.prototype;
};
// clone given item
function _clone(src) {
if (!src) {
return src;
}
if (typeof src.clone === 'function') {
return src.clone();
} else if (_isPlainObject(src) || _isArray(src)) {
var ret = new src.constructor();
Object.getOwnPropertyNames(src).forEach(function (key) {
if (typeof src[key] !== 'function') {
ret[key] = _clone(src[key]);
}
});
return ret;
} else {
return JSON.parse(JSON.stringify(src));
}
};
/**
* Register a value type handler
*
* Note: this will override any existing handler registered for this value type.
*/
function _registerValueHandler(handlers, type, handler) {
var typeofType = typeof type === 'undefined' ? 'undefined' : _typeof(type);
if (typeofType !== 'function' && typeofType !== 'string') {
throw new Error("type must be a class constructor or string");
}
if (typeof handler !== 'function') {
throw new Error("handler must be a function");
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = handlers[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var typeHandler = _step2.value;
if (typeHandler.type === type) {
typeHandler.handler = handler;
return;
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
handlers.push({
type: type,
handler: handler
});
};
/**
* Get value type handler for given type
*/
function getValueHandler(value, localHandlers, globalHandlers) {
return _getValueHandler(value, localHandlers) || _getValueHandler(value, globalHandlers);
};
function _getValueHandler(value, handlers) {
for (var i = 0; i < handlers.length; i++) {
var typeHandler = handlers[i];
// if type is a string then use `typeof` or else use `instanceof`
if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === typeHandler.type || typeof typeHandler.type !== 'string' && value instanceof typeHandler.type) {
return typeHandler.handler;
}
}
};
/**
* Build base squel classes and methods
*/
function _buildSquel() {
var flavour = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var cls = {
// Get whether obj is a query builder
isSquelBuilder: function isSquelBuilder(obj) {
return obj && !!obj._toParamString;
}
};
// Get whether nesting should be applied for given item
var _shouldApplyNesting = function _shouldApplyNesting(obj) {
return !cls.isSquelBuilder(obj) || !obj.options.rawNesting;
};
// default query builder options
cls.DefaultQueryBuilderOptions = {
// If true then table names will be rendered inside quotes. The quote character used is configurable via the nameQuoteCharacter option.
autoQuoteTableNames: false,
// If true then field names will rendered inside quotes. The quote character used is configurable via the nameQuoteCharacter option.
autoQuoteFieldNames: false,
// If true then alias names will rendered inside quotes. The quote character used is configurable via the `tableAliasQuoteCharacter` and `fieldAliasQuoteCharacter` options.
autoQuoteAliasNames: true,
// If true then table alias names will rendered after AS keyword.
useAsForTableAliasNames: false,
// The quote character used for when quoting table and field names
nameQuoteCharacter: '`',
// The quote character used for when quoting table alias names
tableAliasQuoteCharacter: '`',
// The quote character used for when quoting table alias names
fieldAliasQuoteCharacter: '"',
// Custom value handlers where key is the value type and the value is the handler function
valueHandlers: [],
// Character used to represent a parameter value
parameterCharacter: '?',
// Numbered parameters returned from toParam() as $1, $2, etc.
numberedParameters: false,
// Numbered parameters prefix character(s)
numberedParametersPrefix: '$',
// Numbered parameters start at this number.
numberedParametersStartAt: 1,
// If true then replaces all single quotes within strings. The replacement string used is configurable via the `singleQuoteReplacement` option.
replaceSingleQuotes: false,
// The string to replace single quotes with in query strings
singleQuoteReplacement: '\'\'',
// String used to join individual blocks in a query when it's stringified
separator: ' ',
// Function for formatting string values prior to insertion into query string
stringFormatter: null,
// Whether to prevent the addition of brackets () when nesting this query builder's output
rawNesting: false
};
// Global custom value handlers for all instances of builder
cls.globalValueHandlers = [];
/*
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
# Custom value types
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
*/
// Register a new value handler
cls.registerValueHandler = function (type, handler) {
_registerValueHandler(cls.globalValueHandlers, type, handler);
};
/*
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
# Base classes
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
*/
// Base class for cloneable builders
cls.Cloneable = function () {
function _class() {
_classCallCheck(this, _class);
}
_createClass(_class, [{
key: 'clone',
/**
* Clone this builder
*/
value: function clone() {
var newInstance = new this.constructor();
return _extend(newInstance, _clone(_extend({}, this)));
}
}]);
return _class;
}();
// Base class for all builders
cls.BaseBuilder = function (_cls$Cloneable) {
_inherits(_class2, _cls$Cloneable);
/**
* Constructor.
* this.param {Object} options Overriding one or more of `cls.DefaultQueryBuilderOptions`.
*/
function _class2(options) {
_classCallCheck(this, _class2);
var _this = _possibleConstructorReturn(this, (_class2.__proto__ || Object.getPrototypeOf(_class2)).call(this));
var defaults = JSON.parse(JSON.stringify(cls.DefaultQueryBuilderOptions));
// for function values, etc we need to manually copy
['stringFormatter'].forEach(function (p) {
defaults[p] = cls.DefaultQueryBuilderOptions[p];
});
_this.options = _extend({}, defaults, options);
return _this;
}
/**
* Register a custom value handler for this builder instance.
*
* Note: this will override any globally registered handler for this value type.
*/
_createClass(_class2, [{
key: 'registerValueHandler',
value: function registerValueHandler(type, handler) {
_registerValueHandler(this.options.valueHandlers, type, handler);
return this;
}
/**
* Sanitize given expression.
*/
}, {
key: '_sanitizeExpression',
value: function _sanitizeExpression(expr) {
// If it's not a base builder instance
if (!cls.isSquelBuilder(expr)) {
// It must then be a string
if (typeof expr !== "string") {
throw new Error("expression must be a string or builder instance");
}
}
return expr;
}
/**
* Sanitize the given name.
*
* The 'type' parameter is used to construct a meaningful error message in case validation fails.
*/
}, {
key: '_sanitizeName',
value: function _sanitizeName(value, type) {
if (typeof value !== "string") {
throw new Error(type + ' must be a string');
}
return value;
}
}, {
key: '_sanitizeField',
value: function _sanitizeField(item) {
if (!cls.isSquelBuilder(item)) {
item = this._sanitizeName(item, "field name");
}
return item;
}
}, {
key: '_sanitizeBaseBuilder',
value: function _sanitizeBaseBuilder(item) {
if (cls.isSquelBuilder(item)) {
return item;
}
throw new Error("must be a builder instance");
}
}, {
key: '_sanitizeTable',
value: function _sanitizeTable(item) {
if (typeof item !== "string") {
try {
item = this._sanitizeBaseBuilder(item);
} catch (e) {
throw new Error("table name must be a string or a builder");
}
} else {
item = this._sanitizeName(item, 'table');
}
return item;
}
}, {
key: '_sanitizeTableAlias',
value: function _sanitizeTableAlias(item) {
return this._sanitizeName(item, "table alias");
}
}, {
key: '_sanitizeFieldAlias',
value: function _sanitizeFieldAlias(item) {
return this._sanitizeName(item, "field alias");
}
// Sanitize the given limit/offset value.
}, {
key: '_sanitizeLimitOffset',
value: function _sanitizeLimitOffset(value) {
value = parseInt(value);
if (0 > value || isNaN(value)) {
throw new Error("limit/offset must be >= 0");
}
return value;
}
// Santize the given field value
}, {
key: '_sanitizeValue',
value: function _sanitizeValue(item) {
var itemType = typeof item === 'undefined' ? 'undefined' : _typeof(item);
if (null === item) {
// null is allowed
} else if ("string" === itemType || "number" === itemType || "boolean" === itemType) {
// primitives are allowed
} else if (cls.isSquelBuilder(item)) {
// Builders allowed
} else {
var typeIsValid = !!getValueHandler(item, this.options.valueHandlers, cls.globalValueHandlers);
if (!typeIsValid) {
throw new Error("field value must be a string, number, boolean, null or one of the registered custom value types");
}
}
return item;
}
// Escape a string value, e.g. escape quotes and other characters within it.
// Will escape string value by default unless replaceSingleQuotes is provided
}, {
key: '_escapeValue',
value: function _escapeValue(value) {
if (!value) {
return '\'\'';
}
return this.options.replaceSingleQuotes ? "'" + value.replace(/\'/g, this.options.singleQuoteReplacement) + "'" : escape(value);
}
}, {
key: '_formatTableName',
value: function _formatTableName(item) {
if (this.options.autoQuoteTableNames) {
var quoteChar = this.options.nameQuoteCharacter;
item = '' + quoteChar + item + quoteChar;
}
return item;
}
}, {
key: '_formatFieldAlias',
value: function _formatFieldAlias(item) {
if (this.options.autoQuoteAliasNames) {
var quoteChar = this.options.fieldAliasQuoteCharacter;
item = '' + quoteChar + item + quoteChar;
}
return item;
}
}, {
key: '_formatTableAlias',
value: function _formatTableAlias(item) {
if (this.options.autoQuoteAliasNames) {
var quoteChar = this.options.tableAliasQuoteCharacter;
item = '' + quoteChar + item + quoteChar;
}
return this.options.useAsForTableAliasNames ? 'AS ' + item : item;
}
}, {
key: '_formatFieldName',
value: function _formatFieldName(item) {
var formattingOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (this.options.autoQuoteFieldNames) {
var quoteChar = this.options.nameQuoteCharacter;
if (formattingOptions.ignorePeriodsForFieldNameQuotes) {
// a.b.c -> `a.b.c`
item = '' + quoteChar + item + quoteChar;
} else {
// a.b.c -> `a`.`b`.`c`
item = item.split('.').map(function (v) {
// treat '*' as special case (#79)
return '*' === v ? v : '' + quoteChar + v + quoteChar;
}).join('.');
}
}
return item;
}
// Format the given custom value
}, {
key: '_formatCustomValue',
value: function _formatCustomValue(value, asParam, formattingOptions) {
// user defined custom handlers takes precedence
var customHandler = getValueHandler(value, this.options.valueHandlers, cls.globalValueHandlers);
// use the custom handler if available
if (customHandler) {
value = customHandler(value, asParam, formattingOptions);
// custom value handler can instruct caller not to process returned value
if (value && value.rawNesting) {
return {
formatted: true,
rawNesting: true,
value: value.value
};
}
}
return {
formatted: !!customHandler,
value: value
};
}
/**
* Format given value for inclusion into parameter values array.
*/
}, {
key: '_formatValueForParamArray',
value: function _formatValueForParamArray(value) {
var _this2 = this;
var formattingOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (_isArray(value)) {
return value.map(function (v) {
return _this2._formatValueForParamArray(v, formattingOptions);
});
} else {
return this._formatCustomValue(value, true, formattingOptions).value;
}
}
/**
* Format the given field value for inclusion into the query string
*/
}, {
key: '_formatValueForQueryString',
value: function _formatValueForQueryString(initialValue) {
var _this3 = this;
var formattingOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// maybe we have a cusotm value handler
var _formatCustomValue2 = this._formatCustomValue(initialValue, false, formattingOptions),
rawNesting = _formatCustomValue2.rawNesting,
formatted = _formatCustomValue2.formatted,
value = _formatCustomValue2.value;
// if formatting took place then return it directly
if (formatted) {
if (rawNesting) {
return value;
} else {
return this._applyNestingFormatting(value, _shouldApplyNesting(initialValue));
}
}
// if it's an array then format each element separately
if (_isArray(value)) {
value = value.map(function (v) {
return _this3._formatValueForQueryString(v);
});
value = this._applyNestingFormatting(value.join(', '), _shouldApplyNesting(value));
} else {
var typeofValue = typeof value === 'undefined' ? 'undefined' : _typeof(value);
if (null === value) {
value = "NULL";
} else if (typeofValue === "boolean") {
value = value ? "TRUE" : "FALSE";
} else if (cls.isSquelBuilder(value)) {
value = this._applyNestingFormatting(value.toString(), _shouldApplyNesting(value));
} else if (typeofValue !== "number") {
// if it's a string and we have custom string formatting turned on then use that
if ('string' === typeofValue && this.options.stringFormatter) {
return this.options.stringFormatter(value, formattingOptions);
}
if (formattingOptions.dontQuote) {
value = '' + value;
} else {
value = this._escapeValue(value);
}
}
}
return value;
}
}, {
key: '_applyNestingFormatting',
value: function _applyNestingFormatting(str) {
var nesting = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
if (str && typeof str === 'string' && nesting && !this.options.rawNesting) {
// apply brackets if they're not already existing
var alreadyHasBrackets = '(' === str.charAt(0) && ')' === str.charAt(str.length - 1);
if (alreadyHasBrackets) {
// check that it's the form "((x)..(y))" rather than "(x)..(y)"
var idx = 0,
open = 1;
while (str.length - 1 > ++idx) {
var c = str.charAt(idx);
if ('(' === c) {
open++;
} else if (')' === c) {
open--;
if (1 > open) {
alreadyHasBrackets = false;
break;
}
}
}
}
if (!alreadyHasBrackets) {
str = '(' + str + ')';
}
}
return str;
}
/**
* Build given string and its corresponding parameter values into
* output.
*
* @param {String} str
* @param {Array} values
* @param {Object} [options] Additional options.
* @param {Boolean} [options.buildParameterized] Whether to build paramterized string. Default is false.
* @param {Boolean} [options.nested] Whether this expression is nested within another.
* @param {Boolean} [options.formattingOptions] Formatting options for values in query string.
* @return {Object}
*/
}, {
key: '_buildString',
value: function _buildString(str, values) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var nested = options.nested,
buildParameterized = options.buildParameterized,
formattingOptions = options.formattingOptions;
values = values || [];
str = str || '';
var formattedStr = '',
curValue = -1,
formattedValues = [];
var paramChar = this.options.parameterCharacter;
var idx = 0;
while (str.length > idx) {
// param char?
if (str.substr(idx, paramChar.length) === paramChar) {
var value = values[++curValue];
if (buildParameterized) {
if (cls.isSquelBuilder(value)) {
var ret = value._toParamString({
buildParameterized: buildParameterized,
nested: true
});
formattedStr += ret.text;
ret.values.forEach(function (value) {
return formattedValues.push(value);
});
} else {
value = this._formatValueForParamArray(value, formattingOptions);
if (_isArray(value)) {
// Array(6) -> "(??, ??, ??, ??, ??, ??)"
var tmpStr = value.map(function () {
return paramChar;
}).join(', ');
formattedStr += '(' + tmpStr + ')';
value.forEach(function (val) {
return formattedValues.push(val);
});
} else {
formattedStr += paramChar;
formattedValues.push(value);
}
}
} else {
formattedStr += this._formatValueForQueryString(value, formattingOptions);
}
idx += paramChar.length;
} else {
formattedStr += str.charAt(idx);
idx++;
}
}
return {
text: this._applyNestingFormatting(formattedStr, !!nested),
values: formattedValues
};
}
/**
* Build all given strings and their corresponding parameter values into
* output.
*
* @param {Array} strings
* @param {Array} strValues array of value arrays corresponding to each string.
* @param {Object} [options] Additional options.
* @param {Boolean} [options.buildParameterized] Whether to build paramterized string. Default is false.
* @param {Boolean} [options.nested] Whether this expression is nested within another.
* @return {Object}
*/
}, {
key: '_buildManyStrings',
value: function _buildManyStrings(strings, strValues) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var totalStr = [],
totalValues = [];
for (var idx = 0; strings.length > idx; ++idx) {
var inputString = strings[idx],
inputValues = strValues[idx];
var _buildString2 = this._buildString(inputString, inputValues, {
buildParameterized: options.buildParameterized,
nested: false
}),
text = _buildString2.text,
values = _buildString2.values;
totalStr.push(text);
values.forEach(function (value) {
return totalValues.push(value);
});
}
totalStr = totalStr.join(this.options.separator);
return {
text: totalStr.length ? this._applyNestingFormatting(totalStr, !!options.nested) : '',
values: totalValues
};
}
/**
* Get parameterized representation of this instance.
*
* @param {Object} [options] Options.
* @param {Boolean} [options.buildParameterized] Whether to build paramterized string. Default is false.
* @param {Boolean} [options.nested] Whether this expression is nested within another.
* @return {Object}
*/
}, {
key: '_toParamString',
value: function _toParamString(options) {
throw new Error('Not yet implemented');
}
/**
* Get the expression string.
* @return {String}
*/
}, {
key: 'toString',
value: function toString() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this._toParamString(options).text;
}
/**
* Get the parameterized expression string.
* @return {Object}
*/
}, {
key: 'toParam',
value: function toParam() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this._toParamString(_extend({}, options, {
buildParameterized: true
}));
}
}]);
return _class2;
}(cls.Cloneable);
/*
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
# cls.Expressions
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
*/
/**
* An SQL expression builder.
*
* SQL expressions are used in WHERE and ON clauses to filter data by various criteria.
*
* Expressions can be nested. Nested expression contains can themselves
* contain nested expressions. When rendered a nested expression will be
* fully contained within brackets.
*
* All the build methods in this object return the object instance for chained method calling purposes.
*/
cls.Expression = function (_cls$BaseBuilder) {
_inherits(_class3, _cls$BaseBuilder);
// Initialise the expression.
function _class3(options) {
_classCallCheck(this, _class3);
var _this4 = _possibleConstructorReturn(this, (_class3.__proto__ || Object.getPrototypeOf(_class3)).call(this, options));
_this4._nodes = [];
return _this4;
}
// Combine the current expression with the given expression using the intersection operator (AND).
_createClass(_class3, [{
key: 'and',
value: function and(expr) {
for (var _len2 = arguments.length, params = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
params[_key2 - 1] = arguments[_key2];
}
expr = this._sanitizeExpression(expr);
this._nodes.push({
type: 'AND',
expr: expr,
para: params
});
return this;
}
// Combine the current expression with the given expression using the union operator (OR).
}, {
key: 'or',
value: function or(expr) {
for (var _len3 = arguments.length, params = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
params[_key3 - 1] = arguments[_key3];
}
expr = this._sanitizeExpression(expr);
this._nodes.push({
type: 'OR',
expr: expr,
para: params
});
return this;
}
}, {
key: '_toParamString',
value: function _toParamString() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var totalStr = [],
totalValues = [];
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = this._nodes[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var node = _step3.value;
var type = node.type,
expr = node.expr,
para = node.para;
var _ref = cls.isSquelBuilder(expr) ? expr._toParamString({
buildParameterized: options.buildParameterized,
nested: true
}) : this._buildString(expr, para, {
buildParameterized: options.buildParameterized
}),
text = _ref.text,
values = _ref.values;
if (totalStr.length) {
totalStr.push(type);
}
totalStr.push(text);
values.forEach(function (value) {
return totalValues.push(value);
});
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
totalStr = totalStr.join(' ');
return {
text: this._applyNestingFormatting(totalStr, !!options.nested),
values: totalValues
};
}
}]);
return _class3;
}(cls.BaseBuilder);
/*
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
# cls.Case
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
*/
/**
* An SQL CASE expression builder.
*
* SQL cases are used to select proper values based on specific criteria.
*/
cls.Case = function (_cls$BaseBuilder2) {
_inherits(_class4, _cls$BaseBuilder2);
function _class4(fieldName) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, _class4);
var _this5 = _possibleConstructorReturn(this, (_class4.__proto__ || Object.getPrototypeOf(_class4)).call(this, options));
if (_isPlainObject(fieldName)) {
options = fieldName;
fieldName = null;
}
if (fieldName) {
_this5._fieldName = _this5._sanitizeField(fieldName);
}
_this5.options = _extend({}, cls.DefaultQueryBuilderOptions, options);
_this5._cases = [];
_this5._elseValue = null;
return _this5;
}
_createClass(_class4, [{
key: 'when',
value: function when(expression) {
for (var _len4 = arguments.length, values = Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
values[_key4 - 1] = arguments[_key4];
}
this._cases.unshift({
expression: expression,
values: values || []
});
return this;
}
}, {
key: 'then',
value: function then(result) {
if (this._cases.length == 0) {
throw new Error("when() needs to be called first");
}
this._cases[0].result = result;
return this;
}
}, {
key: 'else',
value: function _else(elseValue) {
this._elseValue = elseValue;
return this;
}
}, {
key: '_toParamString',
value: function _toParamString() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var totalStr = '',
totalValues = [];
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = this._cases[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var _ref2 = _step4.value;
var expression = _ref2.expression;
var _values = _ref2.values;
var result = _ref2.result;
totalStr = _pad(totalStr, ' ');
var ret = this._buildString(expression, _values, {
buildParameterized: options.buildParameterized,
nested: true
});
totalStr += 'WHEN ' + ret.text + ' THEN ' + this._formatValueForQueryString(result);
ret.values.forEach(function (value) {
return totalValues.push(value);
});
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
if (totalStr.length) {
totalStr += ' ELSE ' + this._formatValueForQueryString(this._elseValue) + ' END';
if (this._fieldName) {
totalStr = this._fieldName + ' ' + totalStr;
}
totalStr = 'CASE ' + totalStr;
} else {
totalStr = this._formatValueForQueryString(this._elseValue);
}
return {
text: totalStr,
values: totalValues
};
}
}]);
return _class4;
}(cls.BaseBuilder);
/*
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
# Building blocks
# ---------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------
*/
/*
# A building block represents a single build-step within a query building process.
#
# Query builders consist of one or more building blocks which get run in a particular order. Building blocks can
# optionally specify methods to expose through the query builder interface. They can access all the input data for
# the query builder and manipulate it as necessary, as well as append to the final query string output.
#
# If you wish to customize how queries get built or add proprietary query phrases and content then it is recommended
# that you do so using one or more custom building blocks.
#
# Original idea posted in https://github.com/hiddentao/export/issues/10#issuecomment-15016427
*/
cls.Block = function (_cls$BaseBuilder3) {
_inherits(_class5, _cls$BaseBuilder3);
function _class5(options) {
_classCallCheck(this, _class5);
return _possibleConstructorReturn(this, (_class5.__proto__ || Object.getPrototypeOf(_class5)).call(this, options));
}
/**
# Get input methods to expose within the query builder.
#
# By default all methods except the following get returned:
# methods prefixed with _
# constructor and toString()
#
# @return Object key -> function pairs
*/
_createClass(_class5, [{
key: 'exposedMethods',
value: function exposedMethods() {
var ret = {};
var obj = this;
while (obj) {
Object.getOwnPropertyNames(obj).forEach(function (prop) {
if ('constructor' !== prop && typeof obj[prop] === "function" && prop.charAt(0) !== '_' && !cls.Block.prototype[prop]) {
ret[prop] = obj[prop];
}
});
obj = Object.getPrototypeOf(obj);
};
return ret;
}
}]);
return _class5;
}(cls.BaseBuilder);
// A fixed string which always gets output
cls.StringBlock = function (_cls$Block) {
_inherits(_class6, _cls$Block);
function _class6(options, str) {
_classCallCheck(this, _class6);
var _this7 = _possibleConstructorReturn(this, (_class6.__proto__ || Object.getPrototypeOf(_class6)).call(this, options));
_this7._str = str;
return _this7;
}
_createClass(_class6, [{
key: '_toParamString',
value: function _toParamString() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return {
text: this._str,
values: []
};
}
}]);
return _class6;
}(cls.Block);
// A function string block
cls.FunctionBlock = function (_cls$Block2) {
_inherits(_class7, _cls$Block2);
function _class7(options) {
_classCallCheck(this, _class7);
var _this8 = _possibleConstructorReturn(this, (_class7.__proto__ || Object.getPrototypeOf(_class7)).call(this, options));
_this8._strings = [];
_this8._values = [];
return _this8;
}
_createClass(_class7, [{
key: 'function',
value: function _function(str) {
this._strings.push(str);
for (var _len5 = arguments.length, values = Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
values[_key5 - 1] = arguments[_key5];
}
this._values.push(values);
}
}, {
key: '_toParamString',
value: function _toParamString() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this._buildManyStrings(this._strings, this._values, options);
}
}]);
return _class7;
}(cls.Block);
// value handler for FunctionValueBlock objects
cls.registerValueHandler(cls.FunctionBlock, function (value) {
var asParam = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
return asParam ? value.toParam() : value.toString();
});
/*
# Table specifier base class
*/
cls.AbstractTableBlock = function (_cls$Block3) {
_inherits(_class8, _cls$Block3);
/**
* @param {Boolean} [options.singleTable] If true then only allow one table spec.
* @param {String} [options.prefix] String prefix for output.
*/
function _class8(options, prefix) {
_classCallCheck(this, _class8);
var _this9 = _possibleConstructorReturn(this, (_class8.__proto__ || Object.getPrototypeOf(_class8)).call(this, options));
_this9._tables = [];
return _this9;
}
/**
# Update given table.
#
# An alias may also be specified for the table.
#
# Concrete subclasses should provide a method which calls this
*/
_createClass(_class8, [{
key: '_table',
value: function _table(table) {
var alias = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
alias = alias ? this._sanitizeTableAlias(alias) : alias;
table = this._sanitizeTable(table);
if (this.options.singleTable) {
this._tables = [];
}
this._tables.push({
table: table,
alias: alias
});
}
// get whether a table has been set
}, {
key: '_hasTable',
value: function _hasTable() {
return 0 < this._tables.length;
}
/**
* @override
*/
}, {
key: '_toParamString',
value: function _toParamString() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var totalStr = '',
totalValues = [];
if (this._hasTable()) {
// retrieve the parameterised queries
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = this._tables[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var _ref3 = _step5.value;
var table = _ref3.table;
var alias = _ref3.alias;
totalStr = _pad(totalStr, ', ');
var tableStr = void 0;
if (cls.isSquelBuilder(table)) {
var _table$_toParamString = table._toParamString({
buildParameterized: options.buildParameterized,
nested: true
}),
text = _table$_toParamString.text,
values = _table$_toParamString.values;
tableStr = text;
values.forEach(function (value) {
return totalValues.push(value);
});
} else {
tableStr = this._formatTableName(table);
}
if (alias) {
tableStr += ' ' + this._formatTableAlias(alias);
}
totalStr += tableStr;
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
if (this.options.prefix) {
totalStr = this.options.prefix + ' ' + totalStr;
}
}
return {
text: totalStr,
values: totalValues
};
}
}]);
return _class8;
}(cls.Block);
// target table for DELETE queries, DELETE <??> FROM
cls.TargetTableBlock = function (_cls$AbstractTableBlo) {
_inherits(_class9, _cls$AbstractTableBlo);
function _class9() {
_classCallCheck(this, _class9);
return _possibleConstructorReturn(this, (_class9.__proto__ || Object.getPrototypeOf(_class9)).apply(this, arguments));
}
_createClass(_class9, [{
key: 'target',
value: function target(table) {
this._table(table);
}
}]);
return _class9;
}(cls.AbstractTableBlock);
// Update Table
cls.UpdateTableBlock = function (_cls$AbstractTableBlo2) {
_inherits(_class10, _cls$AbstractTableBlo2);
function _class10() {
_classCallCheck(this, _class10);
return _possibleConstructorReturn(this, (_class10.__proto__ || Object.getPrototypeOf(_class10)).apply(this, arguments));
}
_createClass(_class10, [{
key: 'table',
value: function table(_table2) {
var alias = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
this._table(_table2, alias);
}
}, {
key: '_toParamString',
value: function _toParamString() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
if (!this._hasTable()) {
throw new Error("table() needs to be called");
}
return _get(_class10.prototype.__proto__ || Object.getPrototypeOf(_class10.prototype), '_toParamString', this).call(this, options);
}
}]);
return _class10;
}(cls.AbstractTableBlock);
// FROM table
cls.FromTableBlock = function (_cls$AbstractTableBlo3) {
_inherits(_class11, _cls$AbstractTableBlo3);
function _class11(options) {
_classCallCheck(this, _class11);
return _possibleConstructorReturn(this, (_class11.__proto__ || Object.getPrototypeOf(_class11)).call(this, _extend({}, options, {
prefix: 'FROM'
})));
}
_createClass(_class11, [{
key: 'from',
value: function from(table) {
var alias = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
this._table(table, alias);
}
}]);
return _class11;
}(cls.AbstractTableBlock);
// INTO table
cls.IntoTableBlock = function (_cls$AbstractTableBlo4) {
_inherits(_class12, _cls$AbstractTableBlo4);
function _class12(options) {
_classCallCheck(this, _class12);
return _possibleConstructorReturn(this, (_class12.__proto__ || Object.getPrototypeOf(_class12)).call(this, _extend({}, options, {
prefix: 'INTO',
singleTable: true
})));
}
_createClass(_class12, [{
key: 'into',
value: function into(table) {
this._table(table);
}
}, {
key: '_toParamString',
value: function _toParamString() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
if (!this._hasTable()) {
throw new Error("into() needs to be called");
}
return _get(_class12.prototype.__proto__ || Object.getPrototypeOf(_class12.prototype), '_toParamString', this).call(this, options);
}
}]);
return _class12;
}(cls.AbstractTableBlock);
// (SELECT) Get field
cls.GetFieldBlock = function (_cls$Block4) {
_inherits(_class13, _cls$Block4);
function _class13(options) {
_classCallCheck(this, _class13);
var _this14 = _possibleConstructorReturn(this, (_class13.__proto__ || Object.getPrototypeOf(_class13)).call(this, options));
_this14._fields = [];
return _this14;
}
/**
# Add the given fields to the final result set.
#
# The parameter is an Object containing field names (or database functions) as the keys and aliases for the fields
# as the values. If the value for a key is null then no alias is set for that field.
#
# Internally this method simply calls the field() method of this block to add each individual field.
#
# options.ignorePeriodsForFieldNameQuotes - whether to ignore period (.) when automatically quoting the field name
*/
_createClass(_class13, [{
key: 'fields',
value: function fields(_fields) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (_isArray(_fields)) {
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = _fields[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var field = _step6.value;
this.field(field, null, options);
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
} else {
for (var _field2 in _fields) {
var alias = _fields[_field2];
this.field(_field2, alias, options);
}
}
}
/**
# Add the given field to the final result set.
#
# The 'field' parameter does not necessarily have to be a fieldname. It can use database functions too,
# e.g. DATE_FORMAT(a.started, "%H")
#
# An alias may also be specified for this field.
#
# options.ignorePeriodsForFieldNameQuotes - whether to ignore period (.) when automatically quoting the field name
*/
}, {
key: 'field',
value: function field(_field) {
var alias = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var options = a