Merge branch 'develop' of git.timshomepage.net:timw4mail/node-query into develop
This commit is contained in:
commit
26febfd7ab
33
docker-compose.yml
Normal file
33
docker-compose.yml
Normal 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
|
@ -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');
|
||||||
|
@ -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;
|
@ -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: {
|
||||||
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = config => {
|
||||||
|
|
||||||
|
};
|
@ -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 => {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
lib/adapters/Pg/PgNative.js
Normal file
28
lib/adapters/Pg/PgNative.js
Normal 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;
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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 => {
|
||||||
|
17
lib/drivers/MSSQLDriver.js
Normal file
17
lib/drivers/MSSQLDriver.js
Normal 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;
|
||||||
|
})();
|
@ -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\"",
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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`)
|
||||||
|
@ -13,4 +13,4 @@ CREATE TABLE "create_test" (
|
|||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
key text,
|
key text,
|
||||||
val text
|
val text
|
||||||
);
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user