From 7a3c5b7e79b532df3990c3f5ed7fc46d2642b72f Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Tue, 28 Oct 2014 14:40:03 -0400 Subject: [PATCH] Streamline some dependencies, and add tests for query parser --- lib/es6-polyfill.js | 78 ----------------------------------- lib/helpers.js | 3 +- lib/query-builder.js | 3 +- lib/query-parser.js | 48 +++++++++++---------- package.json | 8 ++-- tests/adapters/mysql2_test.js | 2 +- tests/adapters/mysql_test.js | 2 +- tests/adapters/pg_test.js | 2 +- tests/query-parser_test.js | 52 +++++++++++++++++++++++ 9 files changed, 88 insertions(+), 110 deletions(-) delete mode 100644 lib/es6-polyfill.js create mode 100644 tests/query-parser_test.js diff --git a/lib/es6-polyfill.js b/lib/es6-polyfill.js deleted file mode 100644 index 993c5ad..0000000 --- a/lib/es6-polyfill.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Polyfills for very handy methods that are standardized, but not fully implemented in Javascript engines - */ -module.exports = (function() { - if (!Array.prototype.fill) { - Array.prototype.fill = function(value) { - // Steps 1-2. - if (this == null) { - throw new TypeError('this is null or not defined'); - } - - var O = Object(this); - - // Steps 3-5. - var len = O.length >>> 0; - - // Steps 6-7. - var start = arguments[1]; - var relativeStart = start >> 0; - - // Step 8. - var k = relativeStart < 0 ? - Math.max(len + relativeStart, 0) : - Math.min(relativeStart, len); - - // Steps 9-10. - var end = arguments[2]; - var relativeEnd = end === undefined ? - len : end >> 0; - - // Step 11. - var final = relativeEnd < 0 ? - Math.max(len + relativeEnd, 0) : - Math.min(relativeEnd, len); - - // Step 12. - while (k < final) { - O[k] = value; - k++; - } - - // Step 13. - return O; - }; - } - - if ( !String.prototype.contains ) { - String.prototype.contains = function() { - return String.prototype.indexOf.apply( this, arguments ) !== -1; - }; - } - - if (!String.prototype.startsWith) { - Object.defineProperty(String.prototype, 'startsWith', { - enumerable: false, - configurable: false, - writable: false, - value: function (searchString, position) { - position = position || 0; - return this.lastIndexOf(searchString, position) === position; - } - }); - } - - if (!String.prototype.endsWith) { - Object.defineProperty(String.prototype, 'endsWith', { - value: function (searchString, position) { - var subjectString = this.toString(); - if (position === undefined || position > subjectString.length) { - position = subjectString.length; - } - position -= searchString.length; - var lastIndex = subjectString.indexOf(searchString, position); - return lastIndex !== -1 && lastIndex === position; - } - }); - } -}()); \ No newline at end of file diff --git a/lib/helpers.js b/lib/helpers.js index 7ad124a..84106e1 100755 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -1,8 +1,7 @@ "use strict"; /** @module helpers */ - -require('./es6-polyfill'); +require('es6-shim'); /** @alias module:helpers */ var h = { diff --git a/lib/query-builder.js b/lib/query-builder.js index 71256b5..13ea417 100755 --- a/lib/query-builder.js +++ b/lib/query-builder.js @@ -792,13 +792,12 @@ var QueryBuilder = function(driver, adapter) { /** * Run the generated delete query * - * @method delete * @param {String} table - The table to insert into * @param {Object} [where] - Where clause for delete statement * @param {Function} callback - Callback for handling response from the database * @return void */ - this['delete'] = function (/*table, [where], callback*/) { + this.delete = function (/*table, [where], callback*/) { var args = getArgs('table:string, [where], callback:function', arguments); if (args.where) diff --git a/lib/query-parser.js b/lib/query-parser.js index 6dad42a..73544c3 100644 --- a/lib/query-parser.js +++ b/lib/query-parser.js @@ -29,26 +29,6 @@ var filterMatches = function(array) { return output; }; -var parseJoin = function(sql) { - var matches = {}; - var output = {}; - - // Get clause components - matches['function'] = sql.match(matchPatterns['function']); - matches.identifiers = sql.match(matchPatterns.identifier); - matches.operators = sql.match(matchPatterns.operator); - - // Get everything at once for ordering - matches.combined = sql.match(matchPatterns.combined); - - // Flatten the matches to increase relevance - Object.keys(matches).forEach(function(key) { - output[key] = filterMatches(matches[key]); - }); - - return output; -}; - // -------------------------------------------------------------------------- /** @@ -61,6 +41,32 @@ var QueryParser = function(driver) { // That 'new' keyword is annoying if ( ! (this instanceof QueryParser)) return new QueryParser(driver); + /** + * Tokenize the sql into parts for additional processing + * + * @param {String} sql + * @return {Object} + */ + this.parseJoin = function(sql) { + var matches = {}; + var output = {}; + + // Get clause components + matches['function'] = sql.match(matchPatterns['function']); + matches.identifiers = sql.match(matchPatterns.identifier); + matches.operators = sql.match(matchPatterns.operator); + + // Get everything at once for ordering + matches.combined = sql.match(matchPatterns.combined); + + // Flatten the matches to increase relevance + Object.keys(matches).forEach(function(key) { + output[key] = filterMatches(matches[key]); + }); + + return output; + }; + /** * Return the output of the parsing of the join condition * @@ -68,7 +74,7 @@ var QueryParser = function(driver) { * @return {String} - The parsed/escaped join condition */ this.compileJoin = function(condition) { - var parts = parseJoin(condition); + var parts = this.parseJoin(condition); var count = parts.identifiers.length; var i; diff --git a/package.json b/package.json index d02e85d..751d0b1 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ci-node-query", - "version": "0.0.2", + "version": "0.0.3", "description": "A query builder for node based on the one in CodeIgniter", "author": "Timothy J Warren ", "engines": { @@ -15,11 +15,11 @@ }, "main": "lib/node-query.js", "dependencies": { - "async": "^0.9.0", - "getargs": "" + "getargs": "", + "es6-shim":"" }, "bundledDependencies": [ - "async","getargs" + "es6-shim","getargs" ], "devDependencies": { "grunt": "^0.4.5", diff --git a/tests/adapters/mysql2_test.js b/tests/adapters/mysql2_test.js index d0d1aab..3f6357f 100644 --- a/tests/adapters/mysql2_test.js +++ b/tests/adapters/mysql2_test.js @@ -26,7 +26,7 @@ testBase._setUp(qb, function(test, err, rows) { throw new Error(err); } - test.ok(rows, 'Valid result for generated query'); + test.ok(rows, 'mysql2: Valid result for generated query'); test.done(); }); diff --git a/tests/adapters/mysql_test.js b/tests/adapters/mysql_test.js index a4c317b..d1d16a7 100644 --- a/tests/adapters/mysql_test.js +++ b/tests/adapters/mysql_test.js @@ -26,7 +26,7 @@ testBase._setUp(qb, function(test, err, rows) { throw new Error(err); } - test.ok(rows, 'Valid result for generated query'); + test.ok(rows, 'mysql: Valid result for generated query'); test.done(); }); diff --git a/tests/adapters/pg_test.js b/tests/adapters/pg_test.js index 1b32d64..0bfe718 100644 --- a/tests/adapters/pg_test.js +++ b/tests/adapters/pg_test.js @@ -32,7 +32,7 @@ testBase._setUp(qb, function(test, err, result) { console.error('SQL syntax error', err); } - test.ok(result, 'Valid result for generated query'); + test.ok(result, 'pg: Valid result for generated query'); test.done(); }); diff --git a/tests/query-parser_test.js b/tests/query-parser_test.js new file mode 100644 index 0000000..4a3c46c --- /dev/null +++ b/tests/query-parser_test.js @@ -0,0 +1,52 @@ +'use strict'; + +// Use the base driver as a mock for testing +var driver = require('../lib/driver'); +var parser = require('../lib/query-parser')(driver); + +module.exports = { + 'Parse join tests' : { + 'Simple equals condition': function(test) { + var matches = parser.parseJoin('table1.field1=table2.field2'); + test.deepEqual(['table1.field1','=','table2.field2'], matches.combined); + test.done(); + }, + 'Db.table.field condition': function(test) { + var matches = parser.parseJoin('db1.table1.field1!=db2.table2.field2'); + test.deepEqual(['db1.table1.field1','!=', 'db2.table2.field2'], matches.combined); + test.done(); + }, + 'Underscore in identifier': function(test) { + var matches = parser.parseJoin('table_1.field1 = tab_le2.field_2'); + test.deepEqual(['table_1.field1', '=', 'tab_le2.field_2'], matches.combined); + test.done(); + }, + 'Function in condition': function(test) { + var matches = parser.parseJoin('table1.field1 > SUM(3+6)'); + test.deepEqual(['table1.field1', '>', 'SUM(3+6)'], matches.combined); + test.done(); + } + }, + 'Compile join tests': { + 'Simple equals condition': function(test) { + var join = parser.compileJoin('table1.field1=table2.field2'); + test.deepEqual('"table1"."field1"="table2"."field2"', join); + test.done(); + }, + 'Db.table.field condition': function(test) { + var join = parser.compileJoin('db1.table1.field1!=db2.table2.field2'); + test.deepEqual('"db1"."table1"."field1"!="db2"."table2"."field2"', join); + test.done(); + }, + 'Underscore in identifier': function(test) { + var join = parser.compileJoin('table_1.field1 = tab_le2.field_2'); + test.deepEqual('"table_1"."field1"="tab_le2"."field_2"', join); + test.done(); + }, + 'Function in condition': function(test) { + var join = parser.compileJoin('table1.field1 > SUM(3+6)'); + test.deepEqual('"table1"."field1">SUM(3+6)', join); + test.done(); + } + } +}; \ No newline at end of file