Streamline some dependencies, and add tests for query parser

This commit is contained in:
Timothy Warren 2014-10-28 14:40:03 -04:00
parent 0b9d4bf7c1
commit 7a3c5b7e79
9 changed files with 88 additions and 110 deletions

View File

@ -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;
}
});
}
}());

View File

@ -1,8 +1,7 @@
"use strict";
/** @module helpers */
require('./es6-polyfill');
require('es6-shim');
/** @alias module:helpers */
var h = {

View File

@ -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)

View File

@ -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;

View File

@ -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 <tim@timshomepage.net>",
"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",

View File

@ -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();
});

View File

@ -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();
});

View File

@ -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();
});

View File

@ -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();
}
}
};