Start of coversion to ES6-style code with transpiling
This commit is contained in:
parent
5f20e0adb4
commit
6a9c67b924
733
docs/index.html
733
docs/index.html
File diff suppressed because it is too large
Load Diff
127
gulpfile.js
127
gulpfile.js
@ -1,30 +1,123 @@
|
||||
var gulp = require('gulp'),
|
||||
var babel = require('gulp-babel'),
|
||||
concat = require('gulp-concat'),
|
||||
documentation = require('gulp-documentation'),
|
||||
eslint = require('gulp-eslint'),
|
||||
gulp = require('gulp'),
|
||||
istanbul = require('gulp-babel-istanbul'),
|
||||
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.src('./lib/node-query.js')
|
||||
gulp.task('lint', function() {
|
||||
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(gulp.dest('docs'));
|
||||
gulp.src('./lib/node-query.js')
|
||||
/*gulp.src('./lib/QueryBuilder.js')
|
||||
.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'])
|
||||
.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() {
|
||||
return gulp.src(['tests/**/*_test.js'])
|
||||
.pipe(nodeunit_runner())
|
||||
.pipe(istanbul.writeReports({
|
||||
dir: './coverage',
|
||||
reporters: ['lcov', 'lcovonly', 'html', 'text']
|
||||
}));
|
||||
});
|
||||
gulp.task('default', ['lint', 'sloc', 'docs', 'test']);
|
42
lib/Adapter.js
Executable file
42
lib/Adapter.js
Executable 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
1
lib/Adapter.js.map
Normal 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
157
lib/DriverBase.js
Executable 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
1
lib/DriverBase.js.map
Normal file
File diff suppressed because one or more lines are too long
22
lib/DriverClass.js
Normal file
22
lib/DriverClass.js
Normal 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
1
lib/DriverClass.js.map
Normal 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
103
lib/NodeQuery.js
Executable 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
1
lib/NodeQuery.js.map
Normal 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
1063
lib/QueryBuilder.js
Executable file
File diff suppressed because it is too large
Load Diff
1
lib/QueryBuilder.js.map
Normal file
1
lib/QueryBuilder.js.map
Normal file
File diff suppressed because one or more lines are too long
278
lib/QueryParser.js
Normal file
278
lib/QueryParser.js
Normal 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
1
lib/QueryParser.js.map
Normal file
File diff suppressed because one or more lines are too long
34
lib/State.js
Normal file
34
lib/State.js
Normal 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
1
lib/State.js.map
Normal 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/"}
|
@ -1,29 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
var adapter = require('../adapter'),
|
||||
getArgs = require('getargs');
|
||||
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);
|
||||
|
||||
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 */
|
||||
var Dblite = function(instance) {
|
||||
module.exports = (function (_Adapter) {
|
||||
_inherits(dblite, _Adapter);
|
||||
|
||||
// That 'new' keyword is annoying
|
||||
if ( ! (this instanceof Dblite)) return new Dblite(instance);
|
||||
function dblite() {
|
||||
_classCallCheck(this, dblite);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
return _possibleConstructorReturn(this, Object.getPrototypeOf(dblite).apply(this, 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
|
||||
|
1
lib/adapters/dblite.js.map
Normal file
1
lib/adapters/dblite.js.map
Normal 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/"}
|
@ -1,27 +1,45 @@
|
||||
'use strict';
|
||||
|
||||
var adapter = require('../adapter.js');
|
||||
var conn;
|
||||
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/mysql */
|
||||
var MySQL = function(instance) {
|
||||
module.exports = (function (_Adapter) {
|
||||
_inherits(mysql, _Adapter);
|
||||
|
||||
// That 'new' keyword is annoying
|
||||
if ( ! (this instanceof MySQL)) return new MySQL(instance);
|
||||
function mysql() {
|
||||
_classCallCheck(this, 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
|
||||
*/
|
||||
adapter.execute = function(sql, params, callback) {
|
||||
instance.query.apply(instance, arguments);
|
||||
};
|
||||
return _possibleConstructorReturn(this, Object.getPrototypeOf(mysql).apply(this, 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
|
||||
|
1
lib/adapters/mysql.js.map
Normal file
1
lib/adapters/mysql.js.map
Normal 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/"}
|
@ -1,26 +1,45 @@
|
||||
'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 */
|
||||
var MySQL2 = function(instance) {
|
||||
module.exports = (function (_Adapter) {
|
||||
_inherits(mysql2, _Adapter);
|
||||
|
||||
// That 'new' keyword is annoying
|
||||
if ( ! (this instanceof MySQL2)) return new MySQL2(instance);
|
||||
function mysql2() {
|
||||
_classCallCheck(this, 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
|
||||
*/
|
||||
adapter.execute = function(sql, params, callback) {
|
||||
instance.execute.apply(instance, arguments);
|
||||
};
|
||||
return _possibleConstructorReturn(this, Object.getPrototypeOf(mysql2).apply(this, 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
|
||||
|
1
lib/adapters/mysql2.js.map
Normal file
1
lib/adapters/mysql2.js.map
Normal 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/"}
|
@ -1,29 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
var adapter = require('../adapter'),
|
||||
getArgs = require('getargs');
|
||||
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);
|
||||
|
||||
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 */
|
||||
var NodeFirebird = function(instance) {
|
||||
module.exports = (function (_Adapter) {
|
||||
_inherits(nodefirebird, _Adapter);
|
||||
|
||||
// That 'new' keyword is annoying
|
||||
if ( ! (this instanceof NodeFirebird)) return new NodeFirebird(instance);
|
||||
function nodefirebird() {
|
||||
_classCallCheck(this, nodefirebird);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
return _possibleConstructorReturn(this, Object.getPrototypeOf(nodefirebird).apply(this, 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
|
||||
|
1
lib/adapters/node-firebird.js.map
Normal file
1
lib/adapters/node-firebird.js.map
Normal 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/"}
|
@ -1,36 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
var adapter = require('../adapter'),
|
||||
getArgs = require('getargs');
|
||||
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);
|
||||
|
||||
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 */
|
||||
var Pg = function(instance) {
|
||||
module.exports = (function (_Adapter) {
|
||||
_inherits(pg, _Adapter);
|
||||
|
||||
// That 'new' keyword is annoying
|
||||
if ( ! (this instanceof Pg)) return new Pg(instance);
|
||||
function pg() {
|
||||
_classCallCheck(this, pg);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
return _possibleConstructorReturn(this, Object.getPrototypeOf(pg).apply(this, arguments));
|
||||
}
|
||||
|
||||
// Replace question marks with numbered placeholders, because this adapter is different...
|
||||
var count = 0;
|
||||
args.sql = args.sql.replace(/\?/g, function() {
|
||||
count++;
|
||||
return '$' + count;
|
||||
});
|
||||
_createClass(pg, [{
|
||||
key: 'execute',
|
||||
|
||||
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
1
lib/adapters/pg.js.map
Normal 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
78
lib/drivers/Firebird.js
Normal 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
|
1
lib/drivers/Firebird.js.map
Normal file
1
lib/drivers/Firebird.js.map
Normal 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
54
lib/drivers/Mysql.js
Executable 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
1
lib/drivers/Mysql.js.map
Normal 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
15
lib/drivers/Pg.js
Executable 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
1
lib/drivers/Pg.js.map
Normal 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
94
lib/drivers/Sqlite.js
Normal 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
|
1
lib/drivers/Sqlite.js.map
Normal file
1
lib/drivers/Sqlite.js.map
Normal 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/"}
|
@ -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;
|
||||
|
||||
}());
|
@ -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;
|
||||
}());
|
@ -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;
|
||||
}());
|
163
lib/helpers.js
163
lib/helpers.js
@ -1,68 +1,66 @@
|
||||
"use strict";
|
||||
"use strict"
|
||||
|
||||
require('es6-shim');
|
||||
/** @module helpers */
|
||||
//require('es6-shim');
|
||||
|
||||
/** @alias module:helpers */
|
||||
var h = {
|
||||
;
|
||||
var 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: function(str) {
|
||||
* Wrap String.prototype.trim in a way that is easily mappable
|
||||
*
|
||||
* @param {String} str - The string to trim
|
||||
* @return {String} - The trimmed string
|
||||
*/
|
||||
stringTrim: function stringTrim(str) {
|
||||
return 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: function (o) {
|
||||
var type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
|
||||
* 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: function type(o) {
|
||||
var 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';
|
||||
}
|
||||
}
|
||||
// handle NaN and Infinity
|
||||
if (type === 'number') {
|
||||
if (isNaN(o)) {
|
||||
return 'nan';
|
||||
}
|
||||
if (!isFinite(o)) {
|
||||
return 'infinity';
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
return type;
|
||||
},
|
||||
/**
|
||||
* Determine whether an object is scalar
|
||||
*
|
||||
* @param {mixed} obj
|
||||
* @return {bool}
|
||||
*/
|
||||
isScalar: function(obj) {
|
||||
* Determine whether an object is scalar
|
||||
*
|
||||
* @param {mixed} obj
|
||||
* @return {bool}
|
||||
*/
|
||||
isScalar: function isScalar(obj) {
|
||||
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
|
||||
*
|
||||
* @param {Array} arr - The array of objects to search
|
||||
* @param {String} key - The key of the object to get
|
||||
* @return {Array}
|
||||
*/
|
||||
arrayPluck: function(arr, key) {
|
||||
* 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: function arrayPluck(arr, key) {
|
||||
var output = [];
|
||||
|
||||
// Empty case
|
||||
if (arr.length === 0) return output;
|
||||
|
||||
arr.forEach(function(obj) {
|
||||
if ( ! h.isUndefined(obj[key]))
|
||||
{
|
||||
arr.forEach(function (obj) {
|
||||
if (!helpers.isUndefined(obj[key])) {
|
||||
output.push(obj[key]);
|
||||
}
|
||||
});
|
||||
@ -70,51 +68,62 @@ var h = {
|
||||
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: function(arr, pattern) {
|
||||
* 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: function regexInArray(arr, pattern) {
|
||||
// Empty case(s)
|
||||
if ( ! h.isArray(arr)) return false;
|
||||
if (!helpers.isArray(arr)) 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
|
||||
if (pattern.test(arr[i])) return true;
|
||||
}
|
||||
|
||||
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
|
||||
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) {
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
h['is' + t] = function (o) {
|
||||
if (t.toLowerCase() === 'infinite')
|
||||
{
|
||||
t = 'infinity';
|
||||
}
|
||||
* 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 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
1
lib/helpers.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -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();
|
@ -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;
|
29
lib/state.js
29
lib/state.js
@ -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
|
16
package.json
16
package.json
@ -38,7 +38,10 @@
|
||||
"mysql2": "^0.15.8",
|
||||
"node-firebird": "^0.7.0",
|
||||
"pg": "^4.4.3",
|
||||
"es6-shim": ""
|
||||
"es6-shim": "",
|
||||
"babel": "",
|
||||
"babel-preset-es2015": "",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": ""
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dblite": "*",
|
||||
@ -49,14 +52,19 @@
|
||||
"documentation": "",
|
||||
"nodeunit": "",
|
||||
"gulp": "",
|
||||
"gulp-babel": "",
|
||||
"gulp-babel-istanbul": "",
|
||||
"gulp-sourcemaps": "",
|
||||
"gulp-concat": "",
|
||||
"gulp-documentation": "",
|
||||
"gulp-istanbul": "",
|
||||
"gulp-nodeunit-runner": "",
|
||||
"jsdoc": "",
|
||||
"gulp-sloc": "",
|
||||
"gulp-eslint": "",
|
||||
"eslint": "",
|
||||
"istanbul": ""
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "grunt tests"
|
||||
"test": "gulp nodeunit"
|
||||
}
|
||||
}
|
||||
|
26
src/Adapter.js
Executable file
26
src/Adapter.js
Executable 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");
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var helpers = require('./helpers');
|
||||
import helpers from './helpers'
|
||||
|
||||
/**
|
||||
* Base Database Driver
|
13
src/DriverClass.js
Normal file
13
src/DriverClass.js
Normal 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
74
src/NodeQuery.js
Executable 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
924
src/QueryBuilder.js
Executable 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);
|
||||
}
|
||||
}
|
@ -1,48 +1,7 @@
|
||||
'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
|
||||
* @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
|
||||
if ( ! (this instanceof QueryParser)) return new QueryParser(driver);
|
||||
let 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}
|
||||
*/
|
||||
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).
|
||||
@ -63,8 +75,8 @@ var QueryParser = function(driver) {
|
||||
* @param {String} string - the string to check
|
||||
* @return {Array|null}
|
||||
*/
|
||||
this.hasOperator = function(string) {
|
||||
return filterMatches(string.match(matchPatterns.operator));
|
||||
hasOperator(string) {
|
||||
return this.filterMatches(string.match(this.matchPatterns.operator));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,26 +85,31 @@ var QueryParser = function(driver) {
|
||||
* @param {String} sql
|
||||
* @return {Object}
|
||||
*/
|
||||
this.parseJoin = function(sql) {
|
||||
var matches = {};
|
||||
var output = {};
|
||||
parseJoin(sql) {
|
||||
let matches = {};
|
||||
let output = {
|
||||
functions: [],
|
||||
identifiers: [],
|
||||
operators: [],
|
||||
literals: []
|
||||
};
|
||||
|
||||
// Get clause components
|
||||
matches.functions = sql.match(new RegExp(matchPatterns['function'].source, 'ig'));
|
||||
matches.identifiers = sql.match(matchPatterns.identifier);
|
||||
matches.operators = sql.match(matchPatterns.operator);
|
||||
matches.literals = sql.match(matchPatterns.literal);
|
||||
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(matchPatterns.joinCombined);
|
||||
matches.combined = sql.match(this.matchPatterns.joinCombined);
|
||||
|
||||
// Flatten the matches to increase relevance
|
||||
Object.keys(matches).forEach(function(key) {
|
||||
output[key] = filterMatches(matches[key]);
|
||||
Object.keys(matches).forEach((key) => {
|
||||
output[key] = this.filterMatches(matches[key]);
|
||||
});
|
||||
|
||||
return output;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return {String} - The parsed/escaped join condition
|
||||
*/
|
||||
this.compileJoin = function(condition) {
|
||||
var parts = this.parseJoin(condition);
|
||||
var count = parts.identifiers.length;
|
||||
var i;
|
||||
compileJoin(condition) {
|
||||
let parts = this.parseJoin(condition);
|
||||
let count = parts.identifiers.length;
|
||||
let i;
|
||||
|
||||
// Quote the identifiers
|
||||
parts.combined.forEach(function(part, i) {
|
||||
parts.combined.forEach((part, i) => {
|
||||
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(' ');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a where clause to separate functions from values
|
||||
*
|
||||
* @param {Object} driver
|
||||
* @param {Driver} driver
|
||||
* @param {State} state
|
||||
* @return {String} - The parsed/escaped where condition
|
||||
*/
|
||||
this.parseWhere = function(driver, state) {
|
||||
var whereMap = state.whereMap,
|
||||
whereValues = state.rawWhereValues;
|
||||
parseWhere(driver, state) {
|
||||
let whereMap = state.whereMap;
|
||||
let whereValues = state.rawWhereValues;
|
||||
|
||||
var outputMap = [];
|
||||
var outputValues = [];
|
||||
let outputMap = [];
|
||||
let outputValues = [];
|
||||
|
||||
Object.keys(whereMap).forEach(function(key) {
|
||||
Object.keys(whereMap).forEach((key) => {
|
||||
// Combine fields, operators, functions and values into a full clause
|
||||
// to have a common starting flow
|
||||
var fullClause = '';
|
||||
let fullClause = '';
|
||||
|
||||
// Add an explicit = sign where one is inferred
|
||||
if ( ! this.hasOperator(key))
|
||||
@ -150,17 +167,17 @@ var QueryParser = function(driver) {
|
||||
}
|
||||
|
||||
// Separate the clause into separate pieces
|
||||
var parts = this.parseJoin(fullClause);
|
||||
let parts = this.parseJoin(fullClause);
|
||||
|
||||
// Filter explicit literals from lists of matches
|
||||
if (whereValues.indexOf(whereMap[key]) !== -1)
|
||||
{
|
||||
var value = whereMap[key];
|
||||
var identIndex = (helpers.isArray(parts.identifiers)) ? parts.identifiers.indexOf(value) : -1;
|
||||
var litIndex = (helpers.isArray(parts.literals)) ? parts.literals.indexOf(value) : -1;
|
||||
var combIndex = (helpers.isArray(parts.combined)) ? parts.combined.indexOf(value) : -1;
|
||||
var funcIndex = (helpers.isArray(parts.functions)) ? parts.functions.indexOf(value) : -1;
|
||||
var inOutputArray = outputValues.indexOf(value) !== -1;
|
||||
let value = whereMap[key];
|
||||
let identIndex = (helpers.isArray(parts.identifiers)) ? parts.identifiers.indexOf(value) : -1;
|
||||
let litIndex = (helpers.isArray(parts.literals)) ? parts.literals.indexOf(value) : -1;
|
||||
let combIndex = (helpers.isArray(parts.combined)) ? parts.combined.indexOf(value) : -1;
|
||||
let funcIndex = (helpers.isArray(parts.functions)) ? parts.functions.indexOf(value) : -1;
|
||||
let inOutputArray = outputValues.indexOf(value) !== -1;
|
||||
|
||||
// Remove the identifier in question,
|
||||
// and add to the output values array
|
||||
@ -207,18 +224,19 @@ var QueryParser = function(driver) {
|
||||
}
|
||||
|
||||
// Filter false positive identifiers
|
||||
parts.identifiers = parts.identifiers.filter(function(item) {
|
||||
var isInCombinedMatches = parts.combined.indexOf(item) !== -1;
|
||||
var isNotInBlackList = identifierBlacklist.indexOf(item.toLowerCase()) === -1;
|
||||
parts.identifiers = parts.identifiers || [];
|
||||
parts.identifiers = parts.identifiers.filter((item) => {
|
||||
let isInCombinedMatches = parts.combined.indexOf(item) !== -1;
|
||||
let isNotInBlackList = this.identifierBlacklist.indexOf(item.toLowerCase()) === -1;
|
||||
|
||||
return isInCombinedMatches && isNotInBlackList;
|
||||
});
|
||||
}, this);
|
||||
|
||||
// Quote identifiers
|
||||
if (helpers.isArray(parts.identifiers))
|
||||
{
|
||||
parts.identifiers.forEach(function(ident) {
|
||||
var index = parts.combined.indexOf(ident);
|
||||
parts.identifiers.forEach((ident) => {
|
||||
let index = parts.combined.indexOf(ident);
|
||||
if (index !== -1)
|
||||
{
|
||||
parts.combined[index] = driver.quoteIdentifiers(ident);
|
||||
@ -233,8 +251,8 @@ var QueryParser = function(driver) {
|
||||
// a where condition,
|
||||
if (helpers.isArray(parts.literals))
|
||||
{
|
||||
parts.literals.forEach(function(lit) {
|
||||
var litIndex = parts.combined.indexOf(lit);
|
||||
parts.literals.forEach((lit) => {
|
||||
let litIndex = parts.combined.indexOf(lit);
|
||||
|
||||
if (litIndex !== -1)
|
||||
{
|
||||
@ -245,14 +263,12 @@ var QueryParser = function(driver) {
|
||||
}
|
||||
|
||||
outputMap.push(parts.combined.join(' '));
|
||||
}, this);
|
||||
});
|
||||
|
||||
state.rawWhereValues = [];
|
||||
state.whereValues = state.whereValues.concat(outputValues);
|
||||
state.whereMap = outputMap;
|
||||
|
||||
return state;
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = QueryParser;
|
||||
}
|
||||
}
|
29
src/State.js
Normal file
29
src/State.js
Normal 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
20
src/adapters/dblite.js
Normal 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
11
lib/adapter.js → src/adapters/mysql.js
Executable file → Normal file
@ -1,8 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
/** @module adapter */
|
||||
module.exports = {
|
||||
import Adapter from '../Adapter';
|
||||
|
||||
/** @module adapters/mysql */
|
||||
module.exports = class mysql extends Adapter {
|
||||
/**
|
||||
* 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
|
||||
* @return void
|
||||
*/
|
||||
execute: function(/*sql, params, callback*/) {
|
||||
throw new Error("Correct adapter not defined for query execution");
|
||||
execute(sql, params, callback) {
|
||||
this.instance.query.apply(instance, arguments);
|
||||
}
|
||||
};
|
||||
}
|
18
src/adapters/mysql2.js
Normal file
18
src/adapters/mysql2.js
Normal 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);
|
||||
};
|
||||
}
|
20
src/adapters/node-firebird.js
Normal file
20
src/adapters/node-firebird.js
Normal 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
28
src/adapters/pg.js
Normal 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);
|
||||
}
|
||||
}
|
@ -1,17 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
var helpers = require('../helpers');
|
||||
import helpers from '../helpers';
|
||||
import Driver from '../DriverClass';
|
||||
|
||||
/**
|
||||
* Driver for Firebird databases
|
||||
*
|
||||
* @module drivers/firebird
|
||||
*/
|
||||
module.exports = (function() {
|
||||
delete require.cache[require.resolve('../driver')];
|
||||
var driver = require('../driver');
|
||||
|
||||
driver.hasTruncate = false;
|
||||
class Firebird extends Driver {
|
||||
constructor() {
|
||||
super({
|
||||
hasTruncate: false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return {String}
|
||||
*/
|
||||
driver.limit = function(origSql, limit, offset) {
|
||||
var sql = 'FIRST ' + limit;
|
||||
limit(origSql, limit, offset) {
|
||||
let sql = `FIRST ${limit}`;
|
||||
|
||||
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
|
||||
@ -39,9 +41,9 @@ module.exports = (function() {
|
||||
* @param {Array} [data] - The array of object containing data to insert
|
||||
* @return {String}
|
||||
*/
|
||||
driver.insertBatch = function(table, data) {
|
||||
insertBatch() {
|
||||
throw new Error("Not Implemented");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return driver;
|
||||
}());
|
||||
module.exports = new Firebird();
|
29
src/drivers/Mysql.js
Executable file
29
src/drivers/Mysql.js
Executable 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
10
src/drivers/Pg.js
Executable 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
64
src/drivers/Sqlite.js
Normal 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
127
src/helpers.js
Executable 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;
|
@ -18,13 +18,13 @@ try {
|
||||
// Export an empty testsuite if module not loaded
|
||||
console.log(e);
|
||||
console.log("Database adapter dblite not found");
|
||||
return {};
|
||||
//return {};
|
||||
}
|
||||
|
||||
if (connection)
|
||||
{
|
||||
// Set up the query builder object
|
||||
var nodeQuery = require('../../lib/node-query');
|
||||
var nodeQuery = require('../../lib/NodeQuery');
|
||||
var qb = nodeQuery.init('sqlite', connection, adapterName);
|
||||
|
||||
// Set up the sqlite database
|
||||
|
@ -16,7 +16,7 @@ var mysql2 = require(adapterName);
|
||||
var connection = mysql2.createConnection(config.conn);
|
||||
|
||||
// Set up the query builder object
|
||||
var nodeQuery = require('../../lib/node-query');
|
||||
var nodeQuery = require('../../lib/NodeQuery');
|
||||
var qb = nodeQuery.init('mysql', connection, adapterName);
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@ var mysql = require(adapterName);
|
||||
var connection = mysql.createConnection(config.conn);
|
||||
|
||||
// Set up the query builder object
|
||||
var nodeQuery = require('../../lib/node-query');
|
||||
var nodeQuery = require('../../lib/NodeQuery');
|
||||
var qb = nodeQuery.init('mysql', connection);
|
||||
|
||||
// Set up the test base
|
||||
|
@ -7,7 +7,7 @@ var testBase = require('../query-builder-base');
|
||||
var adapterName = 'node-firebird';
|
||||
var config = require('../config.json')[adapterName];
|
||||
config.conn.database = __dirname + config.conn.database;
|
||||
var nodeQuery = require('../../lib/node-query');
|
||||
var nodeQuery = require('../../lib/NodeQuery');
|
||||
|
||||
// Skip on TravisCi
|
||||
if (process.env.CI || process.env.JENKINS_HOME)
|
||||
|
@ -21,7 +21,7 @@ connection.connect(function(err) {
|
||||
});
|
||||
|
||||
// Set up the query builder object
|
||||
var nodeQuery = require('../../lib/node-query');
|
||||
var nodeQuery = require('../../lib/NodeQuery');
|
||||
var qb = nodeQuery.init('pg', connection);
|
||||
|
||||
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
var modules = {
|
||||
helpers: require('../lib/helpers'),
|
||||
driver: require('../lib/driver'),
|
||||
qb: require('../lib/query-builder'),
|
||||
'node-query': require('../lib/node-query'),
|
||||
'state': require('../lib/state'),
|
||||
'drivers/pg': require('../lib/drivers/pg'),
|
||||
'drivers/mysql': require('../lib/drivers/mysql'),
|
||||
'drivers/sqlite': require('../lib/drivers/sqlite'),
|
||||
driver: require('../lib/DriverBase'),
|
||||
qb: require('../lib/QueryBuilder'),
|
||||
'node-query': require('../lib/NodeQuery'),
|
||||
'state': require('../lib/State'),
|
||||
'drivers/pg': require('../lib/drivers/Pg'),
|
||||
'drivers/mysql': require('../lib/drivers/Mysql'),
|
||||
'drivers/sqlite': require('../lib/drivers/Sqlite'),
|
||||
'adapters/mysql': require('../lib/adapters/mysql'),
|
||||
'adapters/mysql2': require('../lib/adapters/mysql2'),
|
||||
'adapters/pg': require('../lib/adapters/pg'),
|
||||
|
@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var helpers = require('../lib/helpers');
|
||||
var State = require('../lib/state');
|
||||
var State = require('../lib/State');
|
||||
|
||||
module.exports = (function QueryBuilderTestBase() {
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
// Use the base driver as a mock for testing
|
||||
delete require.cache[require.resolve('../lib/driver')];
|
||||
var getArgs = require('getargs');
|
||||
var helpers = require('../lib/helpers');
|
||||
var driver = require('../lib/driver');
|
||||
var parser = require('../lib/query-parser')(driver);
|
||||
var State = require('../lib/state');
|
||||
var driver = require('../lib/DriverBase');
|
||||
|
||||
var p = require('../lib/QueryParser');
|
||||
var parser = new p(driver);
|
||||
|
||||
var State = require('../lib/State');
|
||||
|
||||
// Simulate query builder state
|
||||
var state = new State();
|
||||
@ -63,7 +65,7 @@ var whereMock = function() {
|
||||
// ! Start Tests
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
var tests = {
|
||||
'Has operator tests': {
|
||||
'Has operator': function(test) {
|
||||
var matches = parser.hasOperator('foo <> 2');
|
||||
@ -171,4 +173,6 @@ module.exports = {
|
||||
test.done();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = tests;
|
Loading…
Reference in New Issue
Block a user