2014-09-01 17:18:45 +02:00
|
|
|
'use strict';
|
|
|
|
|
2014-04-08 16:25:57 -04:00
|
|
|
// Builder
|
|
|
|
// -------
|
2014-04-27 19:35:36 -04:00
|
|
|
var _ = require('lodash');
|
|
|
|
var inherits = require('inherits');
|
|
|
|
var EventEmitter = require('events').EventEmitter;
|
2014-04-08 16:25:57 -04:00
|
|
|
|
2014-04-27 19:35:36 -04:00
|
|
|
var Raw = require('../raw');
|
|
|
|
var helpers = require('../helpers');
|
2014-04-08 16:25:57 -04:00
|
|
|
|
|
|
|
var JoinClause = require('./joinclause');
|
|
|
|
|
2014-04-15 11:43:47 -04:00
|
|
|
// Typically called from `knex.builder`,
|
|
|
|
// start a new query building chain.
|
2014-04-08 16:25:57 -04:00
|
|
|
function QueryBuilder() {
|
|
|
|
this._single = {};
|
|
|
|
this._statements = [];
|
|
|
|
this._errors = [];
|
|
|
|
|
|
|
|
// Internal flags used in the builder.
|
|
|
|
this._joinFlag = 'inner';
|
|
|
|
this._boolFlag = 'and';
|
2014-10-01 15:22:49 -04:00
|
|
|
this._notFlag = false;
|
2014-07-01 08:53:35 -04:00
|
|
|
|
|
|
|
this.and = this;
|
2014-04-08 16:25:57 -04:00
|
|
|
}
|
2014-04-27 19:35:36 -04:00
|
|
|
inherits(QueryBuilder, EventEmitter);
|
2014-04-08 16:25:57 -04:00
|
|
|
|
|
|
|
QueryBuilder.prototype.toString = function() {
|
|
|
|
return this.toQuery();
|
|
|
|
};
|
|
|
|
|
2014-04-15 11:43:47 -04:00
|
|
|
// Convert the current query "toSQL"
|
2014-04-09 10:11:41 -04:00
|
|
|
QueryBuilder.prototype.toSQL = function() {
|
|
|
|
var QueryCompiler = this.client.QueryCompiler;
|
|
|
|
return new QueryCompiler(this).toSQL(this._method || 'select');
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Create a shallow clone of the current query builder.
|
|
|
|
// TODO: Test this!!
|
|
|
|
QueryBuilder.prototype.clone = function() {
|
2014-04-21 19:56:01 -04:00
|
|
|
var cloned = new this.constructor();
|
|
|
|
cloned._method = this._method;
|
2014-04-08 16:25:57 -04:00
|
|
|
cloned._single = _.clone(this._single);
|
2014-04-21 09:50:30 -04:00
|
|
|
cloned._options = _.clone(this._options);
|
2014-04-08 16:25:57 -04:00
|
|
|
cloned._statements = this._statements.slice();
|
|
|
|
cloned._errors = this._errors.slice();
|
|
|
|
cloned._debug = this._debug;
|
|
|
|
cloned._transacting = this._transacting;
|
|
|
|
cloned._connection = this._connection;
|
|
|
|
return cloned;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Select
|
|
|
|
// ------
|
|
|
|
|
|
|
|
// Sets the values for a `select` query,
|
|
|
|
// which is the same as specifying the columns.
|
|
|
|
QueryBuilder.prototype.select =
|
|
|
|
|
|
|
|
// Adds a column or columns to the list of "columns"
|
|
|
|
// being selected on the query.
|
|
|
|
QueryBuilder.prototype.columns =
|
2014-06-06 17:27:09 -04:00
|
|
|
QueryBuilder.prototype.column = function(column) {
|
2014-09-02 22:19:22 +02:00
|
|
|
if (!column) return this;
|
2014-04-08 16:25:57 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'columns',
|
2014-04-16 04:29:20 -04:00
|
|
|
value: helpers.normalizeArr.apply(null, arguments)
|
2014-04-08 16:25:57 -04:00
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-06-14 16:26:01 -04:00
|
|
|
// Allow for a sub-select to be explicitly aliased as a column,
|
|
|
|
// without needing to compile the query in a where.
|
|
|
|
QueryBuilder.prototype.as = function(column) {
|
|
|
|
this._single.as = column;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-04-08 16:25:57 -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')
|
|
|
|
QueryBuilder.prototype.table = function(tableName) {
|
|
|
|
this._single.table = tableName;
|
|
|
|
return this;
|
|
|
|
};
|
2014-04-15 13:10:32 -04:00
|
|
|
QueryBuilder.prototype.from = QueryBuilder.prototype.table;
|
|
|
|
QueryBuilder.prototype.into = QueryBuilder.prototype.table;
|
2014-04-08 16:25:57 -04:00
|
|
|
|
|
|
|
// Adds a `distinct` clause to the query.
|
|
|
|
QueryBuilder.prototype.distinct = function() {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'columns',
|
2014-04-16 04:29:20 -04:00
|
|
|
value: helpers.normalizeArr.apply(null, arguments),
|
2014-04-08 16:25:57 -04:00
|
|
|
distinct: true
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a join clause to the query, allowing for advanced joins
|
|
|
|
// with an anonymous function as the second argument.
|
2014-09-29 10:05:53 +02:00
|
|
|
// function(table, first, operator, second)
|
|
|
|
QueryBuilder.prototype.join = function(table, first) {
|
2014-04-08 16:25:57 -04:00
|
|
|
var join;
|
2014-08-14 18:02:50 -04:00
|
|
|
var joinType = this._joinType();
|
2014-08-31 12:20:31 -04:00
|
|
|
if (_.isFunction(first)) {
|
2014-08-14 18:02:50 -04:00
|
|
|
join = new JoinClause(table, joinType);
|
2014-04-08 16:25:57 -04:00
|
|
|
first.call(join, join);
|
2014-08-14 18:02:50 -04:00
|
|
|
} else if (joinType === 'raw') {
|
|
|
|
join = new JoinClause(new Raw(table, first), 'raw');
|
2014-04-08 16:25:57 -04:00
|
|
|
} else {
|
2014-08-14 18:02:50 -04:00
|
|
|
join = new JoinClause(table, joinType);
|
2014-09-29 10:05:53 +02:00
|
|
|
if (arguments.length > 1) {
|
|
|
|
join.on.apply(join, _.toArray(arguments).slice(1));
|
|
|
|
}
|
2014-04-08 16:25:57 -04:00
|
|
|
}
|
|
|
|
this._statements.push(join);
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// JOIN blocks:
|
|
|
|
QueryBuilder.prototype.innerJoin = function() {
|
|
|
|
return this._joinType('inner').join.apply(this, arguments);
|
|
|
|
};
|
|
|
|
QueryBuilder.prototype.leftJoin = function() {
|
|
|
|
return this._joinType('left').join.apply(this, arguments);
|
|
|
|
};
|
|
|
|
QueryBuilder.prototype.leftOuterJoin = function() {
|
|
|
|
return this._joinType('left outer').join.apply(this, arguments);
|
|
|
|
};
|
|
|
|
QueryBuilder.prototype.rightJoin = function() {
|
|
|
|
return this._joinType('right').join.apply(this, arguments);
|
|
|
|
};
|
|
|
|
QueryBuilder.prototype.rightOuterJoin = function() {
|
|
|
|
return this._joinType('right outer').join.apply(this, arguments);
|
|
|
|
};
|
|
|
|
QueryBuilder.prototype.outerJoin = function() {
|
|
|
|
return this._joinType('outer').join.apply(this, arguments);
|
|
|
|
};
|
|
|
|
QueryBuilder.prototype.fullOuterJoin = function() {
|
|
|
|
return this._joinType('full outer').join.apply(this, arguments);
|
|
|
|
};
|
|
|
|
QueryBuilder.prototype.crossJoin = function() {
|
|
|
|
return this._joinType('cross').join.apply(this, arguments);
|
|
|
|
};
|
2014-08-14 18:02:50 -04:00
|
|
|
QueryBuilder.prototype.joinRaw = function() {
|
|
|
|
return this._joinType('raw').join.apply(this, arguments);
|
2014-08-14 16:00:06 -04:00
|
|
|
};
|
2014-04-08 16:25:57 -04:00
|
|
|
|
|
|
|
// The where function can be used in several ways:
|
|
|
|
// The most basic is `where(key, value)`, which expands to
|
|
|
|
// where key = value.
|
|
|
|
QueryBuilder.prototype.where =
|
|
|
|
QueryBuilder.prototype.andWhere = function(column, operator, value) {
|
|
|
|
|
2014-10-01 15:50:48 -04:00
|
|
|
// Support "where true || where false"
|
|
|
|
if (column === false || column === true) {
|
|
|
|
return this.whereRaw(column);
|
|
|
|
}
|
|
|
|
|
2014-04-08 16:25:57 -04:00
|
|
|
// Check if the column is a function, in which case it's
|
|
|
|
// a where statement wrapped in parens.
|
|
|
|
if (_.isFunction(column)) {
|
|
|
|
return this.whereWrapped(column);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow a raw statement to be passed along to the query.
|
2014-05-09 14:42:29 -04:00
|
|
|
if (column instanceof Raw) return this.whereRaw(column);
|
2014-04-08 16:25:57 -04:00
|
|
|
|
|
|
|
// Allows `where({id: 2})` syntax.
|
2014-04-09 10:11:41 -04:00
|
|
|
if (_.isObject(column)) return this._objectWhere(column);
|
2014-04-08 16:25:57 -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) {
|
|
|
|
value = operator;
|
|
|
|
operator = '=';
|
2014-05-09 14:42:29 -04:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
2014-04-08 16:25:57 -04:00
|
|
|
}
|
|
|
|
|
2014-04-16 02:50:19 -04:00
|
|
|
// lower case the operator for comparison purposes
|
2014-05-09 14:42:29 -04:00
|
|
|
var checkOperator = ('' + operator).toLowerCase().trim();
|
|
|
|
|
|
|
|
// If there are 3 arguments, check whether 'in' is one of them.
|
|
|
|
if (arguments.length === 3) {
|
|
|
|
if (checkOperator === 'in' || checkOperator === 'not in') {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._not(checkOperator === 'not in').whereIn(arguments[0], arguments[2]);
|
2014-05-09 14:42:29 -04:00
|
|
|
}
|
|
|
|
if (checkOperator === 'between' || checkOperator === 'not between') {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._not(checkOperator === 'not between').whereBetween(arguments[0], arguments[2]);
|
2014-04-16 02:50:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-09 14:42:29 -04:00
|
|
|
// 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') {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._not(checkOperator === 'is not').whereNull(column);
|
2014-05-09 14:42:29 -04:00
|
|
|
}
|
2014-04-08 16:25:57 -04:00
|
|
|
}
|
|
|
|
|
2014-05-09 14:42:29 -04:00
|
|
|
// Push onto the where statement stack.
|
2014-04-08 16:25:57 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereBasic',
|
|
|
|
column: column,
|
|
|
|
operator: operator,
|
|
|
|
value: value,
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
2014-05-09 14:42:29 -04:00
|
|
|
// Adds an `or where` clause to the query.
|
|
|
|
QueryBuilder.prototype.orWhere = function() {
|
|
|
|
return this._bool('or').where.apply(this, arguments);
|
|
|
|
};
|
2014-04-08 16:25:57 -04:00
|
|
|
|
2014-04-09 10:11:41 -04:00
|
|
|
// Processes an object literal provided in a "where" clause.
|
|
|
|
QueryBuilder.prototype._objectWhere = function(obj) {
|
|
|
|
var boolVal = this._bool();
|
|
|
|
for (var key in obj) {
|
2014-05-09 14:42:29 -04:00
|
|
|
this[boolVal + 'Where'](key, obj[key]);
|
2014-04-09 10:11:41 -04:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-04-21 08:24:23 -04:00
|
|
|
// Adds a raw `where` clause to the query.
|
2014-05-09 14:42:29 -04:00
|
|
|
QueryBuilder.prototype.whereRaw =
|
|
|
|
QueryBuilder.prototype.andWhereRaw = function(sql, bindings) {
|
2014-04-08 16:25:57 -04:00
|
|
|
var raw = (sql instanceof Raw ? sql : new Raw(sql, bindings));
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereRaw',
|
|
|
|
value: raw,
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
2014-05-09 14:42:29 -04:00
|
|
|
QueryBuilder.prototype.orWhereRaw = function(sql, bindings) {
|
|
|
|
return this._bool('or').whereRaw(sql, bindings);
|
|
|
|
};
|
2014-04-08 16:25:57 -04:00
|
|
|
|
|
|
|
// Helper for compiling any advanced `where` queries.
|
|
|
|
QueryBuilder.prototype.whereWrapped = function(callback) {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereWrapped',
|
|
|
|
value: callback,
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-11-20 20:52:18 +01:00
|
|
|
// Helper for compiling any advanced `having` queries.
|
|
|
|
QueryBuilder.prototype.havingWrapped = function(callback) {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'whereWrapped',
|
|
|
|
value: callback,
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-04-08 16:25:57 -04:00
|
|
|
// Adds a `where exists` clause to the query.
|
2014-10-01 15:22:49 -04:00
|
|
|
QueryBuilder.prototype.whereExists = function(callback) {
|
2014-04-08 16:25:57 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereExists',
|
|
|
|
value: callback,
|
2014-10-01 15:22:49 -04:00
|
|
|
not: this._not(),
|
2014-04-08 16:25:57 -04:00
|
|
|
bool: this._bool(),
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds an `or where exists` clause to the query.
|
|
|
|
QueryBuilder.prototype.orWhereExists = function(callback) {
|
|
|
|
return this._bool('or').whereExists(callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `where not exists` clause to the query.
|
|
|
|
QueryBuilder.prototype.whereNotExists = function(callback) {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._not(true).whereExists(callback);
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `or where not exists` clause to the query.
|
|
|
|
QueryBuilder.prototype.orWhereNotExists = function(callback) {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._bool('or').whereNotExists(callback);
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `where in` clause to the query.
|
2014-10-01 15:22:49 -04:00
|
|
|
QueryBuilder.prototype.whereIn = function(column, values) {
|
2014-10-01 15:50:48 -04:00
|
|
|
if (_.isArray(values) && _.isEmpty(values)) return this.where(this._not());
|
2014-04-08 16:25:57 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereIn',
|
|
|
|
column: column,
|
|
|
|
value: values,
|
2014-10-01 15:22:49 -04:00
|
|
|
not: this._not(),
|
2014-04-08 16:25:57 -04:00
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `or where in` clause to the query.
|
|
|
|
QueryBuilder.prototype.orWhereIn = function(column, values) {
|
|
|
|
return this._bool('or').whereIn(column, values);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `where not in` clause to the query.
|
|
|
|
QueryBuilder.prototype.whereNotIn = function(column, values) {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._not(true).whereIn(column, values);
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `or where not in` clause to the query.
|
|
|
|
QueryBuilder.prototype.orWhereNotIn = function(column, values) {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._bool('or')._not(true).whereIn(column, values);
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `where null` clause to the query.
|
2014-10-01 15:22:49 -04:00
|
|
|
QueryBuilder.prototype.whereNull = function(column) {
|
2014-04-08 16:25:57 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereNull',
|
|
|
|
column: column,
|
2014-10-01 15:22:49 -04:00
|
|
|
not: this._not(),
|
2014-04-08 16:25:57 -04:00
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `or where null` clause to the query.
|
|
|
|
QueryBuilder.prototype.orWhereNull = function(column) {
|
|
|
|
return this._bool('or').whereNull(column);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `where not null` clause to the query.
|
|
|
|
QueryBuilder.prototype.whereNotNull = function(column) {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._not(true).whereNull(column);
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `or where not null` clause to the query.
|
|
|
|
QueryBuilder.prototype.orWhereNotNull = function(column) {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._bool('or').whereNotNull(column);
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `where between` clause to the query.
|
2014-10-01 15:22:49 -04:00
|
|
|
QueryBuilder.prototype.whereBetween = function(column, values) {
|
2014-04-08 16:25:57 -04:00
|
|
|
if (!_.isArray(values)) {
|
|
|
|
return this._errors.push(new Error('The second argument to whereBetween must be an array.'));
|
|
|
|
}
|
|
|
|
if (values.length !== 2) {
|
|
|
|
return this._errors.push(new Error('You must specify 2 values for the whereBetween clause'));
|
|
|
|
}
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'where',
|
|
|
|
type: 'whereBetween',
|
|
|
|
column: column,
|
|
|
|
value: values,
|
2014-10-01 15:22:49 -04:00
|
|
|
not: this._not(),
|
2014-04-08 16:25:57 -04:00
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `where not between` clause to the query.
|
|
|
|
QueryBuilder.prototype.whereNotBetween = function(column, values) {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._not(true).whereBetween(column, values);
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `or where between` clause to the query.
|
|
|
|
QueryBuilder.prototype.orWhereBetween = function(column, values) {
|
|
|
|
return this._bool('or').whereBetween(column, values);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `or where not between` clause to the query.
|
|
|
|
QueryBuilder.prototype.orWhereNotBetween = function(column, values) {
|
2014-10-01 15:22:49 -04:00
|
|
|
return this._bool('or').whereNotBetween(column, values);
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `group by` clause to the query.
|
2014-06-27 11:48:09 -04:00
|
|
|
QueryBuilder.prototype.groupBy = function(item) {
|
|
|
|
if (item instanceof Raw) {
|
|
|
|
return this.groupByRaw.apply(this, arguments);
|
|
|
|
}
|
2014-04-08 16:25:57 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'group',
|
2014-06-27 11:48:09 -04:00
|
|
|
type: 'groupByBasic',
|
2014-04-16 04:29:20 -04:00
|
|
|
value: helpers.normalizeArr.apply(null, arguments)
|
2014-04-08 16:25:57 -04:00
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-06-27 11:48:09 -04:00
|
|
|
// Adds a raw `group by` clause to the query.
|
|
|
|
QueryBuilder.prototype.groupByRaw = function(sql, bindings) {
|
|
|
|
var raw = (sql instanceof Raw ? sql : new Raw(sql, bindings));
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'group',
|
|
|
|
type: 'groupByRaw',
|
|
|
|
value: raw
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-04-08 16:25:57 -04:00
|
|
|
// Adds a `order by` clause to the query.
|
|
|
|
QueryBuilder.prototype.orderBy = function(column, direction) {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'order',
|
2014-06-27 11:48:09 -04:00
|
|
|
type: 'orderByBasic',
|
2014-04-08 16:25:57 -04:00
|
|
|
value: column,
|
|
|
|
direction: direction
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-06-27 11:48:09 -04:00
|
|
|
// Add a raw `order by` clause to the query.
|
|
|
|
QueryBuilder.prototype.orderByRaw = function(sql, bindings) {
|
|
|
|
var raw = (sql instanceof Raw ? sql : new Raw(sql, bindings));
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'order',
|
|
|
|
type: 'orderByRaw',
|
|
|
|
value: raw
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-04-08 16:25:57 -04:00
|
|
|
// Add a union statement to the query.
|
2015-02-03 12:33:17 -05:00
|
|
|
QueryBuilder.prototype.union = function(callbacks, wrap) {
|
|
|
|
if (arguments.length === 1 ||
|
|
|
|
(arguments.length === 2 && _.isBoolean(wrap))) {
|
|
|
|
if (!_.isArray(callbacks)) {
|
|
|
|
callbacks = [callbacks];
|
2014-04-08 16:25:57 -04:00
|
|
|
}
|
2015-02-03 12:33:17 -05:00
|
|
|
for (var i = 0, l = callbacks.length; i < l; i++) {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'union',
|
|
|
|
clause: 'union',
|
|
|
|
value: callbacks[i],
|
|
|
|
wrap: wrap || false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
callbacks = _.toArray(arguments).slice(0, arguments.length - 2);
|
|
|
|
wrap = arguments[arguments.length - 1];
|
|
|
|
if (!_.isBoolean(wrap)) {
|
|
|
|
callbacks.push(wrap);
|
|
|
|
wrap = undefined;
|
|
|
|
}
|
|
|
|
this.union(callbacks, wrap);
|
2014-04-08 16:25:57 -04:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a union all statement to the query.
|
|
|
|
QueryBuilder.prototype.unionAll = function(callback, wrap) {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'union',
|
|
|
|
clause: 'union all',
|
|
|
|
value: callback,
|
|
|
|
wrap: wrap || false
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds a `having` clause to the query.
|
2014-05-09 15:03:48 -04:00
|
|
|
QueryBuilder.prototype.having =
|
|
|
|
QueryBuilder.prototype.andHaving = function(column, operator, value) {
|
2014-04-08 16:25:57 -04:00
|
|
|
if (column instanceof Raw && arguments.length === 1) {
|
2014-04-21 09:33:24 -04:00
|
|
|
return this._havingRaw(column);
|
2014-04-08 16:25:57 -04:00
|
|
|
}
|
2014-11-20 20:52:18 +01:00
|
|
|
|
|
|
|
// Check if the column is a function, in which case it's
|
|
|
|
// a having statement wrapped in parens.
|
|
|
|
if (_.isFunction(column)) {
|
|
|
|
return this.havingWrapped(column);
|
|
|
|
}
|
|
|
|
|
2014-04-08 16:25:57 -04:00
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'havingBasic',
|
|
|
|
column: column,
|
|
|
|
operator: operator,
|
|
|
|
value: value,
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
2014-04-21 09:33:24 -04:00
|
|
|
// Adds an `or having` clause to the query.
|
|
|
|
QueryBuilder.prototype.orHaving = function() {
|
|
|
|
return this._bool('or').having.apply(this, arguments);
|
|
|
|
};
|
2014-04-08 16:25:57 -04:00
|
|
|
QueryBuilder.prototype.havingRaw = function(sql, bindings) {
|
2014-04-21 09:33:24 -04:00
|
|
|
return this._havingRaw(sql, bindings);
|
|
|
|
};
|
|
|
|
QueryBuilder.prototype.orHavingRaw = function(sql, bindings) {
|
|
|
|
return this._bool('or').havingRaw(sql, bindings);
|
|
|
|
};
|
|
|
|
// Adds a raw `having` clause to the query.
|
|
|
|
QueryBuilder.prototype._havingRaw = function(sql, bindings) {
|
2014-04-08 16:25:57 -04:00
|
|
|
var raw = (sql instanceof Raw ? sql : new Raw(sql, bindings));
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'having',
|
|
|
|
type: 'havingRaw',
|
|
|
|
value: raw,
|
|
|
|
bool: this._bool()
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Only allow a single "offset" to be set for the current query.
|
|
|
|
QueryBuilder.prototype.offset = function(value) {
|
|
|
|
this._single.offset = value;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Only allow a single "limit" to be set for the current query.
|
|
|
|
QueryBuilder.prototype.limit = function(value) {
|
|
|
|
this._single.limit = value;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Retrieve the "count" result of the query.
|
|
|
|
QueryBuilder.prototype.count = function(column) {
|
|
|
|
return this._aggregate('count', (column || '*'));
|
|
|
|
};
|
|
|
|
|
|
|
|
// Retrieve the minimum value of a given column.
|
|
|
|
QueryBuilder.prototype.min = function(column) {
|
|
|
|
return this._aggregate('min', column);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Retrieve the maximum value of a given column.
|
|
|
|
QueryBuilder.prototype.max = function(column) {
|
|
|
|
return this._aggregate('max', column);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Retrieve the sum of the values of a given column.
|
|
|
|
QueryBuilder.prototype.sum = function(column) {
|
|
|
|
return this._aggregate('sum', column);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Retrieve the average of the values of a given column.
|
|
|
|
QueryBuilder.prototype.avg = function(column) {
|
|
|
|
return this._aggregate('avg', column);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Increments a column's value by the specified amount.
|
|
|
|
QueryBuilder.prototype.increment = function(column, amount) {
|
|
|
|
return this._counter(column, amount);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Decrements a column's value by the specified amount.
|
|
|
|
QueryBuilder.prototype.decrement = function(column, amount) {
|
|
|
|
return this._counter(column, amount, '-');
|
|
|
|
};
|
|
|
|
|
|
|
|
// Sets the values for a `select` query, informing that only the first
|
|
|
|
// row should be returned (limit 1).
|
|
|
|
QueryBuilder.prototype.first = function() {
|
2014-04-16 03:22:47 -04:00
|
|
|
var i, args = new Array(arguments.length);
|
2014-04-08 16:25:57 -04:00
|
|
|
for (i = 0; i < args.length; i++) {
|
|
|
|
args[i] = arguments[i];
|
|
|
|
}
|
|
|
|
this.select.apply(this, args);
|
|
|
|
this._method = 'first';
|
|
|
|
this.limit(1);
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Pluck a column from a query.
|
|
|
|
QueryBuilder.prototype.pluck = function(column) {
|
|
|
|
this._method = 'pluck';
|
2014-06-04 16:24:29 -04:00
|
|
|
this._single.pluck = column;
|
2014-04-08 16:25:57 -04:00
|
|
|
this._statements.push({
|
2014-06-04 16:24:29 -04:00
|
|
|
grouping: 'columns',
|
2014-04-08 16:25:57 -04:00
|
|
|
type: 'pluck',
|
|
|
|
value: column
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Insert & Update
|
|
|
|
// ------
|
|
|
|
|
|
|
|
// Sets the values for an `insert` query.
|
|
|
|
QueryBuilder.prototype.insert = function(values, returning) {
|
|
|
|
this._method = 'insert';
|
|
|
|
if (!_.isEmpty(returning)) this.returning(returning);
|
|
|
|
this._single.insert = values;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Sets the values for an `update`, allowing for both
|
|
|
|
// `.update(key, value, [returning])` and `.update(obj, [returning])` syntaxes.
|
|
|
|
QueryBuilder.prototype.update = function(values, returning) {
|
|
|
|
var ret, obj = {};
|
|
|
|
this._method = 'update';
|
2014-04-16 02:50:19 -04:00
|
|
|
var i, args = new Array(arguments.length);
|
2014-04-08 16:25:57 -04:00
|
|
|
for (i = 0; i < args.length; i++) {
|
|
|
|
args[i] = arguments[i];
|
|
|
|
}
|
|
|
|
if (_.isString(values)) {
|
|
|
|
obj[values] = returning;
|
|
|
|
if (args.length > 2) {
|
|
|
|
ret = args[2];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
obj = values;
|
|
|
|
ret = args[1];
|
|
|
|
}
|
|
|
|
if (!_.isEmpty(ret)) this.returning(ret);
|
|
|
|
this._single.update = obj;
|
2014-04-15 11:43:47 -04:00
|
|
|
return this;
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Sets the returning value for the query.
|
|
|
|
QueryBuilder.prototype.returning = function(returning) {
|
|
|
|
this._single.returning = returning;
|
2014-04-16 01:23:50 -04:00
|
|
|
return this;
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Delete
|
|
|
|
// ------
|
|
|
|
|
|
|
|
// Executes a delete statement on the query;
|
|
|
|
QueryBuilder.prototype.del =
|
2014-04-16 02:50:19 -04:00
|
|
|
QueryBuilder.prototype.delete = function(ret) {
|
2014-04-16 02:59:27 -04:00
|
|
|
this._method = 'del';
|
2014-04-16 02:50:19 -04:00
|
|
|
if (!_.isEmpty(ret)) this.returning(ret);
|
2014-04-08 16:25:57 -04:00
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Truncates a table, ends the query chain.
|
|
|
|
QueryBuilder.prototype.truncate = function() {
|
|
|
|
this._method = 'truncate';
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-04-21 23:08:59 -04:00
|
|
|
// Retrieves columns for the table specified by `knex(tableName)`
|
2014-06-03 14:21:31 -04:00
|
|
|
QueryBuilder.prototype.columnInfo = function(column) {
|
2014-04-21 23:08:59 -04:00
|
|
|
this._method = 'columnInfo';
|
2014-06-03 14:21:31 -04:00
|
|
|
this._single.columnInfo = column;
|
2014-04-21 23:08:59 -04:00
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-04-08 16:25:57 -04:00
|
|
|
// Set a lock for update constraint.
|
|
|
|
QueryBuilder.prototype.forUpdate = function() {
|
|
|
|
this._single.lock = 'forUpdate';
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Set a lock for share constraint.
|
|
|
|
QueryBuilder.prototype.forShare = function() {
|
|
|
|
this._single.lock = 'forShare';
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Helper for the incrementing/decrementing queries.
|
|
|
|
QueryBuilder.prototype._counter = function(column, amount, symbol) {
|
|
|
|
var amt = parseInt(amount, 10);
|
|
|
|
if (isNaN(amt)) amt = 1;
|
2014-04-16 01:23:50 -04:00
|
|
|
this._method = 'counter';
|
|
|
|
this._single.counter = {
|
|
|
|
column: column,
|
|
|
|
amount: amt,
|
|
|
|
symbol: (symbol || '+')
|
|
|
|
};
|
|
|
|
return this;
|
2014-04-08 16:25:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Helper to get or set the "boolFlag" value.
|
|
|
|
QueryBuilder.prototype._bool = function(val) {
|
|
|
|
if (arguments.length === 1) {
|
|
|
|
this._boolFlag = val;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
var ret = this._boolFlag;
|
|
|
|
this._boolFlag = 'and';
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
2014-07-01 08:53:35 -04:00
|
|
|
// Helper to get or set the "notFlag" value.
|
|
|
|
QueryBuilder.prototype._not = function(val) {
|
|
|
|
if (arguments.length === 1) {
|
|
|
|
this._notFlag = val;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
var ret = this._notFlag;
|
|
|
|
this._notFlag = false;
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
2014-04-08 16:25:57 -04:00
|
|
|
// Helper to get or set the "joinFlag" value.
|
|
|
|
QueryBuilder.prototype._joinType = function (val) {
|
|
|
|
if (arguments.length === 1) {
|
|
|
|
this._joinFlag = val;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
var ret = this._joinFlag || 'inner';
|
|
|
|
this._joinFlag = 'inner';
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Helper for compiling any aggregate queries.
|
|
|
|
QueryBuilder.prototype._aggregate = function(method, column) {
|
|
|
|
this._statements.push({
|
|
|
|
grouping: 'columns',
|
|
|
|
type: 'aggregate',
|
|
|
|
method: method,
|
|
|
|
value: column
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-07-01 08:53:35 -04:00
|
|
|
Object.defineProperty(QueryBuilder.prototype, 'or', {
|
|
|
|
get: function () {
|
|
|
|
return this._bool('or');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(QueryBuilder.prototype, 'not', {
|
|
|
|
get: function () {
|
|
|
|
return this._not(true);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2014-04-08 16:25:57 -04:00
|
|
|
// Attach all of the top level promise methods that should be chainable.
|
|
|
|
require('../interface')(QueryBuilder);
|
|
|
|
|
2014-08-21 17:35:51 -04:00
|
|
|
module.exports = QueryBuilder;
|