From 711cc0c4f879cfb31c46a7143f17530c5cd7652b Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Tue, 28 Oct 2014 16:46:48 -0400 Subject: [PATCH] Nearly 100% code coverage, and lots of miscellaneous fixes --- lib/driver.js | 44 ------- lib/helpers.js | 5 + lib/node-query.js | 2 +- lib/query-builder.js | 25 ++-- tests/adapters/mysql2_test.js | 4 + tests/adapters/mysql_test.js | 4 + tests/adapters/pg_test.js | 5 +- tests/base_test.js | 9 ++ tests/helpers_test.js | 22 ++++ tests/query-builder-base.js | 220 +++++++++++++++++++++++++++++++--- tests/query-parser_test.js | 1 + 11 files changed, 267 insertions(+), 74 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index d5bec5e..83f4c76 100755 --- a/lib/driver.js +++ b/lib/driver.js @@ -25,22 +25,6 @@ var d = { : str; }, - /** - * Sets the table prefix on the passed string - * - * @param {String} str - * @return {String} - * @private - */ - _prefix: function(str) { - if (str.startsWith(d.prefix)) - { - return str; - } - - return d.prefix + str; - }, - /** * Set the limit clause @@ -60,32 +44,6 @@ var d = { return sql; }, - /** - * Prefixes a table if it is not already prefixed - * - * @param {String} table - * @return {String} - */ - prefixTable: function(table) { - if (d.tablePrefix) - { - // Split identifier by period, will split into: - // database.schema.table OR - // schema.table OR - // database.table OR - // table - var idents = table.split('.', table); - var segments = idents.length; - - // Add the database prefix - idents[segments - 1] = d._prefix(idents[segments - 1]); - - table = idents.join('.'); - } - - return table; - }, - /** * Quote database table name, and set prefix * @@ -93,8 +51,6 @@ var d = { * @return {String} */ quoteTable: function(table) { - table = d.prefixTable(table); - // Quote after prefix return d.quoteIdentifiers(table); }, diff --git a/lib/helpers.js b/lib/helpers.js index 84106e1..aa42bba 100755 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -63,6 +63,11 @@ types.forEach(function (t) { * @return {Boolean} */ h['is' + t] = function (o) { + if (t.toLowerCase() === 'infinite') + { + t = 'infinity'; + } + return h.type(o) === t.toLowerCase(); }; }); diff --git a/lib/node-query.js b/lib/node-query.js index ed59c58..0e3a7a5 100755 --- a/lib/node-query.js +++ b/lib/node-query.js @@ -29,7 +29,7 @@ nodeQuery.init = function (driverType, connObject, connLib) { } }); - return new qb(require(paths.driver), require(paths.adapter)(connObject)); + return qb(require(paths.driver), require(paths.adapter)(connObject)); }; diff --git a/lib/query-builder.js b/lib/query-builder.js index 13ea417..23c86ef 100755 --- a/lib/query-builder.js +++ b/lib/query-builder.js @@ -163,10 +163,6 @@ var QueryBuilder = function(driver, adapter) { { obj = args.$key; } - else - { - throw new Error("Invalid arguments passed"); - } Object.keys(obj).forEach(function(k) { // If a single value for the return @@ -192,8 +188,6 @@ var QueryBuilder = function(driver, adapter) { _p.mixedSet('whereValues', 'value', args.key, args.val); }, where: function(key, val, conj) { - conj = conj || 'AND'; - // Normalize key and value and insert into state.whereMap _p.whereMixedSet(key, val); @@ -225,6 +219,9 @@ var QueryBuilder = function(driver, adapter) { } _p.appendMap(conj, item, 'where'); + + // Clear the where Map + state.whereMap = {}; }); }, having: function(/*key, val, conj*/) { @@ -251,6 +248,9 @@ var QueryBuilder = function(driver, adapter) { string: item }); }); + + // Clear the where Map + state.whereMap = {}; }, whereIn: function(/*key, val, inClause, conj*/) { var args = getArgs('key:string, val:array, inClause:string, conj:string', arguments); @@ -307,7 +307,7 @@ var QueryBuilder = function(driver, adapter) { orderArray: [], groupArray: [], havingMap: [], - whereMap: [], + whereMap: {}, // Partials selectString: '', @@ -684,7 +684,7 @@ var QueryBuilder = function(driver, adapter) { * @return this */ this.groupStart = function() { - var conj = (state.queryMap.length < 1) ? ' WHERE ' : ' '; + var conj = (state.queryMap.length < 1) ? ' WHERE ' : ' AND '; _p.appendMap(conj, '(', 'groupStart'); return this; @@ -820,13 +820,14 @@ var QueryBuilder = function(driver, adapter) { * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built * @return String */ - this.getCompiledSelect = function(table, reset) { - if (table) + this.getCompiledSelect = function(/*table, reset*/) { + var args = getArgs('[table]:string, [reset]:boolean', arguments); + if (args.table) { - this.from(table); + this.from(args.table); } - return _p.getCompile('get', table, reset); + return _p.getCompile('get', args.table, args.reset); }; /** diff --git a/tests/adapters/mysql2_test.js b/tests/adapters/mysql2_test.js index 3f6357f..493af89 100644 --- a/tests/adapters/mysql2_test.js +++ b/tests/adapters/mysql2_test.js @@ -32,7 +32,11 @@ testBase._setUp(qb, function(test, err, rows) { // Export the final test object tests["mysql2 adapter with query builder"] = function(test) { + test.expect(1); test.ok(testBase.qb); + + // Close the db connection + connection.end(); test.done(); }; diff --git a/tests/adapters/mysql_test.js b/tests/adapters/mysql_test.js index d1d16a7..13e360e 100644 --- a/tests/adapters/mysql_test.js +++ b/tests/adapters/mysql_test.js @@ -31,7 +31,11 @@ testBase._setUp(qb, function(test, err, rows) { }); tests["mysql adapter with query builder"] = function(test) { + test.expect(1); test.ok(testBase.qb); + + // Close the db connection + connection.end(); test.done(); }; diff --git a/tests/adapters/pg_test.js b/tests/adapters/pg_test.js index 0bfe718..4496e2e 100644 --- a/tests/adapters/pg_test.js +++ b/tests/adapters/pg_test.js @@ -28,7 +28,6 @@ var qb = nodeQuery('pg', connection, adapterName); // Set up the test base testBase._setUp(qb, function(test, err, result) { if (err != null) { - //throw new Error(err); console.error('SQL syntax error', err); } @@ -38,7 +37,11 @@ testBase._setUp(qb, function(test, err, result) { tests["pg adapter with query builder"] = function(test) { + test.expect(1); test.ok(testBase.qb); + + // Close the db connection + connection.end(); test.done(); }; diff --git a/tests/base_test.js b/tests/base_test.js index e3733c1..04fac94 100755 --- a/tests/base_test.js +++ b/tests/base_test.js @@ -18,6 +18,15 @@ module.exports = { test.ok(modules[mod], mod + " module is sane"); }); + test.done(); + }, + 'Invalid driver type': function(test) { + test.expect(1); + test.throws(function() { + modules['node-query']('foo', {}, 'bar'); + }, function(err) { + if (err instanceof Error) return true; + }); test.done(); } }; \ No newline at end of file diff --git a/tests/helpers_test.js b/tests/helpers_test.js index 9381b0d..0b5d4f0 100644 --- a/tests/helpers_test.js +++ b/tests/helpers_test.js @@ -20,6 +20,28 @@ var helperTests = { test.ok(helpers['is' + type], 'is' + type + ' method exists'); }); + test.done(); + }, + 'isNaN': function(test) { + test.expect(2); + test.equal(helpers.type(0 / 0), 'nan'); + test.deepEqual(helpers.isNaN(0 / 0), true); + + test.done(); + }, + 'isInfinity': function(test) { + test.expect(2); + + test.equal(helpers.type(1/0), 'infinity'); + test.deepEqual(helpers.isInfinite(1/0), true); + test.done(); + }, + 'stringTrim': function(test) { + var orig = [' x y ', 'z ', ' q']; + var ret = ['x y', 'z', 'q']; + + test.deepEqual(ret, orig.map(helpers.stringTrim)); + test.done(); } }; diff --git a/tests/query-builder-base.js b/tests/query-builder-base.js index fa502ff..b265d03 100644 --- a/tests/query-builder-base.js +++ b/tests/query-builder-base.js @@ -1,6 +1,12 @@ 'use strict'; -module.exports = (function() { +var helpers = require('../lib/helpers'); + +module.exports = (function QueryBuilderTestBase() { + + // That 'new' keyword is annoying + if ( ! (this instanceof QueryBuilderTestBase)) return new QueryBuilderTestBase(); + var base = {}; /** @@ -10,55 +16,55 @@ module.exports = (function() { * @param {Function} callback - The test callback * @return void */ - base._setUp = function(qb, callback) { + this._setUp = function(qb, callback) { base.qb = qb; base.testCallback = callback; + + this.qb = base.qb; }; /** * Generic query builder tests */ - base.tests = { - setUp: function(callback) { - var sql = base.qb.driver.truncate('create_test'); - base.qb.adapter.execute(sql, function(err, result) { - if (err) { - throw new Error(err); - } - - callback(); - }); - }, + this.tests = { // ! Get tests 'Get tests' : { 'Get with function': function(test) { + test.expect(1); base.qb.select('id, COUNT(id) as count') .from('create_test') .groupBy('id') .get(base.testCallback.bind(this, test)); }, 'Basic select all get': function(test) { + test.expect(1); base.qb.get('create_test', base.testCallback.bind(this, test)); }, 'Basic select all with from': function(test) { + test.expect(1); base.qb.from('create_test') .get(base.testCallback.bind(this, test)); }, 'Get with limit': function(test) { + test.expect(1); base.qb.get('create_test', 2, base.testCallback.bind(this, test)); }, 'Get with limit and offset': function(test) { + test.expect(1); base.qb.get('create_test', 2, 1, base.testCallback.bind(this, test)); }, 'Test get with having': function(test) { + test.expect(1); base.qb.select('id') .from('create_test') .groupBy('id') .having({'id >':1}) .having('id !=', 3) + .having('id', 900) .get(base.testCallback.bind(this, test)); }, "Test get with 'orHaving'": function(test) { + test.expect(1); base.qb.select('id') .from('create_test') .groupBy('id') @@ -70,32 +76,38 @@ module.exports = (function() { // ! Select tests 'Select tests' : { 'Select where get': function(test) { + test.expect(1); base.qb.select(['id', 'key as k', 'val']) .where('id >', 1) .where('id <', 900) .get('create_test', 2, 1, base.testCallback.bind(this, test)); }, 'Select where get 2': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .where('id !=', 1) .get('create_test', 2, 1, base.testCallback.bind(this, test)); }, 'Multi Order By': function(test) { + test.expect(1); base.qb.from('create_test') .orderBy('id, key') .get(base.testCallback.bind(this, test)); }, 'Select get': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .get('create_test', 2, 1, base.testCallback.bind(this, test)); }, 'Select from get': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .from('create_test ct') .where('id >', 1) .get(base.testCallback.bind(this, test)); }, 'Select from limit get': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .from('create_test ct') .where('id >', 1) @@ -106,6 +118,7 @@ module.exports = (function() { // ! Grouping tests 'Grouping tests' : { 'Using grouping method': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .from('create_test') .groupStart() @@ -115,7 +128,20 @@ module.exports = (function() { .limit(2, 1) .get(base.testCallback.bind(this, test)); }, + 'Using where first grouping': function(test) { + test.expect(1); + base.qb.select('id, key as k, val') + .from('create_test') + .where('id !=', 5) + .groupStart() + .where('id >', 1) + .where('id <', 900) + .groupEnd() + .limit(2, 1) + .get(base.testCallback.bind(this, test)); + }, 'Using or grouping method': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .from('create_test') .groupStart() @@ -129,6 +155,7 @@ module.exports = (function() { .get(base.testCallback.bind(this, test)); }, 'Using or not grouping method': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .from('create_test') .groupStart() @@ -145,23 +172,27 @@ module.exports = (function() { // ! Where in tests 'Where in tests' : { 'Where in': function(test) { + test.expect(1); base.qb.from('create_test') .whereIn('id', [0, 6, 56, 563, 341]) .get(base.testCallback.bind(this, test)); }, 'Or Where in': function(test) { + test.expect(1); base.qb.from('create_test') .where('key', 'false') .orWhereIn('id', [0, 6, 56, 563, 341]) .get(base.testCallback.bind(this, test)); }, 'Where Not in': function(test) { + test.expect(1); base.qb.from('create_test') .where('key', 'false') .whereNotIn('id', [0, 6, 56, 563, 341]) .get(base.testCallback.bind(this, test)); }, 'Or Where Not in': function(test) { + test.expect(1); base.qb.from('create_test') .where('key', 'false') .orWhereNotIn('id', [0, 6, 56, 563, 341]) @@ -171,6 +202,7 @@ module.exports = (function() { // ! Query modifier tests 'Query modifier tests': { 'Order By': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .from('create_test') .where('id >', 0) @@ -181,6 +213,7 @@ module.exports = (function() { .get(base.testCallback.bind(this, test)); }, 'Group by': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .from('create_test') .where('id >', 0) @@ -193,6 +226,7 @@ module.exports = (function() { .get(base.testCallback.bind(this, test)); }, 'Or Where': function(test) { + test.expect(1); base.qb.select('id, key as k, val') .from('create_test') .where(' id ', 1) @@ -201,49 +235,58 @@ module.exports = (function() { .get(base.testCallback.bind(this, test)); }, 'Like' : function(test) { + test.expect(1); base.qb.from('create_test') .like('key', 'og') .get(base.testCallback.bind(this, test)); }, 'Or Like': function(test) { + test.expect(1); base.qb.from('create_test') .like('key', 'og') .orLike('key', 'val') .get(base.testCallback.bind(this, test)); }, 'Not Like': function(test) { + test.expect(1); base.qb.from('create_test') .like('key', 'og', 'before') .notLike('key', 'val') .get(base.testCallback.bind(this, test)); }, 'Or Not Like': function(test) { + test.expect(1); base.qb.from('create_test') .like('key', 'og', 'before') .orNotLike('key', 'val') .get(base.testCallback.bind(this, test)); }, 'Like Before': function(test) { + test.expect(1); base.qb.from('create_test') .like('key', 'og', 'before') .get(base.testCallback.bind(this, test)); }, 'Like After': function(test) { + test.expect(1); base.qb.from('create_test') .like('key', 'og', 'after') .get(base.testCallback.bind(this, test)); }, 'Basic Join': function(test) { + test.expect(1); base.qb.from('create_test ct') .join('create_join cj', 'cj.id=ct.id') .get(base.testCallback.bind(this, test)); }, 'Left Join': function(test) { + test.expect(1); base.qb.from('create_test ct') .join('create_join cj', 'cj.id=ct.id', 'left') .get(base.testCallback.bind(this, test)); }, 'InnerJoin': function(test) { + test.expect(1); base.qb.from('create_test ct') .join('create_join cj', 'cj.id=ct.id', 'inner') .get(base.testCallback.bind(this, test)); @@ -251,13 +294,28 @@ module.exports = (function() { }, // ! DB Update test 'DB update tests' : { + setUp: function(callback) { + var sql = base.qb.driver.truncate('create_test'); + base.qb.adapter.execute(sql, function(err, result) { + if (err) { + throw new Error(err); + } + + callback(); + }); + }, + tearDown: function(callback) { + callback(); + }, 'Test Insert': function(test) { + test.expect(1); base.qb.set('id', 98) .set('key', 84) .set('val', 120) .insert('create_test', base.testCallback.bind(this, test)); }, 'Test Insert Object': function(test) { + test.expect(1); base.qb.insert('create_test', { id: 587, key: 1, @@ -265,6 +323,7 @@ module.exports = (function() { }, base.testCallback.bind(this, test)); }, 'Test Update': function(test) { + test.expect(1); base.qb.where('id', 7) .update('create_test', { id: 7, @@ -273,6 +332,7 @@ module.exports = (function() { }, base.testCallback.bind(this, test)); }, 'Test set Array Update': function(test) { + test.expect(1); var object = { id: 22, key: 'gogle', @@ -284,6 +344,7 @@ module.exports = (function() { .update('create_test', base.testCallback.bind(this, test)); }, 'Test where set update': function(test) { + test.expect(1); base.qb.where('id', 36) .set('id', 36) .set('key', 'gogle') @@ -291,14 +352,141 @@ module.exports = (function() { .update('create_test', base.testCallback.bind(this, test)); }, 'Test delete': function(test) { + test.expect(1); base.qb.delete('create_test', {id: 5}, base.testCallback.bind(this, test)); + }/*, + 'delete with where': function(test) { + test.expect(1); + base.qb.where('id', 5) + .delete('create_test', base.testCallback.bind(this, test)); + }*/ + }, + // ! Get compiled tests + 'Get compiled tests' : { + 'select': function(test) { + test.expect(1); + var string = base.qb.select('id') + .from('create_test') + .getCompiledSelect(true); + + test.equal(true, helpers.isString(string)); + + test.done(); + }, + 'select from': function(test) { + test.expect(1); + var string = base.qb.select('id') + .getCompiledSelect('create_test', true); + + test.equal(true, helpers.isString(string)); + + test.done(); + }, + 'insert': function(test) { + test.expect(1); + + var string = base.qb.set('id', 3) + .getCompiledInsert('create_test'); + + test.equal(true, helpers.isString(string)); + + test.done(); + }, + 'update': function(test) { + test.expect(1); + + var string = base.qb.set('id', 3) + .where('id', 5) + .getCompiledUpdate('create_test'); + + test.equal(true, helpers.isString(string)); + + test.done(); + }, + 'delete': function(test) { + test.expect(1); + + var string = base.qb.where('id', 5) + .getCompiledDelete('create_test'); + + test.equal(true, helpers.isString(string)); + + test.done(); } }, - // ! Compiled query tests - 'Compiled query tests' : { + // ! Misc tests + 'Misc tests' : { + 'Get State': function(test) { + test.expect(1); + base.qb.select('foo') + .from('bar') + .where('baz', 'foobar'); + + var state = { + // Arrays/Maps + queryMap: [], + values: [], + whereValues: [], + setArrayKeys: [], + orderArray: [], + groupArray: [], + havingMap: [], + whereMap: {}, + + // Partials + selectString: '', + fromString: '', + setString: '', + orderString: '', + groupString: '', + + // Other various values + limit: null, + offset: null + }; + + test.notDeepEqual(JSON.stringify(state), JSON.stringify(base.qb.getState())); + test.done(); + }, + 'Reset State': function(test) { + test.expect(1); + + base.qb.select('foo') + .from('bar') + .where('baz', 'foobar'); + + base.qb.resetQuery(); + + var state = { + // Arrays/Maps + queryMap: [], + values: [], + whereValues: [], + setArrayKeys: [], + orderArray: [], + groupArray: [], + havingMap: [], + whereMap: {}, + + // Partials + selectString: '', + fromString: '', + setString: '', + orderString: '', + groupString: '', + + // Other various values + limit: null, + offset: null + }; + + test.deepEqual(state, base.qb.getState()); + + test.done(); + } } }; - return base; + return this; }()); \ No newline at end of file diff --git a/tests/query-parser_test.js b/tests/query-parser_test.js index 4a3c46c..77c4f32 100644 --- a/tests/query-parser_test.js +++ b/tests/query-parser_test.js @@ -1,6 +1,7 @@ 'use strict'; // Use the base driver as a mock for testing +delete require.cache[require.resolve('../lib/driver')]; var driver = require('../lib/driver'); var parser = require('../lib/query-parser')(driver);