mirror of
https://github.com/knex/knex.git
synced 2025-12-28 23:48:58 +00:00
Allow object syntax for join, #743
This commit is contained in:
parent
471b2bae8f
commit
c529358fcb
@ -21,6 +21,7 @@ function QueryBuilder(client) {
|
||||
this._statements = [];
|
||||
|
||||
// Internal flags used in the builder.
|
||||
this._method = 'select'
|
||||
this._joinFlag = 'inner';
|
||||
this._boolFlag = 'and';
|
||||
this._notFlag = false;
|
||||
@ -35,8 +36,8 @@ assign(QueryBuilder.prototype, {
|
||||
},
|
||||
|
||||
// Convert the current query "toSQL"
|
||||
toSQL: function() {
|
||||
return this.client.queryCompiler(this).toSQL(this._method || 'select');
|
||||
toSQL: function(method) {
|
||||
return this.client.queryCompiler(this).toSQL(method || this._method);
|
||||
},
|
||||
|
||||
// Create a shallow clone of the current query builder.
|
||||
|
||||
@ -151,25 +151,26 @@ assign(QueryCompiler.prototype, {
|
||||
// Compiles all each of the `join` clauses on the query,
|
||||
// including any nested join queries.
|
||||
join: function() {
|
||||
var joins = this.grouped.join;
|
||||
var sql = '', i = -1, joins = this.grouped.join;
|
||||
if (!joins) return '';
|
||||
var sql = _.reduce(joins, function(acc, join) {
|
||||
while (++i < joins.length) {
|
||||
var join = joins[i]
|
||||
if (i > 0) sql += ' '
|
||||
if (join.joinType === 'raw') {
|
||||
acc.push(this.formatter.unwrapRaw(join.table));
|
||||
sql += this.formatter.unwrapRaw(join.table)
|
||||
} else {
|
||||
acc.push(join.joinType + ' join ' + this.formatter.wrap(join.table));
|
||||
var i = -1;
|
||||
while (++i < join.clauses.length) {
|
||||
var clause = join.clauses[i]
|
||||
acc.push(i > 0 ? clause[1] : clause[0]);
|
||||
acc.push(this.formatter.wrap(clause[2]));
|
||||
if (clause[3]) acc.push(this.formatter.operator(clause[3]));
|
||||
if (clause[4]) acc.push(this.formatter.wrap(clause[4]));
|
||||
sql += join.joinType + ' join ' + this.formatter.wrap(join.table)
|
||||
var ii = -1
|
||||
while (++ii < join.clauses.length) {
|
||||
var clause = join.clauses[ii]
|
||||
sql += ' ' + (ii > 0 ? clause[0] : clause[1]) + ' '
|
||||
sql += this.formatter.wrap(clause[2])
|
||||
if (clause[3]) sql += ' ' + this.formatter.operator(clause[3])
|
||||
if (clause[4]) sql += ' ' + this.formatter.wrap(clause[4])
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, [], this);
|
||||
return sql.length > 0 ? sql.join(' ') : '';
|
||||
}
|
||||
return sql;
|
||||
},
|
||||
|
||||
// Compiles all `where` statements on the query.
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var assign = require('lodash/object/assign');
|
||||
|
||||
// JoinClause
|
||||
// -------
|
||||
|
||||
@ -12,51 +14,66 @@ function JoinClause(table, type) {
|
||||
this.clauses = [];
|
||||
}
|
||||
|
||||
JoinClause.prototype.grouping = 'join';
|
||||
assign(JoinClause.prototype, {
|
||||
|
||||
// Adds an "on" clause to the current join object.
|
||||
JoinClause.prototype.on = function(first, operator, second) {
|
||||
var data;
|
||||
switch (arguments.length) {
|
||||
case 1: data = ['on', this._bool(), first]; break;
|
||||
case 2: data = ['on', this._bool(), first, '=', operator]; break;
|
||||
default: data = ['on', this._bool(), first, operator, second];
|
||||
}
|
||||
this.clauses.push(data);
|
||||
return this;
|
||||
};
|
||||
grouping: 'join',
|
||||
|
||||
// Adds a "using" clause to the current join.
|
||||
JoinClause.prototype.using = function(table) {
|
||||
return this.clauses.push(['using', this._bool(), table]);
|
||||
};
|
||||
|
||||
// Adds an "and on" clause to the current join object.
|
||||
JoinClause.prototype.andOn = function() {
|
||||
return this.on.apply(this, arguments);
|
||||
};
|
||||
|
||||
// Adds an "or on" clause to the current join object.
|
||||
JoinClause.prototype.orOn = function(first, operator, second) {
|
||||
/*jshint unused: false*/
|
||||
return this._bool('or').on.apply(this, arguments);
|
||||
};
|
||||
|
||||
// Explicitly set the type of join, useful within a function when creating a grouped join.
|
||||
JoinClause.prototype.type = function(type) {
|
||||
this.joinType = type;
|
||||
return this;
|
||||
};
|
||||
|
||||
JoinClause.prototype._bool = function(bool) {
|
||||
if (arguments.length === 1) {
|
||||
this._boolFlag = bool;
|
||||
// Adds an "on" clause to the current join object.
|
||||
on: function(first, operator, second) {
|
||||
var data, bool = this._bool()
|
||||
switch (arguments.length) {
|
||||
case 1: {
|
||||
if (typeof first === 'object' && typeof first.toSQL !== 'function') {
|
||||
var i = -1, keys = Object.keys(first)
|
||||
var method = bool === 'or' ? 'orOn' : 'on'
|
||||
while (++i < keys.length) {
|
||||
this[method](keys[i], first[keys[i]])
|
||||
}
|
||||
return this;
|
||||
} else {
|
||||
data = [bool, 'on', first]; break;
|
||||
}
|
||||
}
|
||||
case 2: data = [bool, 'on', first, '=', operator]; break;
|
||||
default: data = [bool, 'on', first, operator, second];
|
||||
}
|
||||
this.clauses.push(data);
|
||||
return this;
|
||||
},
|
||||
|
||||
// Adds a "using" clause to the current join.
|
||||
using: function(table) {
|
||||
return this.clauses.push([this._bool(), 'using', table]);
|
||||
},
|
||||
|
||||
// Adds an "and on" clause to the current join object.
|
||||
andOn: function() {
|
||||
return this.on.apply(this, arguments);
|
||||
},
|
||||
|
||||
// Adds an "or on" clause to the current join object.
|
||||
orOn: function(first, operator, second) {
|
||||
/*jshint unused: false*/
|
||||
return this._bool('or').on.apply(this, arguments);
|
||||
},
|
||||
|
||||
// Explicitly set the type of join, useful within a function when creating a grouped join.
|
||||
type: function(type) {
|
||||
this.joinType = type;
|
||||
return this;
|
||||
},
|
||||
|
||||
_bool: function(bool) {
|
||||
if (arguments.length === 1) {
|
||||
this._boolFlag = bool;
|
||||
return this;
|
||||
}
|
||||
var ret = this._boolFlag || 'and';
|
||||
this._boolFlag = 'and';
|
||||
return ret;
|
||||
}
|
||||
var ret = this._boolFlag || 'and';
|
||||
this._boolFlag = 'and';
|
||||
return ret;
|
||||
};
|
||||
|
||||
})
|
||||
|
||||
Object.defineProperty(JoinClause.prototype, 'or', {
|
||||
get: function () {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var tape = require('tape')
|
||||
var tape = require('tape')
|
||||
var QueryBuilder = require('../../lib/query/builder')
|
||||
var Client = require('../../lib/client')
|
||||
|
||||
tape('accumulates multiple update calls #647', function(t) {
|
||||
t.plan(1)
|
||||
@ -9,3 +10,14 @@ tape('accumulates multiple update calls #647', function(t) {
|
||||
qb.update('a', 1).update('b', 2)
|
||||
t.deepEqual(qb._single.update, {a: 1, b: 2})
|
||||
})
|
||||
|
||||
tape('allows for object syntax in join', function(t) {
|
||||
t.plan(1)
|
||||
var qb = new QueryBuilder(new Client())
|
||||
var sql = qb.table('users').innerJoin('accounts', {
|
||||
'accounts.id': 'users.account_id',
|
||||
'accounts.owner_id': 'users.id'
|
||||
}).toSQL('join')
|
||||
t.equal(sql.sql,
|
||||
'inner join "accounts" on "accounts"."id" = "users"."account_id" and "accounts"."owner_id" = "users"."id"')
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user