2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
// Builder
|
|
|
|
// -------
|
2016-05-17 01:01:34 +10:00
|
|
|
import assert from 'assert';
|
|
|
|
import inherits from 'inherits';
|
|
|
|
import { EventEmitter } from 'events';
|
|
|
|
|
|
|
|
import Raw from '../raw';
|
|
|
|
import * as helpers from '../helpers';
|
|
|
|
import JoinClause from './joinclause';
|
|
|
|
import {
|
|
|
|
assign, clone, each, isBoolean, isEmpty, isFunction, isNumber, isObject,
|
2018-02-22 12:33:55 +01:00
|
|
|
isString, isUndefined, tail, toArray, reject, includes
|
2016-05-17 01:01:34 +10:00
|
|
|
} from 'lodash';
|
2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
// Typically called from `knex.builder`,
|
|
|
|
// start a new query building chain.
|
2015-05-12 21:48:02 -04:00
|
|
|
function Builder(client) {
|
2016-05-18 19:59:24 +10:00
|
|
|
this.client = client
|
|
|
|
this.and = this;
|
|
|
|
this._single = {};
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements = [];
|
2016-05-18 19:59:24 +10:00
|
|
|
this._method = 'select'
|
|
|
|
this._debug = client.config && client.config.debug;
|
2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
// Internal flags used in the builder.
|
2016-05-18 19:59:24 +10:00
|
|
|
this._joinFlag = 'inner';
|
|
|
|
this._boolFlag = 'and';
|
|
|
|
this._notFlag = false;
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
2015-05-12 21:48:02 -04:00
|
|
|
inherits(Builder, EventEmitter);
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2015-05-12 21:48:02 -04:00
|
|
|
assign(Builder.prototype, {
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
toString() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this.toQuery();
|
|
|
|
},
|
|
|
|
|
|
|
|
// Convert the current query "toSQL"
|
2016-05-17 01:01:34 +10:00
|
|
|
toSQL(method, tz) {
|
2016-03-15 21:47:14 +01:00
|
|
|
return this.client.queryCompiler(this).toSQL(method || this._method, tz);
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
// Create a shallow clone of the current query builder.
|
2015-11-30 00:21:08 +11:00
|
|
|
clone() {
|
2016-05-18 19:59:24 +10:00
|
|
|
const cloned = new this.constructor(this.client);
|
|
|
|
cloned._method = this._method;
|
|
|
|
cloned._single = clone(this._single);
|
|
|
|
cloned._statements = clone(this._statements);
|
|
|
|
cloned._debug = this._debug;
|
2015-11-30 00:21:08 +11:00
|
|
|
|
|
|
|
// `_option` is assigned by the `Interface` mixin.
|
|
|
|
if (!isUndefined(this._options)) {
|
|
|
|
cloned._options = clone(this._options);
|
|
|
|
}
|
2018-02-01 23:41:01 +01:00
|
|
|
if (!isUndefined(this._queryContext)) {
|
|
|
|
cloned._queryContext = clone(this._queryContext);
|
|
|
|
}
|
2015-11-30 00:21:08 +11:00
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
return cloned;
|
|
|
|
},
|
|
|
|
|
2016-05-26 11:06:33 -07:00
|
|
|
timeout(ms, {cancel} = {}) {
|
2016-02-15 17:06:08 +01:00
|
|
|
if(isNumber(ms) && ms > 0) {
|
|
|
|
this._timeout = ms;
|
2016-05-26 11:06:33 -07:00
|
|
|
if (cancel) {
|
2016-05-27 14:47:12 -07:00
|
|
|
this.client.assertCanCancelQuery();
|
|
|
|
this._cancelOnTimeout = true;
|
2016-05-26 11:06:33 -07:00
|
|
|
}
|
2016-02-15 17:06:08 +01:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2016-09-13 12:14:04 +02:00
|
|
|
// With
|
|
|
|
// ------
|
|
|
|
|
2017-10-31 21:33:28 +02:00
|
|
|
with(alias, statement) {
|
2016-09-13 12:14:04 +02:00
|
|
|
if(typeof alias !== 'string') {
|
|
|
|
throw new Error('with() first argument must be a string');
|
|
|
|
}
|
2017-10-31 21:33:28 +02:00
|
|
|
if (
|
|
|
|
typeof statement === 'function' ||
|
|
|
|
statement instanceof Builder ||
|
|
|
|
statement instanceof Raw
|
|
|
|
) {
|
2016-09-13 12:14:04 +02:00
|
|
|
return this.withWrapped(alias, statement);
|
|
|
|
}
|
2017-10-31 21:33:28 +02:00
|
|
|
throw new Error('with() second argument must be a function / QueryBuilder or a raw');
|
2016-09-13 12:14:04 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Helper for compiling any advanced `with` queries.
|
2017-10-31 21:33:28 +02:00
|
|
|
withWrapped(alias, query) {
|
2016-09-13 12:14:04 +02:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'with',
|
|
|
|
type: 'withWrapped',
|
|
|
|
alias: alias,
|
2017-10-31 21:33:28 +02:00
|
|
|
value: query
|
2016-09-13 12:14:04 +02:00
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Select
|
|
|
|
// ------
|
|
|
|
|
|
|
|
// Adds a column or columns to the list of "columns"
|
|
|
|
// being selected on the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
columns(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (!column) return this;
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'columns',
|
|
|
|
value: helpers.normalizeArr.apply(null, arguments)
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Allow for a sub-select to be explicitly aliased as a column,
|
|
|
|
// without needing to compile the query in a where.
|
2016-05-17 01:01:34 +10:00
|
|
|
as(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._single.as = column;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2015-08-09 20:22:39 -03:00
|
|
|
// Prepends the `schemaName` on `tableName` defined by `.table` and `.join`.
|
2016-05-17 01:01:34 +10:00
|
|
|
withSchema(schemaName) {
|
2015-08-09 20:22:39 -03:00
|
|
|
this._single.schema = schemaName;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Sets the `tableName` on the query.
|
|
|
|
// Alias to "from" for select and "into" for insert statements
|
|
|
|
// e.g. builder.insert({a: value}).into('tableName')
|
2017-01-26 16:22:09 +00:00
|
|
|
// `options`: options object containing keys:
|
|
|
|
// - `only`: whether the query should use SQL's ONLY to not return
|
|
|
|
// inheriting table data. Defaults to false.
|
|
|
|
table(tableName, options = {}) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._single.table = tableName;
|
2017-01-26 16:22:09 +00:00
|
|
|
this._single.only = options.only === true;
|
2015-05-09 13:58:18 -04:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `distinct` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
distinct() {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'columns',
|
|
|
|
value: helpers.normalizeArr.apply(null, arguments),
|
|
|
|
distinct: true
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a join clause to the query, allowing for advanced joins
|
|
|
|
// with an anonymous function as the second argument.
|
|
|
|
// function(table, first, operator, second)
|
2016-05-17 01:01:34 +10:00
|
|
|
join(table, first) {
|
|
|
|
let join;
|
|
|
|
const { schema } = this._single;
|
|
|
|
const joinType = this._joinType();
|
2015-05-09 13:58:18 -04:00
|
|
|
if (typeof first === 'function') {
|
2015-08-09 20:22:39 -03:00
|
|
|
join = new JoinClause(table, joinType, schema);
|
2015-05-09 13:58:18 -04:00
|
|
|
first.call(join, join);
|
|
|
|
} else if (joinType === 'raw') {
|
|
|
|
join = new JoinClause(this.client.raw(table, first), 'raw');
|
|
|
|
} else {
|
2015-08-09 20:22:39 -03:00
|
|
|
join = new JoinClause(table, joinType, schema);
|
2015-05-09 13:58:18 -04:00
|
|
|
if (arguments.length > 1) {
|
2016-03-02 16:52:32 +01:00
|
|
|
join.on.apply(join, toArray(arguments).slice(1));
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
this._statements.push(join);
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// JOIN blocks:
|
2016-05-17 01:01:34 +10:00
|
|
|
innerJoin() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._joinType('inner').join.apply(this, arguments);
|
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
leftJoin() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._joinType('left').join.apply(this, arguments);
|
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
leftOuterJoin() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._joinType('left outer').join.apply(this, arguments);
|
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
rightJoin() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._joinType('right').join.apply(this, arguments);
|
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
rightOuterJoin() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._joinType('right outer').join.apply(this, arguments);
|
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
outerJoin() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._joinType('outer').join.apply(this, arguments);
|
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
fullOuterJoin() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._joinType('full outer').join.apply(this, arguments);
|
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
crossJoin() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._joinType('cross').join.apply(this, arguments);
|
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
joinRaw() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._joinType('raw').join.apply(this, arguments);
|
|
|
|
},
|
|
|
|
|
|
|
|
// The where function can be used in several ways:
|
|
|
|
// The most basic is `where(key, value)`, which expands to
|
|
|
|
// where key = value.
|
2016-05-17 01:01:34 +10:00
|
|
|
where(column, operator, value) {
|
2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
// Support "where true || where false"
|
|
|
|
if (column === false || column === true) {
|
|
|
|
return this.where(1, '=', column ? 1 : 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the column is a function, in which case it's
|
|
|
|
// a where statement wrapped in parens.
|
|
|
|
if (typeof column === 'function') {
|
|
|
|
return this.whereWrapped(column);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow a raw statement to be passed along to the query.
|
|
|
|
if (column instanceof Raw && arguments.length === 1) return this.whereRaw(column);
|
|
|
|
|
|
|
|
// Allows `where({id: 2})` syntax.
|
2016-03-02 16:52:32 +01:00
|
|
|
if (isObject(column) && !(column instanceof Raw)) return this._objectWhere(column);
|
2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
// Enable the where('key', value) syntax, only when there
|
|
|
|
// are explicitly two arguments passed, so it's not possible to
|
|
|
|
// do where('key', '!=') and have that turn into where key != null
|
|
|
|
if (arguments.length === 2) {
|
2016-05-18 19:59:24 +10:00
|
|
|
value = operator;
|
2015-05-09 13:58:18 -04:00
|
|
|
operator = '=';
|
|
|
|
|
|
|
|
// If the value is null, and it's a two argument query,
|
|
|
|
// we assume we're going for a `whereNull`.
|
|
|
|
if (value === null) {
|
|
|
|
return this.whereNull(column);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// lower case the operator for comparison purposes
|
2016-05-17 01:01:34 +10:00
|
|
|
const checkOperator = (`${operator}`).toLowerCase().trim();
|
2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
// If there are 3 arguments, check whether 'in' is one of them.
|
|
|
|
if (arguments.length === 3) {
|
|
|
|
if (checkOperator === 'in' || checkOperator === 'not in') {
|
|
|
|
return this._not(checkOperator === 'not in').whereIn(arguments[0], arguments[2]);
|
|
|
|
}
|
|
|
|
if (checkOperator === 'between' || checkOperator === 'not between') {
|
|
|
|
return this._not(checkOperator === 'not between').whereBetween(arguments[0], arguments[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the value is still null, check whether they're meaning
|
|
|
|
// where value is null
|
|
|
|
if (value === null) {
|
|
|
|
|
|
|
|
// Check for .where(key, 'is', null) or .where(key, 'is not', 'null');
|
|
|
|
if (checkOperator === 'is' || checkOperator === 'is not') {
|
|
|
|
return this._not(checkOperator === 'is not').whereNull(column);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Push onto the where statement stack.
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereBasic',
|
2016-05-17 01:01:34 +10:00
|
|
|
column,
|
|
|
|
operator,
|
|
|
|
value,
|
2015-05-09 13:58:18 -04:00
|
|
|
not: this._not(),
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
// Adds an `or where` clause to the query.
|
2016-01-28 22:25:05 +01:00
|
|
|
orWhere: function orWhere() {
|
|
|
|
this._bool('or');
|
2016-05-17 01:01:34 +10:00
|
|
|
const obj = arguments[0];
|
2016-03-02 16:52:32 +01:00
|
|
|
if(isObject(obj) && !isFunction(obj) && !(obj instanceof Raw)) {
|
2016-01-28 22:25:05 +01:00
|
|
|
return this.whereWrapped(function() {
|
2016-05-17 01:01:34 +10:00
|
|
|
for(const key in obj) {
|
2016-01-28 22:25:05 +01:00
|
|
|
this.andWhere(key, obj[key]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return this.where.apply(this, arguments);
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
// Adds an `not where` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereNot() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._not(true).where.apply(this, arguments);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds an `or not where` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereNot() {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or').whereNot.apply(this, arguments);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Processes an object literal provided in a "where" clause.
|
2016-05-17 01:01:34 +10:00
|
|
|
_objectWhere(obj) {
|
|
|
|
const boolVal = this._bool();
|
|
|
|
const notVal = this._not() ? 'Not' : '';
|
|
|
|
for (const key in obj) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this[boolVal + 'Where' + notVal](key, obj[key]);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a raw `where` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereRaw(sql, bindings) {
|
|
|
|
const raw = (sql instanceof Raw ? sql : this.client.raw(sql, bindings));
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereRaw',
|
|
|
|
value: raw,
|
2016-05-14 22:36:13 +02:00
|
|
|
not: this._not(),
|
2015-05-09 13:58:18 -04:00
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereRaw(sql, bindings) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or').whereRaw(sql, bindings);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Helper for compiling any advanced `where` queries.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereWrapped(callback) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereWrapped',
|
|
|
|
value: callback,
|
|
|
|
not: this._not(),
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `where exists` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereExists(callback) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereExists',
|
|
|
|
value: callback,
|
|
|
|
not: this._not(),
|
|
|
|
bool: this._bool(),
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds an `or where exists` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereExists(callback) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or').whereExists(callback);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `where not exists` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereNotExists(callback) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._not(true).whereExists(callback);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `or where not exists` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereNotExists(callback) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or').whereNotExists(callback);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `where in` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereIn(column, values) {
|
2016-03-02 16:52:32 +01:00
|
|
|
if (Array.isArray(values) && isEmpty(values)) return this.where(this._not());
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereIn',
|
2016-05-17 01:01:34 +10:00
|
|
|
column,
|
2015-05-09 13:58:18 -04:00
|
|
|
value: values,
|
|
|
|
not: this._not(),
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `or where in` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereIn(column, values) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or').whereIn(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `where not in` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereNotIn(column, values) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._not(true).whereIn(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `or where not in` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereNotIn(column, values) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or')._not(true).whereIn(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `where null` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereNull(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereNull',
|
2016-05-17 01:01:34 +10:00
|
|
|
column,
|
2015-05-09 13:58:18 -04:00
|
|
|
not: this._not(),
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `or where null` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereNull(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or').whereNull(column);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `where not null` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereNotNull(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._not(true).whereNull(column);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `or where not null` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereNotNull(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or').whereNotNull(column);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `where between` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereBetween(column, values) {
|
2015-05-09 13:58:18 -04:00
|
|
|
assert(Array.isArray(values), 'The second argument to whereBetween must be an array.')
|
|
|
|
assert(values.length === 2, 'You must specify 2 values for the whereBetween clause')
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereBetween',
|
2016-05-17 01:01:34 +10:00
|
|
|
column,
|
2015-05-09 13:58:18 -04:00
|
|
|
value: values,
|
|
|
|
not: this._not(),
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `where not between` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
whereNotBetween(column, values) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._not(true).whereBetween(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `or where between` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereBetween(column, values) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or').whereBetween(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `or where not between` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orWhereNotBetween(column, values) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or').whereNotBetween(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `group by` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
groupBy(item) {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (item instanceof Raw) {
|
|
|
|
return this.groupByRaw.apply(this, arguments);
|
|
|
|
}
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'group',
|
|
|
|
type: 'groupByBasic',
|
|
|
|
value: helpers.normalizeArr.apply(null, arguments)
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a raw `group by` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
groupByRaw(sql, bindings) {
|
|
|
|
const raw = (sql instanceof Raw ? sql : this.client.raw(sql, bindings));
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'group',
|
|
|
|
type: 'groupByRaw',
|
|
|
|
value: raw
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `order by` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orderBy(column, direction) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'order',
|
|
|
|
type: 'orderByBasic',
|
|
|
|
value: column,
|
2016-05-17 01:01:34 +10:00
|
|
|
direction
|
2015-05-09 13:58:18 -04:00
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Add a raw `order by` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
orderByRaw(sql, bindings) {
|
|
|
|
const raw = (sql instanceof Raw ? sql : this.client.raw(sql, bindings));
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'order',
|
|
|
|
type: 'orderByRaw',
|
|
|
|
value: raw
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Add a union statement to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
union(callbacks, wrap) {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (arguments.length === 1 ||
|
2016-03-02 16:52:32 +01:00
|
|
|
(arguments.length === 2 && isBoolean(wrap))) {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (!Array.isArray(callbacks)) {
|
|
|
|
callbacks = [callbacks];
|
|
|
|
}
|
2016-05-17 01:01:34 +10:00
|
|
|
for (let i = 0, l = callbacks.length; i < l; i++) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'union',
|
|
|
|
clause: 'union',
|
|
|
|
value: callbacks[i],
|
|
|
|
wrap: wrap || false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
2016-03-02 16:52:32 +01:00
|
|
|
callbacks = toArray(arguments).slice(0, arguments.length - 1);
|
2015-05-09 13:58:18 -04:00
|
|
|
wrap = arguments[arguments.length - 1];
|
2016-03-02 16:52:32 +01:00
|
|
|
if (!isBoolean(wrap)) {
|
2015-05-09 13:58:18 -04:00
|
|
|
callbacks.push(wrap);
|
|
|
|
wrap = false;
|
|
|
|
}
|
|
|
|
this.union(callbacks, wrap);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a union all statement to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
unionAll(callback, wrap) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'union',
|
|
|
|
clause: 'union all',
|
|
|
|
value: callback,
|
|
|
|
wrap: wrap || false
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `having` clause to the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
having(column, operator, value) {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (column instanceof Raw && arguments.length === 1) {
|
2016-09-19 18:20:12 +02:00
|
|
|
return this.havingRaw(column);
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
2016-01-09 07:35:12 -05:00
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Check if the column is a function, in which case it's
|
|
|
|
// a having statement wrapped in parens.
|
|
|
|
if (typeof column === 'function') {
|
|
|
|
return this.havingWrapped(column);
|
|
|
|
}
|
2016-01-09 07:35:12 -05:00
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'havingBasic',
|
2016-05-17 01:01:34 +10:00
|
|
|
column,
|
|
|
|
operator,
|
|
|
|
value,
|
2016-09-19 18:20:12 +02:00
|
|
|
bool: this._bool(),
|
|
|
|
not: this._not()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
orHaving: function orHaving() {
|
|
|
|
this._bool('or');
|
|
|
|
const obj = arguments[0];
|
|
|
|
if(isObject(obj) && !isFunction(obj) && !(obj instanceof Raw)) {
|
|
|
|
return this.havingWrapped(function() {
|
|
|
|
for(const key in obj) {
|
|
|
|
this.andHaving(key, obj[key]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return this.having.apply(this, arguments);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Helper for compiling any advanced `having` queries.
|
|
|
|
havingWrapped(callback) {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'havingWrapped',
|
|
|
|
value: callback,
|
|
|
|
bool: this._bool(),
|
|
|
|
not: this._not()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
havingNull(column) {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'havingNull',
|
|
|
|
column,
|
|
|
|
not: this._not(),
|
2015-05-09 13:58:18 -04:00
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
2016-09-19 18:20:12 +02:00
|
|
|
|
|
|
|
orHavingNull(callback) {
|
|
|
|
return this._bool('or').havingNull(callback);
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
2016-09-19 18:20:12 +02:00
|
|
|
|
|
|
|
havingNotNull(callback) {
|
|
|
|
return this._not(true).havingNull(callback);
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
2016-09-19 18:20:12 +02:00
|
|
|
|
|
|
|
orHavingNotNull(callback) {
|
|
|
|
return this._not(true)._bool('or').havingNull(callback);
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
2016-09-19 18:20:12 +02:00
|
|
|
|
|
|
|
havingExists(callback) {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'havingExists',
|
|
|
|
value: callback,
|
|
|
|
not: this._not(),
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
orHavingExists(callback) {
|
|
|
|
return this._bool('or').havingExists(callback);
|
|
|
|
},
|
|
|
|
|
|
|
|
havingNotExists(callback) {
|
|
|
|
return this._not(true).havingExists(callback);
|
|
|
|
},
|
|
|
|
|
|
|
|
orHavingNotExists(callback) {
|
|
|
|
return this._not(true)._bool('or').havingExists(callback);
|
|
|
|
},
|
|
|
|
|
|
|
|
havingBetween(column, values) {
|
|
|
|
assert(Array.isArray(values), 'The second argument to havingBetween must be an array.')
|
|
|
|
assert(values.length === 2, 'You must specify 2 values for the havingBetween clause')
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'havingBetween',
|
|
|
|
column,
|
|
|
|
value: values,
|
|
|
|
not: this._not(),
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
orHavingBetween(column, values) {
|
|
|
|
return this._bool('or').havingBetween(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
havingNotBetween(column, values) {
|
|
|
|
return this._not(true).havingBetween(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
orHavingNotBetween(column, values) {
|
|
|
|
return this._not(true)._bool('or').havingBetween(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
havingIn(column, values) {
|
|
|
|
if (Array.isArray(values) && isEmpty(values)) return this.where(this._not());
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'havingIn',
|
|
|
|
column,
|
|
|
|
value: values,
|
|
|
|
not: this._not(),
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `or where in` clause to the query.
|
|
|
|
orHavingIn(column, values) {
|
|
|
|
return this._bool('or').havingIn(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `where not in` clause to the query.
|
|
|
|
havingNotIn(column, values) {
|
|
|
|
return this._not(true).havingIn(column, values);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adds a `or where not in` clause to the query.
|
|
|
|
orHavingNotIn(column, values) {
|
|
|
|
return this._bool('or')._not(true).havingIn(column, values);
|
|
|
|
},
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Adds a raw `having` clause to the query.
|
2016-09-19 18:20:12 +02:00
|
|
|
havingRaw(sql, bindings) {
|
2016-05-17 01:01:34 +10:00
|
|
|
const raw = (sql instanceof Raw ? sql : this.client.raw(sql, bindings));
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'havingRaw',
|
|
|
|
value: raw,
|
2016-09-19 18:20:12 +02:00
|
|
|
bool: this._bool(),
|
|
|
|
not: this._not()
|
2015-05-09 13:58:18 -04:00
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2016-09-19 18:20:12 +02:00
|
|
|
orHavingRaw(sql, bindings) {
|
|
|
|
return this._bool('or').havingRaw(sql, bindings);
|
|
|
|
},
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Only allow a single "offset" to be set for the current query.
|
2016-05-17 01:01:34 +10:00
|
|
|
offset(value) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._single.offset = value;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Only allow a single "limit" to be set for the current query.
|
2016-05-17 01:01:34 +10:00
|
|
|
limit(value) {
|
|
|
|
const val = parseInt(value, 10)
|
2015-05-09 13:58:18 -04:00
|
|
|
if (isNaN(val)) {
|
|
|
|
helpers.warn('A valid integer must be provided to limit')
|
|
|
|
} else {
|
2016-01-09 07:35:12 -05:00
|
|
|
this._single.limit = val;
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Retrieve the "count" result of the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
count(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._aggregate('count', (column || '*'));
|
|
|
|
},
|
|
|
|
|
|
|
|
// Retrieve the minimum value of a given column.
|
2016-05-17 01:01:34 +10:00
|
|
|
min(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._aggregate('min', column);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Retrieve the maximum value of a given column.
|
2016-05-17 01:01:34 +10:00
|
|
|
max(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._aggregate('max', column);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Retrieve the sum of the values of a given column.
|
2016-05-17 01:01:34 +10:00
|
|
|
sum(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._aggregate('sum', column);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Retrieve the average of the values of a given column.
|
2016-05-17 01:01:34 +10:00
|
|
|
avg(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._aggregate('avg', column);
|
|
|
|
},
|
|
|
|
|
2015-11-04 12:23:20 +00:00
|
|
|
// Retrieve the "count" of the distinct results of the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
countDistinct(column) {
|
2015-11-04 12:23:20 +00:00
|
|
|
return this._aggregate('count', (column || '*'), true);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Retrieve the sum of the distinct values of a given column.
|
2016-05-17 01:01:34 +10:00
|
|
|
sumDistinct(column) {
|
2015-11-04 12:23:20 +00:00
|
|
|
return this._aggregate('sum', column, true);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Retrieve the vg of the distinct results of the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
avgDistinct(column) {
|
2015-11-04 12:23:20 +00:00
|
|
|
return this._aggregate('avg', column, true);
|
|
|
|
},
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Increments a column's value by the specified amount.
|
2016-05-17 01:01:34 +10:00
|
|
|
increment(column, amount) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._counter(column, amount);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Decrements a column's value by the specified amount.
|
2016-05-17 01:01:34 +10:00
|
|
|
decrement(column, amount) {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._counter(column, amount, '-');
|
|
|
|
},
|
|
|
|
|
|
|
|
// Sets the values for a `select` query, informing that only the first
|
|
|
|
// row should be returned (limit 1).
|
2016-05-17 01:01:34 +10:00
|
|
|
first() {
|
2018-02-22 12:33:55 +01:00
|
|
|
const {_method} = this;
|
|
|
|
|
|
|
|
if(!includes(['pluck', 'first', 'select'], _method)) {
|
|
|
|
throw new Error(`Cannot chain .first() on "${_method}" query!`);
|
|
|
|
}
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
const args = new Array(arguments.length);
|
|
|
|
for (let i = 0; i < args.length; i++) {
|
2015-05-09 13:58:18 -04:00
|
|
|
args[i] = arguments[i];
|
|
|
|
}
|
|
|
|
this.select.apply(this, args);
|
|
|
|
this._method = 'first';
|
|
|
|
this.limit(1);
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Pluck a column from a query.
|
2016-05-17 01:01:34 +10:00
|
|
|
pluck(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._method = 'pluck';
|
|
|
|
this._single.pluck = column;
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'columns',
|
|
|
|
type: 'pluck',
|
|
|
|
value: column
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-02-20 13:12:14 -05:00
|
|
|
// Remove everything from select clause
|
|
|
|
clearSelect(){
|
|
|
|
this._clearGrouping('columns');
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Remove everything from select clause
|
|
|
|
clearWhere(){
|
|
|
|
this._clearGrouping('where');
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Insert & Update
|
|
|
|
// ------
|
|
|
|
|
|
|
|
// Sets the values for an `insert` query.
|
2016-05-17 01:01:34 +10:00
|
|
|
insert(values, returning) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._method = 'insert';
|
2016-03-02 16:52:32 +01:00
|
|
|
if (!isEmpty(returning)) this.returning(returning);
|
2015-05-09 13:58:18 -04:00
|
|
|
this._single.insert = values
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Sets the values for an `update`, allowing for both
|
|
|
|
// `.update(key, value, [returning])` and `.update(obj, [returning])` syntaxes.
|
2016-05-17 01:01:34 +10:00
|
|
|
update(values, returning) {
|
|
|
|
let ret;
|
|
|
|
const obj = this._single.update || {};
|
2015-05-09 13:58:18 -04:00
|
|
|
this._method = 'update';
|
2016-03-02 16:52:32 +01:00
|
|
|
if (isString(values)) {
|
2015-05-09 13:58:18 -04:00
|
|
|
obj[values] = returning;
|
|
|
|
if (arguments.length > 2) {
|
|
|
|
ret = arguments[2];
|
|
|
|
}
|
|
|
|
} else {
|
2016-05-17 01:01:34 +10:00
|
|
|
const keys = Object.keys(values);
|
2015-05-09 13:58:18 -04:00
|
|
|
if (this._single.update) {
|
|
|
|
helpers.warn('Update called multiple times with objects.')
|
|
|
|
}
|
2016-05-17 01:01:34 +10:00
|
|
|
let i = -1;
|
2015-05-09 13:58:18 -04:00
|
|
|
while (++i < keys.length) {
|
|
|
|
obj[keys[i]] = values[keys[i]]
|
|
|
|
}
|
|
|
|
ret = arguments[1];
|
|
|
|
}
|
2016-03-02 16:52:32 +01:00
|
|
|
if (!isEmpty(ret)) this.returning(ret);
|
2015-05-09 13:58:18 -04:00
|
|
|
this._single.update = obj;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Sets the returning value for the query.
|
2016-05-17 01:01:34 +10:00
|
|
|
returning(returning) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._single.returning = returning;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Delete
|
|
|
|
// ------
|
|
|
|
|
|
|
|
// Executes a delete statement on the query;
|
2016-05-17 01:01:34 +10:00
|
|
|
delete(ret) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._method = 'del';
|
2016-03-02 16:52:32 +01:00
|
|
|
if (!isEmpty(ret)) this.returning(ret);
|
2015-05-09 13:58:18 -04:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// Truncates a table, ends the query chain.
|
2016-05-17 01:01:34 +10:00
|
|
|
truncate(tableName) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._method = 'truncate';
|
|
|
|
if (tableName) {
|
|
|
|
this._single.table = tableName
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Retrieves columns for the table specified by `knex(tableName)`
|
2016-05-17 01:01:34 +10:00
|
|
|
columnInfo(column) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._method = 'columnInfo';
|
|
|
|
this._single.columnInfo = column;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Set a lock for update constraint.
|
2016-05-17 01:01:34 +10:00
|
|
|
forUpdate() {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._single.lock = 'forUpdate';
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Set a lock for share constraint.
|
2016-05-17 01:01:34 +10:00
|
|
|
forShare() {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._single.lock = 'forShare';
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Takes a JS object of methods to call and calls them
|
2016-05-17 01:01:34 +10:00
|
|
|
fromJS(obj) {
|
2016-03-02 16:52:32 +01:00
|
|
|
each(obj, (val, key) => {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (typeof this[key] !== 'function') {
|
2016-05-17 01:01:34 +10:00
|
|
|
helpers.warn(`Knex Error: unknown key ${key}`)
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
|
|
|
if (Array.isArray(val)) {
|
|
|
|
this[key].apply(this, val)
|
|
|
|
} else {
|
|
|
|
this[key](val)
|
|
|
|
}
|
2016-03-02 16:52:32 +01:00
|
|
|
})
|
2015-05-09 13:58:18 -04:00
|
|
|
return this
|
|
|
|
},
|
|
|
|
|
2015-06-30 09:19:35 +01:00
|
|
|
// Passes query to provided callback function, useful for e.g. composing
|
|
|
|
// domain-specific helpers
|
2016-05-17 01:01:34 +10:00
|
|
|
modify(callback) {
|
2016-03-02 16:52:32 +01:00
|
|
|
callback.apply(this, [this].concat(tail(arguments)));
|
2015-06-30 09:19:35 +01:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Helper for the incrementing/decrementing queries.
|
2016-05-17 01:01:34 +10:00
|
|
|
_counter(column, amount, symbol) {
|
|
|
|
let amt = parseInt(amount, 10);
|
2015-05-09 13:58:18 -04:00
|
|
|
if (isNaN(amt)) amt = 1;
|
|
|
|
this._method = 'counter';
|
|
|
|
this._single.counter = {
|
2016-05-17 01:01:34 +10:00
|
|
|
column,
|
2015-05-09 13:58:18 -04:00
|
|
|
amount: amt,
|
|
|
|
symbol: (symbol || '+')
|
|
|
|
};
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Helper to get or set the "boolFlag" value.
|
2016-05-17 01:01:34 +10:00
|
|
|
_bool(val) {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (arguments.length === 1) {
|
|
|
|
this._boolFlag = val;
|
|
|
|
return this;
|
|
|
|
}
|
2016-05-17 01:01:34 +10:00
|
|
|
const ret = this._boolFlag;
|
2015-05-09 13:58:18 -04:00
|
|
|
this._boolFlag = 'and';
|
|
|
|
return ret;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Helper to get or set the "notFlag" value.
|
2016-05-17 01:01:34 +10:00
|
|
|
_not(val) {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (arguments.length === 1) {
|
|
|
|
this._notFlag = val;
|
|
|
|
return this;
|
|
|
|
}
|
2016-05-17 01:01:34 +10:00
|
|
|
const ret = this._notFlag;
|
2015-05-09 13:58:18 -04:00
|
|
|
this._notFlag = false;
|
|
|
|
return ret;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Helper to get or set the "joinFlag" value.
|
2016-05-17 01:01:34 +10:00
|
|
|
_joinType (val) {
|
2015-05-09 13:58:18 -04:00
|
|
|
if (arguments.length === 1) {
|
|
|
|
this._joinFlag = val;
|
|
|
|
return this;
|
|
|
|
}
|
2016-05-17 01:01:34 +10:00
|
|
|
const ret = this._joinFlag || 'inner';
|
2015-05-09 13:58:18 -04:00
|
|
|
this._joinFlag = 'inner';
|
|
|
|
return ret;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Helper for compiling any aggregate queries.
|
2016-05-17 01:01:34 +10:00
|
|
|
_aggregate(method, column, aggregateDistinct) {
|
2015-05-09 13:58:18 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'columns',
|
Allow raw expressions in query builder aggregate methods (#2257)
The aggregate methods include `count`, `min`, `max`, `sum`, `avg`,
`countDistinct`, `sumDistinct`, and `avgDistinct`, all of which
can now receive raw expressions, e.g.
```js
knex('users').count(knex.raw("data->'active'"));
```
There seems to be some demand for this, and I think it's cleaner than the alternative of
```js
knex('users').select(knex.raw("count(data->'active')"));
```
2017-10-14 08:19:06 -07:00
|
|
|
type: column instanceof Raw ? 'aggregateRaw' : 'aggregate',
|
2016-05-17 01:01:34 +10:00
|
|
|
method,
|
2015-11-04 12:23:20 +00:00
|
|
|
value: column,
|
|
|
|
aggregateDistinct: aggregateDistinct || false
|
2015-05-09 13:58:18 -04:00
|
|
|
});
|
|
|
|
return this;
|
2017-02-20 13:12:14 -05:00
|
|
|
},
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2017-02-20 13:12:14 -05:00
|
|
|
// Helper function for clearing or reseting a grouping type from the builder
|
|
|
|
_clearGrouping(grouping){
|
|
|
|
this._statements = reject(this._statements, { grouping });
|
|
|
|
}
|
2015-05-09 13:58:18 -04:00
|
|
|
})
|
|
|
|
|
2015-05-12 21:48:02 -04:00
|
|
|
Object.defineProperty(Builder.prototype, 'or', {
|
2016-05-17 01:01:34 +10:00
|
|
|
get () {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._bool('or');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-05-12 21:48:02 -04:00
|
|
|
Object.defineProperty(Builder.prototype, 'not', {
|
2016-05-17 01:01:34 +10:00
|
|
|
get () {
|
2015-05-09 13:58:18 -04:00
|
|
|
return this._not(true);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-05-18 19:59:24 +10:00
|
|
|
Builder.prototype.select = Builder.prototype.columns
|
|
|
|
Builder.prototype.column = Builder.prototype.columns
|
|
|
|
Builder.prototype.andWhereNot = Builder.prototype.whereNot
|
|
|
|
Builder.prototype.andWhere = Builder.prototype.where
|
|
|
|
Builder.prototype.andWhereRaw = Builder.prototype.whereRaw
|
|
|
|
Builder.prototype.andWhereBetween = Builder.prototype.whereBetween
|
2016-01-09 07:35:12 -05:00
|
|
|
Builder.prototype.andWhereNotBetween = Builder.prototype.whereNotBetween
|
2016-05-18 19:59:24 +10:00
|
|
|
Builder.prototype.andHaving = Builder.prototype.having
|
2016-09-19 18:20:12 +02:00
|
|
|
Builder.prototype.andHavingIn = Builder.prototype.havingIn
|
|
|
|
Builder.prototype.andHavingNotIn = Builder.prototype.havingNotIn
|
|
|
|
Builder.prototype.andHavingNull = Builder.prototype.havingNull
|
|
|
|
Builder.prototype.andHavingNotNull = Builder.prototype.havingNotNull
|
|
|
|
Builder.prototype.andHavingExists = Builder.prototype.havingExists
|
|
|
|
Builder.prototype.andHavingNotExists = Builder.prototype.havingNotExists
|
|
|
|
Builder.prototype.andHavingBetween = Builder.prototype.havingBetween
|
|
|
|
Builder.prototype.andHavingNotBetween = Builder.prototype.havingNotBetween
|
2016-05-18 19:59:24 +10:00
|
|
|
Builder.prototype.from = Builder.prototype.table
|
|
|
|
Builder.prototype.into = Builder.prototype.table
|
|
|
|
Builder.prototype.del = Builder.prototype.delete
|
2015-05-09 13:58:18 -04:00
|
|
|
|
|
|
|
// Attach all of the top level promise methods that should be chainable.
|
2015-05-12 21:48:02 -04:00
|
|
|
require('../interface')(Builder);
|
2018-02-01 23:41:01 +01:00
|
|
|
helpers.addQueryContext(Builder);
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
export default Builder;
|