Remove bluebird dependency, add public query method, and re-add tests for node-firebird

This commit is contained in:
Timothy Warren 2016-02-12 11:40:21 -05:00
父節點 383d632bb0
當前提交 0ccd692267
共有 22 個文件被更改,包括 187 次插入101 次删除

查看文件

@ -3,8 +3,15 @@ sudo: false
node_js:
- "node"
- "5.6"
- "5.5"
- "5.4"
- "5.3"
- "5.2"
- "5.1"
- "5.0"
- "4.3"
- "4.2"
- "4.1"
- "4.0"

8
CHANGELOG.md Normal file
查看文件

@ -0,0 +1,8 @@
# Changelog
## 3.2.0
* Added public `query` method for making arbitrary sql calls
* Added back tests for `node-query` adapter. Using this adapter with promises is not currently supported.
## 3.1.0
* Added support for promises on query execution methods

9
LICENSE.md Normal file
查看文件

@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright (c) 2015 Timothy J. Warren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

查看文件

@ -7,6 +7,9 @@ A node query builder for various SQL databases, based on [CodeIgniter](http://ww
[![Code Climate](https://codeclimate.com/github/timw4mail/node-query/badges/gpa.svg)](https://codeclimate.com/github/timw4mail/node-query)
[![Test Coverage](https://codeclimate.com/github/timw4mail/node-query/badges/coverage.svg)](https://codeclimate.com/github/timw4mail/node-query/coverage)
### Features
* Callback and Promise API for making database calls.
### Supported adapters
* mysql
@ -72,7 +75,6 @@ As of version 2, `where` and `having` type methods parse the values passed to lo
* Generated documentation is in the docs/ folder
* The API is documented in [API.md](./API.md)
* `tests/query-builder-base.js` contains a lot of usage examples
* The `tests/adapters` folder contains examples of how to set up a connection for the appropriate database library
* The documentation generated for the latest dev build is also [Available](https://github.timshomepage.net/node-query/docs/)

查看文件

@ -269,9 +269,9 @@ class QueryBuilder {
// Pass the sql and values to the adapter to run on the database
if (callback) {
return this.adapter.execute(sql, vals, callback);
return this.query(sql, vals, callback);
} else {
return this.adapter.execute(sql, vals);
return this.query(sql, vals);
}
}
@ -295,6 +295,19 @@ class QueryBuilder {
// ! Miscellaneous Methods
// ----------------------------------------------------------------------------
/**
* Manually make an sql query
* Returns a promise if no callback is provided
*
* @param {string} sql - The sql to execute
* @param {array} [params] - The query parameters
* @param {function} [callback] - Optional callback
* @return {void|Promise} - Returns a promise if no callback is supplied
*/
query(/*sql:string, [params]:array, [callback]:function*/) {
return this.adapter.execute.apply(this.adapter, arguments);
}
/**
* Reset the object state for a new query
*

查看文件

@ -2,7 +2,7 @@
let Adapter = require('../Adapter'),
getArgs = require('getargs'),
Promise = require('bluebird');
promisify = require('../promisify');
module.exports = class dblite extends Adapter {
/**
@ -15,10 +15,9 @@ module.exports = class dblite extends Adapter {
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params]:array, [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
if (! args.callback) {
return instance.queryAsync(args.sql, args.params);
return promisify(this.instance.query)(args.sql, args.params);
}
return this.instance.query(args.sql, args.params, args.callback);

查看文件

@ -2,7 +2,7 @@
let Adapter = require('../Adapter'),
getArgs = require('getargs'),
Promise = require('bluebird');
promisify = require('../promisify');
module.exports = class mysql extends Adapter {
/**
@ -14,11 +14,10 @@ module.exports = class mysql extends Adapter {
* @return {void|Promise} - Returns a promise if no callback is provided
*/
execute(sql, params, callback) {
let args = getArgs('sql:string, [params], [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
let args = getArgs('sql:string, [params]:array, [callback]:function', arguments);
if (! args.callback) {
return instance.queryAsync(args.sql, args.params);
return promisify(this.instance.query)(args.sql, args.params);
}
return this.instance.query(args.sql, args.params, args.callback);

查看文件

@ -2,7 +2,7 @@
let Adapter = require('../Adapter'),
getArgs = require('getargs'),
Promise = require('bluebird');
promisify = require('../promisify');
module.exports = class mysql2 extends Adapter {
/**
@ -14,11 +14,10 @@ module.exports = class mysql2 extends Adapter {
* @return {void|Promise} - Returns a promise if no callback is provided
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params], [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
let args = getArgs('sql:string, [params]:array, [callback]:function', arguments);
if (! args.callback) {
return instance.executeAsync(args.sql, args.params);
return promisify(this.instance.execute)(args.sql, args.params);
}
return this.instance.execute(args.sql, args.params, args.callback);

查看文件

@ -1,8 +1,7 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs'),
Promise = require('bluebird');
getArgs = require('getargs');
module.exports = class nodefirebird extends Adapter {
/**
@ -15,10 +14,20 @@ module.exports = class nodefirebird extends Adapter {
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params], [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
if (! args.callback) {
return instance.queryAsync(args.sql, args.params);
//return instance.queryAsync(args.sql, args.params);
if (! args.callback) {
return new Promise((resolve, reject) => {
this.instance.query(args.sql, args.params, (err, result) => {
if (err) {
return reject(err);
}
return resolve(result);
});
});
}
}
return this.instance.query(args.sql, args.params, args.callback);

查看文件

@ -1,8 +1,7 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs'),
Promise = require('bluebird');
getArgs = require('getargs');
module.exports = class pg extends Adapter {
/**
@ -15,7 +14,6 @@ module.exports = class pg extends Adapter {
*/
execute(/*sql, params, callback*/) {
let args = getArgs('sql:string, [params]:array, [callback]:function', arguments);
let instance = Promise.promisifyAll(this.instance);
// Replace question marks with numbered placeholders, because this adapter is different...
let count = 0;
@ -25,7 +23,15 @@ module.exports = class pg extends Adapter {
});
if (! args.callback) {
return instance.queryAsync(args.sql, args.params);
return new Promise((resolve, reject) => {
this.instance.query(args.sql, args.params, (err, result) => {
if (err) {
return reject(err);
}
return resolve(result);
});
});
}
return this.instance.query(args.sql, args.params, args.callback);

查看文件

@ -7,7 +7,7 @@ let helpers = require('../helpers');
*
* @module drivers/firebird
*/
module.exports = (function() {
module.exports = (() => {
delete require.cache[require.resolve('../Driver')];
let driver = require('../Driver');
@ -21,7 +21,7 @@ module.exports = (function() {
* @param {Number|null} offset - Number of rows to skip
* @return {String} - Modified SQL statement
*/
driver.limit = function(origSql, limit, offset) {
driver.limit = (origSql, limit, offset) => {
let sql = `FIRST ${limit}`;
if (helpers.isNumber(offset))
@ -38,9 +38,9 @@ module.exports = (function() {
* @return {void}
* @throws {Error}
*/
driver.insertBatch = function() {
driver.insertBatch = () => {
throw new Error('Not Implemented');
};
return driver;
}());
})();

查看文件

@ -5,7 +5,7 @@
*
* @module drivers/mysql
*/
module.exports = (function() {
module.exports = (() => {
delete require.cache[require.resolve('../Driver')];
let driver = require('../Driver'),
helpers = require('../helpers');
@ -21,7 +21,7 @@ module.exports = (function() {
* @param {Number|null} offset - Number of rows to skip
* @return {String} - Modified SQL statement
*/
driver.limit = function(sql, limit, offset) {
driver.limit = (sql, limit, offset) => {
if (! helpers.isNumber(offset)) {
return sql += ` LIMIT ${limit}`;
}
@ -31,4 +31,4 @@ module.exports = (function() {
return driver;
}());
})();

查看文件

@ -5,9 +5,9 @@
*
* @module drivers/pg
*/
module.exports = (function() {
module.exports = (() => {
delete require.cache[require.resolve('../Driver')];
let driver = require('../Driver');
return driver;
}());
})();

26
lib/promisify.js Normal file
查看文件

@ -0,0 +1,26 @@
'use strict';
/*eslint-disable prefer-arrow-callback*/
/**
* Function to convert a callback function into a promise
*
* @see http://eddmann.com/posts/promisifying-error-first-asynchronous-callbacks-in-javascript/
* @example promisify(fs.readFile)('hello.txt', 'utf8')
* .then(console.log)
* .catch(console.error)
* @param {Function} fn - the callback function to convert
* @return {Promise} - the new promise
*/
function promisify(fn) {
return function () {
let args = [].slice.call(arguments);
return new Promise(function(resolve, reject) {
fn.apply(undefined, args.concat((error, value) => {
return error ? reject(error) : resolve(value);
}));
});
};
}
module.exports = promisify;
/*eslint-enable prefer-arrow-callback*/

查看文件

@ -1,6 +1,6 @@
{
"name": "ci-node-query",
"version": "3.1.0",
"version": "3.2.0",
"description": "A query builder for node based on the one in CodeIgniter",
"author": "Timothy J Warren <tim@timshomepage.net>",
"engines": {
@ -36,7 +36,6 @@
},
"main": "lib/NodeQuery.js",
"dependencies": {
"bluebird": "^3.1.4",
"dblite": "~0.7.6",
"getargs": "~0.0.8",
"mysql": "~2.10.2",

查看文件

@ -93,6 +93,6 @@ if (connection) {
.get();
expect(promise).to.be.fulfilled;
});
});
});
}

查看文件

@ -23,30 +23,32 @@ let connection = mysql2.createConnection(config.conn);
// Set up the query builder object
let nodeQuery = reload('../../lib/NodeQuery');
let qb = nodeQuery.init('mysql', connection, adapterName);
qb.query(qb.driver.truncate('create_test')).then(() => {
suite('Mysql2 adapter tests -', () => {
suite('Mysql2 adapter tests -', () => {
require('./mysql-base')(qb, nodeQuery, expect, testRunner, promiseTestRunner);
require('./mysql-base')(qb, nodeQuery, expect, testRunner, promiseTestRunner);
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'),
},
];
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) => {
expect(err).is.not.ok;
return done();
qb.insertBatch('create_test', data, (err, rows) => {
expect(err).is.not.ok;
return done();
});
});
});
});

查看文件

@ -24,29 +24,32 @@ let connection = mysql.createConnection(config.conn);
let nodeQuery = reload('../../lib/NodeQuery');
let qb = nodeQuery.init('mysql', connection);
suite('Mysql adapter tests -', () => {
require('./mysql-base')(qb, nodeQuery, expect, testRunner, promiseTestRunner);
qb.query(qb.driver.truncate('create_test')).then(() => {
suite('Mysql adapter tests -', () => {
test('Test Insert Batch', done => {
let data = [
{
id: 544,
key: 3,
val: new Buffer('7'),
}, {
id: 89,
key: 34,
val: new Buffer('10 o\'clock'),
}, {
id: 48,
key: 403,
val: new Buffer('97'),
},
];
require('./mysql-base')(qb, nodeQuery, expect, testRunner, promiseTestRunner);
qb.insertBatch('create_test', data, (err, rows) => {
expect(err).is.not.ok;
return done();
test('Test Insert Batch', done => {
let data = [
{
id: 544,
key: 3,
val: new Buffer('7'),
}, {
id: 89,
key: 34,
val: new Buffer('10 o\'clock'),
}, {
id: 48,
key: 403,
val: new Buffer('97'),
},
];
qb.insertBatch('create_test', data, (err, rows) => {
expect(err).is.not.ok;
return done();
});
});
});
});

查看文件

@ -4,6 +4,7 @@
const path = require('path');
const reload = require('require-reload')(require);
const testBase = reload('../base');
const promisify = require('../../lib/promisify');
const expect = reload('chai').expect;
const testRunner = testBase.testRunner;
const promiseTestRunner = testBase.promiseTestRunner;
@ -22,19 +23,11 @@ if (process.env.CI || process.env.JENKINS_HOME) {
return;
}
suite('Firebird adapter tests -', () => {
// Set up the query builder object
suiteSetup('Database connection', connected => {
Firebird.attach(config.conn, (err, db) => {
qb = nodeQuery.init('firebird', db, adapterName);
return connected(err);
});
});
testRunner(qb, (err, done) => {
expect(err).is.not.ok;
done();
});
suite('Adapter-specific tests', () => {
// Promisifying the connection seems to be the only way to get
// this test suite to run consistently.
promisify(Firebird.attach)(config.conn).then(db => {
qb = nodeQuery.init('firebird', db, adapterName);
suite('Firebird adapter tests -', () => {
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
@ -44,8 +37,23 @@ suite('Firebird adapter tests -', () => {
qb.driver.insertBatch('create_test', []);
}).to.throw(Error, "Not Implemented");
});
/*---------------------------------------------------------------------------
Callback Tests
---------------------------------------------------------------------------*/
testRunner(qb, (err, done) => {
expect(err).is.not.ok;
done();
});
/*---------------------------------------------------------------------------
Promise Tests
---------------------------------------------------------------------------*/
/*qb.adapter.execute(qb.driver.truncate('create_test')).then(() => {
promiseTestRunner(qb);
});*/
suiteTeardown(() => {
qb.end();
});
});
suiteTeardown(() => {
qb.end();
});
});
}).catch(err => {
throw new Error(err);
});

查看文件

@ -17,17 +17,15 @@ let config = reload(configFile)[adapterName];
// Set up the connection
let pg = reload(adapterName);
let connection = new pg.Client(config.conn);
connection.connect(err => {
if (err) {
throw new Error(err);
}
});
// Set up the query builder object
let nodeQuery = reload('../../lib/NodeQuery');
let qb = nodeQuery.init('pg', connection);
suite('Pg adapter tests -', () => {
suiteSetup(done => {
return connection.connect(done);
});
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);

查看文件

@ -3,10 +3,9 @@
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const expect = chai.expect;
module.exports = {
expect: expect,
expect: chai.expect,
tests: require('./base/tests'),
testRunner: require('./base/adapterCallbackTestRunner'),
promiseTestRunner: require('./base/adapterPromiseTestRunner'),

查看文件

@ -42,7 +42,7 @@ let mixedSet = function mixedSet(/* $letName, $valType, $key, [$val] */) {
return state[args.$letName];
};
let whereMock = function() {
let whereMock = function () {
let args = getArgs('key:string|object, [val]', arguments);
state.whereMap = [];