2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
// Raw
|
|
|
|
// -------
|
2016-05-17 01:01:34 +10:00
|
|
|
import inherits from 'inherits';
|
|
|
|
import { EventEmitter } from 'events';
|
2016-03-02 16:52:32 +01:00
|
|
|
|
2016-05-18 20:22:50 +10:00
|
|
|
import { assign, reduce, isPlainObject, isObject, isUndefined, isNumber } from 'lodash'
|
2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
function Raw(client) {
|
2016-05-18 19:59:24 +10:00
|
|
|
this.client = client
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2016-05-18 19:59:24 +10:00
|
|
|
this.sql = ''
|
2015-05-09 13:58:18 -04:00
|
|
|
this.bindings = []
|
2016-05-18 19:59:24 +10:00
|
|
|
this._cached = undefined
|
2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
// Todo: Deprecate
|
|
|
|
this._wrappedBefore = undefined
|
2016-05-18 19:59:24 +10:00
|
|
|
this._wrappedAfter = undefined
|
|
|
|
this._debug = client && client.config && client.config.debug
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
inherits(Raw, EventEmitter)
|
|
|
|
|
|
|
|
assign(Raw.prototype, {
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
set(sql, bindings) {
|
2016-05-18 19:59:24 +10:00
|
|
|
this._cached = undefined
|
|
|
|
this.sql = sql
|
2016-03-02 16:52:32 +01:00
|
|
|
this.bindings = (isObject(bindings) || isUndefined(bindings)) ? bindings : [bindings]
|
2016-01-30 14:52:07 +01:00
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
return this
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
timeout(ms) {
|
2016-03-08 13:07:50 +01:00
|
|
|
if(isNumber(ms) && ms > 0) {
|
|
|
|
this._timeout = ms;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Wraps the current sql with `before` and `after`.
|
2016-05-17 01:01:34 +10:00
|
|
|
wrap(before, after) {
|
2016-05-18 19:59:24 +10:00
|
|
|
this._cached = undefined
|
2015-05-09 13:58:18 -04:00
|
|
|
this._wrappedBefore = before
|
2016-05-18 19:59:24 +10:00
|
|
|
this._wrappedAfter = after
|
2015-05-09 13:58:18 -04:00
|
|
|
return this
|
|
|
|
},
|
|
|
|
|
|
|
|
// Calls `toString` on the Knex object.
|
2016-05-17 01:01:34 +10:00
|
|
|
toString() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this.toQuery()
|
|
|
|
},
|
|
|
|
|
|
|
|
// Returns the raw sql for the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
toSQL(method, tz) {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (this._cached) return this._cached
|
|
|
|
if (Array.isArray(this.bindings)) {
|
2016-03-08 08:41:13 +01:00
|
|
|
this._cached = replaceRawArrBindings(this)
|
2015-11-06 16:17:50 -07:00
|
|
|
} else if (this.bindings && isPlainObject(this.bindings)) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._cached = replaceKeyBindings(this)
|
|
|
|
} else {
|
|
|
|
this._cached = {
|
|
|
|
method: 'raw',
|
|
|
|
sql: this.sql,
|
2016-03-15 21:47:14 +01:00
|
|
|
bindings: isUndefined(this.bindings) ? void 0 : [this.bindings]
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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, {})
|
2016-03-08 13:07:50 +01:00
|
|
|
if(this._timeout) {
|
|
|
|
this._cached.timeout = this._timeout;
|
|
|
|
}
|
2016-03-15 21:33:39 +01:00
|
|
|
if(this.client && this.client.prepBindings) {
|
2016-03-15 21:47:14 +01:00
|
|
|
this._cached.bindings = this.client.prepBindings(this._cached.bindings || [], tz);
|
2016-03-15 21:33:39 +01:00
|
|
|
}
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._cached
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
function replaceRawArrBindings(raw) {
|
2016-05-17 01:01:34 +10:00
|
|
|
const expectedBindings = raw.bindings.length
|
2016-05-18 19:59:24 +10:00
|
|
|
const values = raw.bindings
|
|
|
|
const { client } = raw
|
|
|
|
let index = 0;
|
|
|
|
let bindings = []
|
2015-11-13 21:01:01 +02:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
const sql = raw.sql.replace(/\\?\?\??/g, function(match) {
|
2015-11-13 21:01:01 +02:00
|
|
|
if (match === '\\?') {
|
|
|
|
return match
|
|
|
|
}
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
const value = values[index++]
|
2016-03-08 08:41:13 +01:00
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
if (value && typeof value.toSQL === 'function') {
|
2016-05-17 01:01:34 +10:00
|
|
|
const bindingSQL = value.toSQL()
|
2015-06-01 07:30:38 -04:00
|
|
|
if (bindingSQL.bindings !== undefined) {
|
2016-03-08 08:41:13 +01:00
|
|
|
bindings = bindings.concat(bindingSQL.bindings)
|
2015-06-01 07:30:38 -04:00
|
|
|
}
|
2015-05-09 13:58:18 -04:00
|
|
|
return bindingSQL.sql
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match === '??') {
|
2015-11-06 01:19:47 +02:00
|
|
|
return client.formatter().columnize(value)
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
bindings.push(value)
|
|
|
|
return '?'
|
|
|
|
})
|
|
|
|
|
|
|
|
if (expectedBindings !== index) {
|
2016-05-17 01:01:34 +10:00
|
|
|
throw new Error(`Expected ${expectedBindings} bindings, saw ${index}`)
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
method: 'raw',
|
2016-05-17 01:01:34 +10:00
|
|
|
sql,
|
|
|
|
bindings
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function replaceKeyBindings(raw) {
|
2016-05-18 19:59:24 +10:00
|
|
|
const values = raw.bindings
|
|
|
|
const { client } = raw
|
|
|
|
let { sql } = raw, bindings = []
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
const regex = new RegExp('(\\:\\w+\\:?)', 'g')
|
2015-11-06 19:18:21 +02:00
|
|
|
sql = raw.sql.replace(regex, function(full) {
|
2016-05-17 01:01:34 +10:00
|
|
|
const key = full.trim();
|
|
|
|
const isIdentifier = key[key.length - 1] === ':'
|
|
|
|
const value = isIdentifier ? values[key.slice(1, -1)] : values[key.slice(1)]
|
2016-03-07 16:31:39 +01:00
|
|
|
if (value === undefined) {
|
|
|
|
return full;
|
|
|
|
}
|
2015-05-09 13:58:18 -04:00
|
|
|
if (value && typeof value.toSQL === 'function') {
|
2016-05-17 01:01:34 +10:00
|
|
|
const bindingSQL = value.toSQL()
|
2015-06-01 07:30:38 -04:00
|
|
|
if (bindingSQL.bindings !== undefined) {
|
2016-03-08 08:41:13 +01:00
|
|
|
bindings = bindings.concat(bindingSQL.bindings)
|
2015-06-01 07:30:38 -04:00
|
|
|
}
|
2015-05-09 13:58:18 -04:00
|
|
|
return full.replace(key, bindingSQL.sql)
|
|
|
|
}
|
|
|
|
if (isIdentifier) {
|
2015-11-06 01:19:47 +02:00
|
|
|
return full.replace(key, client.formatter().columnize(value))
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
bindings.push(value)
|
|
|
|
return full.replace(key, '?')
|
|
|
|
})
|
|
|
|
|
|
|
|
return {
|
|
|
|
method: 'raw',
|
2016-05-17 01:01:34 +10:00
|
|
|
sql,
|
|
|
|
bindings
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow the `Raw` object to be utilized with full access to the relevant
|
|
|
|
// promise API.
|
|
|
|
require('./interface')(Raw)
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
export default Raw
|