Start of coversion to ES6-style code with transpiling

This commit is contained in:
Timothy Warren 2015-12-02 13:01:31 -05:00
parent 5f20e0adb4
commit 6a9c67b924
68 changed files with 4157 additions and 1949 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +1,123 @@
var gulp = require('gulp'), var babel = require('gulp-babel'),
concat = require('gulp-concat'),
documentation = require('gulp-documentation'), documentation = require('gulp-documentation'),
eslint = require('gulp-eslint'),
gulp = require('gulp'),
istanbul = require('gulp-babel-istanbul'),
nodeunit_runner = require('gulp-nodeunit-runner'), nodeunit_runner = require('gulp-nodeunit-runner'),
istanbul = require('gulp-istanbul'); sloc = require('gulp-sloc'),
sourcemaps = require('gulp-sourcemaps');
gulp.task('default', ['docs', 'test']); gulp.task('transpile', function() {
return gulp.src('src/**/*.js')
.pipe(sourcemaps.init())
.pipe(babel({
presets: ['es2015'],
plugins: ['transform-es2015-modules-commonjs']
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('lib'));
});
gulp.task('docs', function() { gulp.task('lint', function() {
gulp.src('./lib/node-query.js') return gulp.src('src/**/*.js')
.pipe(eslint({
"env": {
"node": true,
"es6": true
},
"ecmaFeatures": {
"arrowFunctions": true,
"blockBindings": true,
"classes": true,
"defaultParams": true,
"destructuring": true,
"forOf": true,
"modules": true
},
"rules": {
"radix": [2],
"no-with": [2],
"no-eval": [2],
"no-unreachable": [2],
"no-irregular-whitespace": [1],
"no-new-wrappers": [2],
"curly" : [2, "multi-line"],
"no-implied-eval": [2],
"no-invalid-this": [2],
"constructor-super": [2],
"no-dupe-class-members": [2],
"no-this-before-super": [2],
"prefer-arrow-callback": [1],
"no-var": [1],
"valid-jsdoc": [1]
}
}))
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
gulp.task('lint-tests', ['lint'], function() {
return gulp.src('tests/**/*.js')
.pipe(eslint({
"env": {
"node": true
},
"rules": {
"radix": [2],
"no-with": [2],
"no-eval": [2],
"no-unreachable": [1],
"no-irregular-whitespace": [1],
"curly" : [2, "multi-line"],
"no-implied-eval": [2],
"no-invalid-this": [2],
"no-dupe-class-members": [2],
"block-scoped-var": [2]
}
}))
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
gulp.task('sloc', ['transpile'], function() {
gulp.src(['src/**/*.js'])
.pipe(sloc());
gulp.src(['lib/**/*.js'])
.pipe(sloc());
})
gulp.task('docs', ['transpile'], function() {
gulp.src('./src/QueryBuilder.js')
.pipe(documentation({format: 'html'})) .pipe(documentation({format: 'html'}))
.pipe(gulp.dest('docs')); .pipe(gulp.dest('docs'));
gulp.src('./lib/node-query.js') /*gulp.src('./lib/QueryBuilder.js')
.pipe(documentation({format: 'md'})) .pipe(documentation({format: 'md'}))
.pipe(gulp.dest('api-docs')); .pipe(gulp.dest('api-docs'));*/
}); });
gulp.task('pre-test', function() { gulp.task('nodeunit', ['transpile', 'lint-tests'], function() {
return gulp.src(['tests/**/*_test.js'])
.pipe(nodeunit_runner());
});
gulp.task('fast-test', ['transpile', 'lint-tests'], function() {
return gulp.src(['tests/**/*_test.js'])
.pipe(nodeunit_runner());
});
gulp.task('test', ['transpile', 'lint-tests'], function(cb) {
return gulp.src(['lib/**/*.js']) return gulp.src(['lib/**/*.js'])
.pipe(istanbul()) .pipe(istanbul())
.pipe(istanbul.hookRequire()); .pipe(istanbul.hookRequire())
.on('finish', function () {
gulp.src(['tests/**/*_test.js'])
.pipe(nodeunit_runner())
.pipe(istanbul.writeReports({
dir: './coverage',
reporters: ['lcov', 'lcovonly', 'html', 'text']
}));
});
}); });
gulp.task('test', ['pre-test'], function() { gulp.task('default', ['lint', 'sloc', 'docs', 'test']);
return gulp.src(['tests/**/*_test.js'])
.pipe(nodeunit_runner())
.pipe(istanbul.writeReports({
dir: './coverage',
reporters: ['lcov', 'lcovonly', 'html', 'text']
}));
});

42
lib/Adapter.js Executable file
View File

@ -0,0 +1,42 @@
'use strict'
/** @module Adapter */
;
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
module.exports = (function () {
/**
* Invoke an adapter
*
* @param {Object} instance - The connection objec
* @return {void}
*/
function Adapter(instance) {
_classCallCheck(this, Adapter);
this.instance = instance;
}
/**
* Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return {void}
*/
_createClass(Adapter, [{
key: "execute",
value: function execute() /*sql, params, callback*/{
throw new Error("Correct adapter not defined for query execution");
}
}]);
return Adapter;
})();
//# sourceMappingURL=Adapter.js.map

1
lib/Adapter.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["Adapter.js"],"names":[],"mappings":"AAAA;;;AAAY,CAAC;;;;;;AAGb,MAAM,CAAC,OAAO;;;;;;;;AAOb,UAPsB,OAAO,CAOjB,QAAQ,EAAE;wBAPA,OAAO;;AAQ5B,MAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;EACzB;;;;;;;;;;AAAA;cATqB,OAAO;;qDAmBM;AAClC,SAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;GACnE;;;QArBqB,OAAO;IAsB7B,CAAA","file":"Adapter.js","sourcesContent":["'use strict';\n\n/** @module Adapter */\nmodule.exports = class Adapter {\n\t/**\n\t * Invoke an adapter\n\t *\n\t * @param {Object} instance - The connection objec\n\t * @return {void}\n\t */\n\tconstructor(instance) {\n\t\tthis.instance = instance;\n\t}\n\n\t/**\n\t * Run the sql query as a prepared statement\n\t *\n\t * @param {String} sql - The sql with placeholders\n\t * @param {Array} params - The values to insert into the query\n\t * @param {Function} callback - Callback to run when a response is recieved\n\t * @return {void}\n\t */\n\texecute(/*sql, params, callback*/) {\n\t\tthrow new Error(\"Correct adapter not defined for query execution\");\n\t}\n}"],"sourceRoot":"/source/"}

157
lib/DriverBase.js Executable file
View File

@ -0,0 +1,157 @@
'use strict';
var _helpers = require('./helpers');
var _helpers2 = _interopRequireDefault(_helpers);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Base Database Driver
*
* @module driver
*/
var d = {
identifierStartChar: '"',
identifierEndChar: '"',
tablePrefix: null,
hasTruncate: true,
/**
* Low level function for naive quoting of strings
* @param {String} str
* @return {String}
* @private
*/
_quote: function _quote(str) {
return _helpers2.default.isString(str) && !(str.startsWith(d.identifierStartChar) || str.endsWith(d.identifierEndChar)) ? d.identifierStartChar + str + d.identifierEndChar : str;
},
/**
* Set the limit clause
* @param {String} sql
* @param {Number} limit
* @param {Number|null} offset
* @return {String}
*/
limit: function limit(sql, _limit, offset) {
sql += " LIMIT " + _limit;
if (_helpers2.default.isNumber(offset)) {
sql += " OFFSET " + offset;
}
return sql;
},
/**
* Quote database table name, and set prefix
*
* @param {String} table
* @return {String}
*/
quoteTable: function quoteTable(table) {
// Quote after prefix
return d.quoteIdentifiers(table);
},
/**
* Use the driver's escape character to quote identifiers
*
* @param {String|Array}
* @return {String|Array}
*/
quoteIdentifiers: function quoteIdentifiers(str) {
var hiers, raw;
var pattern = new RegExp(d.identifierStartChar + '(' + '([a-zA-Z0-9_]+)' + '(\((.*?)\))' + ')' + d.identifierEndChar, 'ig');
// Recurse for arrays of identifiiers
if (Array.isArray(str)) {
return str.map(d.quoteIdentifiers);
}
// Handle commas
if (str.includes(',')) {
var parts = str.split(',').map(_helpers2.default.stringTrim);
str = parts.map(d.quoteIdentifiers).join(',');
}
// Split identifiers by period
hiers = str.split('.').map(d._quote);
raw = hiers.join('.');
// Fix functions
if (raw.includes('(') && raw.includes(')')) {
var funcs = pattern.exec(raw);
// Unquote the function
raw = raw.replace(funcs[0], funcs[1]);
// Quote the identifiers inside of the parens
var inParens = funcs[3].substring(1, funcs[3].length - 1);
raw = raw.replace(inParens, d.quoteIdentifiers(inParens));
}
return raw;
},
/**
* SQL to truncate the passed table
*
* @param {String} table
* @return {String} - sql
*/
truncate: function truncate(table) {
var sql = d.hasTruncate ? 'TRUNCATE ' : 'DELETE FROM ';
sql += d.quoteTable(table);
return sql;
},
/**
* SQL to insert a group of rows
*
* @param {String} table - The table to insert to
* @param {Array} [data] - The array of object containing data to insert
* @return {String}
*/
insertBatch: function insertBatch(table, data) {
var vals = [],
fields = Object.keys(data[0]),
sql = "",
params = [],
paramString = "",
paramList = [];
// Get the data values to insert, so they can
// be parameterized
data.forEach(function (obj) {
Object.keys(obj).forEach(function (key) {
vals.push(obj[key]);
});
});
// Get the field names from the keys of the first
// object inserted
table = d.quoteTable(table);
sql += "INSERT INTO " + table + " (" + d.quoteIdentifiers(fields).join(",") + ") VALUES ";
// Create placeholder groups
params = Array(fields.length).fill('?');
paramString = "(" + params.join(',') + ")";
paramList = Array(data.length).fill(paramString);
sql += paramList.join(',');
return {
sql: sql,
values: vals
};
}
};
module.exports = d;
//# sourceMappingURL=DriverBase.js.map

1
lib/DriverBase.js.map Normal file

File diff suppressed because one or more lines are too long

22
lib/DriverClass.js Normal file
View File

@ -0,0 +1,22 @@
'use strict';
var _DriverBase = require('./DriverBase');
var _DriverBase2 = _interopRequireDefault(_DriverBase);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
module.exports = function DriverClass() {
var _this = this;
var properties = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
_classCallCheck(this, DriverClass);
Object.keys(_DriverBase2.default).forEach(function (key) {
_this[key] = Object.keys(properties).indexOf(key) !== -1 ? properties[key] : _DriverBase2.default[key];
});
};
//# sourceMappingURL=DriverClass.js.map

1
lib/DriverClass.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["DriverClass.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;AAIb,MAAM,CAAC,OAAO,GACb,SADsB,WAAW,GACJ;;;KAAjB,UAAU,yDAAG,EAAE;;uBADL,WAAW;;AAEhC,OAAM,CAAC,IAAI,sBAAY,CAAC,OAAO,CAAC,UAAC,GAAG,EAAK;AACxC,QAAK,GAAG,CAAC,GAAG,AAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GACrD,UAAU,CAAC,GAAG,CAAC,GACf,qBAAW,GAAG,CAAC,CAAC;EACnB,CAAC,CAAC;CACH,AACD,CAAA","file":"DriverClass.js","sourcesContent":["'use strict';\n\nimport driverBase from './DriverBase';\n\nmodule.exports = class DriverClass {\n\tconstructor(properties = {}) {\n\t\tObject.keys(driverBase).forEach((key) => {\n\t\t\tthis[key] = (Object.keys(properties).indexOf(key) !== -1)\n\t\t\t\t? properties[key]\n\t\t\t\t: driverBase[key];\n\t\t});\n\t}\n}"],"sourceRoot":"/source/"}

103
lib/NodeQuery.js Executable file
View File

@ -0,0 +1,103 @@
"use strict";
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
var _helpers = require('./helpers');
var _helpers2 = _interopRequireDefault(_helpers);
var _QueryBuilder = require('./QueryBuilder');
var _QueryBuilder2 = _interopRequireDefault(_QueryBuilder);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var instance = null;
/**
* @module NodeQuery
*/
var NodeQuery = (function () {
/**
* Constructor
*/
function NodeQuery() {
_classCallCheck(this, NodeQuery);
this.instance = null;
}
/**
* Create a query builder object
*
* @memberOf NodeQuery
* @param {String} drivername - The name of the database type, eg. mysql or pg
* @param {Object} connObject - A connection object from the database library you are connecting with
* @param {String} [connLib] - The name of the db connection library you are using, eg. mysql or mysql2. Optional if the same as drivername
* @return {QueryBuilder}
*/
_createClass(NodeQuery, [{
key: 'init',
value: function init(driverType, connObject, connLib) {
connLib = connLib || driverType;
var paths = {
driver: __dirname + '/drivers/' + _helpers2.default.upperCaseFirst(driverType),
adapter: __dirname + '/adapters/' + connLib
};
/*Object.keys(paths).forEach((type) => {
if ( ! fs.existsSync(paths[type]))
{
console.log(paths[type]);
throw new Error(
`Selected ${type} (` +
helpers.upperCaseFirst(driverType) +
`) does not exist!`
);
}
});*/
var driver = require(paths.driver);
var $adapter = require(paths.adapter);
var adapter = new $adapter(connObject);
this.instance = new _QueryBuilder2.default(driver, adapter);
return this.instance;
}
}, {
key: 'getQuery',
/**
* Return an existing query builder instance
*
* @memberOf NodeQuery
* @return {QueryBuilder}
*/
value: function getQuery() {
if (!this.instance) {
throw new Error("No Query Builder instance to return");
}
return this.instance;
}
}]);
return NodeQuery;
})();
;
module.exports = new NodeQuery();
//# sourceMappingURL=NodeQuery.js.map

1
lib/NodeQuery.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["NodeQuery.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;AAEb,IAAI,QAAQ,GAAG,IAAI,CAAC;;;;;;IAQd,SAAS;;;;;;AAKd,UALK,SAAS,GAKA;wBALT,SAAS;;AAMb,MAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;EACrB;;;;;;;;;;;AAAA;cAPI,SAAS;;uBAkBT,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE;AACrC,UAAO,GAAG,OAAO,IAAI,UAAU,CAAC;;AAEhC,OAAI,KAAK,GAAG;AACX,UAAM,EAAE,AAAG,SAAS,iBAAc,kBAAQ,cAAc,CAAC,UAAU,CAAC;AACpE,WAAO,EAAK,SAAS,kBAAa,OAAO,AAAE;IAC3C;;;;;;;;;;;;;;AAAC,AAcF,OAAI,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AACnC,OAAI,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACtC,OAAI,OAAO,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;;AAEvC,OAAI,CAAC,QAAQ,GAAG,2BAAiB,MAAM,EAAE,OAAO,CAAC,CAAC;;AAElD,UAAO,IAAI,CAAC,QAAQ,CAAC;GACrB;;;;;;;;;;6BAQU;AACV,OAAK,CAAE,IAAI,CAAC,QAAQ,EAAE;AACrB,UAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACvD;;AAED,UAAO,IAAI,CAAC,QAAQ,CAAC;GACrB;;;QA3DI,SAAS;;;AA6Dd,CAAC;;AAEF,MAAM,CAAC,OAAO,GAAG,IAAI,SAAS,EAAE,CAAC","file":"NodeQuery.js","sourcesContent":["\"use strict\";\n\nlet instance = null;\nimport fs from 'fs';\nimport helpers from './helpers';\nimport QueryBuilder from './QueryBuilder';\n\n/**\n * @module NodeQuery\n */\nclass NodeQuery {\n\n\t/**\n\t * Constructor\n\t */\n\tconstructor() {\n\t\tthis.instance = null;\n\t}\n\n\t/**\n\t * Create a query builder object\n\t *\n\t * @memberOf NodeQuery\n\t * @param {String} drivername - The name of the database type, eg. mysql or pg\n\t * @param {Object} connObject - A connection object from the database library you are connecting with\n\t * @param {String} [connLib] - The name of the db connection library you are using, eg. mysql or mysql2. Optional if the same as drivername\n\t * @return {QueryBuilder}\n\t */\n\tinit(driverType, connObject, connLib) {\n\t\tconnLib = connLib || driverType;\n\n\t\tlet paths = {\n\t\t\tdriver: `${__dirname}/drivers/` + helpers.upperCaseFirst(driverType),\n\t\t\tadapter: `${__dirname}/adapters/${connLib}`\n\t\t};\n\n\t\t/*Object.keys(paths).forEach((type) => {\n\t\t\tif ( ! fs.existsSync(paths[type]))\n\t\t\t{\n\t\t\t\tconsole.log(paths[type]);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Selected ${type} (` +\n\t\t\t\t\thelpers.upperCaseFirst(driverType) +\n\t\t\t\t\t`) does not exist!`\n\t\t\t\t);\n\t\t\t}\n\t\t});*/\n\n\t\tlet driver = require(paths.driver);\n\t\tlet $adapter = require(paths.adapter);\n\t\tlet adapter = new $adapter(connObject);\n\n\t\tthis.instance = new QueryBuilder(driver, adapter);\n\n\t\treturn this.instance;\n\t};\n\n\t/**\n\t * Return an existing query builder instance\n\t *\n\t * @memberOf NodeQuery\n\t * @return {QueryBuilder}\n\t */\n\tgetQuery() {\n\t\tif ( ! this.instance) {\n\t\t\tthrow new Error(\"No Query Builder instance to return\");\n\t\t}\n\n\t\treturn this.instance;\n\t};\n\n};\n\nmodule.exports = new NodeQuery();"],"sourceRoot":"/source/"}

1063
lib/QueryBuilder.js Executable file

File diff suppressed because it is too large Load Diff

1
lib/QueryBuilder.js.map Normal file

File diff suppressed because one or more lines are too long

278
lib/QueryParser.js Normal file
View File

@ -0,0 +1,278 @@
'use strict';
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _helpers = require('./helpers');
var _helpers2 = _interopRequireDefault(_helpers);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
// --------------------------------------------------------------------------
/**
* @constructor
* @param {Driver} - The driver object for the database in use
* @module query-parser
*/
module.exports = (function () {
/**
* @constructor
* @param {Driver} - The driver object for the database in use
* @return {void}
*/
function QueryParser(driver) {
_classCallCheck(this, QueryParser);
this.driver = driver;
var matchPatterns = {
'function': /([a-z0-9_]+\((.*)\))/i,
operator: /\!=?|\=|\+|&&?|~|\|\|?|\^|\/|<>|>=?|<=?|\-|%|OR|AND|NOT|XOR/ig,
literal: /([0-9]+)|'(.*?)'|true|false/ig
};
// Full pattern for identifiers
// Making sure that literals and functions aren't matched
matchPatterns.identifier = new RegExp('(' + '(?!' + matchPatterns['function'].source + '|' + matchPatterns.literal.source + ')' + '([a-z_\-]+[0-9]*\\.?)' + ')+', 'ig');
// Full pattern for determining ordering of the pieces
matchPatterns.joinCombined = new RegExp(matchPatterns['function'].source + "+|" + matchPatterns.literal.source + '+|' + matchPatterns.identifier.source + '|(' + matchPatterns.operator.source + ')+', 'ig');
this.matchPatterns = matchPatterns;
this.identifierBlacklist = ['true', 'false', 'null'];
}
/**
* Filter matched patterns
*
* @param {Array} array
* @return {Array|null}
*/
_createClass(QueryParser, [{
key: 'filterMatches',
value: function filterMatches(array) {
var output = [];
// Return non-array matches
if (_helpers2.default.isNull(array)) return null;
if (_helpers2.default.isScalar(array) || _helpers2.default.isUndefined(array)) return output;
array.forEach(function (item) {
output.push(item);
});
return output;
}
/**
* Check if the string contains an operator, and if so, return the operator(s).
* If there are no matches, return null
*
* @param {String} string - the string to check
* @return {Array|null}
*/
}, {
key: 'hasOperator',
value: function hasOperator(string) {
return this.filterMatches(string.match(this.matchPatterns.operator));
}
/**
* Tokenize the sql into parts for additional processing
*
* @param {String} sql
* @return {Object}
*/
}, {
key: 'parseJoin',
value: function parseJoin(sql) {
var _this = this;
var matches = {};
var output = {
functions: [],
identifiers: [],
operators: [],
literals: []
};
// Get clause components
matches.functions = sql.match(new RegExp(this.matchPatterns['function'].source, 'ig'));
matches.identifiers = sql.match(this.matchPatterns.identifier);
matches.operators = sql.match(this.matchPatterns.operator);
matches.literals = sql.match(this.matchPatterns.literal);
// Get everything at once for ordering
matches.combined = sql.match(this.matchPatterns.joinCombined);
// Flatten the matches to increase relevance
Object.keys(matches).forEach(function (key) {
output[key] = _this.filterMatches(matches[key]);
});
return output;
}
/**
* 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
*/
}, {
key: 'compileJoin',
value: function compileJoin(condition) {
var _this2 = this;
var parts = this.parseJoin(condition);
var count = parts.identifiers.length;
var i = undefined;
// Quote the identifiers
parts.combined.forEach(function (part, i) {
if (parts.identifiers.indexOf(part) !== -1 && !_helpers2.default.isNumber(part)) {
parts.combined[i] = _this2.driver.quoteIdentifiers(part);
}
});
return parts.combined.join(' ');
}
/**
* Parse a where clause to separate functions from values
*
* @param {Driver} driver
* @param {State} state
* @return {String} - The parsed/escaped where condition
*/
}, {
key: 'parseWhere',
value: function parseWhere(driver, state) {
var _this3 = this;
var whereMap = state.whereMap;
var whereValues = state.rawWhereValues;
var outputMap = [];
var outputValues = [];
Object.keys(whereMap).forEach(function (key) {
// Combine fields, operators, functions and values into a full clause
// to have a common starting flow
var fullClause = '';
// Add an explicit = sign where one is inferred
if (!_this3.hasOperator(key)) {
fullClause = key + ' = ' + whereMap[key];
} else if (whereMap[key] === key) {
fullClause = key;
} else {
fullClause = key + ' ' + whereMap[key];
}
// Separate the clause into separate pieces
var parts = _this3.parseJoin(fullClause);
// Filter explicit literals from lists of matches
if (whereValues.indexOf(whereMap[key]) !== -1) {
var value = whereMap[key];
var identIndex = _helpers2.default.isArray(parts.identifiers) ? parts.identifiers.indexOf(value) : -1;
var litIndex = _helpers2.default.isArray(parts.literals) ? parts.literals.indexOf(value) : -1;
var combIndex = _helpers2.default.isArray(parts.combined) ? parts.combined.indexOf(value) : -1;
var funcIndex = _helpers2.default.isArray(parts.functions) ? parts.functions.indexOf(value) : -1;
var inOutputArray = outputValues.indexOf(value) !== -1;
// Remove the identifier in question,
// and add to the output values array
if (identIndex !== -1) {
parts.identifiers.splice(identIndex, 1);
if (!inOutputArray) {
outputValues.push(value);
inOutputArray = true;
}
}
// Remove the value from the literals list
// so it is not added twice
if (litIndex !== -1) {
parts.literals.splice(litIndex, 1);
if (!inOutputArray) {
outputValues.push(value);
inOutputArray = true;
}
}
// Remove the value from the combined list
// and replace it with a placeholder
if (combIndex !== -1) {
// Make sure to skip functions when replacing values
if (funcIndex === -1) {
parts.combined[combIndex] = '?';
if (!inOutputArray) {
outputValues.push(value);
inOutputArray = true;
}
}
}
}
// Filter false positive identifiers
parts.identifiers = parts.identifiers || [];
parts.identifiers = parts.identifiers.filter(function (item) {
var isInCombinedMatches = parts.combined.indexOf(item) !== -1;
var isNotInBlackList = _this3.identifierBlacklist.indexOf(item.toLowerCase()) === -1;
return isInCombinedMatches && isNotInBlackList;
}, _this3);
// Quote identifiers
if (_helpers2.default.isArray(parts.identifiers)) {
parts.identifiers.forEach(function (ident) {
var index = parts.combined.indexOf(ident);
if (index !== -1) {
parts.combined[index] = driver.quoteIdentifiers(ident);
}
});
}
// Replace each literal with a placeholder in the map
// and add the literal to the values,
// This should only apply to literal values that are not
// explicitly mapped to values, but have to be parsed from
// a where condition,
if (_helpers2.default.isArray(parts.literals)) {
parts.literals.forEach(function (lit) {
var litIndex = parts.combined.indexOf(lit);
if (litIndex !== -1) {
parts.combined[litIndex] = _helpers2.default.isArray(parts.operators) ? '?' : '= ?';
outputValues.push(lit);
}
});
}
outputMap.push(parts.combined.join(' '));
});
state.rawWhereValues = [];
state.whereValues = state.whereValues.concat(outputValues);
state.whereMap = outputMap;
return state;
}
}]);
return QueryParser;
})();
//# sourceMappingURL=QueryParser.js.map

1
lib/QueryParser.js.map Normal file

File diff suppressed because one or more lines are too long

34
lib/State.js Normal file
View File

@ -0,0 +1,34 @@
'use strict'
/** @module State */
;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
module.exports = function State() {
_classCallCheck(this, State);
// Arrays/maps
this.queryMap = [];
this.values = [];
this.whereValues = [];
this.setArrayKeys = [];
this.orderArray = [];
this.groupArray = [];
this.havingMap = [];
this.whereMap = [];
this.rawWhereValues = [];
// Partials
this.selectString = '';
this.fromString = '';
this.setString = '';
this.orderString = '';
this.groupString = '';
// Other various values
this.limit = null;
this.offset = null;
};
// End of module State
//# sourceMappingURL=State.js.map

1
lib/State.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["State.js"],"names":[],"mappings":"AAAA;;;AAAY,CAAC;;;;AAGb,MAAM,CAAC,OAAO,GACb,SADsB,KAAK,GACb;uBADQ,KAAK;;;AAG1B,KAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;AACnB,KAAI,CAAC,MAAM,GAAG,EAAE,CAAC;AACjB,KAAI,CAAC,WAAW,GAAG,EAAE,CAAC;AACtB,KAAI,CAAC,YAAY,GAAG,EAAE,CAAC;AACvB,KAAI,CAAC,UAAU,GAAG,EAAE,CAAC;AACrB,KAAI,CAAC,UAAU,GAAG,EAAE,CAAC;AACrB,KAAI,CAAC,SAAS,GAAG,EAAE,CAAC;AACpB,KAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;AACnB,KAAI,CAAC,cAAc,GAAG,EAAE;;;AAAC,AAGzB,KAAI,CAAC,YAAY,GAAG,EAAE,CAAC;AACvB,KAAI,CAAC,UAAU,GAAG,EAAE,CAAC;AACrB,KAAI,CAAC,SAAS,GAAG,EAAE,CAAC;AACpB,KAAI,CAAC,WAAW,GAAG,EAAE,CAAC;AACtB,KAAI,CAAC,WAAW,GAAG,EAAE;;;AAAC,AAGtB,KAAI,CAAC,KAAK,GAAG,IAAI,CAAC;AAClB,KAAI,CAAC,MAAM,GAAG,IAAI,CAAC;CACnB,AACD;;AAAA","file":"State.js","sourcesContent":["'use strict';\n\n/** @module State */\nmodule.exports = class State {\n\tconstructor() {\n\t\t// Arrays/maps\n\t\tthis.queryMap = [];\n\t\tthis.values = [];\n\t\tthis.whereValues = [];\n\t\tthis.setArrayKeys = [];\n\t\tthis.orderArray = [];\n\t\tthis.groupArray = [];\n\t\tthis.havingMap = [];\n\t\tthis.whereMap = [];\n\t\tthis.rawWhereValues = [];\n\n\t\t// Partials\n\t\tthis.selectString = '';\n\t\tthis.fromString = '';\n\t\tthis.setString = '';\n\t\tthis.orderString = '';\n\t\tthis.groupString = '';\n\n\t\t// Other various values\n\t\tthis.limit = null;\n\t\tthis.offset = null;\n\t}\n}\n// End of module State"],"sourceRoot":"/source/"}

View File

@ -1,29 +1,50 @@
'use strict'; 'use strict';
var adapter = require('../adapter'), var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
getArgs = require('getargs');
var _Adapter2 = require('../Adapter');
var _Adapter3 = _interopRequireDefault(_Adapter2);
var _getargs = require('getargs');
var _getargs2 = _interopRequireDefault(_getargs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/** @module adapters/dblite */ /** @module adapters/dblite */
var Dblite = function(instance) { module.exports = (function (_Adapter) {
_inherits(dblite, _Adapter);
// That 'new' keyword is annoying function dblite() {
if ( ! (this instanceof Dblite)) return new Dblite(instance); _classCallCheck(this, dblite);
/** return _possibleConstructorReturn(this, Object.getPrototypeOf(dblite).apply(this, arguments));
* Run the sql query as a prepared statement }
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
adapter.execute = function(/*sql, params, callback*/) {
var args = getArgs('sql:string, [params]:array, callback:function', arguments);
instance.query(args.sql, args.params, args.callback); _createClass(dblite, [{
}; key: 'execute',
return adapter; /**
} * Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
value: function execute() /*sql, params, callback*/{
var args = (0, _getargs2.default)('sql:string, [params]:array, callback:function', arguments);
this.instance.query(args.sql, args.params, args.callback);
}
}]);
module.exports = Dblite; return dblite;
})(_Adapter3.default);
//# sourceMappingURL=dblite.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["dblite.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;AAMb,MAAM,CAAC,OAAO;WAAS,MAAM;;UAAN,MAAM;wBAAN,MAAM;;gEAAN,MAAM;;;cAAN,MAAM;;;;;;;;;;;qDASO;AAClC,OAAI,IAAI,GAAG,uBAAQ,+CAA+C,EAAE,SAAS,CAAC,CAAC;AAC/E,OAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;GAC1D;;;QAZqB,MAAM;qBAa5B,CAAA","file":"adapters/dblite.js","sourcesContent":["'use strict';\n\nimport Adapter from '../Adapter';\nimport getArgs from 'getargs';\n\n/** @module adapters/dblite */\nmodule.exports = class dblite extends Adapter {\n\t/**\n\t * Run the sql query as a prepared statement\n\t *\n\t * @param {String} sql - The sql with placeholders\n\t * @param {Array} params - The values to insert into the query\n\t * @param {Function} callback - Callback to run when a response is recieved\n\t * @return void\n\t */\n\texecute(/*sql, params, callback*/) {\n\t\tlet args = getArgs('sql:string, [params]:array, callback:function', arguments);\n\t\tthis.instance.query(args.sql, args.params, args.callback);\n\t};\n}"],"sourceRoot":"/source/"}

View File

@ -1,27 +1,45 @@
'use strict'; 'use strict';
var adapter = require('../adapter.js'); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var conn;
var _Adapter2 = require('../Adapter');
var _Adapter3 = _interopRequireDefault(_Adapter2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/** @module adapters/mysql */ /** @module adapters/mysql */
var MySQL = function(instance) { module.exports = (function (_Adapter) {
_inherits(mysql, _Adapter);
// That 'new' keyword is annoying function mysql() {
if ( ! (this instanceof MySQL)) return new MySQL(instance); _classCallCheck(this, mysql);
/** return _possibleConstructorReturn(this, Object.getPrototypeOf(mysql).apply(this, arguments));
* Run the sql query as a prepared statement }
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
adapter.execute = function(sql, params, callback) {
instance.query.apply(instance, arguments);
};
return adapter; _createClass(mysql, [{
}; key: 'execute',
module.exports = MySQL; /**
* Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
value: function execute(sql, params, callback) {
this.instance.query.apply(instance, arguments);
}
}]);
return mysql;
})(_Adapter3.default);
//# sourceMappingURL=mysql.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["mysql.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;AAKb,MAAM,CAAC,OAAO;WAAS,KAAK;;UAAL,KAAK;wBAAL,KAAK;;gEAAL,KAAK;;;cAAL,KAAK;;;;;;;;;;;0BASnB,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE;AAC9B,OAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;GAC/C;;;QAXqB,KAAK;qBAY3B,CAAA","file":"adapters/mysql.js","sourcesContent":["'use strict';\n\nimport Adapter from '../Adapter';\n\n/** @module adapters/mysql */\nmodule.exports = class mysql extends Adapter {\n\t/**\n\t * Run the sql query as a prepared statement\n\t *\n\t * @param {String} sql - The sql with placeholders\n\t * @param {Array} params - The values to insert into the query\n\t * @param {Function} callback - Callback to run when a response is recieved\n\t * @return void\n\t */\n\texecute(sql, params, callback) {\n\t\tthis.instance.query.apply(instance, arguments);\n\t}\n}"],"sourceRoot":"/source/"}

View File

@ -1,26 +1,45 @@
'use strict'; 'use strict';
var adapter = require('../adapter.js'); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _Adapter2 = require('../Adapter');
var _Adapter3 = _interopRequireDefault(_Adapter2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/** @module adapters/mysql2 */ /** @module adapters/mysql2 */
var MySQL2 = function(instance) { module.exports = (function (_Adapter) {
_inherits(mysql2, _Adapter);
// That 'new' keyword is annoying function mysql2() {
if ( ! (this instanceof MySQL2)) return new MySQL2(instance); _classCallCheck(this, mysql2);
/** return _possibleConstructorReturn(this, Object.getPrototypeOf(mysql2).apply(this, arguments));
* Run the sql query as a prepared statement }
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
adapter.execute = function(sql, params, callback) {
instance.execute.apply(instance, arguments);
};
return adapter; _createClass(mysql2, [{
} key: 'execute',
module.exports = MySQL2; /**
* Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
value: function execute(sql, params, callback) {
this.instance.execute.apply(this.instance, arguments);
}
}]);
return mysql2;
})(_Adapter3.default);
//# sourceMappingURL=mysql2.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["mysql2.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;AAKb,MAAM,CAAC,OAAO;WAAS,MAAM;;UAAN,MAAM;wBAAN,MAAM;;gEAAN,MAAM;;;cAAN,MAAM;;;;;;;;;;;0BASpB,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE;AAC9B,OAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;GACtD;;;QAXqB,MAAM;qBAY5B,CAAA","file":"adapters/mysql2.js","sourcesContent":["'use strict';\n\nimport Adapter from '../Adapter';\n\n/** @module adapters/mysql2 */\nmodule.exports = class mysql2 extends Adapter {\n\t/**\n\t * Run the sql query as a prepared statement\n\t *\n\t * @param {String} sql - The sql with placeholders\n\t * @param {Array} params - The values to insert into the query\n\t * @param {Function} callback - Callback to run when a response is recieved\n\t * @return void\n\t */\n\texecute(sql, params, callback) {\n\t\tthis.instance.execute.apply(this.instance, arguments);\n\t};\n}"],"sourceRoot":"/source/"}

View File

@ -1,29 +1,50 @@
'use strict'; 'use strict';
var adapter = require('../adapter'), var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
getArgs = require('getargs');
var _Adapter2 = require('../Adapter');
var _Adapter3 = _interopRequireDefault(_Adapter2);
var _getargs = require('getargs');
var _getargs2 = _interopRequireDefault(_getargs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/** @module adapters/node-firebird */ /** @module adapters/node-firebird */
var NodeFirebird = function(instance) { module.exports = (function (_Adapter) {
_inherits(nodefirebird, _Adapter);
// That 'new' keyword is annoying function nodefirebird() {
if ( ! (this instanceof NodeFirebird)) return new NodeFirebird(instance); _classCallCheck(this, nodefirebird);
/** return _possibleConstructorReturn(this, Object.getPrototypeOf(nodefirebird).apply(this, arguments));
* Run the sql query as a prepared statement }
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
adapter.execute = function(sql, params, callback) {
var args = getArgs('sql:string, [params], callback:function', arguments);
instance.execute(args.sql, args.params, args.callback); _createClass(nodefirebird, [{
}; key: 'execute',
return adapter; /**
} * Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
value: function execute() /*sql, params, callback*/{
var args = (0, _getargs2.default)('sql:string, [params], callback:function', arguments);
this.instance.execute(args.sql, args.params, args.callback);
}
}]);
module.exports = NodeFirebird; return nodefirebird;
})(_Adapter3.default);
//# sourceMappingURL=node-firebird.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["node-firebird.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;AAMb,MAAM,CAAC,OAAO;WAAS,YAAY;;UAAZ,YAAY;wBAAZ,YAAY;;gEAAZ,YAAY;;;cAAZ,YAAY;;;;;;;;;;;qDASC;AAClC,OAAI,IAAI,GAAG,uBAAQ,yCAAyC,EAAE,SAAS,CAAC,CAAC;AACzE,OAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;GAC5D;;;QAZqB,YAAY;qBAalC,CAAA","file":"adapters/node-firebird.js","sourcesContent":["'use strict';\n\nimport Adapter from '../Adapter';\nimport getArgs from 'getargs';\n\n/** @module adapters/node-firebird */\nmodule.exports = class nodefirebird extends Adapter {\n\t/**\n\t * Run the sql query as a prepared statement\n\t *\n\t * @param {String} sql - The sql with placeholders\n\t * @param {Array} params - The values to insert into the query\n\t * @param {Function} callback - Callback to run when a response is recieved\n\t * @return void\n\t */\n\texecute(/*sql, params, callback*/) {\n\t\tlet args = getArgs('sql:string, [params], callback:function', arguments);\n\t\tthis.instance.execute(args.sql, args.params, args.callback);\n\t}\n}"],"sourceRoot":"/source/"}

View File

@ -1,36 +1,58 @@
'use strict'; 'use strict';
var adapter = require('../adapter'), var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
getArgs = require('getargs');
var _Adapter2 = require('../Adapter');
var _Adapter3 = _interopRequireDefault(_Adapter2);
var _getargs = require('getargs');
var _getargs2 = _interopRequireDefault(_getargs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/** @module adapters/pg */ /** @module adapters/pg */
var Pg = function(instance) { module.exports = (function (_Adapter) {
_inherits(pg, _Adapter);
// That 'new' keyword is annoying function pg() {
if ( ! (this instanceof Pg)) return new Pg(instance); _classCallCheck(this, pg);
/** return _possibleConstructorReturn(this, Object.getPrototypeOf(pg).apply(this, arguments));
* Run the sql query as a prepared statement }
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
adapter.execute = function(/*sql, params, callback*/) {
var args = getArgs('sql:string, [params]:array, callback:function', arguments);
// Replace question marks with numbered placeholders, because this adapter is different... _createClass(pg, [{
var count = 0; key: 'execute',
args.sql = args.sql.replace(/\?/g, function() {
count++;
return '$' + count;
});
instance.query(args.sql, args.params, args.callback); /**
}; * Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
value: function execute() /*sql, params, callback*/{
var args = (0, _getargs2.default)('sql:string, [params]:array, callback:function', arguments);
return adapter; // Replace question marks with numbered placeholders, because this adapter is different...
} var count = 0;
args.sql = args.sql.replace(/\?/g, function () {
count++;
return '$' + count;
});
module.exports = Pg; this.instance.query(args.sql, args.params, args.callback);
}
}]);
return pg;
})(_Adapter3.default);
//# sourceMappingURL=pg.js.map

1
lib/adapters/pg.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["pg.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;AAMb,MAAM,CAAC,OAAO;WAAS,EAAE;;UAAF,EAAE;wBAAF,EAAE;;gEAAF,EAAE;;;cAAF,EAAE;;;;;;;;;;;qDASW;AAClC,OAAI,IAAI,GAAG,uBAAQ,+CAA+C,EAAE,SAAS,CAAC;;;AAAC,AAG/E,OAAI,KAAK,GAAG,CAAC,CAAC;AACd,OAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,YAAM;AACxC,SAAK,EAAE,CAAC;AACR,WAAO,GAAG,GAAG,KAAK,CAAC;IACnB,CAAC,CAAC;;AAEH,OAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;GAC1D;;;QApBqB,EAAE;qBAqBxB,CAAA","file":"adapters/pg.js","sourcesContent":["'use strict';\n\nimport Adapter from '../Adapter';\nimport getArgs from 'getargs';\n\n/** @module adapters/pg */\nmodule.exports = class pg extends Adapter {\n\t/**\n\t * Run the sql query as a prepared statement\n\t *\n\t * @param {String} sql - The sql with placeholders\n\t * @param {Array} params - The values to insert into the query\n\t * @param {Function} callback - Callback to run when a response is recieved\n\t * @return void\n\t */\n\texecute(/*sql, params, callback*/) {\n\t\tlet args = getArgs('sql:string, [params]:array, callback:function', arguments);\n\n\t\t// Replace question marks with numbered placeholders, because this adapter is different...\n\t\tlet count = 0;\n\t\targs.sql = args.sql.replace(/\\?/g, () => {\n\t\t\tcount++;\n\t\t\treturn '$' + count;\n\t\t});\n\n\t\tthis.instance.query(args.sql, args.params, args.callback);\n\t}\n}"],"sourceRoot":"/source/"}

78
lib/drivers/Firebird.js Normal file
View File

@ -0,0 +1,78 @@
"use strict";
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _helpers = require('../helpers');
var _helpers2 = _interopRequireDefault(_helpers);
var _DriverClass = require('../DriverClass');
var _DriverClass2 = _interopRequireDefault(_DriverClass);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/**
* Driver for Firebird databases
*
* @module drivers/firebird
*/
var Firebird = (function (_Driver) {
_inherits(Firebird, _Driver);
function Firebird() {
_classCallCheck(this, Firebird);
return _possibleConstructorReturn(this, Object.getPrototypeOf(Firebird).call(this, {
hasTruncate: false
}));
}
/**
* Generate a limit clause for firebird, which uses the syntax closest to the SQL standard
*
* @param {String} sql
* @param {Number} limit
* @param {Number} offset
* @return {String}
*/
_createClass(Firebird, [{
key: 'limit',
value: function limit(origSql, _limit, offset) {
var sql = 'FIRST ' + _limit;
if (_helpers2.default.isNumber(offset)) {
sql += ' SKIP ' + offset;
}
return origSql.replace(/SELECT/i, "SELECT " + sql);
}
/**
* SQL to insert a group of rows
*
* @param {String} table - The table to insert to
* @param {Array} [data] - The array of object containing data to insert
* @return {String}
*/
}, {
key: 'insertBatch',
value: function insertBatch() {
throw new Error("Not Implemented");
}
}]);
return Firebird;
})(_DriverClass2.default);
module.exports = new Firebird();
//# sourceMappingURL=Firebird.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["Firebird.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;IAUP,QAAQ;WAAR,QAAQ;;AACb,UADK,QAAQ,GACC;wBADT,QAAQ;;gEAAR,QAAQ,aAEN;AACL,cAAW,EAAE,KAAK;GAClB;EACD;;;;;;;;;;AAAA;cALI,QAAQ;;wBAeP,OAAO,EAAE,MAAK,EAAE,MAAM,EAAE;AAC7B,OAAI,GAAG,eAAa,MAAK,AAAE,CAAC;;AAE5B,OAAI,kBAAQ,QAAQ,CAAC,MAAM,CAAC,EAC5B;AACC,OAAG,gBAAc,MAAM,AAAE,CAAC;IAC1B;;AAED,UAAO,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC,CAAC;GACnD;;;;;;;;;;;;gCASa;AACb,SAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;GACnC;;;QAnCI,QAAQ;;;AAsCd,MAAM,CAAC,OAAO,GAAG,IAAI,QAAQ,EAAE,CAAC","file":"drivers/Firebird.js","sourcesContent":["\"use strict\";\n\nimport helpers from '../helpers';\nimport Driver from '../DriverClass';\n\n/**\n * Driver for Firebird databases\n *\n * @module drivers/firebird\n */\nclass Firebird extends Driver {\n\tconstructor() {\n\t\tsuper({\n\t\t\thasTruncate: false\n\t\t});\n\t}\n\n\t/**\n\t * Generate a limit clause for firebird, which uses the syntax closest to the SQL standard\n\t *\n\t * @param {String} sql\n\t * @param {Number} limit\n\t * @param {Number} offset\n\t * @return {String}\n\t */\n\tlimit(origSql, limit, offset) {\n\t\tlet sql = `FIRST ${limit}`;\n\n\t\tif (helpers.isNumber(offset))\n\t\t{\n\t\t\tsql += ` SKIP ${offset}`;\n\t\t}\n\n\t\treturn origSql.replace(/SELECT/i, \"SELECT \" + sql);\n\t}\n\n\t/**\n\t * SQL to insert a group of rows\n\t *\n\t * @param {String} table - The table to insert to\n\t * @param {Array} [data] - The array of object containing data to insert\n\t * @return {String}\n\t */\n\tinsertBatch() {\n\t\tthrow new Error(\"Not Implemented\");\n\t}\n}\n\nmodule.exports = new Firebird();"],"sourceRoot":"/source/"}

54
lib/drivers/Mysql.js Executable file
View File

@ -0,0 +1,54 @@
"use strict";
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _helpers = require('../helpers');
var _helpers2 = _interopRequireDefault(_helpers);
var _DriverClass = require('../DriverClass');
var _DriverClass2 = _interopRequireDefault(_DriverClass);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/**
* Driver for MySQL databases
*
* @module drivers/mysql
*/
var Mysql = (function (_Driver) {
_inherits(Mysql, _Driver);
function Mysql() {
_classCallCheck(this, Mysql);
return _possibleConstructorReturn(this, Object.getPrototypeOf(Mysql).call(this, {
identifierStartChar: '`',
identifierEndChar: '`'
}));
}
_createClass(Mysql, [{
key: 'limit',
value: function limit(sql, _limit, offset) {
if (!_helpers2.default.isNumber(offset)) {
return sql += ' LIMIT ' + _limit;
}
return sql += ' LIMIT ' + offset + ', ' + _limit;
}
}]);
return Mysql;
})(_DriverClass2.default);
module.exports = new Mysql();
//# sourceMappingURL=Mysql.js.map

1
lib/drivers/Mysql.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["Mysql.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;IAUP,KAAK;WAAL,KAAK;;AACV,UADK,KAAK,GACI;wBADT,KAAK;;gEAAL,KAAK,aAEH;AACL,sBAAmB,EAAE,GAAG;AACxB,oBAAiB,EAAE,GAAG;GACtB;EACD;;cANI,KAAK;;wBAQJ,GAAG,EAAE,MAAK,EAAE,MAAM,EAAE;AACzB,OAAK,CAAE,kBAAQ,QAAQ,CAAC,MAAM,CAAC,EAC/B;AACC,WAAO,GAAG,gBAAc,MAAK,AAAE,CAAC;IAChC;;AAED,UAAO,GAAG,gBAAc,MAAM,UAAK,MAAK,AAAE,CAAC;GAC3C;;;QAfI,KAAK;;;AAkBX,MAAM,CAAC,OAAO,GAAG,IAAI,KAAK,EAAE,CAAC","file":"drivers/Mysql.js","sourcesContent":["\"use strict\";\n\nimport helpers from '../helpers';\nimport Driver from '../DriverClass';\n\n/**\n * Driver for MySQL databases\n *\n * @module drivers/mysql\n */\nclass Mysql extends Driver {\n\tconstructor() {\n\t\tsuper({\n\t\t\tidentifierStartChar: '`',\n\t\t\tidentifierEndChar: '`'\n\t\t});\n\t}\n\n\tlimit(sql, limit, offset) {\n\t\tif ( ! helpers.isNumber(offset))\n\t\t{\n\t\t\treturn sql += ` LIMIT ${limit}`;\n\t\t}\n\n\t\treturn sql += ` LIMIT ${offset}, ${limit}`;\n\t}\n}\n\nmodule.exports = new Mysql();"],"sourceRoot":"/source/"}

15
lib/drivers/Pg.js Executable file
View File

@ -0,0 +1,15 @@
"use strict";
var _DriverClass = require("../DriverClass");
var _DriverClass2 = _interopRequireDefault(_DriverClass);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Driver for PostgreSQL databases
*
* @module drivers/pg
*/
module.exports = new _DriverClass2.default();
//# sourceMappingURL=Pg.js.map

1
lib/drivers/Pg.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["Pg.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;AASb,MAAM,CAAC,OAAO,GAAG,2BAAY,CAAC","file":"drivers/Pg.js","sourcesContent":["\"use strict\";\n\nimport Driver from '../DriverClass';\n\n/**\n * Driver for PostgreSQL databases\n *\n * @module drivers/pg\n */\nmodule.exports = new Driver();"],"sourceRoot":"/source/"}

94
lib/drivers/Sqlite.js Normal file
View File

@ -0,0 +1,94 @@
"use strict";
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _helpers = require('../helpers');
var _helpers2 = _interopRequireDefault(_helpers);
var _DriverClass = require('../DriverClass');
var _DriverClass2 = _interopRequireDefault(_DriverClass);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/**
* Driver for Sqlite databases
*
* @module drivers/sqlite
*/
var Sqlite = (function (_Driver) {
_inherits(Sqlite, _Driver);
function Sqlite() {
_classCallCheck(this, Sqlite);
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Sqlite).call(this));
_this.hasTruncate = false;
return _this;
}
_createClass(Sqlite, [{
key: 'insertBatch',
value: function insertBatch(table, data) {
var _this2 = this;
// Get the data values to insert, so they can
// be parameterized
var sql = "",
vals = [],
cols = [],
fields = [],
first = data.shift(),
params = [],
paramString = "",
paramList = [];
data.forEach(function (obj) {
var row = [];
Object.keys(obj).forEach(function (key) {
row.push(obj[key]);
});
vals.push(row);
});
sql += "INSERT INTO " + this.quoteTable(table) + "\n";
// Get the field names from the keys of the first
// object to be inserted
fields = Object.keys(first);
Object.keys(first).forEach(function (key) {
cols.push("'" + _this2._quote(first[key]) + "' AS " + _this2.quoteIdentifiers(key));
});
sql += "SELECT " + cols.join(', ') + "\n";
vals.forEach(function (row_values) {
var quoted = row_values.map(function (value) {
return String(value).replace("'", "'\'");
});
sql += "UNION ALL SELECT '" + quoted.join("', '") + "'\n";
});
return {
sql: sql,
values: null
};
}
}]);
return Sqlite;
})(_DriverClass2.default);
;
module.exports = new Sqlite();
//# sourceMappingURL=Sqlite.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["Sqlite.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;IAUP,MAAM;WAAN,MAAM;;AACX,UADK,MAAM,GACG;wBADT,MAAM;;qEAAN,MAAM;;AAGV,QAAK,WAAW,GAAG,KAAK,CAAC;;EACzB;;cAJI,MAAM;;8BAMC,KAAK,EAAE,IAAI,EAAE;;;;;AAIxB,OAAI,GAAG,GAAG,EAAE;OACX,IAAI,GAAG,EAAE;OACT,IAAI,GAAG,EAAE;OACT,MAAM,GAAG,EAAE;OACX,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE;OACpB,MAAM,GAAG,EAAE;OACX,WAAW,GAAG,EAAE;OAChB,SAAS,GAAG,EAAE,CAAC;;AAGhB,OAAI,CAAC,OAAO,CAAC,UAAC,GAAG,EAAK;AACrB,QAAI,GAAG,GAAG,EAAE,CAAC;AACb,UAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAC,GAAG,EAAK;AACjC,QAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;KACnB,CAAC,CAAC;AACH,QAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACf,CAAC,CAAC;;AAEH,MAAG,IAAI,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,IAAI;;;;AAAC,AAItD,SAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5B,SAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,UAAC,GAAG,EAAK;AACnC,QAAI,CAAC,IAAI,CAAC,GAAG,GAAG,OAAK,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,GAAG,OAAK,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC;IAChF,CAAC,CAAC;;AAEH,MAAG,IAAI,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;;AAE1C,OAAI,CAAC,OAAO,CAAC,UAAC,UAAU,EAAK;AAC5B,QAAI,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,UAAC,KAAK,EAAK;AACtC,YAAO,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;KACzC,CAAC,CAAC;AACH,OAAG,IAAI,oBAAoB,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;IAC1D,CAAC,CAAC;;AAEH,UAAO;AACN,OAAG,EAAE,GAAG;AACR,UAAM,EAAE,IAAI;IACZ,CAAC;GACF;;;QAlDI,MAAM;;;AAmDX,CAAC;;AAEF,MAAM,CAAC,OAAO,GAAG,IAAI,MAAM,EAAE,CAAC","file":"drivers/Sqlite.js","sourcesContent":["\"use strict\";\n\nimport helpers from '../helpers';\nimport Driver from '../DriverClass';\n\n/**\n * Driver for Sqlite databases\n *\n * @module drivers/sqlite\n */\nclass Sqlite extends Driver {\n\tconstructor() {\n\t\tsuper();\n\t\tthis.hasTruncate = false;\n\t}\n\n\tinsertBatch(table, data) {\n\n\t\t// Get the data values to insert, so they can\n\t\t// be parameterized\n\t\tlet sql = \"\",\n\t\t\tvals = [],\n\t\t\tcols = [],\n\t\t\tfields = [],\n\t\t\tfirst = data.shift(),\n\t\t\tparams = [],\n\t\t\tparamString = \"\",\n\t\t\tparamList = [];\n\n\n\t\tdata.forEach((obj) => {\n\t\t\tlet row = [];\n\t\t\tObject.keys(obj).forEach((key) => {\n\t\t\t\trow.push(obj[key]);\n\t\t\t});\n\t\t\tvals.push(row);\n\t\t});\n\n\t\tsql += \"INSERT INTO \" + this.quoteTable(table) + \"\\n\";\n\n\t\t// Get the field names from the keys of the first\n\t\t// object to be inserted\n\t\tfields = Object.keys(first);\n\t\tObject.keys(first).forEach((key) => {\n\t\t\tcols.push(\"'\" + this._quote(first[key]) + \"' AS \" + this.quoteIdentifiers(key));\n\t\t});\n\n\t\tsql += \"SELECT \" + cols.join(', ') + \"\\n\";\n\n\t\tvals.forEach((row_values) => {\n\t\t\tlet quoted = row_values.map((value) => {\n\t\t\t\treturn String(value).replace(\"'\", \"'\\'\");\n\t\t\t});\n\t\t\tsql += \"UNION ALL SELECT '\" + quoted.join(\"', '\") + \"'\\n\";\n\t\t});\n\n\t\treturn {\n\t\t\tsql: sql,\n\t\t\tvalues: null\n\t\t};\n\t}\n};\n\nmodule.exports = new Sqlite();"],"sourceRoot":"/source/"}

View File

@ -1,31 +0,0 @@
"use strict";
/**
* Driver for MySQL databases
*
* @module drivers/mysql
*/
module.exports = (function() {
delete require.cache[require.resolve('../driver')];
var driver = require('../driver');
var driver = require('../driver'),
helpers = require('../helpers');
driver.identifierStartChar = '`';
driver.identifierEndChar = '`';
/**
* Override default limit method because mysql likes to be different
*/
driver.limit = function(sql, limit, offset) {
if ( ! helpers.isNumber(offset))
{
return sql += " LIMIT " + limit;
}
return sql += " LIMIT " + offset + "," + limit;
};
return driver;
}());

View File

@ -1,13 +0,0 @@
"use strict";
/**
* Driver for PostgreSQL databases
*
* @module drivers/pg
*/
module.exports = (function() {
delete require.cache[require.resolve('../driver')];
var driver = require('../driver');
return driver;
}());

View File

@ -1,71 +0,0 @@
"use strict";
/**
* Driver for Sqlite databases
*
* @module drivers/sqlite
*/
module.exports = (function() {
delete require.cache[require.resolve('../driver')];
var driver = require('../driver'),
helpers = require('../helpers');
// Sqlite doesn't have a truncate command
driver.hasTruncate = false;
/**
* SQL to insert a group of rows
* Override default to have better compatibility
*
* @param {String} table - The table to insert to
* @param {Array} [data] - The array of object containing data to insert
* @return {String}
*/
driver.insertBatch = function(table, data) {
// Get the data values to insert, so they can
// be parameterized
var sql = "",
vals = [],
cols = [],
fields = [],
first = data.shift(),
params = [],
paramString = "",
paramList = [];
data.forEach(function(obj) {
var row = [];
Object.keys(obj).forEach(function(key) {
row.push(obj[key]);
});
vals.push(row);
});
sql += "INSERT INTO " + driver.quoteTable(table) + "\n";
// Get the field names from the keys of the first
// object to be inserted
fields = Object.keys(first);
Object.keys(first).forEach(function(key) {
cols.push("'" + driver._quote(first[key]) + "' AS " + driver.quoteIdentifiers(key));
});
sql += "SELECT " + cols.join(', ') + "\n";
vals.forEach(function(row_values) {
var quoted = row_values.map(function(value) {
return String(value).replace("'", "'\'");
});
sql += "UNION ALL SELECT '" + quoted.join("', '") + "'\n";
});
return {
sql: sql,
values: null
};
}
return driver;
}());

View File

@ -1,68 +1,66 @@
"use strict"; "use strict"
require('es6-shim'); //require('es6-shim');
/** @module helpers */
/** @alias module:helpers */ ;
var h = { var helpers = {
/** /**
* Wrap String.prototype.trim in a way that is easily mappable * Wrap String.prototype.trim in a way that is easily mappable
* *
* @param {String} str - The string to trim * @param {String} str - The string to trim
* @return {String} - The trimmed string * @return {String} - The trimmed string
*/ */
stringTrim: function(str) { stringTrim: function stringTrim(str) {
return str.trim(); return str.trim();
}, },
/** /**
* Get the type of the variable passed * Get the type of the variable passed
* *
* @see https://techblog.badoo.com/blog/2013/11/01/type-checking-in-javascript/ * @see https://techblog.badoo.com/blog/2013/11/01/type-checking-in-javascript/
* @see http://toddmotto.com/understanding-javascript-types-and-reliable-type-checking/ * @see http://toddmotto.com/understanding-javascript-types-and-reliable-type-checking/
* @param {mixed} o * @param {mixed} o
* @return {String} * @return {String}
*/ */
type: function (o) { type: function type(o) {
var type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase(); var type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
// handle NaN and Infinity // handle NaN and Infinity
if (type === 'number') { if (type === 'number') {
if (isNaN(o)) { if (isNaN(o)) {
return 'nan'; return 'nan';
} }
if (!isFinite(o)) { if (!isFinite(o)) {
return 'infinity'; return 'infinity';
} }
} }
return type; return type;
}, },
/** /**
* Determine whether an object is scalar * Determine whether an object is scalar
* *
* @param {mixed} obj * @param {mixed} obj
* @return {bool} * @return {bool}
*/ */
isScalar: function(obj) { isScalar: function isScalar(obj) {
var scalar = ['string', 'number', 'boolean']; var scalar = ['string', 'number', 'boolean'];
return scalar.indexOf(h.type(obj)) !== -1; return scalar.indexOf(helpers.type(obj)) !== -1;
}, },
/** /**
* Get a list of values with a common key from an array of objects * Get a list of values with a common key from an array of objects
* *
* @param {Array} arr - The array of objects to search * @param {Array} arr - The array of objects to search
* @param {String} key - The key of the object to get * @param {String} key - The key of the object to get
* @return {Array} * @return {Array}
*/ */
arrayPluck: function(arr, key) { arrayPluck: function arrayPluck(arr, key) {
var output = []; var output = [];
// Empty case // Empty case
if (arr.length === 0) return output; if (arr.length === 0) return output;
arr.forEach(function(obj) { arr.forEach(function (obj) {
if ( ! h.isUndefined(obj[key])) if (!helpers.isUndefined(obj[key])) {
{
output.push(obj[key]); output.push(obj[key]);
} }
}); });
@ -70,51 +68,62 @@ var h = {
return output; return output;
}, },
/** /**
* Determine if a value matching the passed regular expression is * Determine if a value matching the passed regular expression is
* in the passed array * in the passed array
* *
* @param {Array} arr - The array to search * @param {Array} arr - The array to search
* @param {RegExp} pattern - The pattern to match * @param {RegExp} pattern - The pattern to match
* @return {Boolean} - If an array item matches the pattern * @return {Boolean} - If an array item matches the pattern
*/ */
regexInArray: function(arr, pattern) { regexInArray: function regexInArray(arr, pattern) {
// Empty case(s) // Empty case(s)
if ( ! h.isArray(arr)) return false; if (!helpers.isArray(arr)) return false;
if (arr.length === 0) return false; if (arr.length === 0) return false;
var i, l = arr.length; var i = undefined,
l = arr.length;
for(i=0; i< l; i++) for (i = 0; i < l; i++) {
{
// Short circuit if any items match // Short circuit if any items match
if (pattern.test(arr[i])) return true; if (pattern.test(arr[i])) return true;
} }
return false; return false;
},
/**
* Make the first letter of the string uppercase
*
* @param {String} str
* @return {String}
*/
upperCaseFirst: function upperCaseFirst(str) {
str += '';
var first = str.charAt(0).toUpperCase();
return first + str.substr(1);
} }
}; };
// Define an 'is' method for each type // Define an 'is' method for each type
var types = ['Null','Undefined','Object','Array','String','Number','Boolean','Function','RegExp','NaN','Infinite']; var types = ['Null', 'Undefined', 'Object', 'Array', 'String', 'Number', 'Boolean', 'Function', 'RegExp', 'NaN', 'Infinite'];
types.forEach(function (t) { types.forEach(function (t) {
/** /**
* Determine whether a variable is of the type specified in the * Determine whether a variable is of the type specified in the
* function name, eg isNumber * function name, eg isNumber
* *
* Types available are Null, Undefined, Object, Array, String, Number, Boolean, Function, RegExp, NaN and Infinite * Types available are Null, Undefined, Object, Array, String, Number, Boolean, Function, RegExp, NaN and Infinite
* *
* @name is[type] * @name is[type]
* @param {mixed} o * @param {mixed} o
* @return {Boolean} * @return {Boolean}
*/ */
h['is' + t] = function (o) { helpers['is' + t] = function (o) {
if (t.toLowerCase() === 'infinite') if (t.toLowerCase() === 'infinite') {
{ t = 'infinity';
t = 'infinity'; }
}
return h.type(o) === t.toLowerCase(); return helpers.type(o) === t.toLowerCase();
}; };
}); });
module.exports = h; module.exports = helpers;
//# sourceMappingURL=helpers.js.map

1
lib/helpers.js.map Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,58 +0,0 @@
"use strict";
/** @module node-query */
var NodeQuery = function() {
var instance = null;
/**
* Create a query builder object
*
* @alias module:node-query
* @param {String} drivername - The name of the database type, eg. mysql or pg
* @param {Object} connObject - A connection object from the database library you are connecting with
* @param {String} [connLib] - The name of the db connection library you are using, eg. mysql or mysql2. Optional if the same as drivername
* @return {queryBuilder}
*/
this.init = function (driverType, connObject, connLib) {
connLib = connLib || driverType;
var fs = require('fs'),
qb = require('./query-builder');
var paths = {
driver: __dirname + '/drivers/' + driverType + '.js',
adapter: __dirname + '/adapters/' + connLib + '.js'
};
Object.keys(paths).forEach(function(type) {
if ( ! fs.existsSync(paths[type]))
{
console.log(paths[type]);
throw new Error('Selected ' + type + ' does not exist!');
}
});
instance = qb(require(paths.driver), require(paths.adapter)(connObject));
return instance;
};
/**
* Return an existing query builder instance
*
* @return {queryBuilder}
*/
this.getQuery = function () {
if ( ! instance) {
throw new Error("No Query Builder instance to return");
}
return instance;
};
};
module.exports = new NodeQuery();

View File

@ -1,928 +0,0 @@
'use strict';
/** @module query-builder */
var getArgs = require('getargs'),
helpers = require('./helpers'),
State = require('./state');
/**
* Variables controlling the sql building
*
* @private
*/
var state = new State();
/*
* SQL generation object
*
* @param {driver} - The syntax driver for the database
* @param {adapter} - The database module adapter for running queries
* @constructor
*/
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);
this.driver = driver;
this.adapter = adapter;
/**
* "Private" methods
*
* @private
*/
var _p = {
/**
* Complete the sql building based on the type provided
*
* @param {String} type
* @param {String} table
* @private
* @return {String}
*/
compile: function (type, table) {
// Put together the basic query
var sql = _p.compileType(type, table);
// Set each subClause
['queryMap', 'groupString', 'orderString', 'havingMap'].forEach(function(clause) {
var param = state[clause];
if ( ! helpers.isScalar(param))
{
Object.keys(param).forEach(function(part) {
sql += param[part].conjunction + param[part].string;
});
}
else
{
sql += param;
}
});
// Append the limit, if it exists
if (helpers.isNumber(state.limit))
{
sql = driver.limit(sql, state.limit, state.offset);
}
return sql;
},
compileType: function (type, table) {
var sql = '';
switch(type) {
case "insert":
var params = new Array(state.setArrayKeys.length);
params.fill('?');
sql = "INSERT INTO " + table + " (";
sql += state.setArrayKeys.join(',');
sql += ") VALUES (";
sql += params.join(',') + ')';
break;
case "update":
sql = "UPDATE " + table + " SET " + state.setString;
break;
case "delete":
sql = "DELETE FROM " + table;
break;
default:
sql = "SELECT * FROM " + state.fromString;
// Set the select string
if (state.selectString.length > 0)
{
// Replace the star with the selected fields
sql = sql.replace('*', state.selectString);
}
break;
}
return sql;
},
like: function (field, val, pos, like, conj) {
field = driver.quoteIdentifiers(field);
like = field + " " + like + " ?";
if (pos == 'before')
{
val = "%" + val;
}
else if (pos == 'after')
{
val = val + "%";
}
else
{
val = "%" + val + "%";
}
conj = (state.queryMap.length < 1) ? ' WHERE ' : ' ' + conj + ' ';
_p.appendMap(conj, like, 'like');
state.whereValues.push(val);
},
/**
* Append a clause to the query map
*
* @param {String} conjunction
* @param {String} string
* @param {String} type
* @return void
*/
appendMap: function(conjunction, string, type) {
state.queryMap.push({
type: type,
conjunction: conjunction,
string: string
});
},
/**
* Handle key/value pairs in an object the same way as individual arguments,
* when appending to state
*
* @private
*/
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))
{
// Convert key/val pair to a simple object
obj[args.$key] = args.$val;
}
else if (helpers.isScalar(args.$key) && helpers.isUndefined(args.$val))
{
// If just a string for the key, and no value, create a simple object with duplicate key/val
obj[args.$key] = args.$key;
}
else
{
obj = args.$key;
}
Object.keys(obj).forEach(function(k) {
// If a single value for the return
if (['key','value'].indexOf(args.$valType) !== -1)
{
var pushVal = (args.$valType === 'key') ? k : obj[k];
state[args.$varName].push(pushVal);
}
else
{
state[args.$varName][k] = obj[k];
}
});
return state[args.$varName];
},
whereMixedSet: function(/*key, val*/) {
var args = getArgs('key:string|object, [val]', arguments);
state.whereMap = [];
state.rawWhereValues = [];
_p.mixedSet('whereMap', 'both', args.key, args.val);
_p.mixedSet('rawWhereValues', 'value', args.key, args.val);
},
fixConjunction: function(conj) {
var lastItem = state.queryMap[state.queryMap.length - 1];
var conjunctionList = helpers.arrayPluck(state.queryMap, 'conjunction');
if (state.queryMap.length === 0 || ( ! helpers.regexInArray(conjunctionList, /^ ?WHERE/i)))
{
conj = " WHERE ";
}
else if (lastItem.type === 'groupStart')
{
conj = '';
}
else
{
conj = ' ' + conj + ' ';
}
return conj;
},
where: function(key, val, defaultConj) {
// Normalize key and value and insert into state.whereMap
_p.whereMixedSet(key, val);
// Parse the where condition to account for operators,
// functions, identifiers, and literal values
state = parser.parseWhere(driver, state);
state.whereMap.forEach(function(clause) {
var conj = _p.fixConjunction(defaultConj);
_p.appendMap(conj, clause, 'where');
});
state.whereMap = {};
},
whereNull: function(field, stmt, conj) {
field = driver.quoteIdentifiers(field);
var item = field + ' ' + stmt;
_p.appendMap(_p.fixConjunction(conj), item, 'whereNull');
},
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;
// Normalize key/val and put in state.whereMap
_p.whereMixedSet(args.key, args.val);
// Parse the having condition to account for operators,
// functions, identifiers, and literal values
state = parser.parseWhere(driver, state);
state.whereMap.forEach(function(clause) {
// Put in the having map
state.havingMap.push({
conjunction: (state.havingMap.length > 0) ? " " + args.conj + " " : ' HAVING ',
string: clause
});
});
// Clear the where Map
state.whereMap = {};
},
whereIn: function(/*key, val, inClause, conj*/) {
var args = getArgs('key:string, val:array, inClause:string, conj:string', arguments);
args.key = driver.quoteIdentifiers(args.key);
var params = new Array(args.val.length);
params.fill('?');
args.val.forEach(function(value) {
state.whereValues.push(value);
});
args.conj = (state.queryMap.length > 0) ? " " + args.conj + " " : ' WHERE ';
var str = args.key + " " + args.inClause + " (" + params.join(',') + ") ";
_p.appendMap(args.conj, str, 'whereIn');
},
run: function(type, table, callback, sql, vals) {
if ( ! sql)
{
sql = _p.compile(type, table);
}
if ( ! vals)
{
vals = state.values.concat(state.whereValues);
}
//console.log(state);
//console.log(sql);
//console.log(vals);
//console.log(callback);
//console.log('------------------------');
// Reset the state so another query can be built
_p.resetState();
// Pass the sql and values to the adapter to run on the database
adapter.execute(sql, vals, callback);
},
getCompile: function(type, table, reset) {
reset = reset || false;
var sql = _p.compile(type, table);
if (reset) _p.resetState();
return sql;
},
resetState: function() {
state = new State();
}
};
// ----------------------------------------------------------------------------
// ! Miscellaneous Methods
// ----------------------------------------------------------------------------
/**
* Reset the object state for a new query
*
* @memberOf query-builder
* @return void
*/
this.resetQuery = function() {
_p.resetState();
};
/**
* Returns the current class state for testing or other purposes
*
* @private
* @return {Object}
*/
this.getState = function() {
return state;
};
/**
* Closes the database connection for the current adapter
*
* @return void
*/
this.end = function() {
adapter.close();
};
// ------------------------------------------------------------------------
// ! Query Builder Methods
// ------------------------------------------------------------------------
/**
* Specify rows to select in the query
*
* @param {String|Array} fields - The fields to select from the current table
* @return this
*/
this.select = function(fields) {
// Split/trim fields by comma
fields = (Array.isArray(fields)) ? fields : fields.split(",").map(helpers.stringTrim);
// Split on 'As'
fields.forEach(function (field, index) {
if (field.match(/as/i))
{
fields[index] = field.split(/ as /i).map(helpers.stringTrim);
}
});
var safeArray = driver.quoteIdentifiers(fields);
// Join the strings back together
safeArray.forEach(function (field, index) {
if (Array.isArray(field))
{
safeArray[index] = safeArray[index].join(' AS ');
}
});
state.selectString += safeArray.join(', ');
return this;
};
/**
* Specify the database table to select from
*
* @param {String} tableName - The table to use for the current query
* @return this
*/
this.from = function(tableName) {
// Split identifiers on spaces
var identArray = tableName.trim().split(' ').map(helpers.stringTrim);
// Quote/prefix identifiers
identArray[0] = driver.quoteTable(identArray[0]);
identArray = driver.quoteIdentifiers(identArray);
// Put it back together
state.fromString = identArray.join(' ');
return this;
};
/**
* Add a 'like/ and like' clause to the query
*
* @param {String} field - The name of the field to compare to
* @param {String} val - The value to compare to
* @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
* @return this
*/
this.like = function(field, val, pos) {
_p.like(field, val, pos, ' LIKE ', 'AND');
return this;
};
/**
* Add a 'not like/ and not like' clause to the query
*
* @param {String} field - The name of the field to compare to
* @param {String} val - The value to compare to
* @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
* @return this
*/
this.notLike = function(field, val, pos) {
_p.like(field, val, pos, ' NOT LIKE ', 'AND');
return this;
};
/**
* Add an 'or like' clause to the query
*
* @param {String} field - The name of the field to compare to
* @param {String} val - The value to compare to
* @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
* @return this
*/
this.orLike = function(field, val, pos) {
_p.like(field, val, pos, ' LIKE ', 'OR');
return this;
};
/**
* Add an 'or not like' clause to the query
*
* @param {String} field - The name of the field to compare to
* @param {String} val - The value to compare to
* @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
* @return this
*/
this.orNotLike = function(field, val, pos) {
_p.like(field, val, pos, ' NOT LIKE ', 'OR');
return this;
};
/**
* Add a 'having' clause
*
* @param {String|Object} key - The name of the field and the comparision operator, or an object
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return this
*/
this.having = function(/*key, [val]*/) {
var args = getArgs('key:string|object, [val]:string|number', arguments);
_p.having(args.key, args.val, 'AND');
return this;
};
/**
* Add an 'or having' clause
*
* @param {String|Object} key - The name of the field and the comparision operator, or an object
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return this
*/
this.orHaving = function(/*key, [val]*/) {
var args = getArgs('key:string|object, [val]:string|number', arguments);
_p.having(args.key, args.val, 'OR');
return this;
};
/**
* Set a 'where' clause
*
* @param {String|Object} key - The name of the field and the comparision operator, or an object
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return this
*/
this.where = function(key, val) {
_p.where(key, val, 'AND');
return this;
};
/**
* Set a 'or where' clause
*
* @param {String|Object} key - The name of the field and the comparision operator, or an object
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return this
*/
this.orWhere = function(key, val) {
_p.where(key, val, 'OR');
return this;
};
/**
* Select a field that is Null
*
* @param {String} field - The name of the field that has a NULL value
* @return this
*/
this.whereIsNull = function(field) {
_p.whereNull(field, 'IS NULL', 'AND');
return this;
}
/**
* Specify that a field IS NOT NULL
*
* @param {String} field
* @return this
*/
this.whereIsNotNull = function(field) {
_p.whereNull(field, 'IS NOT NULL', 'AND');
return this;
}
/**
* Field is null prefixed with 'OR'
*
* @param {String} field
* @return this
*/
this.orWhereIsNull = function(field) {
_p.whereNull(field, 'IS NULL', 'OR');
return this;
}
/**
* Field is not null prefixed with 'OR'
*
* @param {String} field
* @return this
*/
this.orWhereIsNotNull = function(field) {
_p.whereNull(field, 'IS NOT NULL', 'OR');
return this;
}
/**
* Set a 'where in' clause
*
* @param {String} key - the field to search
* @param {Array} val - the array of items to search in
* @return this
*/
this.whereIn = function(key, val) {
_p.whereIn(key, val, 'IN', 'AND');
return this;
};
/**
* Set a 'or where in' clause
*
* @param {String} key - the field to search
* @param {Array} val - the array of items to search in
* @return this
*/
this.orWhereIn = function(key, val) {
_p.whereIn(key, val, 'IN', 'OR');
return this;
};
/**
* Set a 'where not in' clause
*
* @param {String} key - the field to search
* @param {Array} val - the array of items to search in
* @return this
*/
this.whereNotIn = function(key, val) {
_p.whereIn(key, val, 'NOT IN', 'AND');
return this;
};
/**
* Set a 'or where not in' clause
*
* @param {String} key - the field to search
* @param {Array} val - the array of items to search in
* @return this
*/
this.orWhereNotIn = function(key, val) {
_p.whereIn(key, val, 'NOT IN', 'OR');
return this;
};
/**
* Set values for insertion or updating
*
* @param {String|Object} key - The key or object to use
* @param {String} [val] - The value if using a scalar key
* @return this
*/
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);
// Use the keys of the array to make the insert/update string
// and escape the field names
state.setArrayKeys = state.setArrayKeys.map(driver._quote);
// Generate the "set" string
state.setString = state.setArrayKeys.join('=?,');
state.setString += '=?';
return this;
};
/**
* Add a join clause to the query
*
* @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(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;
};
/**
* Group the results by the selected field(s)
*
* @param {String|Array} field
* @return this
*/
this.groupBy = function(field) {
if ( ! helpers.isScalar(field))
{
var newGroupArray = field.map(driver.quoteIdentifiers);
state.groupArray = state.groupArray.concat(newGroupArray);
}
else
{
state.groupArray.push(driver.quoteIdentifiers(field));
}
state.groupString = ' GROUP BY ' + state.groupArray.join(',');
return this;
};
/**
* Order the results by the selected field(s)
*
* @param {String} field - The field(s) to order by
* @param {String} [type='ASC'] - The order direction, ASC or DESC
* @return this
*/
this.orderBy = function(field, type) {
type = type || 'ASC';
// Set the fields for later manipulation
field = driver.quoteIdentifiers(field);
state.orderArray[field] = type;
var orderClauses = [];
// Flatten key/val pairs into an array of space-separated pairs
Object.keys(state.orderArray).forEach(function(key) {
orderClauses.push(key + ' ' + state.orderArray[key].toUpperCase());
});
// Set the final string
state.orderString = ' ORDER BY ' + orderClauses.join(', ');
return this;
};
/**
* Put a limit on the query
*
* @param {Number} limit - The maximum number of rows to fetch
* @param {Number} [offset] - The row number to start from
* @return this
*/
this.limit = function(limit, offset) {
state.limit = limit;
state.offset = offset || null;
return this;
};
/**
* Adds an open paren to the current query for logical grouping
*
* @return this
*/
this.groupStart = function() {
var conj = (state.queryMap.length < 1) ? ' WHERE ' : ' AND ';
_p.appendMap(conj, '(', 'groupStart');
return this;
};
/**
* Adds an open paren to the current query for logical grouping,
* prefixed with 'OR'
*
* @return this
*/
this.orGroupStart = function() {
_p.appendMap('', ' OR (', 'groupStart');
return this;
};
/**
* Adds an open paren to the current query for logical grouping,
* prefixed with 'OR NOT'
*
* @return this
*/
this.orNotGroupStart = function() {
_p.appendMap('', ' OR NOT (', 'groupStart');
return this;
};
/**
* Ends a logical grouping started with one of the groupStart methods
*
* @return this
*/
this.groupEnd = function() {
_p.appendMap('', ')', 'groupEnd');
return this;
};
// ------------------------------------------------------------------------
// ! Result Methods
// ------------------------------------------------------------------------
/**
* Get the results of the compiled query
*
* @param {String} [table] - The table to select from
* @param {Number} [limit] - A limit for the query
* @param {Number} [offset] - An offset for the query
* @param {Function} callback - A callback for receiving the result
* @return void
*/
this.get = function(/* [table], [limit], [offset], callback */) {
var args = getArgs('[table]:string, [limit]:number, [offset]:number, callback:function', arguments);
if (args.table) {
this.from(args.table);
}
if (args.limit) {
this.limit(args.limit, args.offset);
}
// Run the query
_p.run('get', args.table, args.callback);
};
/**
* Run the generated insert query
*
* @param {String} table - The table to insert into
* @param {Object} [data] - Data to insert, if not already added with the 'set' method
* @param {Function} callback - Callback for handling response from the database
* @return void
*/
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', driver.quoteTable(args.table), args.callback);
};
/**
* Insert multiple sets of rows at a time
*
* @param {String} table - The table to insert into
* @param {Array} data - The array of objects containing data rows to insert
* @param {Function} callback - Callback for handling database response
* @example query.insertBatch('foo',[{id:1,val:'bar'},{id:2,val:'baz'}], callbackFunction);
* @return void
*/
this.insertBatch = function(/* table, data, callback */) {
var args = getArgs('table:string, data:array, callback:function', arguments);
var batch = driver.insertBatch(args.table, args.data);
// Run the query
_p.run('', '', args.callback, batch.sql, batch.values);
};
/**
* Run the generated update query
*
* @param {String} table - The table to insert into
* @param {Object} [data] - Data to insert, if not already added with the 'set' method
* @param {Function} callback - Callback for handling response from the database
* @return void
*/
this.update = 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('update', driver.quoteTable(args.table), args.callback);
};
/**
* Run the generated delete query
*
* @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*/) {
var args = getArgs('table:string, [where]:object, callback:function', arguments);
if (args.where)
{
this.where(args.where);
}
// Run the query
_p.run('delete', driver.quoteTable(args.table), args.callback);
};
// ------------------------------------------------------------------------
// ! Methods returning SQL
// ------------------------------------------------------------------------
/**
* Return generated select query SQL
*
* @param {String} [table] - the name of the table to retrieve from
* @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
* @return String
*/
this.getCompiledSelect = function(/*table, reset*/) {
var args = getArgs('[table]:string, [reset]:boolean', arguments);
if (args.table)
{
this.from(args.table);
}
return _p.getCompile('get', args.table, args.reset);
};
/**
* Return generated insert query SQL
*
* @param {String} table - the name of the table to insert into
* @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
* @return {String}
*/
this.getCompiledInsert = function(table, reset) {
return _p.getCompile('insert', driver.quoteTable(table), reset);
};
/**
* Return generated update query SQL
*
* @param {String} table - the name of the table to update
* @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
* @return {String}
*/
this.getCompiledUpdate = function(table, reset) {
return _p.getCompile('update', driver.quoteTable(table), reset);
};
/**
* Return generated delete query SQL
*
* @param {String} table - the name of the table to delete from
* @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
* @return {String}
*/
this.getCompiledDelete = function(table, reset) {
return _p.getCompile('delete', driver.quoteTable(table), reset);
};
return this;
};
module.exports = QueryBuilder;

View File

@ -1,29 +0,0 @@
'use strict';
/** @module State */
module.exports = function State() {
return {
// Arrays/Maps
queryMap: [],
values: [],
whereValues: [],
setArrayKeys: [],
orderArray: [],
groupArray: [],
havingMap: [],
whereMap: {},
rawWhereValues: [],
// Partials
selectString: '',
fromString: '',
setString: '',
orderString: '',
groupString: '',
// Other various values
limit: null,
offset: null
};
};
// End of module State

View File

@ -38,7 +38,10 @@
"mysql2": "^0.15.8", "mysql2": "^0.15.8",
"node-firebird": "^0.7.0", "node-firebird": "^0.7.0",
"pg": "^4.4.3", "pg": "^4.4.3",
"es6-shim": "" "es6-shim": "",
"babel": "",
"babel-preset-es2015": "",
"babel-plugin-transform-es2015-modules-commonjs": ""
}, },
"optionalDependencies": { "optionalDependencies": {
"dblite": "*", "dblite": "*",
@ -49,14 +52,19 @@
"documentation": "", "documentation": "",
"nodeunit": "", "nodeunit": "",
"gulp": "", "gulp": "",
"gulp-babel": "",
"gulp-babel-istanbul": "",
"gulp-sourcemaps": "",
"gulp-concat": "",
"gulp-documentation": "", "gulp-documentation": "",
"gulp-istanbul": "",
"gulp-nodeunit-runner": "", "gulp-nodeunit-runner": "",
"jsdoc": "", "gulp-sloc": "",
"gulp-eslint": "",
"eslint": "",
"istanbul": "" "istanbul": ""
}, },
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"test": "grunt tests" "test": "gulp nodeunit"
} }
} }

26
src/Adapter.js Executable file
View File

@ -0,0 +1,26 @@
'use strict';
/** @module Adapter */
module.exports = class Adapter {
/**
* Invoke an adapter
*
* @param {Object} instance - The connection objec
* @return {void}
*/
constructor(instance) {
this.instance = instance;
}
/**
* Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return {void}
*/
execute(/*sql, params, callback*/) {
throw new Error("Correct adapter not defined for query execution");
}
}

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
var helpers = require('./helpers'); import helpers from './helpers'
/** /**
* Base Database Driver * Base Database Driver

13
src/DriverClass.js Normal file
View File

@ -0,0 +1,13 @@
'use strict';
import driverBase from './DriverBase';
module.exports = class DriverClass {
constructor(properties = {}) {
Object.keys(driverBase).forEach((key) => {
this[key] = (Object.keys(properties).indexOf(key) !== -1)
? properties[key]
: driverBase[key];
});
}
}

74
src/NodeQuery.js Executable file
View File

@ -0,0 +1,74 @@
"use strict";
let instance = null;
import fs from 'fs';
import helpers from './helpers';
import QueryBuilder from './QueryBuilder';
/**
* @module NodeQuery
*/
class NodeQuery {
/**
* Constructor
*/
constructor() {
this.instance = null;
}
/**
* Create a query builder object
*
* @memberOf NodeQuery
* @param {String} drivername - The name of the database type, eg. mysql or pg
* @param {Object} connObject - A connection object from the database library you are connecting with
* @param {String} [connLib] - The name of the db connection library you are using, eg. mysql or mysql2. Optional if the same as drivername
* @return {QueryBuilder}
*/
init(driverType, connObject, connLib) {
connLib = connLib || driverType;
let paths = {
driver: `${__dirname}/drivers/` + helpers.upperCaseFirst(driverType),
adapter: `${__dirname}/adapters/${connLib}`
};
/*Object.keys(paths).forEach((type) => {
if ( ! fs.existsSync(paths[type]))
{
console.log(paths[type]);
throw new Error(
`Selected ${type} (` +
helpers.upperCaseFirst(driverType) +
`) does not exist!`
);
}
});*/
let driver = require(paths.driver);
let $adapter = require(paths.adapter);
let adapter = new $adapter(connObject);
this.instance = new QueryBuilder(driver, adapter);
return this.instance;
};
/**
* Return an existing query builder instance
*
* @memberOf NodeQuery
* @return {QueryBuilder}
*/
getQuery() {
if ( ! this.instance) {
throw new Error("No Query Builder instance to return");
}
return this.instance;
};
};
module.exports = new NodeQuery();

924
src/QueryBuilder.js Executable file
View File

@ -0,0 +1,924 @@
'use strict';
/** @module QueryBuilder */
import getArgs from 'getargs';
import helpers from './helpers';
import State from './State';
import QueryParser from './QueryParser';
module.exports = class QueryBuilder {
/*
* SQL generation object
*
* @param {driver} - The syntax driver for the database
* @param {adapter} - The database module adapter for running queries
* @returns {QueryBuilder}
* @constructor
*/
constructor(driver, adapter) {
this.driver = driver;
this.adapter = adapter;
this.parser = new QueryParser(this.driver);
this.state = new State();
}
/**
* Complete the sql building based on the type provided
*
* @param {String} type
* @param {String} table
* @private
* @return {String}
*/
_compile(type, table) {
// Put together the basic query
let sql = this._compileType(type, table);
// Set each subClause
['queryMap', 'groupString', 'orderString', 'havingMap'].forEach((clause) => {
let param = this.state[clause];
if ( ! helpers.isScalar(param))
{
Object.keys(param).forEach((part) => {
sql += param[part].conjunction + param[part].string;
});
}
else
{
sql += param;
}
});
// Append the limit, if it exists
if (helpers.isNumber(this.state.limit))
{
sql = this.driver.limit(sql, this.state.limit, this.state.offset);
}
return sql;
}
_compileType(type, table) {
let sql = '';
switch(type) {
case "insert":
let params = Array(this.state.setArrayKeys.length).fill('?');
sql = `INSERT INTO ${table} (`;
sql += this.state.setArrayKeys.join(',');
sql += ") VALUES (";
sql += params.join(',') + ')';
break;
case "update":
sql = `UPDATE ${table} SET ${this.state.setString}`;
break;
case "delete":
sql = `DELETE FROM ${table}`;
break;
default:
sql = `SELECT * FROM ${this.state.fromString}`;
// Set the select string
if (this.state.selectString.length > 0)
{
// Replace the star with the selected fields
sql = sql.replace('*', this.state.selectString);
}
break;
}
return sql;
}
_like(field, val, pos, like, conj) {
field = this.driver.quoteIdentifiers(field);
like = `${field} ${like} ?`;
if (pos == 'before')
{
val = `%${val}`;
}
else if (pos == 'after')
{
val = `${val}%`;
}
else
{
val = `%${val}%`;
}
conj = (this.state.queryMap.length < 1) ? ' WHERE ' : ` ${conj} `;
this._appendMap(conj, like, 'like');
this.state.whereValues.push(val);
}
/**
* Append a clause to the query map
*
* @param {String} conjunction
* @param {String} string
* @param {String} type
* @return {void}
*/
_appendMap(conjunction, string, type) {
this.state.queryMap.push({
type: type,
conjunction: conjunction,
string: string
});
}
/**
* Handle key/value pairs in an object the same way as individual arguments,
* when appending to state
*
* @private
*/
_mixedSet(/* $letName, $valType, $key, [$val] */) {
let args = getArgs('$letName:string, $valType:string, $key:object|string|number, [$val]', arguments);
let obj = {};
if (helpers.isScalar(args.$key) && !helpers.isUndefined(args.$val))
{
// Convert key/val pair to a simple object
obj[args.$key] = args.$val;
}
else if (helpers.isScalar(args.$key) && helpers.isUndefined(args.$val))
{
// If just a string for the key, and no value, create a simple object with duplicate key/val
obj[args.$key] = args.$key;
}
else
{
obj = args.$key;
}
Object.keys(obj).forEach((k) => {
// If a single value for the return
if (['key','value'].indexOf(args.$valType) !== -1)
{
let pushVal = (args.$valType === 'key') ? k : obj[k];
this.state[args.$letName].push(pushVal);
}
else
{
this.state[args.$letName][k] = obj[k];
}
});
return this.state[args.$letName];
}
_whereMixedSet(/*key, val*/) {
let args = getArgs('key:string|object, [val]', arguments);
this.state.whereMap = [];
this.state.rawWhereValues = [];
this._mixedSet('whereMap', 'both', args.key, args.val);
this._mixedSet('rawWhereValues', 'value', args.key, args.val);
}
_fixConjunction(conj) {
let lastItem = this.state.queryMap[this.state.queryMap.length - 1];
let conjunctionList = helpers.arrayPluck(this.state.queryMap, 'conjunction');
if (this.state.queryMap.length === 0 || ( ! helpers.regexInArray(conjunctionList, /^ ?WHERE/i)))
{
conj = " WHERE ";
}
else if (lastItem.type === 'groupStart')
{
conj = '';
}
else
{
conj = ' ' + conj + ' ';
}
return conj;
}
_where(key, val, defaultConj) {
// Normalize key and value and insert into this.state.whereMap
this._whereMixedSet(key, val);
// Parse the where condition to account for operators,
// functions, identifiers, and literal values
this.state = this.parser.parseWhere(this.driver, this.state);
this.state.whereMap.forEach((clause) => {
let conj = this._fixConjunction(defaultConj);
this._appendMap(conj, clause, 'where');
});
this.state.whereMap = {};
}
_whereNull(field, stmt, conj) {
field = this.driver.quoteIdentifiers(field);
let item = field + ' ' + stmt;
this._appendMap(this._fixConjunction(conj), item, 'whereNull');
}
_having(/*key, val, conj*/) {
let args = getArgs('key:string|object, [val]:string|number, [conj]:string', arguments);
args.conj = args.conj || 'AND';
args.val = args.val || null;
// Normalize key/val and put in state.whereMap
this._whereMixedSet(args.key, args.val);
// Parse the having condition to account for operators,
// functions, identifiers, and literal values
this.state = this.parser.parseWhere(this.driver, this.state);
this.state.whereMap.forEach((clause) => {
// Put in the having map
this.state.havingMap.push({
conjunction: (this.state.havingMap.length > 0) ? ` ${args.conj} ` : ' HAVING ',
string: clause
});
});
// Clear the where Map
this.state.whereMap = {};
}
_whereIn(/*key, val, inClause, conj*/) {
let args = getArgs('key:string, val:array, inClause:string, conj:string', arguments);
args.key = this.driver.quoteIdentifiers(args.key);
let params = new Array(args.val.length);
params.fill('?');
args.val.forEach((value) => {
this.state.whereValues.push(value);
});
args.conj = (this.state.queryMap.length > 0) ? " " + args.conj + " " : ' WHERE ';
let str = args.key + " " + args.inClause + " (" + params.join(',') + ") ";
this._appendMap(args.conj, str, 'whereIn');
}
_run(type, table, callback, sql, vals) {
if ( ! sql)
{
sql = this._compile(type, table);
}
if ( ! vals)
{
vals = this.state.values.concat(this.state.whereValues);
}
//console.log(this.state);
//console.log(sql);
//console.log(vals);
//console.log(callback);
//console.log('------------------------');
// Reset the state so another query can be built
this._resetState();
// Pass the sql and values to the adapter to run on the database
this.adapter.execute(sql, vals, callback);
}
_getCompile(type, table, reset) {
reset = reset || false;
let sql = this._compile(type, table);
if (reset) this._resetState();
return sql;
}
_resetState() {
this.state = new State();
}
// ----------------------------------------------------------------------------
// ! Miscellaneous Methods
// ----------------------------------------------------------------------------
/**
* Reset the object state for a new query
*
* @memberOf QueryBuilder
* @return {void}
*/
resetQuery() {
this._resetState();
}
/**
* Returns the current class state for testing or other purposes
*
* @private
* @return {Object}
*/
getState() {
return this.state;
}
/**
* Closes the database connection for the current adapter
*
* @return {void}
*/
end() {
this.adapter.close();
}
// ------------------------------------------------------------------------
// ! Query Builder Methods
// ------------------------------------------------------------------------
/**
* Specify rows to select in the query
*
* @memberOf QueryBuilder
* @param {String|Array} fields - The fields to select from the current table
* @return {QueryBuilder}
*/
select(fields) {
// Split/trim fields by comma
fields = (Array.isArray(fields))
? fields
: fields.split(",").map(helpers.stringTrim);
// Split on 'As'
fields.forEach((field, index) => {
if (field.match(/as/i))
{
fields[index] = field.split(/ as /i).map(helpers.stringTrim);
}
});
let safeArray = this.driver.quoteIdentifiers(fields);
// Join the strings back together
safeArray.forEach((field, index) => {
if (Array.isArray(field))
{
safeArray[index] = safeArray[index].join(' AS ');
}
});
this.state.selectString += safeArray.join(', ');
return this;
}
/**
* Specify the database table to select from
*
* @param {String} tableName - The table to use for the current query
* @return {QueryBuilder}
*/
from(tableName) {
// Split identifiers on spaces
let identArray = tableName.trim().split(' ').map(helpers.stringTrim);
// Quote/prefix identifiers
identArray[0] = this.driver.quoteTable(identArray[0]);
identArray = this.driver.quoteIdentifiers(identArray);
// Put it back together
this.state.fromString = identArray.join(' ');
return this;
}
/**
* Add a 'like/ and like' clause to the query
*
* @param {String} field - The name of the field to compare to
* @param {String} val - The value to compare to
* @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
* @return {QueryBuilder}
*/
like(field, val, pos) {
this._like(field, val, pos, ' LIKE ', 'AND');
return this;
}
/**
* Add a 'not like/ and not like' clause to the query
*
* @param {String} field - The name of the field to compare to
* @param {String} val - The value to compare to
* @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
* @return {QueryBuilder}
*/
notLike(field, val, pos) {
this._like(field, val, pos, ' NOT LIKE ', 'AND');
return this;
}
/**
* Add an 'or like' clause to the query
*
* @param {String} field - The name of the field to compare to
* @param {String} val - The value to compare to
* @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
* @return {QueryBuilder}
*/
orLike(field, val, pos) {
this._like(field, val, pos, ' LIKE ', 'OR');
return this;
}
/**
* Add an 'or not like' clause to the query
*
* @param {String} field - The name of the field to compare to
* @param {String} val - The value to compare to
* @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
* @return {QueryBuilder}
*/
orNotLike(field, val, pos) {
this._like(field, val, pos, ' NOT LIKE ', 'OR');
return this;
}
/**
* Add a 'having' clause
*
* @param {String|Object} key - The name of the field and the comparision operator, or an object
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return {QueryBuilder}
*/
having(/*key, [val]*/) {
let args = getArgs('key:string|object, [val]:string|number', arguments);
this._having(args.key, args.val, 'AND');
return this;
}
/**
* Add an 'or having' clause
*
* @param {String|Object} key - The name of the field and the comparision operator, or an object
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return {QueryBuilder}
*/
orHaving(/*key, [val]*/) {
let args = getArgs('key:string|object, [val]:string|number', arguments);
this._having(args.key, args.val, 'OR');
return this;
}
/**
* Set a 'where' clause
*
* @param {String|Object} key - The name of the field and the comparision operator, or an object
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return {QueryBuilder}
*/
where(key, val) {
this._where(key, val, 'AND');
return this;
}
/**
* Set a 'or where' clause
*
* @param {String|Object} key - The name of the field and the comparision operator, or an object
* @param {String|Number} [val] - The value to compare if the value of key is a string
* @return {QueryBuilder}
*/
orWhere(key, val) {
this._where(key, val, 'OR');
return this;
}
/**
* Select a field that is Null
*
* @param {String} field - The name of the field that has a NULL value
* @return {QueryBuilder}
*/
whereIsNull(field) {
this._whereNull(field, 'IS NULL', 'AND');
return this;
}
/**
* Specify that a field IS NOT NULL
*
* @param {String} field
* @return {QueryBuilder}
*/
whereIsNotNull(field) {
this._whereNull(field, 'IS NOT NULL', 'AND');
return this;
}
/**
* Field is null prefixed with 'OR'
*
* @param {String} field
* @return {QueryBuilder}
*/
orWhereIsNull(field) {
this._whereNull(field, 'IS NULL', 'OR');
return this;
}
/**
* Field is not null prefixed with 'OR'
*
* @param {String} field
* @return {QueryBuilder}
*/
orWhereIsNotNull(field) {
this._whereNull(field, 'IS NOT NULL', 'OR');
return this;
}
/**
* Set a 'where in' clause
*
* @param {String} key - the field to search
* @param {Array} val - the array of items to search in
* @return {QueryBuilder}
*/
whereIn(key, val) {
this._whereIn(key, val, 'IN', 'AND');
return this;
}
/**
* Set a 'or where in' clause
*
* @param {String} key - the field to search
* @param {Array} val - the array of items to search in
* @return {QueryBuilder}
*/
orWhereIn(key, val) {
this._whereIn(key, val, 'IN', 'OR');
return this;
}
/**
* Set a 'where not in' clause
*
* @param {String} key - the field to search
* @param {Array} val - the array of items to search in
* @return {QueryBuilder}
*/
whereNotIn(key, val) {
this._whereIn(key, val, 'NOT IN', 'AND');
return this;
}
/**
* Set a 'or where not in' clause
*
* @param {String} key - the field to search
* @param {Array} val - the array of items to search in
* @return {QueryBuilder}
*/
orWhereNotIn(key, val) {
this._whereIn(key, val, 'NOT IN', 'OR');
return this;
}
/**
* Set values for insertion or updating
*
* @param {String|Object} key - The key or object to use
* @param {String} [val] - The value if using a scalar key
* @return {QueryBuilder}
*/
set(/* $key, [$val] */) {
let args = getArgs('$key, [$val]', arguments);
// Set the appropriate state variables
this._mixedSet('setArrayKeys', 'key', args.$key, args.$val);
this._mixedSet('values', 'value', args.$key, args.$val);
// Use the keys of the array to make the insert/update string
// and escape the field names
this.state.setArrayKeys = this.state.setArrayKeys.map(this.driver._quote);
// Generate the "set" string
this.state.setString = this.state.setArrayKeys.join('=?,');
this.state.setString += '=?';
return this;
}
/**
* Add a join clause to the query
*
* @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 {QueryBuilder}
*/
join(table, cond, type) {
type = type || "inner";
// Prefix/quote table name
table = table.split(' ').map(helpers.stringTrim);
table[0] = this.driver.quoteTable(table[0]);
table = table.map(this.driver.quoteIdentifiers);
table = table.join(' ');
// Parse out the join condition
let parsedCondition = this.parser.compileJoin(cond);
let condition = table + ' ON ' + parsedCondition;
// Append the join condition to the query map
this._appendMap("\n" + type.toUpperCase() + ' JOIN ', condition, 'join');
return this;
}
/**
* Group the results by the selected field(s)
*
* @param {String|Array} field
* @return {QueryBuilder}
*/
groupBy(field) {
if ( ! helpers.isScalar(field))
{
let newGroupArray = field.map(this.driver.quoteIdentifiers);
this.state.groupArray = this.state.groupArray.concat(newGroupArray);
}
else
{
this.state.groupArray.push(this.driver.quoteIdentifiers(field));
}
this.state.groupString = ' GROUP BY ' + this.state.groupArray.join(',');
return this;
}
/**
* Order the results by the selected field(s)
*
* @param {String} field - The field(s) to order by
* @param {String} [type='ASC'] - The order direction, ASC or DESC
* @return {QueryBuilder}
*/
orderBy(field, type) {
type = type || 'ASC';
// Set the fields for later manipulation
field = this.driver.quoteIdentifiers(field);
this.state.orderArray[field] = type;
let orderClauses = [];
// Flatten key/val pairs into an array of space-separated pairs
Object.keys(this.state.orderArray).forEach((key) => {
orderClauses.push(key + ' ' + this.state.orderArray[key].toUpperCase());
});
// Set the final string
this.state.orderString = ' ORDER BY ' + orderClauses.join(', ');
return this;
}
/**
* Put a limit on the query
*
* @param {Number} limit - The maximum number of rows to fetch
* @param {Number} [offset] - The row number to start from
* @return {QueryBuilder}
*/
limit(limit, offset) {
this.state.limit = limit;
this.state.offset = offset || null;
return this;
}
/**
* Adds an open paren to the current query for logical grouping
*
* @return {QueryBuilder}
*/
groupStart() {
let conj = (this.state.queryMap.length < 1) ? ' WHERE ' : ' AND ';
this._appendMap(conj, '(', 'groupStart');
return this;
}
/**
* Adds an open paren to the current query for logical grouping,
* prefixed with 'OR'
*
* @return {QueryBuilder}
*/
orGroupStart() {
this._appendMap('', ' OR (', 'groupStart');
return this;
}
/**
* Adds an open paren to the current query for logical grouping,
* prefixed with 'OR NOT'
*
* @return {QueryBuilder}
*/
orNotGroupStart() {
this._appendMap('', ' OR NOT (', 'groupStart');
return this;
}
/**
* Ends a logical grouping started with one of the groupStart methods
*
* @return {QueryBuilder}
*/
groupEnd() {
this._appendMap('', ')', 'groupEnd');
return this;
}
// ------------------------------------------------------------------------
// ! Result Methods
// ------------------------------------------------------------------------
/**
* Get the results of the compiled query
*
* @param {String} [table] - The table to select from
* @param {Number} [limit] - A limit for the query
* @param {Number} [offset] - An offset for the query
* @param {Function} callback - A callback for receiving the result
* @return {void}
*/
get(/* [table], [limit], [offset], callback */) {
let args = getArgs('[table]:string, [limit]:number, [offset]:number, callback:function', arguments);
if (args.table) {
this.from(args.table);
}
if (args.limit) {
this.limit(args.limit, args.offset);
}
// Run the query
this._run('get', args.table, args.callback);
}
/**
* Run the generated insert query
*
* @param {String} table - The table to insert into
* @param {Object} [data] - Data to insert, if not already added with the 'set' method
* @param {Function} callback - Callback for handling response from the database
* @return {void}
*/
insert(/* table, data, callback */) {
let args = getArgs('table:string, [data]:object, callback:function', arguments);
if (args.data) {
this.set(args.data);
}
// Run the query
this._run('insert', this.driver.quoteTable(args.table), args.callback);
}
/**
* Insert multiple sets of rows at a time
*
* @param {String} table - The table to insert into
* @param {Array} data - The array of objects containing data rows to insert
* @param {Function} callback - Callback for handling database response
* @example query.insertBatch('foo',[{id:1,val:'bar'},{id:2,val:'baz'}], callbackFunction);
* @return {void}
*/
insertBatch(/* table, data, callback */) {
let args = getArgs('table:string, data:array, callback:function', arguments);
let batch = this.driver.insertBatch(args.table, args.data);
// Run the query
this._run('', '', args.callback, batch.sql, batch.values);
}
/**
* Run the generated update query
*
* @param {String} table - The table to insert into
* @param {Object} [data] - Data to insert, if not already added with the 'set' method
* @param {Function} callback - Callback for handling response from the database
* @return {void}
*/
update(/*table, data, callback*/) {
let args = getArgs('table:string, [data]:object, callback:function', arguments);
if (args.data) {
this.set(args.data);
}
// Run the query
this._run('update', this.driver.quoteTable(args.table), args.callback);
}
/**
* Run the generated delete query
*
* @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}
*/
delete(/*table, [where], callback*/) {
let args = getArgs('table:string, [where]:object, callback:function', arguments);
if (args.where)
{
this.where(args.where);
}
// Run the query
this._run('delete', this.driver.quoteTable(args.table), args.callback);
}
// ------------------------------------------------------------------------
// ! Methods returning SQL
// ------------------------------------------------------------------------
/**
* Return generated select query SQL
*
* @param {String} [table] - the name of the table to retrieve from
* @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
* @return {String}
*/
getCompiledSelect(/*table, reset*/) {
let args = getArgs('[table]:string, [reset]:boolean', arguments);
if (args.table)
{
this.from(args.table);
}
return this._getCompile('get', args.table, args.reset);
}
/**
* Return generated insert query SQL
*
* @param {String} table - the name of the table to insert into
* @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
* @return {String}
*/
getCompiledInsert(table, reset) {
return this._getCompile('insert', this.driver.quoteTable(table), reset);
}
/**
* Return generated update query SQL
*
* @param {String} table - the name of the table to update
* @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
* @return {String}
*/
getCompiledUpdate(table, reset) {
return this._getCompile('update', this.driver.quoteTable(table), reset);
}
/**
* Return generated delete query SQL
*
* @param {String} table - the name of the table to delete from
* @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
* @return {String}
*/
getCompiledDelete(table, reset) {
return this._getCompile('delete', this.driver.quoteTable(table), reset);
}
}

View File

@ -1,48 +1,7 @@
'use strict'; 'use strict';
var helpers = require('./helpers'); import helpers from './helpers';
var matchPatterns = {
'function': /([a-z0-9_]+\((.*)\))/i,
operator: /\!=?|\=|\+|&&?|~|\|\|?|\^|\/|<>|>=?|<=?|\-|%|OR|AND|NOT|XOR/ig,
literal: /([0-9]+)|'(.*?)'|true|false/ig
};
// Full pattern for identifiers
// Making sure that literals and functions aren't matched
matchPatterns.identifier = new RegExp(
'('
+ '(?!'
+ matchPatterns['function'].source + '|'
+ matchPatterns.literal.source
+ ')'
+ '([a-z_\-]+[0-9]*\\.?)'
+ ')+'
, 'ig');
// Full pattern for determining ordering of the pieces
matchPatterns.joinCombined = new RegExp(
matchPatterns['function'].source + "+|"
+ matchPatterns.literal.source + '+|'
+ matchPatterns.identifier.source
+ '|(' + matchPatterns.operator.source + ')+'
, 'ig');
var identifierBlacklist = ['true','false','null'];
var filterMatches = function(array) {
var output = [];
// Return non-array matches
if (helpers.isNull(array)) return null;
if (helpers.isScalar(array) || helpers.isUndefined(array)) return output;
array.forEach(function(item) {
output.push(item);
});
return output;
};
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -51,10 +10,63 @@ var filterMatches = function(array) {
* @param {Driver} - The driver object for the database in use * @param {Driver} - The driver object for the database in use
* @module query-parser * @module query-parser
*/ */
var QueryParser = function(driver) { module.exports = class QueryParser {
/**
* @constructor
* @param {Driver} - The driver object for the database in use
* @return {void}
*/
constructor(driver) {
this.driver = driver;
// That 'new' keyword is annoying let matchPatterns = {
if ( ! (this instanceof QueryParser)) return new QueryParser(driver); 'function': /([a-z0-9_]+\((.*)\))/i,
operator: /\!=?|\=|\+|&&?|~|\|\|?|\^|\/|<>|>=?|<=?|\-|%|OR|AND|NOT|XOR/ig,
literal: /([0-9]+)|'(.*?)'|true|false/ig
};
// Full pattern for identifiers
// Making sure that literals and functions aren't matched
matchPatterns.identifier = new RegExp(
'('
+ '(?!'
+ matchPatterns['function'].source + '|'
+ matchPatterns.literal.source
+ ')'
+ '([a-z_\-]+[0-9]*\\.?)'
+ ')+'
, 'ig');
// Full pattern for determining ordering of the pieces
matchPatterns.joinCombined = new RegExp(
matchPatterns['function'].source + "+|"
+ matchPatterns.literal.source + '+|'
+ matchPatterns.identifier.source
+ '|(' + matchPatterns.operator.source + ')+'
, 'ig');
this.matchPatterns = matchPatterns;
this.identifierBlacklist = ['true','false','null'];
}
/**
* Filter matched patterns
*
* @param {Array} array
* @return {Array|null}
*/
filterMatches(array) {
let output = [];
// Return non-array matches
if (helpers.isNull(array)) return null;
if (helpers.isScalar(array) || helpers.isUndefined(array)) return output;
array.forEach((item) => {
output.push(item);
});
return output;
}
/** /**
* Check if the string contains an operator, and if so, return the operator(s). * Check if the string contains an operator, and if so, return the operator(s).
@ -63,8 +75,8 @@ var QueryParser = function(driver) {
* @param {String} string - the string to check * @param {String} string - the string to check
* @return {Array|null} * @return {Array|null}
*/ */
this.hasOperator = function(string) { hasOperator(string) {
return filterMatches(string.match(matchPatterns.operator)); return this.filterMatches(string.match(this.matchPatterns.operator));
} }
/** /**
@ -73,26 +85,31 @@ var QueryParser = function(driver) {
* @param {String} sql * @param {String} sql
* @return {Object} * @return {Object}
*/ */
this.parseJoin = function(sql) { parseJoin(sql) {
var matches = {}; let matches = {};
var output = {}; let output = {
functions: [],
identifiers: [],
operators: [],
literals: []
};
// Get clause components // Get clause components
matches.functions = sql.match(new RegExp(matchPatterns['function'].source, 'ig')); matches.functions = sql.match(new RegExp(this.matchPatterns['function'].source, 'ig'));
matches.identifiers = sql.match(matchPatterns.identifier); matches.identifiers = sql.match(this.matchPatterns.identifier);
matches.operators = sql.match(matchPatterns.operator); matches.operators = sql.match(this.matchPatterns.operator);
matches.literals = sql.match(matchPatterns.literal); matches.literals = sql.match(this.matchPatterns.literal);
// Get everything at once for ordering // Get everything at once for ordering
matches.combined = sql.match(matchPatterns.joinCombined); matches.combined = sql.match(this.matchPatterns.joinCombined);
// Flatten the matches to increase relevance // Flatten the matches to increase relevance
Object.keys(matches).forEach(function(key) { Object.keys(matches).forEach((key) => {
output[key] = filterMatches(matches[key]); output[key] = this.filterMatches(matches[key]);
}); });
return output; return output;
}; }
/** /**
* Return the output of the parsing of the join condition * Return the output of the parsing of the join condition
@ -100,40 +117,40 @@ var QueryParser = function(driver) {
* @param {String} condition - The join condition to evalate * @param {String} condition - The join condition to evalate
* @return {String} - The parsed/escaped join condition * @return {String} - The parsed/escaped join condition
*/ */
this.compileJoin = function(condition) { compileJoin(condition) {
var parts = this.parseJoin(condition); let parts = this.parseJoin(condition);
var count = parts.identifiers.length; let count = parts.identifiers.length;
var i; let i;
// Quote the identifiers // Quote the identifiers
parts.combined.forEach(function(part, i) { parts.combined.forEach((part, i) => {
if (parts.identifiers.indexOf(part) !== -1 && ! helpers.isNumber(part)) if (parts.identifiers.indexOf(part) !== -1 && ! helpers.isNumber(part))
{ {
parts.combined[i] = driver.quoteIdentifiers(part); parts.combined[i] = this.driver.quoteIdentifiers(part);
} }
}); });
return parts.combined.join(' '); return parts.combined.join(' ');
}; }
/** /**
* Parse a where clause to separate functions from values * Parse a where clause to separate functions from values
* *
* @param {Object} driver * @param {Driver} driver
* @param {State} state * @param {State} state
* @return {String} - The parsed/escaped where condition * @return {String} - The parsed/escaped where condition
*/ */
this.parseWhere = function(driver, state) { parseWhere(driver, state) {
var whereMap = state.whereMap, let whereMap = state.whereMap;
whereValues = state.rawWhereValues; let whereValues = state.rawWhereValues;
var outputMap = []; let outputMap = [];
var outputValues = []; let outputValues = [];
Object.keys(whereMap).forEach(function(key) { Object.keys(whereMap).forEach((key) => {
// Combine fields, operators, functions and values into a full clause // Combine fields, operators, functions and values into a full clause
// to have a common starting flow // to have a common starting flow
var fullClause = ''; let fullClause = '';
// Add an explicit = sign where one is inferred // Add an explicit = sign where one is inferred
if ( ! this.hasOperator(key)) if ( ! this.hasOperator(key))
@ -150,17 +167,17 @@ var QueryParser = function(driver) {
} }
// Separate the clause into separate pieces // Separate the clause into separate pieces
var parts = this.parseJoin(fullClause); let parts = this.parseJoin(fullClause);
// Filter explicit literals from lists of matches // Filter explicit literals from lists of matches
if (whereValues.indexOf(whereMap[key]) !== -1) if (whereValues.indexOf(whereMap[key]) !== -1)
{ {
var value = whereMap[key]; let value = whereMap[key];
var identIndex = (helpers.isArray(parts.identifiers)) ? parts.identifiers.indexOf(value) : -1; let identIndex = (helpers.isArray(parts.identifiers)) ? parts.identifiers.indexOf(value) : -1;
var litIndex = (helpers.isArray(parts.literals)) ? parts.literals.indexOf(value) : -1; let litIndex = (helpers.isArray(parts.literals)) ? parts.literals.indexOf(value) : -1;
var combIndex = (helpers.isArray(parts.combined)) ? parts.combined.indexOf(value) : -1; let combIndex = (helpers.isArray(parts.combined)) ? parts.combined.indexOf(value) : -1;
var funcIndex = (helpers.isArray(parts.functions)) ? parts.functions.indexOf(value) : -1; let funcIndex = (helpers.isArray(parts.functions)) ? parts.functions.indexOf(value) : -1;
var inOutputArray = outputValues.indexOf(value) !== -1; let inOutputArray = outputValues.indexOf(value) !== -1;
// Remove the identifier in question, // Remove the identifier in question,
// and add to the output values array // and add to the output values array
@ -207,18 +224,19 @@ var QueryParser = function(driver) {
} }
// Filter false positive identifiers // Filter false positive identifiers
parts.identifiers = parts.identifiers.filter(function(item) { parts.identifiers = parts.identifiers || [];
var isInCombinedMatches = parts.combined.indexOf(item) !== -1; parts.identifiers = parts.identifiers.filter((item) => {
var isNotInBlackList = identifierBlacklist.indexOf(item.toLowerCase()) === -1; let isInCombinedMatches = parts.combined.indexOf(item) !== -1;
let isNotInBlackList = this.identifierBlacklist.indexOf(item.toLowerCase()) === -1;
return isInCombinedMatches && isNotInBlackList; return isInCombinedMatches && isNotInBlackList;
}); }, this);
// Quote identifiers // Quote identifiers
if (helpers.isArray(parts.identifiers)) if (helpers.isArray(parts.identifiers))
{ {
parts.identifiers.forEach(function(ident) { parts.identifiers.forEach((ident) => {
var index = parts.combined.indexOf(ident); let index = parts.combined.indexOf(ident);
if (index !== -1) if (index !== -1)
{ {
parts.combined[index] = driver.quoteIdentifiers(ident); parts.combined[index] = driver.quoteIdentifiers(ident);
@ -233,8 +251,8 @@ var QueryParser = function(driver) {
// a where condition, // a where condition,
if (helpers.isArray(parts.literals)) if (helpers.isArray(parts.literals))
{ {
parts.literals.forEach(function(lit) { parts.literals.forEach((lit) => {
var litIndex = parts.combined.indexOf(lit); let litIndex = parts.combined.indexOf(lit);
if (litIndex !== -1) if (litIndex !== -1)
{ {
@ -245,14 +263,12 @@ var QueryParser = function(driver) {
} }
outputMap.push(parts.combined.join(' ')); outputMap.push(parts.combined.join(' '));
}, this); });
state.rawWhereValues = []; state.rawWhereValues = [];
state.whereValues = state.whereValues.concat(outputValues); state.whereValues = state.whereValues.concat(outputValues);
state.whereMap = outputMap; state.whereMap = outputMap;
return state; return state;
}; }
}; }
module.exports = QueryParser;

29
src/State.js Normal file
View File

@ -0,0 +1,29 @@
'use strict';
/** @module State */
module.exports = class State {
constructor() {
// Arrays/maps
this.queryMap = [];
this.values = [];
this.whereValues = [];
this.setArrayKeys = [];
this.orderArray = [];
this.groupArray = [];
this.havingMap = [];
this.whereMap = [];
this.rawWhereValues = [];
// Partials
this.selectString = '';
this.fromString = '';
this.setString = '';
this.orderString = '';
this.groupString = '';
// Other various values
this.limit = null;
this.offset = null;
}
}
// End of module State

20
src/adapters/dblite.js Normal file
View File

@ -0,0 +1,20 @@
'use strict';
import Adapter from '../Adapter';
import getArgs from 'getargs';
/** @module adapters/dblite */
module.exports = class dblite extends Adapter {
/**
* Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params]:array, callback:function', arguments);
this.instance.query(args.sql, args.params, args.callback);
};
}

11
lib/adapter.js → src/adapters/mysql.js Executable file → Normal file
View File

@ -1,8 +1,9 @@
'use strict'; 'use strict';
/** @module adapter */ import Adapter from '../Adapter';
module.exports = {
/** @module adapters/mysql */
module.exports = class mysql extends Adapter {
/** /**
* Run the sql query as a prepared statement * Run the sql query as a prepared statement
* *
@ -11,7 +12,7 @@ module.exports = {
* @param {Function} callback - Callback to run when a response is recieved * @param {Function} callback - Callback to run when a response is recieved
* @return void * @return void
*/ */
execute: function(/*sql, params, callback*/) { execute(sql, params, callback) {
throw new Error("Correct adapter not defined for query execution"); this.instance.query.apply(instance, arguments);
} }
}; }

18
src/adapters/mysql2.js Normal file
View File

@ -0,0 +1,18 @@
'use strict';
import Adapter from '../Adapter';
/** @module adapters/mysql2 */
module.exports = class mysql2 extends Adapter {
/**
* Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
execute(sql, params, callback) {
this.instance.execute.apply(this.instance, arguments);
};
}

View File

@ -0,0 +1,20 @@
'use strict';
import Adapter from '../Adapter';
import getArgs from 'getargs';
/** @module adapters/node-firebird */
module.exports = class nodefirebird extends Adapter {
/**
* Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params], callback:function', arguments);
this.instance.execute(args.sql, args.params, args.callback);
}
}

28
src/adapters/pg.js Normal file
View File

@ -0,0 +1,28 @@
'use strict';
import Adapter from '../Adapter';
import getArgs from 'getargs';
/** @module adapters/pg */
module.exports = class pg extends Adapter {
/**
* Run the sql query as a prepared statement
*
* @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query
* @param {Function} callback - Callback to run when a response is recieved
* @return void
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params]:array, callback:function', arguments);
// Replace question marks with numbered placeholders, because this adapter is different...
let count = 0;
args.sql = args.sql.replace(/\?/g, () => {
count++;
return '$' + count;
});
this.instance.query(args.sql, args.params, args.callback);
}
}

View File

@ -1,17 +1,19 @@
"use strict"; "use strict";
var helpers = require('../helpers'); import helpers from '../helpers';
import Driver from '../DriverClass';
/** /**
* Driver for Firebird databases * Driver for Firebird databases
* *
* @module drivers/firebird * @module drivers/firebird
*/ */
module.exports = (function() { class Firebird extends Driver {
delete require.cache[require.resolve('../driver')]; constructor() {
var driver = require('../driver'); super({
hasTruncate: false
driver.hasTruncate = false; });
}
/** /**
* Generate a limit clause for firebird, which uses the syntax closest to the SQL standard * Generate a limit clause for firebird, which uses the syntax closest to the SQL standard
@ -21,16 +23,16 @@ module.exports = (function() {
* @param {Number} offset * @param {Number} offset
* @return {String} * @return {String}
*/ */
driver.limit = function(origSql, limit, offset) { limit(origSql, limit, offset) {
var sql = 'FIRST ' + limit; let sql = `FIRST ${limit}`;
if (helpers.isNumber(offset)) if (helpers.isNumber(offset))
{ {
sql += ' SKIP ' + offset; sql += ` SKIP ${offset}`;
} }
return origSql.replace(/SELECT/i, "SELECT " + sql);; return origSql.replace(/SELECT/i, "SELECT " + sql);
}; }
/** /**
* SQL to insert a group of rows * SQL to insert a group of rows
@ -39,9 +41,9 @@ module.exports = (function() {
* @param {Array} [data] - The array of object containing data to insert * @param {Array} [data] - The array of object containing data to insert
* @return {String} * @return {String}
*/ */
driver.insertBatch = function(table, data) { insertBatch() {
throw new Error("Not Implemented"); throw new Error("Not Implemented");
}; }
}
return driver; module.exports = new Firebird();
}());

29
src/drivers/Mysql.js Executable file
View File

@ -0,0 +1,29 @@
"use strict";
import helpers from '../helpers';
import Driver from '../DriverClass';
/**
* Driver for MySQL databases
*
* @module drivers/mysql
*/
class Mysql extends Driver {
constructor() {
super({
identifierStartChar: '`',
identifierEndChar: '`'
});
}
limit(sql, limit, offset) {
if ( ! helpers.isNumber(offset))
{
return sql += ` LIMIT ${limit}`;
}
return sql += ` LIMIT ${offset}, ${limit}`;
}
}
module.exports = new Mysql();

10
src/drivers/Pg.js Executable file
View File

@ -0,0 +1,10 @@
"use strict";
import Driver from '../DriverClass';
/**
* Driver for PostgreSQL databases
*
* @module drivers/pg
*/
module.exports = new Driver();

64
src/drivers/Sqlite.js Normal file
View File

@ -0,0 +1,64 @@
"use strict";
import helpers from '../helpers';
import Driver from '../DriverClass';
/**
* Driver for Sqlite databases
*
* @module drivers/sqlite
*/
class Sqlite extends Driver {
constructor() {
super();
this.hasTruncate = false;
}
insertBatch(table, data) {
// Get the data values to insert, so they can
// be parameterized
let sql = "",
vals = [],
cols = [],
fields = [],
first = data.shift(),
params = [],
paramString = "",
paramList = [];
data.forEach((obj) => {
let row = [];
Object.keys(obj).forEach((key) => {
row.push(obj[key]);
});
vals.push(row);
});
sql += "INSERT INTO " + this.quoteTable(table) + "\n";
// Get the field names from the keys of the first
// object to be inserted
fields = Object.keys(first);
Object.keys(first).forEach((key) => {
cols.push("'" + this._quote(first[key]) + "' AS " + this.quoteIdentifiers(key));
});
sql += "SELECT " + cols.join(', ') + "\n";
vals.forEach((row_values) => {
let quoted = row_values.map((value) => {
return String(value).replace("'", "'\'");
});
sql += "UNION ALL SELECT '" + quoted.join("', '") + "'\n";
});
return {
sql: sql,
values: null
};
}
};
module.exports = new Sqlite();

127
src/helpers.js Executable file
View File

@ -0,0 +1,127 @@
"use strict";
//require('es6-shim');
let helpers = {
/**
* Wrap String.prototype.trim in a way that is easily mappable
*
* @param {String} str - The string to trim
* @return {String} - The trimmed string
*/
stringTrim: (str) => str.trim(),
/**
* Get the type of the variable passed
*
* @see https://techblog.badoo.com/blog/2013/11/01/type-checking-in-javascript/
* @see http://toddmotto.com/understanding-javascript-types-and-reliable-type-checking/
* @param {mixed} o
* @return {String}
*/
type: (o) => {
let type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
// handle NaN and Infinity
if (type === 'number') {
if (isNaN(o)) {
return 'nan';
}
if (!isFinite(o)) {
return 'infinity';
}
}
return type;
},
/**
* Determine whether an object is scalar
*
* @param {mixed} obj
* @return {bool}
*/
isScalar: (obj) => {
let scalar = ['string', 'number', 'boolean'];
return scalar.indexOf(helpers.type(obj)) !== -1;
},
/**
* Get a list of values with a common key from an array of objects
*
* @param {Array} arr - The array of objects to search
* @param {String} key - The key of the object to get
* @return {Array}
*/
arrayPluck: (arr, key) => {
let output = [];
// Empty case
if (arr.length === 0) return output;
arr.forEach((obj) => {
if ( ! helpers.isUndefined(obj[key]))
{
output.push(obj[key]);
}
});
return output;
},
/**
* Determine if a value matching the passed regular expression is
* in the passed array
*
* @param {Array} arr - The array to search
* @param {RegExp} pattern - The pattern to match
* @return {Boolean} - If an array item matches the pattern
*/
regexInArray: (arr, pattern) => {
// Empty case(s)
if ( ! helpers.isArray(arr)) return false;
if (arr.length === 0) return false;
let i, l = arr.length;
for(i=0; i< l; i++)
{
// Short circuit if any items match
if (pattern.test(arr[i])) return true;
}
return false;
},
/**
* Make the first letter of the string uppercase
*
* @param {String} str
* @return {String}
*/
upperCaseFirst: (str) => {
str += '';
let first = str.charAt(0).toUpperCase();
return first + str.substr(1);
}
};
// Define an 'is' method for each type
let types = ['Null','Undefined','Object','Array','String','Number','Boolean','Function','RegExp','NaN','Infinite'];
types.forEach((t) => {
/**
* Determine whether a variable is of the type specified in the
* function name, eg isNumber
*
* Types available are Null, Undefined, Object, Array, String, Number, Boolean, Function, RegExp, NaN and Infinite
*
* @name is[type]
* @param {mixed} o
* @return {Boolean}
*/
helpers['is' + t] = function (o) {
if (t.toLowerCase() === 'infinite')
{
t = 'infinity';
}
return helpers.type(o) === t.toLowerCase();
};
});
module.exports = helpers;

View File

@ -18,13 +18,13 @@ try {
// Export an empty testsuite if module not loaded // Export an empty testsuite if module not loaded
console.log(e); console.log(e);
console.log("Database adapter dblite not found"); console.log("Database adapter dblite not found");
return {}; //return {};
} }
if (connection) if (connection)
{ {
// Set up the query builder object // Set up the query builder object
var nodeQuery = require('../../lib/node-query'); var nodeQuery = require('../../lib/NodeQuery');
var qb = nodeQuery.init('sqlite', connection, adapterName); var qb = nodeQuery.init('sqlite', connection, adapterName);
// Set up the sqlite database // Set up the sqlite database

View File

@ -16,7 +16,7 @@ var mysql2 = require(adapterName);
var connection = mysql2.createConnection(config.conn); var connection = mysql2.createConnection(config.conn);
// Set up the query builder object // Set up the query builder object
var nodeQuery = require('../../lib/node-query'); var nodeQuery = require('../../lib/NodeQuery');
var qb = nodeQuery.init('mysql', connection, adapterName); var qb = nodeQuery.init('mysql', connection, adapterName);

View File

@ -16,7 +16,7 @@ var mysql = require(adapterName);
var connection = mysql.createConnection(config.conn); var connection = mysql.createConnection(config.conn);
// Set up the query builder object // Set up the query builder object
var nodeQuery = require('../../lib/node-query'); var nodeQuery = require('../../lib/NodeQuery');
var qb = nodeQuery.init('mysql', connection); var qb = nodeQuery.init('mysql', connection);
// Set up the test base // Set up the test base

View File

@ -7,7 +7,7 @@ var testBase = require('../query-builder-base');
var adapterName = 'node-firebird'; var adapterName = 'node-firebird';
var config = require('../config.json')[adapterName]; var config = require('../config.json')[adapterName];
config.conn.database = __dirname + config.conn.database; config.conn.database = __dirname + config.conn.database;
var nodeQuery = require('../../lib/node-query'); var nodeQuery = require('../../lib/NodeQuery');
// Skip on TravisCi // Skip on TravisCi
if (process.env.CI || process.env.JENKINS_HOME) if (process.env.CI || process.env.JENKINS_HOME)

View File

@ -21,7 +21,7 @@ connection.connect(function(err) {
}); });
// Set up the query builder object // Set up the query builder object
var nodeQuery = require('../../lib/node-query'); var nodeQuery = require('../../lib/NodeQuery');
var qb = nodeQuery.init('pg', connection); var qb = nodeQuery.init('pg', connection);

View File

@ -2,13 +2,13 @@
var modules = { var modules = {
helpers: require('../lib/helpers'), helpers: require('../lib/helpers'),
driver: require('../lib/driver'), driver: require('../lib/DriverBase'),
qb: require('../lib/query-builder'), qb: require('../lib/QueryBuilder'),
'node-query': require('../lib/node-query'), 'node-query': require('../lib/NodeQuery'),
'state': require('../lib/state'), 'state': require('../lib/State'),
'drivers/pg': require('../lib/drivers/pg'), 'drivers/pg': require('../lib/drivers/Pg'),
'drivers/mysql': require('../lib/drivers/mysql'), 'drivers/mysql': require('../lib/drivers/Mysql'),
'drivers/sqlite': require('../lib/drivers/sqlite'), 'drivers/sqlite': require('../lib/drivers/Sqlite'),
'adapters/mysql': require('../lib/adapters/mysql'), 'adapters/mysql': require('../lib/adapters/mysql'),
'adapters/mysql2': require('../lib/adapters/mysql2'), 'adapters/mysql2': require('../lib/adapters/mysql2'),
'adapters/pg': require('../lib/adapters/pg'), 'adapters/pg': require('../lib/adapters/pg'),

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var helpers = require('../lib/helpers'); var helpers = require('../lib/helpers');
var State = require('../lib/state'); var State = require('../lib/State');
module.exports = (function QueryBuilderTestBase() { module.exports = (function QueryBuilderTestBase() {

View File

@ -1,12 +1,14 @@
'use strict'; 'use strict';
// Use the base driver as a mock for testing // Use the base driver as a mock for testing
delete require.cache[require.resolve('../lib/driver')];
var getArgs = require('getargs'); var getArgs = require('getargs');
var helpers = require('../lib/helpers'); var helpers = require('../lib/helpers');
var driver = require('../lib/driver'); var driver = require('../lib/DriverBase');
var parser = require('../lib/query-parser')(driver);
var State = require('../lib/state'); var p = require('../lib/QueryParser');
var parser = new p(driver);
var State = require('../lib/State');
// Simulate query builder state // Simulate query builder state
var state = new State(); var state = new State();
@ -63,7 +65,7 @@ var whereMock = function() {
// ! Start Tests // ! Start Tests
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
module.exports = { var tests = {
'Has operator tests': { 'Has operator tests': {
'Has operator': function(test) { 'Has operator': function(test) {
var matches = parser.hasOperator('foo <> 2'); var matches = parser.hasOperator('foo <> 2');
@ -172,3 +174,5 @@ module.exports = {
} }
} }
}; };
module.exports = tests;