diff --git a/docs/adapter.js.html b/docs/adapter.js.html
index 2ba1829..5393d89 100644
--- a/docs/adapter.js.html
+++ b/docs/adapter.js.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -106,7 +110,7 @@ module.exports = {
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/driver.js.html b/docs/driver.js.html
index fdc9890..ccd305e 100644
--- a/docs/driver.js.html
+++ b/docs/driver.js.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -234,7 +238,7 @@ module.exports = d;
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/es6-polyfill.js.html b/docs/es6-polyfill.js.html
index e757bce..9871a60 100644
--- a/docs/es6-polyfill.js.html
+++ b/docs/es6-polyfill.js.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -167,7 +171,7 @@ module.exports = (function() {
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/helpers.js.html b/docs/helpers.js.html
index e47c2bb..773b19a 100644
--- a/docs/helpers.js.html
+++ b/docs/helpers.js.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -160,7 +164,7 @@ module.exports = h;
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/index.html b/docs/index.html
index fa4d97d..3880e43 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -126,7 +130,7 @@ query.select('foo')
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/module-adapter.html b/docs/module-adapter.html
index f9ace9e..3f2545a 100644
--- a/docs/module-adapter.html
+++ b/docs/module-adapter.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -350,7 +354,7 @@
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/module-driver.html b/docs/module-driver.html
index 52a22e5..a478836 100644
--- a/docs/module-driver.html
+++ b/docs/module-driver.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -166,7 +170,7 @@
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/module-helpers.html b/docs/module-helpers.html
index cae136c..bdc8fd9 100644
--- a/docs/module-helpers.html
+++ b/docs/module-helpers.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -682,7 +686,7 @@ function name, eg isNumber
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/module-node-query.html b/docs/module-node-query.html
index 52146b6..2f52658 100644
--- a/docs/module-node-query.html
+++ b/docs/module-node-query.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -354,7 +358,7 @@
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/module-query-builder.html b/docs/module-query-builder.html
index 42d4134..090b9a6 100644
--- a/docs/module-query-builder.html
+++ b/docs/module-query-builder.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -305,7 +309,7 @@
@@ -550,7 +554,7 @@
@@ -741,7 +745,7 @@
@@ -940,7 +944,7 @@
@@ -1141,7 +1145,7 @@
@@ -1332,7 +1336,7 @@
@@ -1427,7 +1431,7 @@
@@ -1574,7 +1578,7 @@
@@ -1661,7 +1665,7 @@
@@ -1748,7 +1752,7 @@
@@ -1933,7 +1937,7 @@
@@ -2143,7 +2147,7 @@
@@ -2184,7 +2188,7 @@
- join(joinOn, cond, joinTo, type)
+ join(table, cond, type)
@@ -2230,7 +2234,7 @@
- joinOn |
+ table |
@@ -2275,45 +2279,6 @@
- |
-
-
-
-
- <optional>
-
-
-
-
-
- |
-
-
-
-
-
- '='
-
- |
-
-
- The join condition, eg. =,<,>,<>,!=,etc. |
-
-
-
-
-
-
- joinTo |
-
-
-
-
-
-String
-
-
-
|
@@ -2332,7 +2297,7 @@
- The value of the condition you are joining on, whether another table's field, or a literal value |
+ The join condition. |
@@ -2408,7 +2373,7 @@
@@ -2634,7 +2599,7 @@
@@ -2813,7 +2778,7 @@
@@ -3039,7 +3004,7 @@
@@ -3230,7 +3195,7 @@
@@ -3318,7 +3283,7 @@ prefixed with 'OR'
@@ -3503,7 +3468,7 @@ prefixed with 'OR'
@@ -3729,7 +3694,7 @@ prefixed with 'OR'
@@ -3817,7 +3782,7 @@ prefixed with 'OR NOT'
@@ -4043,7 +4008,7 @@ prefixed with 'OR NOT'
@@ -4228,7 +4193,7 @@ prefixed with 'OR NOT'
@@ -4387,7 +4352,7 @@ prefixed with 'OR NOT'
@@ -4546,7 +4511,7 @@ prefixed with 'OR NOT'
@@ -4685,7 +4650,7 @@ prefixed with 'OR NOT'
@@ -4867,7 +4832,7 @@ prefixed with 'OR NOT'
@@ -5077,7 +5042,7 @@ prefixed with 'OR NOT'
@@ -5262,7 +5227,7 @@ prefixed with 'OR NOT'
@@ -5421,7 +5386,7 @@ prefixed with 'OR NOT'
@@ -5580,7 +5545,7 @@ prefixed with 'OR NOT'
@@ -5644,7 +5609,7 @@ prefixed with 'OR NOT'
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/module-query-parser.html b/docs/module-query-parser.html
new file mode 100644
index 0000000..9801a92
--- /dev/null
+++ b/docs/module-query-parser.html
@@ -0,0 +1,409 @@
+
+
+
+
+
+ DocStrap Module: query-parser
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: query-parser
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+-
+
compileJoin(condition) → {String}
+
+
+
+-
+
+
+
+
Return the output of the parsing of the join condition
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ condition |
+
+
+
+
+
+String
+
+
+
+ |
+
+
+
+
+
+ The join condition to evalate |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Returns:
+
+
+
+
+- The parsed/escaped join condition
+
+
+
+
+
+
+ -
+ Type
+
+ -
+
+String
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/modules.list.html b/docs/modules.list.html
index 26212b8..4bf805e 100644
--- a/docs/modules.list.html
+++ b/docs/modules.list.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -154,7 +158,7 @@
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/node-query.js.html b/docs/node-query.js.html
index 636017c..b2b7855 100644
--- a/docs/node-query.js.html
+++ b/docs/node-query.js.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -125,7 +129,7 @@ module.exports = nodeQuery.init;
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/query-builder.js.html b/docs/query-builder.js.html
index 26b483b..82b21e9 100644
--- a/docs/query-builder.js.html
+++ b/docs/query-builder.js.html
@@ -47,6 +47,10 @@
query-builder
+
+ query-parser
+
+
@@ -94,6 +98,8 @@ var QueryBuilder = function(driver, adapter) {
// That 'new' keyword is annoying
if ( ! (this instanceof QueryBuilder)) return new QueryBuilder(driver, adapter);
+ var parser = require('./query-parser')(driver);
+
/**
* "Private" methods
*
@@ -141,9 +147,8 @@ var QueryBuilder = function(driver, adapter) {
switch(type) {
case "insert":
- var paramCount = state.setArrayKeys.length;
- var params = [];
- params.fill('?', 0, paramCount);
+ var params = new Array(state.setArrayKeys.length);
+ params.fill('?');
sql = "INSERT INTO " + table + " (";
sql += state.setArrayKeys.join(',');
@@ -191,7 +196,7 @@ var QueryBuilder = function(driver, adapter) {
val = "%" + val + "%";
}
- conj = (state.queryMap.length < 1) ? ' WHERE ' : ' ' + conj + '';
+ conj = (state.queryMap.length < 1) ? ' WHERE ' : ' ' + conj + ' ';
_p.appendMap(conj, like, 'like');
state.whereValues.push(val);
@@ -217,34 +222,38 @@ var QueryBuilder = function(driver, adapter) {
*
* @private
*/
- mixedSet: function(/* varName, valType, key, [val] */) {
- var args = getArgs('varName:string, valType:string, key:string|object, [val]:string|number|boolean', arguments);
+ mixedSet: function(/* $varName, $valType, $key, [$val] */) {
+ var args = getArgs('$varName:string, $valType:string, $key:object|string|number, [$val]', arguments);
var obj = {};
- if (helpers.isScalar(args.key) && !helpers.isUndefined(args.val) && !helpers.isNull(args.val))
+ if (helpers.isScalar(args.$key) && !helpers.isUndefined(args.$val) && !helpers.isNull(args.$val))
{
- obj[args.key] = args.val;
+ obj[args.$key] = args.$val;
+ }
+ else if ( ! helpers.isScalar(args.$key))
+ {
+ obj = args.$key;
}
else
{
- obj = args.key;
+ throw new Error("Invalid arguments passed");
}
Object.keys(obj).forEach(function(k) {
// If a single value for the return
- if (['key','value'].indexOf(args.valType) !== -1)
+ if (['key','value'].indexOf(args.$valType) !== -1)
{
- var pushVal = (args.valType === 'key') ? k : obj[k];
- state[args.varName].push(pushVal);
+ var pushVal = (args.$valType === 'key') ? k : obj[k];
+ state[args.$varName].push(pushVal);
}
else
{
- state[args.varName][k] = obj[k];
+ state[args.$varName][k] = obj[k];
}
});
- return state[args.varName];
+ return state[args.$varName];
},
whereMixedSet: function(/*key, val*/) {
var args = getArgs('key:string|object, [val]', arguments);
@@ -263,12 +272,12 @@ var QueryBuilder = function(driver, adapter) {
Object.keys(state.whereMap).forEach(function(field) {
// Split each key by spaces, in case there
// is an operator such as >, <, !=, etc.
- var fieldArray = field.split(' ');
+ var fieldArray = field.trim().split(' ').map(helpers.stringTrim);
var item = driver.quoteIdentifiers(fieldArray[0]);
// Simple key value, or an operator?
- item += (fieldArray.length === 1) ? '=?' : " " + fieldArray[1] + " ?";
+ item += (fieldArray.length === 1 || fieldArray[1] === '') ? '=?' : " " + fieldArray[1] + " ?";
var firstItem = state.queryMap[0],
lastItem = state.queryMap[state.queryMap.length - 1];
@@ -315,25 +324,29 @@ var QueryBuilder = function(driver, adapter) {
});
});
},
- whereIn: function(key, val, inClause, conj) {
- key = driver.quoteIdentifiers(key);
- var params = [];
- params.fill('?', 0, val.length);
+ whereIn: function(/*key, val, inClause, conj*/) {
+ var args = getArgs('key:string, val:array, inClause:string, conj:string', arguments);
- val.forEach(function(value) {
+ args.key = driver.quoteIdentifiers(args.key);
+ var params = new Array(args.val.length);
+ params.fill('?');
+
+ args.val.forEach(function(value) {
state.whereValues.push(value);
});
- conj = (state.queryMap.length > 0) ? " " + conj + " " : ' WHERE ';
- var str = key + " " + inClause + " (" + params.join(',') + ") ";
+ args.conj = (state.queryMap.length > 0) ? " " + args.conj + " " : ' WHERE ';
+ var str = args.key + " " + args.inClause + " (" + params.join(',') + ") ";
- _p.appendMap(conj, str, 'whereIn');
+ _p.appendMap(args.conj, str, 'whereIn');
},
run: function(type, table, callback, sql, vals) {
if ( ! sql)
{
sql = _p.compile(type, table);
}
+//console.log(sql);
+//console.log('------------------------');
if ( ! vals)
{
@@ -628,12 +641,12 @@ var QueryBuilder = function(driver, adapter) {
* @param {String} [val] - The value if using a scalar key
* @return this
*/
- this.set = function(/* key, [val] */) {
- var args = getArgs('key:string|object, [val]:string', arguments);
+ this.set = function(/* $key, [$val] */) {
+ var args = getArgs('$key, [$val]', arguments);
// Set the appropriate state variables
- _p.mixedSet('setArrayKeys', 'key', args.key, args.val);
- _p.mixedSet('values', 'value', args.key, args.val);
+ _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
@@ -649,16 +662,26 @@ var QueryBuilder = function(driver, adapter) {
/**
* Add a join clause to the query
*
- * @param {String} joinOn - The table you are joining
- * @param {String} [cond='='] - The join condition, eg. =,<,>,<>,!=,etc.
- * @param {String} joinTo - The value of the condition you are joining on, whether another table's field, or a literal value
+ * @param {String} table - The table you are joining
+ * @param {String} cond - The join condition.
* @param {String} [type='inner'] - The type of join, which defaults to inner
* @return this
*/
- this.join = function(/* joinOn, [cond='='], joinTo, [type='inner']*/) {
- var args = getArgs('joinOn:string, [cond]:string, joinTo:string, [type]:string', arguments);
- args.cond = args.cond || '=';
- args.type = args.type || "inner";
+ this.join = function(table, cond, type) {
+ type = type || "inner";
+
+ // Prefix/quote table name
+ var table = table.split(' ').map(helpers.stringTrim);
+ table[0] = driver.quoteTable(table[0]);
+ table = table.map(driver.quoteIdentifiers);
+ table = table.join(' ');
+
+ // Parse out the join condition
+ var parsedCondition = parser.compileJoin(cond);
+ var condition = table + ' ON ' + parsedCondition;
+
+ // Append the join condition to the query map
+ _p.appendMap("\n" + type.toUpperCase() + ' JOIN ', condition, 'join');
return this;
};
@@ -810,13 +833,14 @@ var QueryBuilder = function(driver, adapter) {
* @param {Function} callback - Callback for handling response from the database
* @return void
*/
- this.insert = function(table, data, callback) {
- if (data) {
- this.set(data);
+ this.insert = function(/* table, data, callback */) {
+ var args = getArgs('table:string, [data]:object, callback:function', arguments);
+ if (args.data) {
+ this.set(args.data);
}
// Run the query
- _p.run('insert', table, callback);
+ _p.run('insert', args.table, args.callback);
};
/**
@@ -925,7 +949,7 @@ module.exports = QueryBuilder;
Documentation generated by JSDoc 3.3.0-alpha9
- on Thu Oct 23rd 2014 using the DocStrap template.
diff --git a/docs/query-parser.js.html b/docs/query-parser.js.html
new file mode 100644
index 0000000..d930381
--- /dev/null
+++ b/docs/query-parser.js.html
@@ -0,0 +1,264 @@
+
+
+
+
+
+ DocStrap Source: query-parser.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Source: query-parser.js
+
+
+
+ 'use strict';
+
+var helpers = require('./helpers');
+
+var matchPatterns = {
+ 'function': /([a-zA-Z0-9_]+\((.*?)\))/i,
+ identifier: /([a-zA-Z0-9_\-]+\.?)+/ig,
+ operator: /\=|AND|&&?|~|\|\|?|\^|\/|>=?|<=?|-|%|OR|\+|NOT|\!=?|<>|XOR/i
+};
+
+// Full pattern for determining ordering of the pieces
+matchPatterns.combined = new RegExp(matchPatterns['function'].source + "+|"
+ + matchPatterns.identifier.source
+ + '|(' + matchPatterns.operator.source + ')+', 'ig');
+
+var filterMatches = function(array) {
+ var output = [];
+
+ // Return non-array matches
+ if (helpers.isScalar(array) || helpers.isNull(array) || helpers.isUndefined(array)) return output;
+
+ array.forEach(function(item) {
+ if ( ! helpers.isUndefined(item))
+ {
+ output.push(item);
+ }
+ });
+
+ 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;
+};
+
+// --------------------------------------------------------------------------
+
+/**
+ * @constructor
+ * @param {Driver} - The driver object for the database in use
+ * @module query-parser
+ */
+var QueryParser = function(driver) {
+
+ // That 'new' keyword is annoying
+ if ( ! (this instanceof QueryParser)) return new QueryParser(driver);
+
+ /**
+ * Return the output of the parsing of the join condition
+ *
+ * @param {String} condition - The join condition to evalate
+ * @return {String} - The parsed/escaped join condition
+ */
+ this.compileJoin = function(condition) {
+ var parts = parseJoin(condition);
+ var count = parts.identifiers.length;
+ var i;
+
+ // Quote the identifiers
+ parts.combined.forEach(function(part, i) {
+ if (parts.identifiers.indexOf(part) !== -1 && ! helpers.isNumber(part))
+ {
+ parts.combined[i] = driver.quoteIdentifiers(part);
+ }
+ });
+
+ return parts.combined.join('');
+ };
+};
+
+module.exports = QueryParser;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+