From 1f03c8c0ddb9cf12b389734a1687484ab7b9cba7 Mon Sep 17 00:00:00 2001
From: "Timothy J. Warren"
Date: Thu, 23 Oct 2014 15:33:20 -0400
Subject: [PATCH] Fix having and where methods
---
docs/module-query-builder.html | 62 +++++++++++++++++-----------------
docs/query-builder.js.html | 59 +++++++++++++++++++-------------
lib/query-builder.js | 58 ++++++++++++++++++-------------
tests/query-builder-base.js | 26 ++++++++++++++
4 files changed, 126 insertions(+), 79 deletions(-)
diff --git a/docs/module-query-builder.html b/docs/module-query-builder.html
index 0e170bc..3be2283 100644
--- a/docs/module-query-builder.html
+++ b/docs/module-query-builder.html
@@ -305,7 +305,7 @@
@@ -550,7 +550,7 @@
@@ -741,7 +741,7 @@
@@ -940,7 +940,7 @@
@@ -1141,7 +1141,7 @@
@@ -1332,7 +1332,7 @@
@@ -1427,7 +1427,7 @@
@@ -1574,7 +1574,7 @@
@@ -1661,7 +1661,7 @@
@@ -1748,7 +1748,7 @@
@@ -1933,7 +1933,7 @@
@@ -2143,7 +2143,7 @@
@@ -2408,7 +2408,7 @@
@@ -2634,7 +2634,7 @@
@@ -2813,7 +2813,7 @@
@@ -3039,7 +3039,7 @@
@@ -3230,7 +3230,7 @@
@@ -3318,7 +3318,7 @@ prefixed with 'OR'
@@ -3503,7 +3503,7 @@ prefixed with 'OR'
@@ -3729,7 +3729,7 @@ prefixed with 'OR'
@@ -3817,7 +3817,7 @@ prefixed with 'OR NOT'
@@ -4043,7 +4043,7 @@ prefixed with 'OR NOT'
@@ -4228,7 +4228,7 @@ prefixed with 'OR NOT'
@@ -4387,7 +4387,7 @@ prefixed with 'OR NOT'
@@ -4546,7 +4546,7 @@ prefixed with 'OR NOT'
@@ -4685,7 +4685,7 @@ prefixed with 'OR NOT'
@@ -4867,7 +4867,7 @@ prefixed with 'OR NOT'
@@ -5077,7 +5077,7 @@ prefixed with 'OR NOT'
@@ -5262,7 +5262,7 @@ prefixed with 'OR NOT'
@@ -5421,7 +5421,7 @@ prefixed with 'OR NOT'
@@ -5580,7 +5580,7 @@ prefixed with 'OR NOT'
diff --git a/docs/query-builder.js.html b/docs/query-builder.js.html
index 7cd8728..6eb3da5 100644
--- a/docs/query-builder.js.html
+++ b/docs/query-builder.js.html
@@ -72,7 +72,7 @@
class="sunlight-highlight-javascript linenums">'use strict';
/** @module query-builder */
-
+require('./es6-polyfill');
var getArgs = require('getargs'),
helpers = require('./helpers');
@@ -218,12 +218,12 @@ var QueryBuilder = function(driver, adapter) {
*
* @private
*/
- mixedSet: function(/* varName, key, [val], valType */) {
- var args = getArgs('varName:string, key:string|array, [val]:string, valType:string', arguments);
+ mixedSet: function(/* varName, valType, key, [val] */) {
+ var args = getArgs('varName:string, valType:string, key:string|object, [val]:string|number|boolean', arguments);
var obj = {};
- if (helpers.isString(args.key) && helpers.isString(args.val))
+ if (helpers.isScalar(args.key) && !helpers.isUndefined(args.val) && !helpers.isNull(args.val))
{
obj[args.key] = args.val;
}
@@ -233,11 +233,11 @@ var QueryBuilder = function(driver, adapter) {
}
Object.keys(obj).forEach(function(k) {
- if (args.valType != 'both')
+ // If a single value for the return
+ if (['key','value'].indexOf(args.valType) !== -1)
{
- state[args.varName].push(
- (args.valType === 'key')? k: obj[k]
- );
+ var pushVal = (args.valType === 'key') ? k : obj[k];
+ state[args.varName].push(pushVal);
}
else
{
@@ -247,14 +247,18 @@ var QueryBuilder = function(driver, adapter) {
return state[args.varName];
},
- whereMixedSet: function(key, val) {
- _p.mixedSet('whereValues', key, val, 'value');
- _p.mixedSet('whereMap', key, val, 'both');
+ whereMixedSet: function(/*key, val*/) {
+ var args = getArgs('key:string|object, [val]', arguments);
+
+ state.whereMap = [];
+
+ _p.mixedSet('whereMap', 'both', args.key, args.val);
+ _p.mixedSet('whereValues', 'value', args.key, args.val);
},
where: function(key, val, conj) {
conj = conj || 'AND';
- // Get an object to iterate over
+ // Normalize key and value and insert into state.whereMap
_p.whereMixedSet(key, val);
Object.keys(state.whereMap).forEach(function(field) {
@@ -271,7 +275,7 @@ var QueryBuilder = function(driver, adapter) {
lastItem = state.queryMap[state.queryMap.length - 1];
// Determine the correct conjunction
- if (state.queryMap.length < 1 || firstItem.contains('JOIN'))
+ if (state.queryMap.length < 1 || firstItem.conjunction.contains('JOIN'))
{
conj = " WHERE ";
}
@@ -287,10 +291,13 @@ var QueryBuilder = function(driver, adapter) {
_p.appendMap(conj, item, 'where');
});
},
- having: function(key, val, conj) {
- conj = conj || 'AND';
+ having: function(/*key, val, conj*/) {
+ var args = getArgs('key:string|object, [val]:string|number, [conj]:string', arguments);
+ args.conj = args.conj || 'AND';
+ args.val = args.val || null;
- _p.whereMixedSet(key, val);
+ // Normalize key/val and put in state.whereMap
+ _p.whereMixedSet(args.key, args.val);
Object.keys(state.whereMap).forEach(function(field) {
// Split each key by spaces, in case there
@@ -304,7 +311,7 @@ var QueryBuilder = function(driver, adapter) {
// Put in the having map
state.havingMap.push({
- conjunction: (state.havingMap.length > 0) ? " " + conj + " " : ' HAVING ',
+ conjunction: (state.havingMap.length > 0) ? " " + args.conj + " " : ' HAVING ',
string: item
});
});
@@ -353,7 +360,7 @@ var QueryBuilder = function(driver, adapter) {
resetState: function() {
state = {
// Arrays/Maps
- queryMap: {},
+ queryMap: [],
values: [],
whereValues: [],
setArrayKeys: [],
@@ -522,8 +529,10 @@ var QueryBuilder = function(driver, adapter) {
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return this
*/
- this.having = function(key, val) {
- _p.having(key, val, 'AND');
+ this.having = function(/*key, [val]*/) {
+ var args = getArgs('key:string|object, [val]:string|number', arguments);
+
+ _p.having(args.key, args.val, 'AND');
return this;
};
@@ -534,8 +543,10 @@ var QueryBuilder = function(driver, adapter) {
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return this
*/
- this.orHaving = function(key, val) {
- _p.having(key, val, 'OR');
+ this.orHaving = function(/*key, [val]*/) {
+ var args = getArgs('key:string|object, [val]:string|number', arguments);
+
+ _p.having(args.key, args.val, 'OR');
return this;
};
@@ -622,8 +633,8 @@ var QueryBuilder = function(driver, adapter) {
var args = getArgs('key:string|object, [val]:string', arguments);
// Set the appropriate state variables
- _p.mixedSet('setArrayKeys', args.key, args.val, 'key');
- _p.mixedSet('values', args.key, args.val, 'value');
+ _p.mixedSet('setArrayKeys', 'key', args.key, args.val);
+ _p.mixedSet('values', 'value', args.key, args.val);
// Use the keys of the array to make the insert/update string
// and escape the field names
diff --git a/lib/query-builder.js b/lib/query-builder.js
index 38f070c..5ebb02f 100755
--- a/lib/query-builder.js
+++ b/lib/query-builder.js
@@ -1,7 +1,6 @@
'use strict';
/** @module query-builder */
-
var getArgs = require('getargs'),
helpers = require('./helpers');
@@ -147,12 +146,12 @@ var QueryBuilder = function(driver, adapter) {
*
* @private
*/
- mixedSet: function(/* varName, key, [val], valType */) {
- var args = getArgs('varName:string, key:string|array, [val]:string, valType:string', arguments);
+ mixedSet: function(/* varName, valType, key, [val] */) {
+ var args = getArgs('varName:string, valType:string, key:string|object, [val]:string|number|boolean', arguments);
var obj = {};
- if (helpers.isString(args.key) && helpers.isString(args.val))
+ if (helpers.isScalar(args.key) && !helpers.isUndefined(args.val) && !helpers.isNull(args.val))
{
obj[args.key] = args.val;
}
@@ -162,11 +161,11 @@ var QueryBuilder = function(driver, adapter) {
}
Object.keys(obj).forEach(function(k) {
- if (args.valType != 'both')
+ // If a single value for the return
+ if (['key','value'].indexOf(args.valType) !== -1)
{
- state[args.varName].push(
- (args.valType === 'key')? k: obj[k]
- );
+ var pushVal = (args.valType === 'key') ? k : obj[k];
+ state[args.varName].push(pushVal);
}
else
{
@@ -176,14 +175,18 @@ var QueryBuilder = function(driver, adapter) {
return state[args.varName];
},
- whereMixedSet: function(key, val) {
- _p.mixedSet('whereValues', key, val, 'value');
- _p.mixedSet('whereMap', key, val, 'both');
+ whereMixedSet: function(/*key, val*/) {
+ var args = getArgs('key:string|object, [val]', arguments);
+
+ state.whereMap = [];
+
+ _p.mixedSet('whereMap', 'both', args.key, args.val);
+ _p.mixedSet('whereValues', 'value', args.key, args.val);
},
where: function(key, val, conj) {
conj = conj || 'AND';
- // Get an object to iterate over
+ // Normalize key and value and insert into state.whereMap
_p.whereMixedSet(key, val);
Object.keys(state.whereMap).forEach(function(field) {
@@ -200,7 +203,7 @@ var QueryBuilder = function(driver, adapter) {
lastItem = state.queryMap[state.queryMap.length - 1];
// Determine the correct conjunction
- if (state.queryMap.length < 1 || firstItem.contains('JOIN'))
+ if (state.queryMap.length < 1 || firstItem.conjunction.contains('JOIN'))
{
conj = " WHERE ";
}
@@ -216,10 +219,13 @@ var QueryBuilder = function(driver, adapter) {
_p.appendMap(conj, item, 'where');
});
},
- having: function(key, val, conj) {
- conj = conj || 'AND';
+ having: function(/*key, val, conj*/) {
+ var args = getArgs('key:string|object, [val]:string|number, [conj]:string', arguments);
+ args.conj = args.conj || 'AND';
+ args.val = args.val || null;
- _p.whereMixedSet(key, val);
+ // Normalize key/val and put in state.whereMap
+ _p.whereMixedSet(args.key, args.val);
Object.keys(state.whereMap).forEach(function(field) {
// Split each key by spaces, in case there
@@ -233,7 +239,7 @@ var QueryBuilder = function(driver, adapter) {
// Put in the having map
state.havingMap.push({
- conjunction: (state.havingMap.length > 0) ? " " + conj + " " : ' HAVING ',
+ conjunction: (state.havingMap.length > 0) ? " " + args.conj + " " : ' HAVING ',
string: item
});
});
@@ -282,7 +288,7 @@ var QueryBuilder = function(driver, adapter) {
resetState: function() {
state = {
// Arrays/Maps
- queryMap: {},
+ queryMap: [],
values: [],
whereValues: [],
setArrayKeys: [],
@@ -451,8 +457,10 @@ var QueryBuilder = function(driver, adapter) {
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return this
*/
- this.having = function(key, val) {
- _p.having(key, val, 'AND');
+ this.having = function(/*key, [val]*/) {
+ var args = getArgs('key:string|object, [val]:string|number', arguments);
+
+ _p.having(args.key, args.val, 'AND');
return this;
};
@@ -463,8 +471,10 @@ var QueryBuilder = function(driver, adapter) {
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return this
*/
- this.orHaving = function(key, val) {
- _p.having(key, val, 'OR');
+ this.orHaving = function(/*key, [val]*/) {
+ var args = getArgs('key:string|object, [val]:string|number', arguments);
+
+ _p.having(args.key, args.val, 'OR');
return this;
};
@@ -551,8 +561,8 @@ var QueryBuilder = function(driver, adapter) {
var args = getArgs('key:string|object, [val]:string', arguments);
// Set the appropriate state variables
- _p.mixedSet('setArrayKeys', args.key, args.val, 'key');
- _p.mixedSet('values', args.key, args.val, 'value');
+ _p.mixedSet('setArrayKeys', 'key', args.key, args.val);
+ _p.mixedSet('values', 'value', args.key, args.val);
// Use the keys of the array to make the insert/update string
// and escape the field names
diff --git a/tests/query-builder-base.js b/tests/query-builder-base.js
index 6819b19..6667d16 100644
--- a/tests/query-builder-base.js
+++ b/tests/query-builder-base.js
@@ -44,10 +44,36 @@ module.exports = (function() {
'Get with limit and offset': function(test) {
base.qb.get('create_test', 2, 1, base.testCallback.bind(test, test));
test.done();
+ },
+ 'Test get with having': function(test) {
+ base.qb.select('id')
+ .from('create_test')
+ .groupBy('id')
+ .having({'id >':1})
+ .having('id !=', 3)
+ .get(base.testCallback.bind(test, test));
+
+ test.done();
+ },
+ "Test get with 'orHaving'": function(test) {
+ base.qb.select('id')
+ .from('create_test')
+ .groupBy('id')
+ .having({'id >':1})
+ .orHaving('id !=', 3)
+ .get(base.testCallback.bind(test, test));
+
+ test.done();
}
},
'Select tests' : {
+ 'Select where get': function(test) {
+ base.qb.select('id, key as k, val')
+ .where('id !=', 1)
+ .get('create_test', 2, 1, base.testCallback.bind(test, test));
+ test.done();
+ }
},
'Grouping tests' : {