Add promise interface to database execution methods

This commit is contained in:
Timothy Warren 2016-01-26 19:29:12 -05:00
parent 4b24771716
commit da8b473bc7
33 changed files with 3096 additions and 2639 deletions

View File

@ -18,6 +18,7 @@ A node query builder for various SQL databases, based on CodeIgniter's query bui
### Installation
npm install ci-node-query
[![NPM](https://nodei.co/npm/ci-node-query.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/ci-node-query/)
### Basic use

View File

@ -6,7 +6,7 @@
margin:0;
}
.force-inline p {
.force-inline, .force-inline p {
display: inline;
color: #222;
}

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,13 @@ const ESLINT_SETTINGS = {
}
};
const MOCHA_OPTIONS = {
ui: 'tdd',
bail: true,
reporter: 'list',
timeout: 10000,
};
gulp.task('lint', () => {
pipe(gulp.src(SRC_FILES), [
eslint(ESLINT_SETTINGS),
@ -82,22 +89,14 @@ gulp.task('sloc', () => gulp.src(SRC_FILES).pipe(sloc()));
gulp.task('test-sloc', () => gulp.src(TEST_FILES).pipe(sloc()));
gulp.task('docs', () => {
gulp.src('./lib/QueryBuilder.js')
gulp.src(['lib/*.js'])
.pipe(documentation({format: 'html'}))
.pipe(gulp.dest('docs'));
/*gulp.src('./lib/QueryBuilder.js')
.pipe(documentation({format: 'md'}))
.pipe(gulp.dest('api-docs'));*/
});
gulp.task('mocha', ['lint-tests', 'sloc'], () => {
return gulp.src(TEST_FILES)
.pipe(mocha({
ui: 'tdd',
bail: true,
reporter: 'list',
timeout: 5000
}))
.pipe(mocha(MOCHA_OPTIONS))
.once('error', () => {
process.exit(1);
})
@ -112,10 +111,7 @@ gulp.task('test', ['test-sloc', 'lint-tests'], function(cb) {
istanbul.hookRequire()
]).on('finish', () => {
pipe(gulp.src(TEST_FILES), [
mocha({
ui: 'tdd',
bail: true
}),
mocha(MOCHA_OPTIONS),
istanbul.writeReports({
dir: './coverage',
reporters: ['lcov', 'lcovonly', 'html', 'text']

View File

@ -1,12 +1,18 @@
'use strict';
/** @module Adapter */
module.exports = class Adapter {
/**
* Class that wraps database connection libraries
*
* @private
* @param {Object} instance - The connection object
*/
class Adapter {
/**
* Invoke an adapter
*
* @param {Object} instance - The connection objec
* @return {void}
* @constructor
* @param {Object} instance - The connection object
*/
constructor(instance) {
this.instance = instance;
@ -17,8 +23,8 @@ module.exports = class Adapter {
*
* @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}
* @param {Function} [callback] - Callback to run when a response is recieved
* @return {void|Promise} - returns a promise if no callback is passed
*/
execute(/*sql, params, callback*/) {
throw new Error('Correct adapter not defined for query execution');
@ -31,4 +37,6 @@ module.exports = class Adapter {
close() {
this.instance.end();
}
};
}
module.exports = Adapter;

View File

@ -1,13 +1,13 @@
'use strict';
let helpers = require('./helpers');
const helpers = require('./helpers');
/**
* Base Database Driver
*
* @module driver
* @private
*/
let d = {
let Driver = {
identifierStartChar: '"',
identifierEndChar: '"',
tablePrefix: null,
@ -15,14 +15,14 @@ let d = {
/**
* Low level function for naive quoting of strings
*
* @param {String} str - The sql fragment to quote
* @return {String} - The quoted sql fragment
* @private
*/
_quote(str) {
return (helpers.isString(str) && ! (str.startsWith(d.identifierStartChar) || str.endsWith(d.identifierEndChar)))
? `${d.identifierStartChar}${str}${d.identifierEndChar}`
return (helpers.isString(str) && ! (str.startsWith(Driver.identifierStartChar) || str.endsWith(Driver.identifierEndChar)))
? `${Driver.identifierStartChar}${str}${Driver.identifierEndChar}`
: str;
},
@ -31,7 +31,7 @@ let d = {
* @param {String} sql - SQL statement to modify
* @param {Number} limit - Maximum number of rows to fetch
* @param {Number|null} offset - Number of rows to skip
* @param {Number} [offset] - Number of rows to skip
* @return {String} - Modified SQL statement
*/
limit(sql, limit, offset) {
@ -53,37 +53,37 @@ let d = {
*/
quoteTable(table) {
// Quote after prefix
return d.quoteIdentifiers(table);
return Driver.quoteIdentifiers(table);
},
/**
* Use the driver's escape character to quote identifiers
*
* @param {String|String[]} - String or array of strings to quote identifiers
* @return {String|String[]} - Quoted identifier(s)
* @param {String|Array} str - String or array of strings to quote identifiers
* @return {String|Array} - Quoted identifier(s)
*/
quoteIdentifiers(str) {
let hiers, raw;
let pattern = new RegExp(
`${d.identifierStartChar}(`
`${Driver.identifierStartChar}(`
+ '([a-zA-Z0-9_]+)' + '(\((.*?)\))'
+ `)${d.identifierEndChar}`, 'ig');
+ `)${Driver.identifierEndChar}`, 'ig');
// Recurse for arrays of identifiiers
if (Array.isArray(str))
{
return str.map(d.quoteIdentifiers);
return str.map(Driver.quoteIdentifiers);
}
// Handle commas
if (str.includes(','))
{
let parts = str.split(',').map(helpers.stringTrim);
str = parts.map(d.quoteIdentifiers).join(',');
str = parts.map(Driver.quoteIdentifiers).join(',');
}
// Split identifiers by period
hiers = str.split('.').map(d._quote);
hiers = str.split('.').map(Driver._quote);
raw = hiers.join('.');
// Fix functions
@ -96,30 +96,30 @@ let d = {
// Quote the identifiers inside of the parens
let inParens = funcs[3].substring(1, funcs[3].length - 1);
raw = raw.replace(inParens, d.quoteIdentifiers(inParens));
raw = raw.replace(inParens, Driver.quoteIdentifiers(inParens));
}
return raw;
},
/**
* SQL to truncate the passed table
* Generate SQL to truncate the passed table
*
* @param {String} table - Table to truncate
* @return {String} - Truncation SQL
*/
truncate(table) {
let sql = (d.hasTruncate)
let sql = (Driver.hasTruncate)
? 'TRUNCATE '
: 'DELETE FROM ';
sql += d.quoteTable(table);
sql += Driver.quoteTable(table);
return sql;
},
/**
* SQL to insert a group of rows
* Generate 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
@ -143,9 +143,9 @@ let d = {
// Get the field names from the keys of the first
// object inserted
table = d.quoteTable(table);
table = Driver.quoteTable(table);
sql += `INSERT INTO ${table} (${d.quoteIdentifiers(fields).join(',')}) VALUES `;
sql += `INSERT INTO ${table} (${Driver.quoteIdentifiers(fields).join(',')}) VALUES `;
// Create placeholder groups
params = Array(fields.length).fill('?');
@ -161,4 +161,4 @@ let d = {
},
};
module.exports = d;
module.exports = Driver;

View File

@ -5,14 +5,15 @@ let fs = require('fs'),
QueryBuilder = require('./QueryBuilder');
/**
* @module NodeQuery
* Class for connection management
*/
class NodeQuery {
/**
* Constructor
*
* @return {void}
* @private
* @constructor
*/
constructor() {
this.instance = null;
@ -23,7 +24,7 @@ class NodeQuery {
*
* @param {String} driverType - 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
* @param {String} [connLib] - The name of the db connection library you are using, eg. mysql or mysql2. Optional if the same as driverType
* @return {QueryBuilder} - The Query Builder object
*/
init(driverType, connObject, connLib) {

View File

@ -1,23 +1,26 @@
'use strict';
/** @module QueryBuilder */
let getArgs = require('getargs'),
helpers = require('./helpers'),
State = require('./State'),
QueryParser = require('./QueryParser');
module.exports = class QueryBuilder {
/*
* SQL generation object
/**
* Main object that builds SQL queries.
*
* @param {driver} - The syntax driver for the database
* @param {adapter} - The database module adapter for running queries
* @return {QueryBuilder} - The Query Builder object, for chaining
* @constructor
* @param {Driver} Driver - The syntax driver for the database
* @param {Adapter} Adapter - The database module adapter for running queries
*/
constructor(driver, adapter) {
this.driver = driver;
this.adapter = adapter;
class QueryBuilder {
/**
* @private
* @constructor
* @param {Driver} Driver - The syntax driver for the database
* @param {Adapter} Adapter - The database module adapter for running queries
*/
constructor(Driver, Adapter) {
this.driver = Driver;
this.adapter = Adapter;
this.parser = new QueryParser(this.driver);
this.state = new State();
}
@ -265,8 +268,11 @@ module.exports = class QueryBuilder {
this._resetState();
// Pass the sql and values to the adapter to run on the database
this.adapter.execute(sql, vals, callback);
if (callback) {
return this.adapter.execute(sql, vals, callback);
} else {
return this.adapter.execute(sql, vals);
}
}
_getCompile(type, table, reset) {
@ -743,11 +749,11 @@ module.exports = class QueryBuilder {
* @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}
* @param {Function} [callback] - A callback for receiving the result
* @return {void|Promise} - If no callback is passed, a promise is returned
*/
get(/* [table], [limit], [offset], callback */) {
let args = getArgs('[table]:string, [limit]:number, [offset]:number, callback:function', arguments);
get(/* [table], [limit], [offset], [callback] */) {
let args = getArgs('[table]:string, [limit]:number, [offset]:number, [callback]:function', arguments);
if (args.table) {
this.from(args.table);
@ -758,7 +764,7 @@ module.exports = class QueryBuilder {
}
// Run the query
this._run('get', args.table, args.callback);
return this._run('get', args.table, args.callback);
}
/**
@ -766,18 +772,18 @@ module.exports = class QueryBuilder {
*
* @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}
* @param {Function} [callback] - Callback for handling response from the database
* @return {void|Promise} - If no callback is passed, a promise is returned
*/
insert(/* table, data, callback */) {
let args = getArgs('table:string, [data]:object, callback:function', arguments);
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);
return this._run('insert', this.driver.quoteTable(args.table), args.callback);
}
/**
@ -785,16 +791,16 @@ module.exports = class QueryBuilder {
*
* @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
* @param {Function} [callback] - Callback for handling database response
* @example query.insertBatch('foo',[{id:1,val:'bar'},{id:2,val:'baz'}], callbackFunction);
* @return {void}
* @return {void|Promise} - If no callback is passed, a promise is returned
*/
insertBatch(/* table, data, callback */) {
let args = getArgs('table:string, data:array, callback:function', arguments);
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);
return this._run('', '', args.callback, batch.sql, batch.values);
}
/**
@ -802,18 +808,18 @@ module.exports = class QueryBuilder {
*
* @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}
* @param {Function} [callback] - Callback for handling response from the database
* @return {void|Promise} - If no callback is passed, a promise is returned
*/
update(/*table, data, callback*/) {
let args = getArgs('table:string, [data]:object, callback:function', arguments);
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);
return this._run('update', this.driver.quoteTable(args.table), args.callback);
}
/**
@ -821,18 +827,18 @@ module.exports = class QueryBuilder {
*
* @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}
* @param {Function} [callback] - Callback for handling response from the database
* @return {void|Promise} - If no callback is passed, a promise is returned
*/
delete(/*table, [where], callback*/) {
let args = getArgs('table:string, [where]:object, callback:function', arguments);
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);
return this._run('delete', this.driver.quoteTable(args.table), args.callback);
}
// ------------------------------------------------------------------------
@ -887,4 +893,6 @@ module.exports = class QueryBuilder {
getCompiledDelete(table, reset) {
return this._getCompile('delete', this.driver.quoteTable(table), reset);
}
};
}
module.exports = QueryBuilder;

View File

@ -4,7 +4,13 @@ let helpers = require('./helpers');
// --------------------------------------------------------------------------
module.exports = class QueryParser {
/**
* Internal object for parsing query fragments
*
* @private
* @param {Driver} driver - The driver object for the database in use
*/
class QueryParser {
/**
* @constructor
*
@ -237,4 +243,6 @@ module.exports = class QueryParser {
return state;
}
};
}
module.exports = QueryParser;

View File

@ -1,7 +1,10 @@
'use strict';
/** @module State */
module.exports = class State {
/**
* Class for objects containing the query builder state
* @private
*/
class State {
constructor() {
// Arrays/maps
this.queryMap = [];
@ -25,6 +28,8 @@ module.exports = class State {
this.limit = null;
this.offset = null;
}
};
}
module.exports = State;
// End of module State

View File

@ -1,7 +1,8 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs');
getArgs = require('getargs'),
Promise = require('bluebird');
module.exports = class dblite extends Adapter {
/**
@ -9,16 +10,23 @@ module.exports = class dblite extends Adapter {
*
* @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}
* @param {Function} [callback] - Callback to run when a response is recieved
* @return {void|Promise} - Returns a promise if no callback is provided
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params]:array, callback:function', arguments);
this.instance.query(args.sql, args.params, args.callback);
let args = getArgs('sql:string, [params]:array, [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
if (! args.callback) {
return instance.queryAsync(args.sql, args.params);
}
return this.instance.query(args.sql, args.params, args.callback);
}
/**
* Close the current database connection
* @return {void}
*/
close() {

View File

@ -1,7 +1,8 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs');
getArgs = require('getargs'),
Promise = require('bluebird');
module.exports = class mysql extends Adapter {
/**
@ -9,11 +10,17 @@ module.exports = class mysql extends Adapter {
*
* @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}
* @param {Function} [callback] - Callback to run when a response is recieved
* @return {void|Promise} - Returns a promise if no callback is provided
*/
execute(sql, params, callback) {
let args = getArgs('sql:string, [params], callback:function', arguments);
let args = getArgs('sql:string, [params], [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
if (! args.callback) {
return instance.queryAsync(args.sql, args.params);
}
return this.instance.query(args.sql, args.params, args.callback);
}
};

View File

@ -1,7 +1,8 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs');
getArgs = require('getargs'),
Promise = require('bluebird');
module.exports = class mysql2 extends Adapter {
/**
@ -9,11 +10,17 @@ module.exports = class mysql2 extends Adapter {
*
* @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}
* @param {Function} [callback] - Callback to run when a response is recieved
* @return {void|Promise} - Returns a promise if no callback is provided
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params], callback:function', arguments);
let args = getArgs('sql:string, [params], [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
if (! args.callback) {
return instance.executeAsync(args.sql, args.params);
}
return this.instance.execute(args.sql, args.params, args.callback);
}
};

View File

@ -1,7 +1,8 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs');
getArgs = require('getargs'),
Promise = require('bluebird');
module.exports = class nodefirebird extends Adapter {
/**
@ -9,11 +10,25 @@ module.exports = class nodefirebird extends Adapter {
*
* @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}
* @param {Function} [callback] - Callback to run when a response is recieved
* @return {void|Promise} - Returns a promise if no callback is provided
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params], callback:function', arguments);
return this.instance.execute(args.sql, args.params, args.callback);
let args = getArgs('sql:string, [params], [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
if (! args.callback) {
return instance.queryAsync(args.sql, args.params);
}
return this.instance.query(args.sql, args.params, args.callback);
}
/**
* Close the current database connection
* @return {void}
*/
close() {
this.instance.detach();
}
};

View File

@ -1,7 +1,8 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs');
getArgs = require('getargs'),
Promise = require('bluebird');
module.exports = class pg extends Adapter {
/**
@ -9,11 +10,12 @@ module.exports = class pg extends Adapter {
*
* @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}
* @param {Function} [callback] - Callback to run when a response is recieved
* @return {void|Promise} - Returns a promise if no callback is provided
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params]:array, callback:function', arguments);
let args = getArgs('sql:string, [params]:array, [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
// Replace question marks with numbered placeholders, because this adapter is different...
let count = 0;
@ -22,6 +24,10 @@ module.exports = class pg extends Adapter {
return `$${count}`;
});
this.instance.query(args.sql, args.params, args.callback);
if (! args.callback) {
return instance.queryAsync(args.sql, args.params);
}
return this.instance.query(args.sql, args.params, args.callback);
}
};

View File

@ -1,5 +1,10 @@
'use strict';
/**
* Various internal helper functions
*
* @private
*/
let helpers = {
/**
* Wrap String.prototype.trim in a way that is easily mappable
@ -124,9 +129,9 @@ types.forEach(t => {
*
* Types available are Null, Undefined, Object, Array, String, Number, Boolean, Function, RegExp, NaN and Infinite
*
* @name is[type]
* @param {mixed} o
* @return {Boolean}
* @private
* @param {mixed} o - The object to check its type
* @return {Boolean} - If the type matches
*/
helpers[`is${t}`] = function(o) {
if (t.toLowerCase() === 'infinite') {

View File

@ -1,11 +1,14 @@
{
"name": "ci-node-query",
"version": "3.0.1",
"version": "3.1.0",
"description": "A query builder for node based on the one in CodeIgniter",
"author": "Timothy J Warren <tim@timshomepage.net>",
"engines": {
"node": ">=4.0.0"
},
"files": [
"lib/"
],
"contributors": [
{
"name": "Timothy J Warren",
@ -33,32 +36,30 @@
},
"main": "lib/NodeQuery.js",
"dependencies": {
"getargs": "",
"mysql": "^2.9.0",
"mysql2": "^0.15.8",
"node-firebird": "^0.7.0",
"pg": "^4.4.3",
"require-reload": "*"
},
"optionalDependencies": {
"dblite": "*",
"node-firebird": "*",
"pg": "*"
"bluebird": "^3.1.4",
"dblite": "~0.7.6",
"getargs": "~0.0.8",
"mysql": "~2.10.2",
"mysql2": "~0.15.8",
"node-firebird": "~0.7.2",
"pg": "~4.4.3",
"require-reload": "~0.2.2"
},
"devDependencies": {
"chai": "",
"chai": "~3.4.1",
"chai-as-promised": "^5.2.0",
"documentation": "",
"eslint": "",
"glob": "^6.0.1",
"gulp": "",
"gulp-documentation": "^2.1.0",
"gulp-eslint": "",
"eslint": "~1.10.3",
"glob": "~6.0.4",
"gulp": "~3.9.0",
"gulp-documentation": "~2.1.0",
"gulp-eslint": "~1.1.1",
"gulp-istanbul": "^0.10.3",
"gulp-jscs": "^3.0.2",
"gulp-mocha": "^2.2.0",
"gulp-pipe": "^1.0.4",
"gulp-sloc": "",
"istanbul": "",
"gulp-sloc": "~1.0.4",
"istanbul": "~0.4.2",
"mocha": ""
},
"license": "MIT",

View File

@ -1,479 +0,0 @@
'use strict';
module.exports.tests = {
'Get tests': {
'Get with function': {
select: ['id, COUNT(id) as count'],
from: ['create_test'],
groupBy: ['id'],
get: [],
},
'Basic select all get': {
get: ['create_test'],
},
'Basic select all with from': {
from: ['create_test'],
get: [],
},
'Get with limit': {
get: ['create_test', 2],
},
'Get with limit and offset': {
get: ['create_test', 2, 1],
},
'Get with having': {
select: ['id'],
from: ['create_test'],
groupBy: ['id'],
having: [
'multiple',
[{'id >': 1}],
['id !=', 3],
['id', 900],
],
get: [],
},
'Get with orHaving': {
select: ['id'],
from: ['create_test'],
groupBy: ['id'],
having: [{'id >': 1}],
orHaving: ['id !=', 3],
get: [],
},
},
'Select tests': {
'Select where get': {
select: [['id', 'key as k', 'val']],
where: [
'multiple',
['id >', 1],
['id <', 900],
],
get: ['create_test', 2, 1],
},
'Select where get 2': {
select: ['id, key as k, val'],
where: ['id !=', 1],
get: ['create_test', 2, 1],
},
'Multi Order By': {
from: ['create_test'],
orderBy: ['id, key'],
get: [],
},
'Select get': {
select: ['id, key as k, val'],
get: ['create_test', 2, 1],
},
'Select from get': {
select: ['id, key as k, val'],
from: ['create_test ct'],
where: ['id >', 1],
get: [],
},
'Select from limit get': {
select: ['id, key as k, val'],
from: ['create_test ct'],
where: ['id >', 1],
limit: [3],
get: [],
},
'Select where IS NOT NULL': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
whereIsNotNull: ['id'],
get: [],
},
'Select where IS NULL': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
whereIsNull: ['id'],
get: [],
},
'Select where OR IS NOT NULL': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
whereIsNull: ['id'],
orWhereIsNotNull: ['id'],
get: [],
},
'Select where OR IS NULL': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
where: ['id', 3],
orWhereIsNull: ['id'],
get: [],
},
'Select with string where value': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
where: ['id > 3'],
get: [],
},
'Select with function and argument in WHERE clause': {
select: ['id'],
from: ['create_test ct'],
where: ['id', 'CEILING(SQRT(88))'],
get: [],
},
},
'Where in tests': {
'Where in': {
from: ['create_test'],
whereIn: ['id', [0, 6, 56, 563, 341]],
get: [],
},
'Or Where in': {
from: ['create_test'],
where: ['key', 'false'],
orWhereIn: ['id', [0, 6, 56, 563, 341]],
get: [],
},
'Where Not in': {
from: ['create_test'],
where: ['key', 'false'],
whereNotIn: ['id', [0, 6, 56, 563, 341]],
get: [],
},
'Or Where Not in': {
from: ['create_test'],
where: ['key', 'false'],
orWhereNotIn: ['id', [0, 6, 56, 563, 341]],
get: [],
},
},
'Query modifier tests': {
'Order By': {
select: ['id, key as k, val'],
from: ['create_test'],
where: [
'multiple',
['id >', 0],
['id <', 9000],
],
orderBy: [
'multiple',
['id', 'DESC'],
['k', 'ASC'],
],
limit: [5, 2],
get: [],
},
'Group By': {
select: ['id, key as k, val'],
from: ['create_test'],
where: [
'multiple',
['id >', 0],
['id <', 9000],
],
groupBy: [
'multiple',
['k'],
[['id', 'val']],
],
orderBy: [
'multiple',
['id', 'DESC'],
['k', 'ASC'],
],
limit: [5, 2],
get: [],
},
'Or Where': {
select: ['id, key as k, val'],
from: ['create_test'],
where: [' id ', 1],
orWhere: ['key > ', 0],
limit: [2, 1],
get: [],
},
Like: {
from: ['create_test'],
like: ['key', 'og'],
get: [],
},
'Or Like': {
from: ['create_test'],
like: ['key', 'og'],
orLike: ['key', 'val'],
get: [],
},
'Not Like': {
from: ['create_test'],
like: ['key', 'og', 'before'],
notLike: ['key', 'val'],
get: [],
},
'Or Not Like': {
from: ['create_test'],
like: ['key', 'og', 'before'],
orNotLike: ['key', 'val'],
get: [],
},
'Like Before': {
from: ['create_test'],
like: ['key', 'og', 'before'],
get: [],
},
'Like After': {
from: ['create_test'],
like: ['key', 'og', 'after'],
get: [],
},
'Basic Join': {
from: ['create_test ct'],
join: ['create_join cj', 'cj.id=ct.id'],
get: [],
},
'Left Join': {
from: ['create_test ct'],
join: ['create_join cj', 'cj.id=ct.id', 'left'],
get: [],
},
'Inner Join': {
from: ['create_test ct'],
join: ['create_join cj', 'cj.id=ct.id', 'inner'],
get: [],
},
'Join with multiple where values': {
from: ['create_test ct'],
join: ['create_join cj', 'cj.id=ct.id', 'inner'],
where: [
{
'ct.id < ': 3,
'ct.key ': 'foo',
},
],
get: [],
},
},
};
let expect = require('chai').expect,
helpers = require('../../lib/helpers'),
State = require('../../lib/State');
module.exports.runner = (tests, qb, callback) => {
Object.keys(tests).forEach(suiteName => {
suite(suiteName, () => {
let currentSuite = tests[suiteName];
Object.keys(currentSuite).forEach(testDesc => {
test(testDesc, done => {
let methodObj = currentSuite[testDesc];
let methodNames = Object.keys(methodObj);
let lastMethodIndex = methodNames[methodNames.length - 1];
methodObj[lastMethodIndex].push((err, rows) => {
callback(err, done);
});
methodNames.forEach(name => {
let args = methodObj[name],
method = qb[name];
if (args[0] === 'multiple') {
args.shift();
args.forEach(argSet => {
method.apply(qb, argSet);
});
} else {
method.apply(qb, args);
}
});
});
});
});
});
suite('DB update tests', () => {
setup(done => {
let sql = qb.driver.truncate('create_test');
qb.adapter.execute(sql, (err, res) => {
done();
});
});
test('Test Insert', done => {
qb.set('id', 98)
.set('key', '84')
.set('val', new Buffer('120'))
.insert('create_test', (err, rows) => {
return callback(err, done);
});
});
test('Test Insert Object', done => {
qb.insert('create_test', {
id: 587,
key: 1,
val: new Buffer('2'),
}, (err, rows) => {
return callback(err, done);
});
});
test('Test Update', done => {
qb.where('id', 7)
.update('create_test', {
id: 7,
key: 'gogle',
val: new Buffer('non-word'),
}, (err, rows) => {
return callback(err, done);
});
});
test('Test set Array Update', done => {
let object = {
id: 22,
key: 'gogle',
val: new Buffer('non-word'),
};
qb.set(object)
.where('id', 22)
.update('create_test', (err, rows) => {
return callback(err, done);
});
});
test('Test where set update', done => {
qb.where('id', 36)
.set('id', 36)
.set('key', 'gogle')
.set('val', new Buffer('non-word'))
.update('create_test', (err, rows) => {
return callback(err, done);
});
});
test('Test delete', done => {
qb.delete('create_test', {id: 5}, (err, rows) => {
return callback(err, done);
});
});
test('Delete with where', done => {
qb.where('id', 5)
.delete('create_test', (err, rows) => {
return callback(err, done);
});
});
test('Delete multiple where values', done => {
qb.delete('create_test', {
id: 5,
key: 'gogle',
}, (err, rows) => {
return callback(err, done);
});
});
});
suite('Grouping tests', () => {
test('Using grouping method', done => {
qb.select('id, key as k, val')
.from('create_test')
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.limit(2, 1)
.get((err, rows) => {
return callback(err, done);
});
});
test('Using where first grouping', done => {
qb.select('id, key as k, val')
.from('create_test')
.where('id !=', 5)
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.limit(2, 1)
.get((err, rows) => {
return callback(err, done);
});
});
test('Using or grouping method', done => {
qb.select('id, key as k, val')
.from('create_test')
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.orGroupStart()
.where('id', 0)
.groupEnd()
.limit(2, 1)
.get((err, rows) => {
return callback(err, done);
});
});
test('Using or not grouping method', done => {
qb.select('id, key as k, val')
.from('create_test')
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.orNotGroupStart()
.where('id', 0)
.groupEnd()
.limit(2, 1)
.get((err, rows) => {
return callback(err, done);
});
});
});
suite('Get compiled tests', () => {
test('select', () => {
let sql = qb.select('id')
.from('create_test')
.getCompiledSelect(true);
expect(helpers.isString(sql)).to.be.true;
});
test('select from', () => {
let sql = qb.select('id')
.getCompiledSelect('create_test', true);
expect(helpers.isString(sql)).to.be.true;
});
test('insert', () => {
let sql = qb.set('id', 3)
.getCompiledInsert('create_test');
expect(helpers.isString(sql)).to.be.true;
});
test('update', () => {
let sql = qb.set('id', 3)
.where('id', 5)
.getCompiledUpdate('create_test');
expect(helpers.isString(sql)).to.be.true;
});
test('delete', () => {
let sql = qb.where('id', 5)
.getCompiledDelete('create_test');
expect(helpers.isString(sql)).to.be.true;
});
});
suite('Misc tests', () => {
test('Get State', () => {
qb.select('foo')
.from('bar')
.where('baz', 'foobar');
let state = new State();
expect(JSON.stringify(state)).to.not.be.deep.equal(qb.getState());
});
test('Reset State', () => {
qb.select('foo')
.from('bar')
.where('baz', 'foobar');
qb.resetQuery();
let state = new State();
expect(qb.getState()).to.be.deep.equal(state);
});
});
};

View File

@ -1,11 +1,14 @@
'use strict';
// Load the test base
let reload = require('require-reload')(require);
let getArgs = require('getargs');
let expect = require('chai').expect;
let tests = reload('./adapterTestBase').tests;
let testRunner = reload('./adapterTestBase').runner;
const reload = require('require-reload')(require);
reload.emptyCache();
const testBase = reload('../base');
const expect = testBase.expect,
promiseTestRunner = testBase.promiseTestRunner,
testRunner = testBase.testRunner;
let tests = reload('../base/tests');
// Load the test config file
let adapterName = 'dblite';
@ -25,31 +28,38 @@ if (connection) {
let nodeQuery = require('../../lib/NodeQuery');
let qb = nodeQuery.init('sqlite', connection, adapterName);
// Add a test for this adapter
tests['Select tests']['Select with function and argument in WHERE clause'] = {
select: ['id'],
from: ['create_test'],
where: ['id', 'ABS(-88)'],
get: [],
};
suite('Dblite adapter tests', () => {
suiteSetup(() => {
suite('Dblite adapter tests -', () => {
suiteSetup(done => {
// Set up the sqlite database
let sql = 'CREATE TABLE IF NOT EXISTS "create_test" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);' +
'CREATE TABLE IF NOT EXISTS "create_join" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);';
connection.query(sql);
connection.query(sql, () => {
return done();
});
testRunner(tests, qb, (err, done) => {
expect(err).is.not.ok;
done();
});
suite('Adapter-specific tests', () => {
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
});
test('Test Insert Batch', done => {
/*---------------------------------------------------------------------------
Callback Tests
---------------------------------------------------------------------------*/
testRunner(qb, (err, done) => {
expect(err).is.not.ok;
done();
});
test('Callback - Select with function and argument in WHERE clause', done => {
qb.select('id')
.from('create_test')
.where('id', 'ABS(-88)')
.get((err, rows) => {
expect(err).is.not.ok;
return done();
});
});
test('Callback - Test Insert Batch', done => {
let data = [
{
id: 544,
@ -71,7 +81,20 @@ if (connection) {
return done();
});
});
/*---------------------------------------------------------------------------
Promise Tests
---------------------------------------------------------------------------*/
promiseTestRunner(qb);
test('Promise - Select with function and argument in WHERE clause', () => {
let promise = qb.select('id')
.from('create_test')
.where('id', 'ABS(-88)')
.get();
expect(promise).to.be.fulfilled;
});
suiteTeardown(() => {
qb.end();
});

View File

@ -0,0 +1,64 @@
'use strict';
module.exports = function mysqlBase(qb, nodeQuery, expect, testRunner, promiseTestRunner) {
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
});
/*---------------------------------------------------------------------------
Callback Tests
---------------------------------------------------------------------------*/
testRunner(qb, (err, done) => {
expect(err).is.not.ok;
done();
});
test('Callback - Select with function and argument in WHERE clause', done => {
qb.select('id')
.from('create_test')
.where('id', 'CEILING(SQRT(88))')
.get((err, rows) => {
expect(err).is.not.ok;
return done();
});
});
test('Test Insert Batch', done => {
let data = [
{
id: 544,
key: 3,
val: new Buffer('7'),
}, {
id: 89,
key: 34,
val: new Buffer('10 o\'clock'),
}, {
id: 48,
key: 403,
val: new Buffer('97'),
},
];
qb.insertBatch('create_test', data, (err, rows) => {
expect(err).is.not.ok;
return done();
});
});
/*---------------------------------------------------------------------------
Promise Tests
---------------------------------------------------------------------------*/
promiseTestRunner(qb);
test('Promise - Select with function and argument in WHERE clause', () => {
let promise = qb.select('id')
.from('create_test')
.where('id', 'CEILING(SQRT(88))')
.get();
expect(promise).to.be.fulfilled;
});
suiteTeardown(() => {
qb.end();
});
};

View File

@ -1,14 +1,16 @@
'use strict';
let configFile = (process.env.CI) ? '../config-travis.json' : '../config.json';
const configFile = (process.env.CI) ? '../config-travis.json' : '../config.json';
// Load the test base
let reload = require('require-reload')(require);
const reload = require('require-reload')(require);
reload.emptyCache();
const testBase = reload('../base');
const expect = testBase.expect,
promiseTestRunner = testBase.promiseTestRunner,
testRunner = testBase.testRunner;
let getArgs = reload('getargs');
let expect = reload('chai').expect;
let tests = reload('./adapterTestBase').tests;
let testRunner = reload('./adapterTestBase').runner;
// Load the test config file
let adapterName = 'mysql2';
@ -22,40 +24,6 @@ let connection = mysql2.createConnection(config.conn);
let nodeQuery = reload('../../lib/NodeQuery');
let qb = nodeQuery.init('mysql', connection, adapterName);
suite('Mysql2 adapter tests', () => {
testRunner(tests, qb, (err, done) => {
expect(err).is.not.ok;
done();
});
suite('Adapter-specific tests', () => {
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
});
test('Test Insert Batch', done => {
let data = [
{
id: 544,
key: 3,
val: new Buffer('7'),
}, {
id: 89,
key: 34,
val: new Buffer('10 o\'clock'),
}, {
id: 48,
key: 403,
val: new Buffer('97'),
},
];
qb.insertBatch('create_test', data, (err, rows) => {
expect(err).is.not.ok;
return done();
});
});
});
suiteTeardown(() => {
qb.end();
});
suite('Mysql2 adapter tests -', () => {
require('./mysql-base')(qb, nodeQuery, expect, testRunner, promiseTestRunner);
});

View File

@ -1,14 +1,16 @@
'use strict';
let configFile = (process.env.CI) ? '../config-travis.json' : '../config.json';
const configFile = (process.env.CI) ? '../config-travis.json' : '../config.json';
// Load the test base
let reload = require('require-reload')(require);
const reload = require('require-reload')(require);
reload.emptyCache();
const testBase = reload('../base');
const expect = testBase.expect,
promiseTestRunner = testBase.promiseTestRunner,
testRunner = testBase.testRunner;
let getArgs = reload('getargs');
let expect = reload('chai').expect;
let tests = reload('./adapterTestBase').tests;
let testRunner = reload('./adapterTestBase').runner;
// Load the test config file
let adapterName = 'mysql';
@ -22,40 +24,6 @@ let connection = mysql.createConnection(config.conn);
let nodeQuery = reload('../../lib/NodeQuery');
let qb = nodeQuery.init('mysql', connection);
suite('Mysql adapter tests', () => {
testRunner(tests, qb, (err, done) => {
expect(err).is.not.ok;
done();
});
suite('Adapter-specific tests', () => {
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
});
test('Test Insert Batch', done => {
let data = [
{
id: 544,
key: 3,
val: new Buffer('7'),
}, {
id: 89,
key: 34,
val: new Buffer('10 o\'clock'),
}, {
id: 48,
key: 403,
val: new Buffer('97'),
},
];
qb.insertBatch('create_test', data, (err, rows) => {
expect(err).is.not.ok;
return done();
});
});
});
suiteTeardown(() => {
qb.end();
});
suite('Mysql adapter tests -', () => {
require('./mysql-base')(qb, nodeQuery, expect, testRunner, promiseTestRunner);
});

View File

@ -0,0 +1,51 @@
'use strict';
// Load the test base
const path = require('path');
const reload = require('require-reload')(require);
const testBase = reload('../base');
const expect = reload('chai').expect;
const testRunner = testBase.testRunner;
const promiseTestRunner = testBase.promiseTestRunner;
// Load the test config file
let adapterName = 'node-firebird';
let Firebird = reload(adapterName);
const config = reload('../config.json')[adapterName];
config.conn.database = path.join(__dirname, config.conn.database);
let nodeQuery = reload('../../lib/NodeQuery');
let qb = null;
// Skip on TravisCi
if (process.env.CI || process.env.JENKINS_HOME) {
return;
}
suite('Firebird adapter tests -', () => {
// Set up the query builder object
suiteSetup('Database connection', connected => {
Firebird.attach(config.conn, (err, db) => {
qb = nodeQuery.init('firebird', db, adapterName);
return connected(err);
});
});
testRunner(qb, (err, done) => {
expect(err).is.not.ok;
done();
});
suite('Adapter-specific tests', () => {
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
});
test('insertBatch throws error', () => {
expect(() => {
qb.driver.insertBatch('create_test', []);
}).to.throw(Error, "Not Implemented");
});
});
suiteTeardown(() => {
qb.end();
});
});

View File

@ -1,46 +0,0 @@
'use strict';
// Load the test base
let reload = require('require-reload')(require);
let expect = reload('chai').expect;
let tests = reload('./adapterTestBase').tests;
let testRunner = reload('./adapterTestBase').runner;
// Load the test config file
let adapterName = 'node-firebird';
let Firebird = reload(adapterName);
let config = reload('../config.json')[adapterName];
config.conn.database = __dirname + config.conn.database;
let nodeQuery = reload('../../lib/NodeQuery');
// Skip on TravisCi
if (process.env.CI || process.env.JENKINS_HOME)
{
return;
}
suite('Firebird adapter tests', () => {
Firebird.attach(config.conn, (err, db) => {
// Set up the query builder object
let qb = nodeQuery.init('firebird', db, adapterName);
testRunner(tests, qb, (err, done) => {
expect(err).is.not.ok;
done();
});
suite('Adapter-specific tests', () => {
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
});
test('insertBatch throws error', () => {
expect(() => {
qb.driver.insertBatch('create_test', []);
}).to.throw(Error, "Not Implemented");
});
});
suiteTeardown(() => {
db.detach();
});
});
});

View File

@ -3,10 +3,12 @@
let configFile = (process.env.CI) ? '../config-travis.json' : '../config.json';
// Load the test base
let reload = require('require-reload')(require);
let expect = reload('chai').expect;
let tests = reload('./adapterTestBase').tests;
let testRunner = reload('./adapterTestBase').runner;
const reload = require('require-reload')(require);
reload.emptyCache();
const testBase = reload('../base');
const expect = testBase.expect,
promiseTestRunner = testBase.promiseTestRunner,
testRunner = testBase.testRunner;
// Load the test config file
let adapterName = 'pg';
@ -25,17 +27,42 @@ connection.connect(err => {
let nodeQuery = reload('../../lib/NodeQuery');
let qb = nodeQuery.init('pg', connection);
suite('Pg adapter tests', () => {
testRunner(tests, qb, (err, done) => {
expect(err).is.not.ok;
done();
});
suite('Adapter-specific tests', () => {
suite('Pg adapter tests -', () => {
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
});
test('Test Insert Batch', done => {
/*---------------------------------------------------------------------------
Callback Tests
---------------------------------------------------------------------------*/
testRunner(qb, (err, done) => {
expect(err).is.not.ok;
done();
});
test('Callback - Select with function and argument in WHERE clause', done => {
qb.select('id')
.from('create_test')
.where('id', 'CEILING(SQRT(88))')
.get((err, rows) => {
expect(err).is.not.ok;
return done();
});
});
/*---------------------------------------------------------------------------
Promise Tests
---------------------------------------------------------------------------*/
promiseTestRunner(qb);
test('Promise - Select with function and argument in WHERE clause', () => {
let promise = qb.select('id')
.from('create_test')
.where('id', 'CEILING(SQRT(88))')
.get();
expect(promise).to.be.fulfilled;
});
test('Promise - Test Insert Batch', () => {
let data = [
{
id: 544,
@ -52,13 +79,7 @@ suite('Pg adapter tests', () => {
},
];
qb.insertBatch('create_test', data, (err, rows) => {
expect(err).is.not.ok;
return done();
});
});
});
suiteTeardown(() => {
qb.end();
let promise = qb.insertBatch('create_test', data);
return expect(promise).to.be.fulfilled;
});
});

13
test/base.js Normal file
View File

@ -0,0 +1,13 @@
'use strict';
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const expect = chai.expect;
module.exports = {
expect: expect,
tests: require('./base/tests'),
testRunner: require('./base/adapterCallbackTestRunner'),
promiseTestRunner: require('./base/adapterPromiseTestRunner'),
};

View File

@ -0,0 +1,236 @@
'use strict';
// Load the test base
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const expect = chai.expect;
const reload = require('require-reload')(require);
let tests = reload('../base/tests');
let helpers = reload('../../lib/helpers'),
State = reload('../../lib/State');
module.exports = function testRunner(qb, callback) {
Object.keys(tests).forEach(suiteName => {
suite(suiteName, () => {
let currentSuite = tests[suiteName];
Object.keys(currentSuite).forEach(testDesc => {
test(`Callback - ${testDesc}`, done => {
let methodObj = currentSuite[testDesc];
let methodNames = Object.keys(methodObj);
let lastMethodIndex = methodNames[methodNames.length - 1];
methodObj[lastMethodIndex].push((err, rows) => {
callback(err, done);
});
methodNames.forEach(name => {
let args = methodObj[name],
method = qb[name];
if (args[0] === 'multiple') {
args.shift();
args.forEach(argSet => {
method.apply(qb, argSet);
});
} else {
method.apply(qb, args);
}
});
});
});
});
});
suite('DB update tests -', () => {
setup(done => {
let sql = qb.driver.truncate('create_test');
qb.adapter.execute(sql, (err, res) => {
done();
});
});
test('Callback - Test Insert', done => {
qb.set('id', 98)
.set('key', '84')
.set('val', new Buffer('120'))
.insert('create_test', (err, rows) => {
return callback(err, done);
});
});
test('Callback - Test Insert Object', done => {
qb.insert('create_test', {
id: 587,
key: 1,
val: new Buffer('2'),
}, (err, rows) => {
return callback(err, done);
});
});
test('Callback - Test Update', done => {
qb.where('id', 7)
.update('create_test', {
id: 7,
key: 'gogle',
val: new Buffer('non-word'),
}, (err, rows) => {
return callback(err, done);
});
});
test('Callback - Test set Array Update', done => {
let object = {
id: 22,
key: 'gogle',
val: new Buffer('non-word'),
};
qb.set(object)
.where('id', 22)
.update('create_test', (err, rows) => {
return callback(err, done);
});
});
test('Callback - Test where set update', done => {
qb.where('id', 36)
.set('id', 36)
.set('key', 'gogle')
.set('val', new Buffer('non-word'))
.update('create_test', (err, rows) => {
return callback(err, done);
});
});
test('Callback - Test delete', done => {
qb.delete('create_test', {id: 5}, (err, rows) => {
return callback(err, done);
});
});
test('Callback - Delete with where', done => {
qb.where('id', 5)
.delete('create_test', (err, rows) => {
return callback(err, done);
});
});
test('Callback - Delete multiple where values', done => {
qb.delete('create_test', {
id: 5,
key: 'gogle',
}, (err, rows) => {
return callback(err, done);
});
});
});
suite('Grouping tests -', () => {
test('Callback - Using grouping method', done => {
qb.select('id, key as k, val')
.from('create_test')
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.limit(2, 1)
.get((err, rows) => {
return callback(err, done);
});
});
test('Callback - Using where first grouping', done => {
qb.select('id, key as k, val')
.from('create_test')
.where('id !=', 5)
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.limit(2, 1)
.get((err, rows) => {
return callback(err, done);
});
});
test('Callback - Using or grouping method', done => {
qb.select('id, key as k, val')
.from('create_test')
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.orGroupStart()
.where('id', 0)
.groupEnd()
.limit(2, 1)
.get((err, rows) => {
return callback(err, done);
});
});
test('Callback - Using or not grouping method', done => {
qb.select('id, key as k, val')
.from('create_test')
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.orNotGroupStart()
.where('id', 0)
.groupEnd()
.limit(2, 1)
.get((err, rows) => {
return callback(err, done);
});
});
});
suite('Get compiled tests -', () => {
test('select', () => {
let sql = qb.select('id')
.from('create_test')
.getCompiledSelect(true);
expect(helpers.isString(sql)).to.be.true;
});
test('select from', () => {
let sql = qb.select('id')
.getCompiledSelect('create_test', true);
expect(helpers.isString(sql)).to.be.true;
});
test('insert', () => {
let sql = qb.set('id', 3)
.getCompiledInsert('create_test');
expect(helpers.isString(sql)).to.be.true;
});
test('update', () => {
let sql = qb.set('id', 3)
.where('id', 5)
.getCompiledUpdate('create_test');
expect(helpers.isString(sql)).to.be.true;
});
test('delete', () => {
let sql = qb.where('id', 5)
.getCompiledDelete('create_test');
expect(helpers.isString(sql)).to.be.true;
});
});
suite('Misc tests -', () => {
test('Get State', () => {
qb.select('foo')
.from('bar')
.where('baz', 'foobar');
let state = new State();
expect(JSON.stringify(state)).to.not.be.deep.equal(qb.getState());
});
test('Reset State', () => {
qb.select('foo')
.from('bar')
.where('baz', 'foobar');
qb.resetQuery();
let state = new State();
expect(qb.getState()).to.be.deep.equal(state);
});
});
};

View File

@ -0,0 +1,181 @@
'use strict';
// Load the test base
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const expect = chai.expect;
const reload = require('require-reload')(require);
let tests = reload('../base/tests');
let helpers = reload('../../lib/helpers'),
State = reload('../../lib/State');
module.exports = function promiseTestRunner(qb) {
Object.keys(tests).forEach(suiteName => {
suite(suiteName, () => {
let currentSuite = tests[suiteName];
Object.keys(currentSuite).forEach(testDesc => {
test(`Promise - ${testDesc}`, () => {
let methodObj = currentSuite[testDesc];
let methodNames = Object.keys(methodObj);
let lastMethodIndex = methodNames[methodNames.length - 1];
let results = [];
methodNames.forEach(name => {
let args = methodObj[name],
method = qb[name];
if (args[0] === 'multiple') {
args.shift();
args.forEach(argSet => {
results.push(method.apply(qb, argSet));
});
} else {
results.push(method.apply(qb, args));
}
});
let promise = results.pop();
expect(promise).to.be.fulfilled;
});
});
});
});
suite('DB update tests -', () => {
suiteSetup(done => {
let sql = qb.driver.truncate('create_test');
qb.adapter.execute(sql).then(res => {
return done();
}).catch(err => {
return done(err);
});
});
test('Promise - Test Insert', () => {
let promise = qb.set('id', 98)
.set('key', '84')
.set('val', new Buffer('120'))
.insert('create_test');
expect(promise).to.be.fulfilled;
});
test('Promise - Test Insert Object', () => {
let promise = qb.insert('create_test', {
id: 587,
key: 1,
val: new Buffer('2'),
});
expect(promise).to.be.fulfilled;
});
test('Promise - Test Update', () => {
let promise = qb.where('id', 7)
.update('create_test', {
id: 7,
key: 'gogle',
val: new Buffer('non-word'),
});
expect(promise).to.be.fulfilled;
});
test('Promise - Test set Array Update', () => {
let object = {
id: 22,
key: 'gogle',
val: new Buffer('non-word'),
};
let promise = qb.set(object)
.where('id', 22)
.update('create_test');
expect(promise).to.be.fulfilled;
});
test('Promise - Test where set update', () => {
let promise = qb.where('id', 36)
.set('id', 36)
.set('key', 'gogle')
.set('val', new Buffer('non-word'))
.update('create_test');
expect(promise).to.be.fulfilled;
});
test('Promise - Test delete', () => {
let promise = qb.delete('create_test', {id: 5});
expect(promise).to.be.fulfilled;
});
test('Promise - Delete with where', () => {
let promise = qb.where('id', 5)
.delete('create_test');
expect(promise).to.be.fulfilled;
});
test('Promise - Delete multiple where values', () => {
let promise = qb.delete('create_test', {
id: 5,
key: 'gogle',
});
expect(promise).to.be.fulfilled;
});
});
suite('Grouping tests -', () => {
test('Promise - Using grouping method', () => {
let promise = qb.select('id, key as k, val')
.from('create_test')
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.limit(2, 1)
.get();
expect(promise).to.be.fulfilled;
});
test('Promise - Using where first grouping', () => {
let promise = qb.select('id, key as k, val')
.from('create_test')
.where('id !=', 5)
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.limit(2, 1)
.get();
expect(promise).to.be.fulfilled;
});
test('Promise - Using or grouping method', () => {
let promise = qb.select('id, key as k, val')
.from('create_test')
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.orGroupStart()
.where('id', 0)
.groupEnd()
.limit(2, 1)
.get();
expect(promise).to.be.fulfilled;
});
test('Promise - Using or not grouping method', () => {
let promise = qb.select('id, key as k, val')
.from('create_test')
.groupStart()
.where('id >', 1)
.where('id <', 900)
.groupEnd()
.orNotGroupStart()
.where('id', 0)
.groupEnd()
.limit(2, 1)
.get();
expect(promise).to.be.fulfilled;
});
});
};

246
test/base/tests.js Normal file
View File

@ -0,0 +1,246 @@
'use strict';
module.exports = {
'Get tests -': {
'Get with function': {
select: ['id, COUNT(id) as count'],
from: ['create_test'],
groupBy: ['id'],
get: [],
},
'Basic select all get': {
get: ['create_test'],
},
'Basic select all with from': {
from: ['create_test'],
get: [],
},
'Get with limit': {
get: ['create_test', 2],
},
'Get with limit and offset': {
get: ['create_test', 2, 1],
},
'Get with having': {
select: ['id'],
from: ['create_test'],
groupBy: ['id'],
having: [
'multiple',
[{'id >': 1}],
['id !=', 3],
['id', 900],
],
get: [],
},
'Get with orHaving': {
select: ['id'],
from: ['create_test'],
groupBy: ['id'],
having: [{'id >': 1}],
orHaving: ['id !=', 3],
get: [],
},
},
'Select tests -': {
'Select where get': {
select: [['id', 'key as k', 'val']],
where: [
'multiple',
['id >', 1],
['id <', 900],
],
get: ['create_test', 2, 1],
},
'Select where get 2': {
select: ['id, key as k, val'],
where: ['id !=', 1],
get: ['create_test', 2, 1],
},
'Multi Order By': {
from: ['create_test'],
orderBy: ['id, key'],
get: [],
},
'Select get': {
select: ['id, key as k, val'],
get: ['create_test', 2, 1],
},
'Select from get': {
select: ['id, key as k, val'],
from: ['create_test ct'],
where: ['id >', 1],
get: [],
},
'Select from limit get': {
select: ['id, key as k, val'],
from: ['create_test ct'],
where: ['id >', 1],
limit: [3],
get: [],
},
'Select where IS NOT NULL': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
whereIsNotNull: ['id'],
get: [],
},
'Select where IS NULL': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
whereIsNull: ['id'],
get: [],
},
'Select where OR IS NOT NULL': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
whereIsNull: ['id'],
orWhereIsNotNull: ['id'],
get: [],
},
'Select where OR IS NULL': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
where: ['id', 3],
orWhereIsNull: ['id'],
get: [],
},
'Select with string where value': {
select: ['id', 'key as k', 'val'],
from: ['create_test ct'],
where: ['id > 3'],
get: [],
},
},
'Where in tests -': {
'Where in': {
from: ['create_test'],
whereIn: ['id', [0, 6, 56, 563, 341]],
get: [],
},
'Or Where in': {
from: ['create_test'],
where: ['key', 'false'],
orWhereIn: ['id', [0, 6, 56, 563, 341]],
get: [],
},
'Where Not in': {
from: ['create_test'],
where: ['key', 'false'],
whereNotIn: ['id', [0, 6, 56, 563, 341]],
get: [],
},
'Or Where Not in': {
from: ['create_test'],
where: ['key', 'false'],
orWhereNotIn: ['id', [0, 6, 56, 563, 341]],
get: [],
},
},
'Query modifier tests -': {
'Order By': {
select: ['id, key as k, val'],
from: ['create_test'],
where: [
'multiple',
['id >', 0],
['id <', 9000],
],
orderBy: [
'multiple',
['id', 'DESC'],
['k', 'ASC'],
],
limit: [5, 2],
get: [],
},
'Group By': {
select: ['id, key as k, val'],
from: ['create_test'],
where: [
'multiple',
['id >', 0],
['id <', 9000],
],
groupBy: [
'multiple',
['k'],
[['id', 'val']],
],
orderBy: [
'multiple',
['id', 'DESC'],
['k', 'ASC'],
],
limit: [5, 2],
get: [],
},
'Or Where': {
select: ['id, key as k, val'],
from: ['create_test'],
where: [' id ', 1],
orWhere: ['key > ', 0],
limit: [2, 1],
get: [],
},
Like: {
from: ['create_test'],
like: ['key', 'og'],
get: [],
},
'Or Like': {
from: ['create_test'],
like: ['key', 'og'],
orLike: ['key', 'val'],
get: [],
},
'Not Like': {
from: ['create_test'],
like: ['key', 'og', 'before'],
notLike: ['key', 'val'],
get: [],
},
'Or Not Like': {
from: ['create_test'],
like: ['key', 'og', 'before'],
orNotLike: ['key', 'val'],
get: [],
},
'Like Before': {
from: ['create_test'],
like: ['key', 'og', 'before'],
get: [],
},
'Like After': {
from: ['create_test'],
like: ['key', 'og', 'after'],
get: [],
},
'Basic Join': {
from: ['create_test ct'],
join: ['create_join cj', 'cj.id=ct.id'],
get: [],
},
'Left Join': {
from: ['create_test ct'],
join: ['create_join cj', 'cj.id=ct.id', 'left'],
get: [],
},
'Inner Join': {
from: ['create_test ct'],
join: ['create_join cj', 'cj.id=ct.id', 'inner'],
get: [],
},
'Join with multiple where values': {
from: ['create_test ct'],
join: ['create_join cj', 'cj.id=ct.id', 'inner'],
where: [
{
'ct.id < ': 3,
'ct.key ': 'foo',
},
],
get: [],
},
},
};

View File

@ -6,7 +6,7 @@ let expect = require('chai').expect,
nodeQuery = reload('../lib/NodeQuery'),
Adapter = reload('../lib/Adapter');
suite('Base tests', () => {
suite('Base tests -', () => {
suite('Sanity check', () => {
let files = glob.sync(`${__dirname}/../lib/**/*.js`);
files.forEach(mod => {

View File

@ -7,8 +7,8 @@ let chai = require('chai'),
let helpers = require('../lib/helpers');
suite('Helper Module Tests', () => {
suite('Type-checking methods', () => {
suite('Helper Module Tests -', () => {
suite('Type-checking methods -', () => {
suite('Object wrappers are listed as their native type', () => {
test('Boolean Wrapper returns \'boolean\' not \'object\'', () => {
let item = Boolean(true);
@ -23,7 +23,7 @@ suite('Helper Module Tests', () => {
expect(helpers.type(item)).to.deep.equal('string');
});
});
suite('is..Method methods exist', () => {
suite('is..Method methods exist -', () => {
let types = [
'Null',
'Undefined',
@ -44,7 +44,7 @@ suite('Helper Module Tests', () => {
});
});
});
suite('isScalar', () => {
suite('isScalar -', () => {
let trueCases = {
'Strings are scalar': 'foo',
'Booleans are scalar': true,
@ -66,7 +66,7 @@ suite('Helper Module Tests', () => {
});
});
});
suite('isInfinity', () => {
suite('isInfinity -', () => {
test('The type of 1/0 is infinity', () => {
expect(helpers.type(1 / 0)).to.equal('infinity');
});
@ -74,7 +74,7 @@ suite('Helper Module Tests', () => {
expect(helpers.isInfinite(1 / 0)).to.be.true;
});
});
suite('isNaN', () => {
suite('isNaN -', () => {
test('The type of 0 / 0 is NaN', () => {
expect(helpers.type(0 / 0)).to.equal('nan');
});
@ -83,8 +83,8 @@ suite('Helper Module Tests', () => {
});
});
});
suite('Other helper methods', () => {
suite('stringTrim', () => {
suite('Other helper methods -', () => {
suite('stringTrim -', () => {
test('stringTrim method works as expected', () => {
let orig = [' x y ', 'z ', ' q'];
let ret = ['x y', 'z', 'q'];
@ -92,7 +92,7 @@ suite('Helper Module Tests', () => {
expect(orig.map(helpers.stringTrim)).to.be.deep.equal(ret);
});
});
suite('arrayPluck', () => {
suite('arrayPluck -', () => {
let orig = [
{
foo: 1,
@ -115,7 +115,7 @@ suite('Helper Module Tests', () => {
expect(helpers.arrayPluck([], 'apple')).to.be.deep.equal([]);
});
});
suite('regexInArray', () => {
suite('regexInArray -', () => {
let orig = ['apple', ' string ', 6, 4, 7];
let cases = [

View File

@ -1,7 +1,9 @@
--ui tdd
--bail
--recursive
--reporter dot
--slow 100
--timeout 5000
--reporter list
--slow 200
--timeout 10000
--check-leaks
--growl
test/**/*_test.js