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' : {