Merge branch 'develop' of git.timshomepage.net:timw4mail/node-query into develop

This commit is contained in:
Timothy Warren 2017-02-28 15:55:30 -05:00
commit 26febfd7ab
23 changed files with 238 additions and 97 deletions

33
docker-compose.yml Normal file
View File

@ -0,0 +1,33 @@
mariadb:
image: mariadb:latest
environment:
- MYSQL_USER=test
- MYSQL_PASSWORD=test
- MYSQL_DATABASE=test
- MYSQL_RANDOM_ROOT_PASSWORD=yes
ports:
- 3306:3306
postgresql:
image: postgres:latest
environment:
- POSTGRES_USER=test
- POSTGRES_PASSWORD=test
- POSTGRES_DB=test
ports:
- 5432:5432
sqlserver:
image: microsoft/mssql-server-linux
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=t3571ng0n1y
ports:
- 1433:1433
firebird:
image: itherz/firebird3:latest
ports:
- 5040:5040
volumes:
- ./test:/databases

View File

@ -22,7 +22,7 @@ class Adapter {
* *
* @param {String} sql - The sql with placeholders * @param {String} sql - The sql with placeholders
* @param {Array} params - The values to insert into the query * @param {Array} params - The values to insert into the query
* @return {Promise} - returns a promise if no callback is passed * @return {Promise} - returns a promise resolving to the result of the database query
*/ */
execute (sql, params) { execute (sql, params) {
throw new Error('Correct adapter not defined for query execution'); throw new Error('Correct adapter not defined for query execution');

View File

@ -1,18 +1,40 @@
'use strict'; 'use strict';
const fs = require('fs');
/** /**
* Various internal helper functions * Various internal helper functions
* *
* @private * @private
*/ */
let helpers = { class Helpers {
/**
* Get the contents of a file
*
* @param {string} file - The path to the file
* @return {Promise<string>} - Promise resolving to the contents of the file
*/
static readFile (file) {
return new Promise((resolve, reject) => {
fs.readFile(file, (err, data) => {
if (err) {
return reject(err);
}
return resolve(Buffer.from(data).toString());
});
});
}
/** /**
* Wrap String.prototype.trim in a way that is easily mappable * Wrap String.prototype.trim in a way that is easily mappable
* *
* @param {String} str - The string to trim * @param {String} str - The string to trim
* @return {String} - The trimmed string * @return {String} - The trimmed string
*/ */
stringTrim: str => str.trim(), static stringTrim (str) {
return str.trim();
}
/** /**
* Get the type of the variable passed * Get the type of the variable passed
* *
@ -21,7 +43,7 @@ let helpers = {
* @param {mixed} o - Object to type check * @param {mixed} o - Object to type check
* @return {String} - Type of the object * @return {String} - Type of the object
*/ */
type: o => { static type (o) {
let type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase(); let type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
// handle NaN and Infinity // handle NaN and Infinity
@ -36,17 +58,19 @@ let helpers = {
} }
return type; return type;
}, }
/** /**
* Determine whether an object is scalar * Determine whether an object is scalar
* *
* @param {mixed} obj - Object to test * @param {mixed} obj - Object to test
* @return {bool} - Is object scalar * @return {bool} - Is object scalar
*/ */
isScalar: obj => { static isScalar (obj) {
let scalar = ['string', 'number', 'boolean']; let scalar = ['string', 'number', 'boolean'];
return scalar.indexOf(helpers.type(obj)) !== -1; return scalar.indexOf(Helpers.type(obj)) !== -1;
}, }
/** /**
* Get a list of values with a common key from an array of objects * Get a list of values with a common key from an array of objects
* *
@ -54,7 +78,7 @@ let helpers = {
* @param {String} key - The key of the object to get * @param {String} key - The key of the object to get
* @return {Array} - The new array of plucked values * @return {Array} - The new array of plucked values
*/ */
arrayPluck: (arr, key) => { static arrayPluck (arr, key) {
let output = []; let output = [];
// Empty case // Empty case
@ -63,13 +87,14 @@ let helpers = {
} }
arr.forEach(obj => { arr.forEach(obj => {
if (!helpers.isUndefined(obj[key])) { if (!Helpers.isUndefined(obj[key])) {
output.push(obj[key]); output.push(obj[key]);
} }
}); });
return output; return output;
}, }
/** /**
* Determine if a value matching the passed regular expression is * Determine if a value matching the passed regular expression is
* in the passed array * in the passed array
@ -78,9 +103,9 @@ let helpers = {
* @param {RegExp} pattern - The pattern to match * @param {RegExp} pattern - The pattern to match
* @return {Boolean} - If an array item matches the pattern * @return {Boolean} - If an array item matches the pattern
*/ */
regexInArray: (arr, pattern) => { static regexInArray (arr, pattern) {
// Empty case(s) // Empty case(s)
if (!helpers.isArray(arr) || arr.length === 0) { if (!Helpers.isArray(arr) || arr.length === 0) {
return false; return false;
} }
@ -93,19 +118,20 @@ let helpers = {
} }
return false; return false;
}, }
/** /**
* Make the first letter of the string uppercase * Make the first letter of the string uppercase
* *
* @param {String} str - The string to modify * @param {String} str - The string to modify
* @return {String} - The modified string * @return {String} - The modified string
*/ */
upperCaseFirst: str => { static upperCaseFirst (str) {
str += ''; str += '';
let first = str.charAt(0).toUpperCase(); let first = str.charAt(0).toUpperCase();
return first + str.substr(1); return first + str.substr(1);
} }
}; }
// Define an 'is' method for each type // Define an 'is' method for each type
let types = [ let types = [
@ -119,7 +145,8 @@ let types = [
'Function', 'Function',
'RegExp', 'RegExp',
'NaN', 'NaN',
'Infinite' 'Infinite',
'Promise'
]; ];
types.forEach(t => { types.forEach(t => {
/** /**
@ -127,19 +154,19 @@ types.forEach(t => {
* function name, eg isNumber * function name, eg isNumber
* *
* Types available are Null, Undefined, Object, Array, String, Number, * Types available are Null, Undefined, Object, Array, String, Number,
* Boolean, Function, RegExp, NaN and Infinite * Boolean, Function, RegExp, NaN, Infinite, Promise
* *
* @private * @private
* @param {mixed} o - The object to check its type * @param {mixed} o - The object to check its type
* @return {Boolean} - If the type matches * @return {Boolean} - If the type matches
*/ */
helpers[`is${t}`] = function (o) { Helpers[`is${t}`] = function (o) {
if (t.toLowerCase() === 'infinite') { if (t.toLowerCase() === 'infinite') {
t = 'infinity'; t = 'infinity';
} }
return helpers.type(o) === t.toLowerCase(); return Helpers.type(o) === t.toLowerCase();
}; };
}); });
module.exports = helpers; module.exports = Helpers;

View File

@ -28,6 +28,12 @@ class NodeQuery {
* Constructor * Constructor
* *
* @param {object} config - connection parameters * @param {object} config - connection parameters
* @param {string} config.driver - the database driver to use, such as mysql, sqlite, mssql, or pgsql
* @param {object|string} config.connection - the connection options for the database
* @param {string} config.connection.host - the ip or hostname of the database server
* @param {string} config.connection.user - the user to log in as
* @param {string} config.connection.password - the password to log in with
* @param {string} config.connection.database - the name of the database to connect to
* @example let nodeQuery = require('ci-node-query')({ * @example let nodeQuery = require('ci-node-query')({
* driver: 'mysql', * driver: 'mysql',
* connection: { * connection: {

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const helpers = require('./helpers'); const Helpers = require('./Helpers');
const QueryBuilderBase = require('./QueryBuilderBase'); const QueryBuilderBase = require('./QueryBuilderBase');
/** /**
@ -15,6 +15,26 @@ class QueryBuilder extends QueryBuilderBase {
// ! Miscellaneous Methods // ! Miscellaneous Methods
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/**
* Run a set of queries from a file
*
* @param {string} file - The path to the sql file
* @param {string} [separator=';'] - The character separating each query
* @return {Promise} - The result of all the queries
*/
queryFile (file, separator = ';') {
return Helpers.readFile(file).then(sqlFile => {
const queries = sqlFile.split(separator);
const results = [];
queries.forEach(sql => {
results.push(this.query(sql));
});
return Promise.all(results);
});
}
/** /**
* Run an arbitrary sql query. Run as a prepared statement. * Run an arbitrary sql query. Run as a prepared statement.
* *
@ -80,12 +100,12 @@ class QueryBuilder extends QueryBuilderBase {
// Split/trim fields by comma // Split/trim fields by comma
fields = (Array.isArray(fields)) fields = (Array.isArray(fields))
? fields ? fields
: fields.split(',').map(helpers.stringTrim); : fields.split(',').map(Helpers.stringTrim);
// Split on 'As' // Split on 'As'
fields.forEach((field, index) => { fields.forEach((field, index) => {
if (/as/i.test(field)) { if (/as/i.test(field)) {
fields[index] = field.split(/ as /i).map(helpers.stringTrim); fields[index] = field.split(/ as /i).map(Helpers.stringTrim);
} }
}); });
@ -113,7 +133,7 @@ class QueryBuilder extends QueryBuilderBase {
*/ */
from (tableName) { from (tableName) {
// Split identifiers on spaces // Split identifiers on spaces
let identArray = tableName.trim().split(' ').map(helpers.stringTrim); let identArray = tableName.trim().split(' ').map(Helpers.stringTrim);
// Quote/prefix identifiers // Quote/prefix identifiers
identArray[0] = this.driver.quoteTable(identArray[0]); identArray[0] = this.driver.quoteTable(identArray[0]);
@ -354,7 +374,7 @@ class QueryBuilder extends QueryBuilderBase {
type = type || 'inner'; type = type || 'inner';
// Prefix/quote table name // Prefix/quote table name
table = table.split(' ').map(helpers.stringTrim); table = table.split(' ').map(Helpers.stringTrim);
table[0] = this.driver.quoteTable(table[0]); table[0] = this.driver.quoteTable(table[0]);
table = table.map(this.driver.quoteIdentifiers); table = table.map(this.driver.quoteIdentifiers);
table = table.join(' '); table = table.join(' ');
@ -376,7 +396,7 @@ class QueryBuilder extends QueryBuilderBase {
* @return {QueryBuilder} - The Query Builder object, for chaining * @return {QueryBuilder} - The Query Builder object, for chaining
*/ */
groupBy (field) { groupBy (field) {
if (!helpers.isScalar(field)) { if (!Helpers.isScalar(field)) {
let newGroupArray = field.map(this.driver.quoteIdentifiers); let newGroupArray = field.map(this.driver.quoteIdentifiers);
this.state.groupArray = this.state.groupArray.concat(newGroupArray); this.state.groupArray = this.state.groupArray.concat(newGroupArray);
} else { } else {
@ -490,7 +510,7 @@ class QueryBuilder extends QueryBuilderBase {
* @example query.get('table_name').then(promiseCallback); // Get all the rows in the table * @example query.get('table_name').then(promiseCallback); // Get all the rows in the table
* @example query.get('table_name', 5); // Get 5 rows from the table * @example query.get('table_name', 5); // Get 5 rows from the table
* @example query.get(); // Get the results of a query generated with other methods * @example query.get(); // Get the results of a query generated with other methods
* @return {void|Promise} - If no callback is passed, a promise is returned * @return {Promise<Result>} - Promise containing the result of the query
*/ */
get (table, limit, offset) { get (table, limit, offset) {
if (table) { if (table) {
@ -510,7 +530,7 @@ class QueryBuilder extends QueryBuilderBase {
* *
* @param {String} table - The table to insert into * @param {String} table - The table to insert into
* @param {Object} [data] - Data to insert, if not already added with the 'set' method * @param {Object} [data] - Data to insert, if not already added with the 'set' method
* @return {Promise} - If no callback is passed, a promise is returned * @return {Promise<Result>} - Promise containing the result of the query
*/ */
insert (table, data) { insert (table, data) {
if (data) { if (data) {
@ -528,7 +548,7 @@ class QueryBuilder extends QueryBuilderBase {
* @param {Array} data - The array of objects containing data rows to insert * @param {Array} data - The array of objects containing data rows to insert
* @example query.insertBatch('foo',[{id:1,val:'bar'},{id:2,val:'baz'}]) * @example query.insertBatch('foo',[{id:1,val:'bar'},{id:2,val:'baz'}])
*.then(promiseCallback); *.then(promiseCallback);
* @return {Promise} - If no callback is passed, a promise is returned * @return {Promise<Result>} - Promise containing the result of the query
*/ */
insertBatch (table, data) { insertBatch (table, data) {
let batch = this.driver.insertBatch(table, data); let batch = this.driver.insertBatch(table, data);
@ -542,7 +562,7 @@ class QueryBuilder extends QueryBuilderBase {
* *
* @param {String} table - The table to insert into * @param {String} table - The table to insert into
* @param {Object} [data] - Data to insert, if not already added with the 'set' method * @param {Object} [data] - Data to insert, if not already added with the 'set' method
* @return {Promise} - If no callback is passed, a promise is returned * @return {Promise<Result>} - Promise containing the result of the query
*/ */
update (table, data) { update (table, data) {
if (data) { if (data) {
@ -558,7 +578,7 @@ class QueryBuilder extends QueryBuilderBase {
* *
* @param {String} table - The table to insert into * @param {String} table - The table to insert into
* @param {Object} [where] - Where clause for delete statement * @param {Object} [where] - Where clause for delete statement
* @return {Promise} - If no callback is passed, a promise is returned * @return {Promise<Result>} - Promise containing the result of the query
*/ */
delete (table, where) { delete (table, where) {
if (where) { if (where) {

View File

@ -115,7 +115,7 @@ class QueryParser {
/** /**
* Return the output of the parsing of the join condition * Return the output of the parsing of the join condition
* *
* @param {String} condition - The join condition to evalate * @param {String} condition - The join condition to evaluate
* @return {String} - The parsed/escaped join condition * @return {String} - The parsed/escaped join condition
*/ */
compileJoin (condition) { compileJoin (condition) {

View File

@ -0,0 +1,5 @@
'use strict';
module.exports = config => {
};

View File

@ -2,7 +2,7 @@
const Adapter = require('../../Adapter'); const Adapter = require('../../Adapter');
const Result = require('../../Result'); const Result = require('../../Result');
const helpers = require('../../helpers'); const Helpers = require('../../Helpers');
const mysql2 = require('mysql2/promise'); const mysql2 = require('mysql2/promise');
class Mysql extends Adapter { class Mysql extends Adapter {
@ -22,7 +22,7 @@ class Mysql extends Adapter {
// For insert and update queries, the result object // For insert and update queries, the result object
// works differently. Just apply the properties of // works differently. Just apply the properties of
// this special result to the standard result object. // this special result to the standard result object.
if (helpers.type(result) === 'object') { if (Helpers.type(result) === 'object') {
let r = new Result(); let r = new Result();
Object.keys(result).forEach(key => { Object.keys(result).forEach(key => {

View File

@ -2,7 +2,7 @@
const Adapter = require('../../Adapter'); const Adapter = require('../../Adapter');
const Result = require('../../Result'); const Result = require('../../Result');
const helpers = require('../../helpers'); const Helpers = require('../../Helpers');
const pg = require('pg'); const pg = require('pg');
const url = require('url'); const url = require('url');
@ -10,7 +10,7 @@ class Pg extends Adapter {
constructor (config) { constructor (config) {
let instance = null; let instance = null;
let connectionString = ''; let connectionString = '';
if (helpers.isObject(config)) { if (Helpers.isObject(config)) {
let host = config.host || 'localhost'; let host = config.host || 'localhost';
let user = config.user || 'postgres'; let user = config.user || 'postgres';
let password = `:${config.password}` || ''; let password = `:${config.password}` || '';
@ -25,7 +25,7 @@ class Pg extends Adapter {
}; };
connectionString = url.format(conn); connectionString = url.format(conn);
} else if (helpers.isString(config)) { } else if (Helpers.isString(config)) {
connectionString = config; connectionString = config;
} }

View File

@ -0,0 +1,28 @@
'use strict';
const Pg = require('./Pg');
const Result = require('../../Result');
const pg = require('pg').native;
const url = require('url');
class PgNative extends Pg {
constructor (config) {
super(config);
let instance = null;
let connectionString = Pg._formatConnectionString(config);
if (connectionString !== '') {
let conn = new pg.Client(connectionString);
conn.connect(err => {
if (err) {
throw new Error(err);
}
});
instance = Promise.resolve(conn);
}
super(instance);
}
}
module.exports = PgNative;

View File

@ -1,7 +1,10 @@
'use strict'; 'use strict';
const Pg = require('./Pg'); const Pg = require('./Pg');
const PgNative = require('./PgNative')
module.exports = config => { module.exports = config => {
return new Pg(config.connection); return (config.native)
? new PgNative(config.connection)
: new Pg(config.connection);
}; };

View File

@ -2,12 +2,12 @@
const Adapter = require('../../Adapter'); const Adapter = require('../../Adapter');
const Result = require('../../Result'); const Result = require('../../Result');
const helpers = require('../../helpers'); const Helpers = require('../../Helpers');
const dbliteAdapter = require('dblite'); const dbliteAdapter = require('dblite');
class SqliteDblite extends Adapter { class SqliteDblite extends Adapter {
constructor (config) { constructor (config) {
let file = (helpers.isString(config)) ? config : config.file; let file = (Helpers.isString(config)) ? config : config.file;
const instance = new Promise((resolve, reject) => { const instance = new Promise((resolve, reject) => {
let conn = dbliteAdapter(file); let conn = dbliteAdapter(file);

View File

@ -1,9 +1,9 @@
'use strict'; 'use strict';
module.exports = config => { module.exports = config => {
const Implementation = (config.adapter && config.adapter === 'dblite') const Implementation = (config.native)
? require('./dblite') ? require('./sqlite3')
: require('./sqlite3'); : require('./dblite');
return new Implementation(config.connection); return new Implementation(config.connection);
}; };

View File

@ -2,12 +2,12 @@
const Adapter = require('../../Adapter'); const Adapter = require('../../Adapter');
const Result = require('../../Result'); const Result = require('../../Result');
const helpers = require('../../helpers'); const Helpers = require('../../Helpers');
const sqlite3 = require('sqlite3').verbose(); const sqlite3 = require('sqlite3').verbose();
class SqliteSqlite3 extends Adapter { class SqliteSqlite3 extends Adapter {
constructor (config) { constructor (config) {
let file = (helpers.isString(config)) ? config : config.file; let file = (Helpers.isString(config)) ? config : config.file;
const instance = new Promise((resolve, reject) => { const instance = new Promise((resolve, reject) => {
let conn = new sqlite3.Database(file, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, err => { let conn = new sqlite3.Database(file, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, err => {

View File

@ -0,0 +1,17 @@
'use strict';
/**
* Driver for Microsoft SQL Server databases
*
* @module drivers/MSSQLDriver
*/
module.exports = (() => {
delete require.cache[require.resolve('../Driver')];
const driver = require('../Driver');
const helpers = require('../helpers');
driver.identifierStartChar = '[';
driver.identifierEndChar = ']';
return driver;
})();

View File

@ -23,12 +23,14 @@
"codeigniter", "codeigniter",
"mariadb", "mariadb",
"mysql", "mysql",
"mssql",
"query builder", "query builder",
"postgres", "postgres",
"postgresql", "postgresql",
"sql", "sql",
"sqlite", "sqlite",
"sqlite3" "sqlite3",
"sqlserver"
], ],
"bugs": { "bugs": {
"url": "https://git.timshomepage.net/timw4mail/node-query/issues" "url": "https://git.timshomepage.net/timw4mail/node-query/issues"
@ -43,6 +45,7 @@
"pg": "^6.0.0", "pg": "^6.0.0",
"require-reload": "~0.2.2", "require-reload": "~0.2.2",
"sqlite3": "^3.1.8", "sqlite3": "^3.1.8",
"tedious": "^1.14.0",
"xregexp": "^3.0.0" "xregexp": "^3.0.0"
}, },
"devDependencies": { "devDependencies": {
@ -53,6 +56,7 @@
"globstar": "^1.0.0", "globstar": "^1.0.0",
"happiness": "^7.1.2", "happiness": "^7.1.2",
"jest": "^19.0.2", "jest": "^19.0.2",
"jsdoc": "^3.4.3",
"npm-run-all": "^3.0.0", "npm-run-all": "^3.0.0",
"nsp": "^2.2.1" "nsp": "^2.2.1"
}, },
@ -77,6 +81,7 @@
"default": "npm-run-all --parallel audit lint:src lint:tests && npm run test", "default": "npm-run-all --parallel audit lint:src lint:tests && npm run test",
"predocs": "globstar -- documentation build -f md -o API.md \"lib/*.js\"", "predocs": "globstar -- documentation build -f md -o API.md \"lib/*.js\"",
"docs": "globstar -- documentation build -f html -o docs \"lib/*.js\"", "docs": "globstar -- documentation build -f html -o docs \"lib/*.js\"",
"postdocs": "jsdoc lib -r -d documentation",
"happy": "happiness \"lib/**/*.js\" \"test/**/*.js\"", "happy": "happiness \"lib/**/*.js\" \"test/**/*.js\"",
"happy:src": "happiness \"lib/**/*.js\"", "happy:src": "happiness \"lib/**/*.js\"",
"happy:tests": "happiness \"test/**/*.js\"", "happy:tests": "happiness \"test/**/*.js\"",

View File

@ -17,15 +17,9 @@ let qb = nodeQuery.getQuery();
describe('Dblite adapter tests -', () => { describe('Dblite adapter tests -', () => {
beforeAll(done => { beforeAll(done => {
// Set up the sqlite database qb.queryFile(`${__dirname}/../sql/sqlite.sql`)
const createTest = 'CREATE TABLE IF NOT EXISTS "create_test" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);'; .then(() => done())
const createJoin = 'CREATE TABLE IF NOT EXISTS "create_join" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);'; .catch(e => done(e));
qb.query(createTest)
.then(() => qb.query(createJoin))
.then(() => {
return done();
});
}); });
testRunner(qb); testRunner(qb);

View File

@ -17,6 +17,12 @@ let nodeQuery = reload('../../lib/NodeQuery')(config);
let qb = nodeQuery.getQuery(); let qb = nodeQuery.getQuery();
describe('Mysql2 adapter tests -', () => { describe('Mysql2 adapter tests -', () => {
beforeAll(done => {
qb.queryFile(`${__dirname}/../sql/mysql.sql`)
.then(() => done())
.catch(e => done(e));
});
it('nodeQuery.getQuery = nodeQuery.init', () => { it('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery()) expect(nodeQuery.getQuery())
.to.be.deep.equal(qb); .to.be.deep.equal(qb);

View File

@ -19,6 +19,12 @@ let qb = nodeQuery.getQuery();
let qb2 = null; let qb2 = null;
describe('Pg adapter tests -', () => { describe('Pg adapter tests -', () => {
beforeAll(done => {
qb.queryFile(`${__dirname}/../sql/pgsql.sql`)
.then(() => done())
.catch(e => done(e));
});
it('nodeQuery.getQuery = nodeQuery.init', () => { it('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery()) expect(nodeQuery.getQuery())
.to.be.deep.equal(qb); .to.be.deep.equal(qb);

View File

@ -18,14 +18,9 @@ let qb = nodeQuery.getQuery();
describe('Sqlite3 adapter tests -', () => { describe('Sqlite3 adapter tests -', () => {
beforeAll(done => { beforeAll(done => {
// Set up the sqlite database // Set up the sqlite database
const createTest = 'CREATE TABLE IF NOT EXISTS "create_test" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);'; qb.queryFile(`${__dirname}/../sql/sqlite.sql`)
const createJoin = 'CREATE TABLE IF NOT EXISTS "create_join" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);'; .then(() => done())
.catch(e => done(e));
qb.query(createTest)
.then(() => qb.query(createJoin))
.then(() => {
return done();
});
}); });
testRunner(qb); testRunner(qb);

View File

@ -5,22 +5,22 @@ const chai = require('chai');
const assert = chai.assert; const assert = chai.assert;
const expect = chai.expect; const expect = chai.expect;
let helpers = require('../lib/helpers'); let Helpers = require('../lib/Helpers');
describe('Helper Module Tests -', () => { describe('Helper Module Tests -', () => {
describe('Type-checking methods -', () => { describe('Type-checking methods -', () => {
describe('Object wrappers are listed as their native type', () => { describe('Object wrappers are listed as their native type', () => {
it('Boolean Wrapper returns \'boolean\' not \'object\'', () => { it('Boolean Wrapper returns \'boolean\' not \'object\'', () => {
let item = Boolean(true); let item = Boolean(true);
expect(helpers.type(item)).to.deep.equal('boolean'); expect(Helpers.type(item)).to.deep.equal('boolean');
}); });
it('Number Wrapper returns \'number\' not \'object\'', () => { it('Number Wrapper returns \'number\' not \'object\'', () => {
let item = Number(4867); let item = Number(4867);
expect(helpers.type(item)).to.deep.equal('number'); expect(Helpers.type(item)).to.deep.equal('number');
}); });
it('String Wrapper returns \'string\' not \'object\'', () => { it('String Wrapper returns \'string\' not \'object\'', () => {
let item = String('Foo'); let item = String('Foo');
expect(helpers.type(item)).to.deep.equal('string'); expect(Helpers.type(item)).to.deep.equal('string');
}); });
}); });
describe('is..Method methods exist -', () => { describe('is..Method methods exist -', () => {
@ -40,7 +40,7 @@ describe('Helper Module Tests -', () => {
types.forEach(type => { types.forEach(type => {
it(`is${type} method exists`, () => { it(`is${type} method exists`, () => {
assert.ok(helpers[`is${type}`]); assert.ok(Helpers[`is${type}`]);
}); });
}); });
}); });
@ -52,7 +52,7 @@ describe('Helper Module Tests -', () => {
}; };
Object.keys(trueCases).forEach(desc => { Object.keys(trueCases).forEach(desc => {
it(desc, () => { it(desc, () => {
expect(helpers.isScalar(trueCases[desc])).to.be.true; expect(Helpers.isScalar(trueCases[desc])).to.be.true;
}); });
}); });
@ -62,24 +62,24 @@ describe('Helper Module Tests -', () => {
}; };
Object.keys(falseCases).forEach(desc => { Object.keys(falseCases).forEach(desc => {
it(desc, () => { it(desc, () => {
expect(helpers.isScalar(falseCases[desc])).to.be.false; expect(Helpers.isScalar(falseCases[desc])).to.be.false;
}); });
}); });
}); });
describe('isInfinity -', () => { describe('isInfinity -', () => {
it('The type of 1/0 is infinity', () => { it('The type of 1/0 is infinity', () => {
expect(helpers.type(1 / 0)).to.equal('infinity'); expect(Helpers.type(1 / 0)).to.equal('infinity');
}); });
it('isInfinity is the same as isInfinite', () => { it('isInfinity is the same as isInfinite', () => {
expect(helpers.isInfinite(1 / 0)).to.be.true; expect(Helpers.isInfinite(1 / 0)).to.be.true;
}); });
}); });
describe('isNaN -', () => { describe('isNaN -', () => {
it('The type of 0 / 0 is NaN', () => { it('The type of 0 / 0 is NaN', () => {
expect(helpers.type(0 / 0)).to.equal('nan'); expect(Helpers.type(0 / 0)).to.equal('nan');
}); });
it('isNaN method agrees with type', () => { it('isNaN method agrees with type', () => {
expect(helpers.isNaN(0 / 0)).to.be.true; expect(Helpers.isNaN(0 / 0)).to.be.true;
}); });
}); });
}); });
@ -89,7 +89,7 @@ describe('Helper Module Tests -', () => {
let orig = [' x y ', 'z ', ' q']; let orig = [' x y ', 'z ', ' q'];
let ret = ['x y', 'z', 'q']; let ret = ['x y', 'z', 'q'];
expect(orig.map(helpers.stringTrim)).to.be.deep.equal(ret); expect(orig.map(Helpers.stringTrim)).to.be.deep.equal(ret);
}); });
}); });
describe('arrayPluck -', () => { describe('arrayPluck -', () => {
@ -106,13 +106,13 @@ describe('Helper Module Tests -', () => {
]; ];
it('Finding members in all objects', () => { it('Finding members in all objects', () => {
expect(helpers.arrayPluck(orig, 'foo')).to.be.deep.equal([1, 2, 3]); expect(Helpers.arrayPluck(orig, 'foo')).to.be.deep.equal([1, 2, 3]);
}); });
it('Some members are missing in some objects', () => { it('Some members are missing in some objects', () => {
expect(helpers.arrayPluck(orig, 'bar')).to.be.deep.equal([10, 15]); expect(Helpers.arrayPluck(orig, 'bar')).to.be.deep.equal([10, 15]);
}); });
it('Empty case', () => { it('Empty case', () => {
expect(helpers.arrayPluck([], 'apple')).to.be.deep.equal([]); expect(Helpers.arrayPluck([], 'apple')).to.be.deep.equal([]);
}); });
}); });
describe('regexInArray -', () => { describe('regexInArray -', () => {
@ -133,25 +133,25 @@ describe('Helper Module Tests -', () => {
Object.keys(boolCase).forEach(desc => { Object.keys(boolCase).forEach(desc => {
it(desc, () => { it(desc, () => {
if (i) { if (i) {
expect(helpers.regexInArray(orig, boolCase[desc])).to.be.true; expect(Helpers.regexInArray(orig, boolCase[desc])).to.be.true;
} else { } else {
expect(helpers.regexInArray(orig, boolCase[desc])).to.be.false; expect(Helpers.regexInArray(orig, boolCase[desc])).to.be.false;
} }
}); });
}); });
}); });
it('First argument is not an array', () => { it('First argument is not an array', () => {
expect(helpers.regexInArray(5, /5/)).to.be.false; expect(Helpers.regexInArray(5, /5/)).to.be.false;
}); });
it('Array is empty', () => { it('Array is empty', () => {
expect(helpers.regexInArray([], /.*/)).to.be.false; expect(Helpers.regexInArray([], /.*/)).to.be.false;
}); });
}); });
describe('upperCaseFirst -', () => { describe('upperCaseFirst -', () => {
it('Capitalizes only the first letter of the string', () => { it('Capitalizes only the first letter of the string', () => {
expect(helpers.upperCaseFirst('foobar')).to.equal('Foobar'); expect(Helpers.upperCaseFirst('foobar')).to.equal('Foobar');
expect(helpers.upperCaseFirst('FOOBAR')).to.equal('FOOBAR'); expect(Helpers.upperCaseFirst('FOOBAR')).to.equal('FOOBAR');
}); });
}); });
}); });

View File

@ -3,25 +3,21 @@
-- --
-- Table structure for table `create_join` -- Table structure for table `create_join`
-- --
DROP TABLE IF EXISTS `create_join` CASCADE; DROP TABLE IF EXISTS `create_join` CASCADE;
CREATE TABLE `create_join` ( CREATE TABLE IF NOT EXISTS `create_join` (
`id` int(10) NOT NULL, `id` int(10) PRIMARY KEY NOT NULL,
`key` text, `key` VARCHAR(128),
`val` text `val` MEDIUMTEXT
); );
ALTER TABLE `create_join`
ADD PRIMARY KEY (`id`);
-- --
-- Table structure for table `create_test` -- Table structure for table `create_test`
-- --
DROP TABLE IF EXISTS `create_test` CASCADE; DROP TABLE IF EXISTS `create_test` CASCADE;
CREATE TABLE `create_test` ( CREATE TABLE `create_test` (
`id` int(10) NOT NULL, `id` int(10) NOT NULL,
`key` text, `key` TEXT,
`val` text `val` LONGTEXT
); );
ALTER TABLE `create_test` ALTER TABLE `create_test`
ADD PRIMARY KEY (`id`); ADD PRIMARY KEY (`id`)

View File

@ -13,4 +13,4 @@ CREATE TABLE "create_test" (
id integer NOT NULL, id integer NOT NULL,
key text, key text,
val text val text
); )