diff --git a/.gitignore b/.gitignore index f048cf0..ad0960b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ build/* coverage -coverage/* npm-debug.log -tests/FB_TEST_DB.FD -node_modules/* \ No newline at end of file +node_modules/* +.sonar/* \ No newline at end of file diff --git a/API.md b/API.md index eabeb0d..f2be412 100644 --- a/API.md +++ b/API.md @@ -20,20 +20,6 @@ Return an existing query builder instance Returns **QueryBuilder** The Query Builder object -## init - -Create a query builder object - -**Parameters** - -- `driverType` **String** The name of the database type, eg. mysql or pg -- `connObject` **Object** A connection object from the database library - you are connecting with -- `connLib` **[String]** The name of the db connection library you are - using, eg. mysql or mysql2. Optional if the same as driverType - -Returns **QueryBuilder** The Query Builder object - # QueryBuilder Main object that builds SQL queries. @@ -439,6 +425,17 @@ query.set({foo:'bar'}); // Set with an object Returns **QueryBuilder** The Query Builder object, for chaining +## truncate + +Empties the selected database table + +**Parameters** + +- `table` **string** the name of the table to truncate +- `callback` **[function]** Optional callback + +Returns **void or Promise** Returns a promise if no callback is supplied + ## update Run the generated update query diff --git a/CHANGELOG.md b/CHANGELOG.md index 81c51bc..f072bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 4.0.0 * Changed connection setup to just use a config object - the appropriate adapter object is created by the library. * Removed mysql adapter, as mysql2 is very similar and does proper prepared statements +* Removed firebird entirely ## 3.2.0 * Added public `query` method for making arbitrary sql calls diff --git a/README.md b/README.md index c25cdb5..00119bf 100755 --- a/README.md +++ b/README.md @@ -10,13 +10,11 @@ A node query builder for various SQL databases, based on [CodeIgniter](http://ww ### Features * Callback and Promise API for making database calls. -### Supported adapters +### Supported databases -* mysql -* mysql2 -* pg -* dblite -* node-firebird (Not supported as of version 3.1.0, as the adapter is very difficult to test) +* Mysql (via `mysql2`) +* PostgreSQL (via `pg`) +* Sqlite (via `dblite`) ### Installation @@ -26,20 +24,20 @@ A node query builder for various SQL databases, based on [CodeIgniter](http://ww ### Basic use ```javascript -var nodeQuery = require('ci-node-query'); -var connection = ... // Database module connection +// Set the database connection details +const nodeQuery = require('ci-node-query')({ +"driver": "mysql", + "connection": { + "host": "localhost", + "user": "test", + "password": "", + "database": "test" + } +}); -// Three arguments: database type, database connection, database connection library -var query = nodeQuery.init('mysql', connection, 'mysql2'); - -// The third argument is optional if the database connection library has the same name as the adapter, eg.. -nodeQuery.init('mysql', connection, 'mysql'); -// Can be instead -nodeQuery.init('mysql', connection); - -// You can also retrieve the instance later -query = nodeQuery.getQuery(); +// Get the query builder +const query = nodeQuery.getQuery(); query.select('foo') .from('bar') diff --git a/docs/index.html b/docs/index.html index 9157b7d..151689e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -37,11 +37,6 @@ class='regular block'> #getQuery - - #init - @@ -212,6 +207,11 @@ class='regular block'> #set + + #truncate + @@ -320,59 +320,6 @@ -
- - - #init(driverType, connObject, [connLib]) - -
-

Create a query builder object

- -
-
-
-
-

- init(driverType, connObject, [connLib]) -

-

Create a query builder object

- -

Parameters

-
    -
  • String driverType - : -
    -

    The name of the database type, eg. mysql or pg

    - -
    -
  • -
  • Object connObject - : -
    -

    A connection object from the database library - you are connecting with

    - -
    -
  • -
  • [String] connLib - : -
    -

    The name of the db connection library you are - using, eg. mysql or mysql2. Optional if the same as driverType

    - -
    -
  • -
-

Returns

- QueryBuilder - : -
-

The Query Builder object

- -
-
-
-

@@ -1813,6 +1760,50 @@ prefixed with 'OR NOT'

+
+ + + #truncate(table, [callback]) + +
+

Empties the selected database table

+ +
+
+
+
+

+ truncate(table, [callback]) +

+

Empties the selected database table

+ +

Parameters

+
    +
  • string table + : +
    +

    the name of the table to truncate

    + +
    +
  • +
  • [function] callback + : +
    +

    Optional callback

    + +
    +
  • +
+

Returns

+ void or Promise + : +
+

Returns a promise if no callback is supplied

+ +
+
+
+
diff --git a/gulpfile.js b/gulpfile.js index c0a84e8..f44752f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -62,11 +62,11 @@ gulp.task('mocha', ['lint-tests', 'sloc'], () => { return gulp.src(TEST_FILES) .pipe(mocha(MOCHA_OPTIONS)) .once('error', () => { - process.exit(1); - }) + process.exit(1); + }) .once('end', () => { - process.exit(); - }); + process.exit(); + }); }); gulp.task('test', ['test-sloc', 'lint-tests'], function(cb) { @@ -78,14 +78,8 @@ gulp.task('test', ['test-sloc', 'lint-tests'], function(cb) { mocha(MOCHA_OPTIONS), istanbul.writeReports({ dir: './coverage', - reporters: ['clover', 'lcov', 'lcovonly', 'html', 'text'] - }) - .once('error', () => { - process.exit(1); - }) - .once('end', () => { - process.exit(); - }) + reporters: ['clover', 'lcov', 'lcovonly', 'html', 'text'], + }), ]); }); }); diff --git a/lib/NodeQuery.js b/lib/NodeQuery.js index eb0de18..c2ccd30 100755 --- a/lib/NodeQuery.js +++ b/lib/NodeQuery.js @@ -34,6 +34,11 @@ class NodeQuery { if (config != null) { let drivername = dbDriverMap.get(config.driver); + + if (! drivername) { + throw new Error(`Selected driver (${config.driver}) does not exist!`); + } + let driver = require(`./drivers/${drivername}`); let $adapter = require(`./adapters/${drivername}`); @@ -42,43 +47,6 @@ class NodeQuery { } } - /** - * Create a query builder object - * - * @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 driverType - * @return {QueryBuilder} - The Query Builder object - */ - init(driverType, connObject, connLib) { - connLib = connLib || driverType; - - let paths = { - driver: `${__dirname}/drivers/${helpers.upperCaseFirst(driverType)}`, - adapter: `${__dirname}/adapters/${connLib}`, - }; - - Object.keys(paths).forEach(type => { - try { - fs.statSync(`${paths[type]}.js`); - } catch (e) { - throw new Error( - `Selected ${type} (${helpers.upperCaseFirst(driverType)}) does not exist!` - ); - } - }); - - let driver = require(paths.driver); - let $adapter = require(paths.adapter); - let adapter = new $adapter(connObject); - - this.instance = new QueryBuilder(driver, adapter); - - return this.instance; - } - /** * Return an existing query builder instance * diff --git a/lib/QueryBuilder.js b/lib/QueryBuilder.js index d097b2a..9831372 100755 --- a/lib/QueryBuilder.js +++ b/lib/QueryBuilder.js @@ -339,6 +339,21 @@ class QueryBuilder extends QueryBuilderBase { return this.state; } + /** + * Empties the selected database table + * + * @param {string} table - the name of the table to truncate + * @param {function} [callback] - Optional callback + * @return {void|Promise} - Returns a promise if no callback is supplied + */ + truncate(/*table:string, [callback]:function*/) { + getArgs('table:string, [callback]:function', arguments); + let args = [].slice.apply(arguments); + let sql = this.driver.truncate(args.shift()); + args.unshift(sql); + return this.query.apply(this, args); + } + /** * Closes the database connection for the current adapter * diff --git a/lib/adapters/Mysql.js b/lib/adapters/Mysql.js index dc0e2ae..0db7089 100644 --- a/lib/adapters/Mysql.js +++ b/lib/adapters/Mysql.js @@ -29,7 +29,15 @@ class Mysql extends Adapter { let args = getArgs('sql:string, [params]:array, [callback]:function', arguments); if (! args.callback) { - return promisify(this.instance.execute)(args.sql, args.params); + return new Promise((resolve, reject) => { + this.instance.execute(args.sql, args.params, (err, result) => { + if (err) { + return reject(err); + } + + return resolve(result); + }); + }); } return this.instance.execute(args.sql, args.params, args.callback); diff --git a/lib/adapters/Sqlite.js b/lib/adapters/Sqlite.js index 02f7e0f..69d3e04 100644 --- a/lib/adapters/Sqlite.js +++ b/lib/adapters/Sqlite.js @@ -10,6 +10,9 @@ class Sqlite extends Adapter { constructor(config) { let file = (helpers.isString(config)) ? config : config.file; super(dbliteAdapter(file)); + + // Stop the stupid 'bye bye' message being output + this.instance.on('close', () => {}); } /** diff --git a/test/adapters/dblite_test.js b/test/adapters/dblite_test.js index 678e456..ccb20ee 100644 --- a/test/adapters/dblite_test.js +++ b/test/adapters/dblite_test.js @@ -78,4 +78,29 @@ CREATE TABLE IF NOT EXISTS "create_join" ("id" INTEGER PRIMARY KEY, "key" TEXT, expect(promise).to.be.fulfilled; }); + test('Promise - Test Insert Batch', () => { + 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'), + }, + ]; + + let promise = qb.query(qb.driver.truncate('create_test')).then( + () => qb.insertBatch('create_test', data) + ); + expect(promise).to.be.fulfilled; + }); + suiteTeardown(() => { + qb.end(); + }); }); diff --git a/test/adapters/mysql2_test.js b/test/adapters/mysql2_test.js index 770e43c..dbb970c 100644 --- a/test/adapters/mysql2_test.js +++ b/test/adapters/mysql2_test.js @@ -10,8 +10,6 @@ const expect = testBase.expect; const promiseTestRunner = testBase.promiseTestRunner; const testRunner = testBase.testRunner; -let getArgs = reload('getargs'); - // Load the test config file let adapterName = 'mysql2'; let config = reload(configFile)[adapterName]; @@ -19,69 +17,89 @@ let config = reload(configFile)[adapterName]; // Set up the query builder object let nodeQuery = reload('../../lib/NodeQuery')(config); let qb = nodeQuery.getQuery(); -qb.query(qb.driver.truncate('create_test')).then(() => { - suite('Mysql2 adapter tests -', () => { - test('nodeQuery.getQuery = nodeQuery.init', () => { - expect(nodeQuery.getQuery()) - .to.be.deep.equal(qb); - }); +suite('Mysql2 adapter tests -', () => { - /*--------------------------------------------------------------------------- - 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(); - }); - }); + suiteSetup(() => qb.truncate('create_test')); - /*--------------------------------------------------------------------------- - 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(); + test('nodeQuery.getQuery = nodeQuery.init', () => { + expect(nodeQuery.getQuery()) + .to.be.deep.equal(qb); + }); - expect(promise).to.be.fulfilled; - }); - - suiteTeardown(() => { - qb.end(); - }); - - test('Test Insert Batch', done => { - let data = [ - { - id: 5441, - key: 3, - val: new Buffer('7'), - }, { - id: 891, - key: 34, - val: new Buffer('10 o\'clock'), - }, { - id: 481, - key: 403, - val: new Buffer('97'), - }, - ]; - - qb.insertBatch('create_test', data, (err, rows) => { + //-------------------------------------------------------------------------- + // Callback Tests + //-------------------------------------------------------------------------- + testRunner(qb, (err, done) => { + expect(err).is.not.ok; + return done(err); + }); + 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('Callback - Test Insert Batch', done => { + let data = [ + { + id: 5441, + key: 3, + val: new Buffer('7'), + }, { + id: 891, + key: 34, + val: new Buffer('10 o\'clock'), + }, { + id: 481, + key: 403, + val: new Buffer('97'), + }, + ]; + + qb.insertBatch('create_test', data, (err, res) => { + expect(err).is.not.ok; + return done(err); }); }); -}); \ No newline at end of file + + //--------------------------------------------------------------------------- + // 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(); + + return expect(promise).to.be.fulfilled; + }); + + test('Test Insert Batch', () => { + let data = [ + { + id: 5442, + key: 4, + val: new Buffer('7'), + }, { + id: 892, + key: 35, + val: new Buffer('10 o\'clock'), + }, { + id: 482, + key: 404, + val: 97, + }, + ]; + + return expect(qb.insertBatch('create_test', data)).to.be.fulfilled; + }); + + suiteTeardown(() => { + qb.end(); + }); +}); diff --git a/test/adapters/pg_test.js b/test/adapters/pg_test.js index becb2f2..db159fc 100644 --- a/test/adapters/pg_test.js +++ b/test/adapters/pg_test.js @@ -12,11 +12,13 @@ const testRunner = testBase.testRunner; // Load the test config file let adapterName = 'pg'; -let config = reload(configFile)[adapterName]; +let allConfig = reload(configFile); +let config = allConfig[adapterName]; // Set up the query builder object let nodeQuery = reload('../../lib/NodeQuery')(config); let qb = nodeQuery.getQuery(); +let qb2 = null; suite('Pg adapter tests -', () => { test('nodeQuery.getQuery = nodeQuery.init', () => { @@ -24,26 +26,57 @@ suite('Pg adapter tests -', () => { .to.be.deep.equal(qb); }); - /*--------------------------------------------------------------------------- - Callback Tests - ---------------------------------------------------------------------------*/ + test('Connecting with an object also works', () => { + let config = allConfig[`${adapterName}-object`]; + let nodeQuery = reload('../../lib/NodeQuery')(config); + qb2 = nodeQuery.getQuery(); + + return expect(qb2).to.be.ok; + }); + + //-------------------------------------------------------------------------- + // Callback Tests + //-------------------------------------------------------------------------- testRunner(qb, (err, done) => { expect(err).is.not.ok; - done(); + return done(err); }); 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(rows).is.ok; expect(err).is.not.ok; - return done(); + return done(err); }); }); + test('Callback - Test Insert Batch', done => { + let data = [ + { + id: 5441, + key: 3, + val: new Buffer('7'), + }, { + id: 891, + key: 34, + val: new Buffer('10 o\'clock'), + }, { + id: 481, + key: 403, + val: new Buffer('97'), + }, + ]; - /*--------------------------------------------------------------------------- - Promise Tests - ---------------------------------------------------------------------------*/ + qb.insertBatch('create_test', data, (err, res) => { + expect(err).is.not.ok; + return done(err); + }); + }); + + //-------------------------------------------------------------------------- + // Promise Tests + //-------------------------------------------------------------------------- promiseTestRunner(qb); test('Promise - Select with function and argument in WHERE clause', () => { let promise = qb.select('id') @@ -51,7 +84,7 @@ suite('Pg adapter tests -', () => { .where('id', 'CEILING(SQRT(88))') .get(); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Test Insert Batch', () => { let data = [ @@ -73,4 +106,8 @@ suite('Pg adapter tests -', () => { let promise = qb.insertBatch('create_test', data); return expect(promise).to.be.fulfilled; }); + suiteTeardown(() => { + qb.end(); + qb2.end(); + }); }); \ No newline at end of file diff --git a/test/base/adapterCallbackTestRunner.js b/test/base/adapterCallbackTestRunner.js index 4555cd0..2ad2d27 100644 --- a/test/base/adapterCallbackTestRunner.js +++ b/test/base/adapterCallbackTestRunner.js @@ -46,12 +46,7 @@ module.exports = function testRunner(qb, callback) { }); }); suite('DB update tests -', () => { - setup(done => { - let sql = qb.driver.truncate('create_test'); - qb.adapter.execute(sql, (err, res) => { - done(); - }); - }); + suiteSetup(() => qb.truncate('create_test')); test('Callback - Test Insert', done => { qb.set('id', 98) .set('key', '84') @@ -184,32 +179,32 @@ module.exports = function testRunner(qb, callback) { .from('create_test') .getCompiledSelect(true); - expect(helpers.isString(sql)).to.be.true; + return 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; + return 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; + return 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; + return 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; + return expect(helpers.isString(sql)).to.be.true; }); }); suite('Misc tests -', () => { diff --git a/test/base/adapterPromiseTestRunner.js b/test/base/adapterPromiseTestRunner.js index 4ccc9da..91865ca 100644 --- a/test/base/adapterPromiseTestRunner.js +++ b/test/base/adapterPromiseTestRunner.js @@ -40,7 +40,7 @@ module.exports = function promiseTestRunner(qb) { }); let promise = results.pop(); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); }); }); @@ -48,7 +48,7 @@ module.exports = function promiseTestRunner(qb) { suite('DB update tests -', () => { suiteSetup(done => { let sql = qb.driver.truncate('create_test'); - qb.adapter.execute(sql).then(res => { + qb.query(sql).then(res => { return done(); }).catch(err => { return done(err); @@ -60,7 +60,7 @@ module.exports = function promiseTestRunner(qb) { .set('val', new Buffer('120')) .insert('create_test'); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Test Insert Object', () => { let promise = qb.insert('create_test', { @@ -69,7 +69,7 @@ module.exports = function promiseTestRunner(qb) { val: new Buffer('2'), }); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Test Update', () => { let promise = qb.where('id', 7) @@ -79,7 +79,7 @@ module.exports = function promiseTestRunner(qb) { val: new Buffer('non-word'), }); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Test set Array Update', () => { let object = { @@ -92,7 +92,7 @@ module.exports = function promiseTestRunner(qb) { .where('id', 22) .update('create_test'); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Test where set update', () => { let promise = qb.where('id', 36) @@ -101,17 +101,17 @@ module.exports = function promiseTestRunner(qb) { .set('val', new Buffer('non-word')) .update('create_test'); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Test delete', () => { let promise = qb.delete('create_test', {id: 5}); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Delete with where', () => { let promise = qb.where('id', 5) .delete('create_test'); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Delete multiple where values', () => { let promise = qb.delete('create_test', { @@ -119,7 +119,7 @@ module.exports = function promiseTestRunner(qb) { key: 'gogle', }); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); }); suite('Grouping tests -', () => { @@ -133,7 +133,7 @@ module.exports = function promiseTestRunner(qb) { .limit(2, 1) .get(); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Using where first grouping', () => { let promise = qb.select('id, key as k, val') @@ -146,7 +146,7 @@ module.exports = function promiseTestRunner(qb) { .limit(2, 1) .get(); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Using or grouping method', () => { let promise = qb.select('id, key as k, val') @@ -161,7 +161,7 @@ module.exports = function promiseTestRunner(qb) { .limit(2, 1) .get(); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); test('Promise - Using or not grouping method', () => { let promise = qb.select('id, key as k, val') @@ -176,7 +176,7 @@ module.exports = function promiseTestRunner(qb) { .limit(2, 1) .get(); - expect(promise).to.be.fulfilled; + return expect(promise).to.be.fulfilled; }); }); }; \ No newline at end of file diff --git a/test/base_test.js b/test/base_test.js index e8ccfb9..b885692 100644 --- a/test/base_test.js +++ b/test/base_test.js @@ -30,7 +30,9 @@ suite('Base tests -', () => { test('Invalid driver type', () => { expect(() => { - nodeQuery.init('foo', {}, 'bar'); + reload('../lib/NodeQuery')({ + driver: 'Foo', + }); }).to.throw(Error, 'Selected driver (Foo) does not exist!'); }); diff --git a/test/config-travis.json b/test/config-travis.json index ad84944..2c325ba 100644 --- a/test/config-travis.json +++ b/test/config-travis.json @@ -15,9 +15,6 @@ "pg-object": { "driver": "pg", "connection": { - "host": "localhost", - "user": "postgres", - "password": "", "database": "test" } }, diff --git a/test/config.json b/test/config.json index de8c08c..f1771f4 100644 --- a/test/config.json +++ b/test/config.json @@ -15,9 +15,6 @@ "pg-object": { "driver": "pg", "connection": { - "host": "localhost", - "user": "test", - "password": "test", "database": "test" } }, diff --git a/test/helpers_test.js b/test/helpers_test.js index ae60d5f..2e5a0b6 100644 --- a/test/helpers_test.js +++ b/test/helpers_test.js @@ -148,5 +148,11 @@ suite('Helper Module Tests -', () => { expect(helpers.regexInArray([], /.*/)).to.be.false; }); }); + suite('upperCaseFirst -', () => { + test('Capitalizes only the first letter of the string', () => { + expect(helpers.upperCaseFirst('foobar')).to.equal('Foobar'); + expect(helpers.upperCaseFirst('FOOBAR')).to.equal('FOOBAR'); + }); + }); }); });