You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
3.8 KiB
JavaScript
153 lines
3.8 KiB
JavaScript
|
|
// Raw
|
|
// -------
|
|
'use strict';
|
|
|
|
var inherits = require('inherits');
|
|
var EventEmitter = require('events').EventEmitter;
|
|
var assign = require('lodash/object/assign');
|
|
var reduce = require('lodash/collection/reduce');
|
|
var isPlainObject = require('lodash/lang/isPlainObject');
|
|
var _ = require('lodash');
|
|
|
|
function Raw(client) {
|
|
this.client = client;
|
|
|
|
this.sql = '';
|
|
this.bindings = [];
|
|
this._cached = undefined;
|
|
|
|
// Todo: Deprecate
|
|
this._wrappedBefore = undefined;
|
|
this._wrappedAfter = undefined;
|
|
this._debug = client && client.config && client.config.debug;
|
|
}
|
|
inherits(Raw, EventEmitter);
|
|
|
|
assign(Raw.prototype, {
|
|
|
|
set: function set(sql, bindings) {
|
|
this._cached = undefined;
|
|
this.sql = sql;
|
|
this.bindings = _.isObject(bindings) || _.isUndefined(bindings) ? bindings : [bindings];
|
|
|
|
return this;
|
|
},
|
|
|
|
// Wraps the current sql with `before` and `after`.
|
|
wrap: function wrap(before, after) {
|
|
this._cached = undefined;
|
|
this._wrappedBefore = before;
|
|
this._wrappedAfter = after;
|
|
return this;
|
|
},
|
|
|
|
// Calls `toString` on the Knex object.
|
|
toString: function toString() {
|
|
return this.toQuery();
|
|
},
|
|
|
|
// Returns the raw sql for the query.
|
|
toSQL: function toSQL() {
|
|
if (this._cached) return this._cached;
|
|
if (Array.isArray(this.bindings)) {
|
|
this._cached = replaceRawArrBindings(this);
|
|
} else if (this.bindings && isPlainObject(this.bindings)) {
|
|
this._cached = replaceKeyBindings(this);
|
|
} else {
|
|
this._cached = {
|
|
method: 'raw',
|
|
sql: this.sql,
|
|
bindings: this.bindings
|
|
};
|
|
}
|
|
if (this._wrappedBefore) {
|
|
this._cached.sql = this._wrappedBefore + this._cached.sql;
|
|
}
|
|
if (this._wrappedAfter) {
|
|
this._cached.sql = this._cached.sql + this._wrappedAfter;
|
|
}
|
|
this._cached.options = reduce(this._options, assign, {});
|
|
return this._cached;
|
|
}
|
|
|
|
});
|
|
|
|
function replaceRawArrBindings(raw) {
|
|
var expectedBindings = raw.bindings.length;
|
|
var values = raw.bindings;
|
|
var client = raw.client;
|
|
var index = 0;
|
|
var bindings = [];
|
|
|
|
var sql = raw.sql.replace(/\\?\?\??/g, function (match) {
|
|
if (match === '\\?') {
|
|
return match;
|
|
}
|
|
|
|
var value = values[index++];
|
|
|
|
if (value && typeof value.toSQL === 'function') {
|
|
var bindingSQL = value.toSQL();
|
|
if (bindingSQL.bindings !== undefined) {
|
|
bindings = bindings.concat(bindingSQL.bindings);
|
|
}
|
|
return bindingSQL.sql;
|
|
}
|
|
|
|
if (match === '??') {
|
|
return client.formatter().columnize(value);
|
|
}
|
|
bindings.push(value);
|
|
return '?';
|
|
});
|
|
|
|
if (expectedBindings !== index) {
|
|
throw new Error('Expected ' + expectedBindings + ' bindings, saw ' + index);
|
|
}
|
|
|
|
return {
|
|
method: 'raw',
|
|
sql: sql,
|
|
bindings: bindings
|
|
};
|
|
}
|
|
|
|
function replaceKeyBindings(raw) {
|
|
var values = raw.bindings;
|
|
var client = raw.client;
|
|
var sql = raw.sql,
|
|
bindings = [];
|
|
|
|
var regex = new RegExp('(^|\\s)(\\:\\w+\\:?)', 'g');
|
|
sql = raw.sql.replace(regex, function (full) {
|
|
var key = full.trim();
|
|
var isIdentifier = key[key.length - 1] === ':';
|
|
var value = isIdentifier ? values[key.slice(1, -1)] : values[key.slice(1)];
|
|
if (value === undefined) return '';
|
|
if (value && typeof value.toSQL === 'function') {
|
|
var bindingSQL = value.toSQL();
|
|
if (bindingSQL.bindings !== undefined) {
|
|
bindings = bindings.concat(bindingSQL.bindings);
|
|
}
|
|
return full.replace(key, bindingSQL.sql);
|
|
}
|
|
if (isIdentifier) {
|
|
return full.replace(key, client.formatter().columnize(value));
|
|
}
|
|
bindings.push(value);
|
|
return full.replace(key, '?');
|
|
});
|
|
|
|
return {
|
|
method: 'raw',
|
|
sql: sql,
|
|
bindings: bindings
|
|
};
|
|
}
|
|
|
|
// Allow the `Raw` object to be utilized with full access to the relevant
|
|
// promise API.
|
|
require('./interface')(Raw);
|
|
|
|
module.exports = Raw; |