First version with library-managed connections

This commit is contained in:
Timothy Warren 2016-03-11 10:41:04 -05:00
parent 26e3bdbf50
commit 5ecd9d523a
15 changed files with 305 additions and 182 deletions

12
API.md
View File

@ -2,6 +2,18 @@
Class for connection management
**Parameters**
- `config`
## constructor
Constructor
**Parameters**
- `config` **object** connection paramaters
## getQuery
Return an existing query builder instance

View File

@ -1,5 +1,9 @@
# Changelog
## 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
## 3.2.0
* Added public `query` method for making arbitrary sql calls
* Added back tests for `node-firebird` adapter. Using this adapter with promises is not currently supported.

View File

@ -27,6 +27,11 @@
class='block bold'>
NodeQuery
</a>
<a
href='#NodeQuery.constructor'
class='regular block'>
#constructor
</a>
<a
href='#NodeQuery.getQuery'
class='regular block'>
@ -244,11 +249,50 @@
<div class='px2'>
<div class='py1'><section class='py2 clearfix'>
<h2 id='NodeQuery' class='mt0'>
NodeQuery<span class='gray'></span>
NodeQuery<span class='gray'>(config)</span>
</h2>
<p>Class for connection management</p>
<h4>Parameters</h4>
<ul class='suppress-p-margin'>
<li> <strong>config</strong>
:
<div class='force-inline'>
</div>
</li>
</ul>
<h4>Instance members</h4>
<div class='collapsible' id='NodeQuery.constructor'>
<a href='#NodeQuery.constructor'>
<code>
#constructor<span class='gray'>(config)</span>
</code>
<div class='force-inline'>
<p>Constructor</p>
</div>
</a>
<div class='collapser border px2'>
<section class='py2 clearfix'>
<h2 id='NodeQuery.constructor' class='mt0'>
constructor<span class='gray'>(config)</span>
</h2>
<p>Constructor</p>
<h4>Parameters</h4>
<ul class='suppress-p-margin'>
<li><code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">object</a></code> <strong>config</strong>
:
<div class='force-inline'>
<p>connection paramaters</p>
</div>
</li>
</ul>
</section>
</div>
</div>
<div class='collapsible' id='NodeQuery.getQuery'>
<a href='#NodeQuery.getQuery'>
<code>

View File

@ -1,8 +1,22 @@
'use strict';
let fs = require('fs'),
helpers = require('./helpers'),
QueryBuilder = require('./QueryBuilder');
const fs = require('fs');
const helpers = require('./helpers');
const QueryBuilder = require('./QueryBuilder');
// Map config driver name to code class name
const dbDriverMap = new Map([
['my', 'Mysql'],
['mysql', 'Mysql'],
['maria', 'Mysql'],
['mariadb', 'Mysql'],
['firebird', 'Firebird'],
['postgresql', 'Pg'],
['postgres', 'Pg'],
['pg', 'Pg'],
['sqlite3', 'Sqlite'],
['sqlite', 'Sqlite'],
]);
/**
* Class for connection management
@ -12,11 +26,20 @@ class NodeQuery {
/**
* Constructor
*
* @private
* @param {object} config - connection paramaters
* @constructor
*/
constructor() {
constructor(config) {
this.instance = null;
if (config != null) {
let drivername = dbDriverMap.get(config.driver);
let driver = require(`./drivers/${drivername}`);
let $adapter = require(`./adapters/${drivername}`);
let adapter = new $adapter(config.connection);
this.instance = new QueryBuilder(driver, adapter);
}
}
/**
@ -70,4 +93,6 @@ class NodeQuery {
}
}
module.exports = new NodeQuery();
module.exports = (config => {
return new NodeQuery(config);
});

View File

@ -1,9 +1,18 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs');
const Adapter = require('../Adapter');
const getArgs = require('getargs');
const fb = require('node-firebird');
class Firebird extends Adapter {
constructor(config) {
super({});
fb.attach(config, (err, instance) => {
this.instance = instance;
});
}
module.exports = class nodefirebird extends Adapter {
/**
* Run the sql query as a prepared statement
*
@ -40,4 +49,6 @@ module.exports = class nodefirebird extends Adapter {
close() {
this.instance.detach();
}
};
}
module.exports = Firebird;

View File

@ -1,10 +1,17 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs'),
promisify = require('../promisify');
const Adapter = require('../Adapter');
const getArgs = require('getargs');
const promisify = require('../promisify');
const mysql2 = require('mysql2');
class Mysql extends Adapter {
constructor(config) {
let instance = mysql2.createConnection(config);
super(instance);
}
module.exports = class mysql2 extends Adapter {
/**
* Run the sql query as a prepared statement
*
@ -22,4 +29,6 @@ module.exports = class mysql2 extends Adapter {
return this.instance.execute(args.sql, args.params, args.callback);
}
};
}
module.exports = Mysql;

View File

@ -1,9 +1,47 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs');
const Adapter = require('../Adapter');
const getArgs = require('getargs');
const helpers = require('../helpers');
const pg = require('pg');
const url = require('url');
class Pg extends Adapter {
constructor(config) {
let instance = null;
let connectionString = '';
if (helpers.isObject(config)) {
let host = config.host || 'localhost';
let user = config.user || 'postgres';
let password = `:${config.password}` || '';
let port = config.port || 5432;
let conn = {
protocol: 'postgres',
slashes: true,
host: `${host}:${port}`,
auth: `${user}${password}`,
pathname: config.database,
};
connectionString = url.format(conn);
} else if (helpers.isString(config)) {
connectionString = config;
}
if (connectionString !== '') {
let connected = false;
instance = new pg.Client(connectionString);
instance.connect(err => {
connected = true;
});
}
super(instance);
}
module.exports = class pg extends Adapter {
/**
* Run the sql query as a prepared statement
*
@ -36,4 +74,6 @@ module.exports = class pg extends Adapter {
return this.instance.query(args.sql, args.params, args.callback);
}
};
}
module.exports = Pg;

View File

@ -1,10 +1,17 @@
'use strict';
let Adapter = require('../Adapter'),
getArgs = require('getargs'),
promisify = require('../promisify');
const Adapter = require('../Adapter');
const getArgs = require('getargs');
const helpers = require('../helpers');
const promisify = require('../promisify');
const dbliteAdapter = require('dblite');
class Sqlite extends Adapter {
constructor(config) {
let file = (helpers.isString(config)) ? config : config.file;
super(dbliteAdapter(file));
}
module.exports = class dblite extends Adapter {
/**
* Run the sql query as a prepared statement
*
@ -31,4 +38,6 @@ module.exports = class dblite extends Adapter {
close() {
this.instance.close();
}
};
}
module.exports = Sqlite;

View File

@ -4,95 +4,80 @@
const reload = require('require-reload')(require);
reload.emptyCache();
const testBase = reload('../base');
const expect = testBase.expect,
promiseTestRunner = testBase.promiseTestRunner,
testRunner = testBase.testRunner;
const expect = testBase.expect;
const promiseTestRunner = testBase.promiseTestRunner;
const testRunner = testBase.testRunner;
let tests = reload('../base/tests');
// Load the test config file
let adapterName = 'dblite';
let sqlite = null;
let connection = null;
const configFile = (process.env.TRAVIS) ? '../config-travis.json' : '../config.json';
const config = reload(configFile);
// Set up the connection
try {
sqlite = require(adapterName).withSQLite('3.7.11');
connection = sqlite(':memory:');
} catch (e) {
// Export an empty testsuite if module not loaded
}
// Set up the query builder object
let nodeQuery = require('../../lib/NodeQuery')(config.dblite);
let qb = nodeQuery.getQuery();
if (connection) {
// Set up the query builder object
let nodeQuery = require('../../lib/NodeQuery');
let qb = nodeQuery.init('sqlite', connection, adapterName);
suite('Dblite adapter tests -', () => {
suiteSetup(done => {
// Set up the sqlite database
let sql = `CREATE TABLE IF NOT EXISTS "create_test" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);
CREATE TABLE IF NOT EXISTS "create_join" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);`;
suite('Dblite adapter tests -', () => {
suiteSetup(done => {
// Set up the sqlite database
let sql = 'CREATE TABLE IF NOT EXISTS "create_test" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);' +
'CREATE TABLE IF NOT EXISTS "create_join" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);';
connection.query(sql, () => {
return done();
});
});
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
qb.query(sql, () => {
return done();
});
});
/*---------------------------------------------------------------------------
Callback 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', 'ABS(-88)')
.get((err, rows) => {
expect(err).is.not.ok;
return done();
});
});
test('Callback - 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) => {
testRunner(qb, (err, done) => {
expect(err).is.not.ok;
done();
});
test('Callback - Select with function and argument in WHERE clause', done => {
qb.select('id')
.from('create_test')
.where('id', 'ABS(-88)')
.get((err, rows) => {
expect(err).is.not.ok;
return done();
});
});
});
test('Callback - Test Insert Batch', done => {
let data = [
{
id: 544,
key: 3,
val: new Buffer('7'),
}, {
id: 89,
key: 34,
val: new Buffer('10 o\'clock'),
}, {
id: 48,
key: 403,
val: new Buffer('97'),
},
];
/*---------------------------------------------------------------------------
Promise Tests
---------------------------------------------------------------------------*/
promiseTestRunner(qb);
test('Promise - Select with function and argument in WHERE clause', () => {
let promise = qb.select('id')
.from('create_test')
.where('id', 'ABS(-88)')
.get();
expect(promise).to.be.fulfilled;
qb.insertBatch('create_test', data, (err, rows) => {
expect(err).is.not.ok;
return done();
});
});
}
/*---------------------------------------------------------------------------
Promise Tests
---------------------------------------------------------------------------*/
promiseTestRunner(qb);
test('Promise - Select with function and argument in WHERE clause', () => {
let promise = qb.select('id')
.from('create_test')
.where('id', 'ABS(-88)')
.get();
expect(promise).to.be.fulfilled;
});
});

View File

@ -6,9 +6,9 @@ const configFile = (process.env.TRAVIS) ? '../config-travis.json' : '../config.j
const reload = require('require-reload')(require);
reload.emptyCache();
const testBase = reload('../base');
const expect = testBase.expect,
promiseTestRunner = testBase.promiseTestRunner,
testRunner = testBase.testRunner;
const expect = testBase.expect;
const promiseTestRunner = testBase.promiseTestRunner;
const testRunner = testBase.testRunner;
let getArgs = reload('getargs');
@ -16,13 +16,9 @@ let getArgs = reload('getargs');
let adapterName = 'mysql2';
let config = reload(configFile)[adapterName];
// Set up the connection
let mysql2 = reload(adapterName);
let connection = mysql2.createConnection(config.conn);
// Set up the query builder object
let nodeQuery = reload('../../lib/NodeQuery');
let qb = nodeQuery.init('mysql', connection, adapterName);
let nodeQuery = reload('../../lib/NodeQuery')(config);
let qb = nodeQuery.getQuery();
qb.query(qb.driver.truncate('create_test')).then(() => {
suite('Mysql2 adapter tests -', () => {

View File

@ -14,48 +14,43 @@
let adapterName = 'node-firebird';
let Firebird = reload(adapterName);
const config = reload('../config.json')[adapterName];
config.conn.database = path.join(__dirname, config.conn.database);
let nodeQuery = reload('../../lib/NodeQuery');
config.connection.database = path.join(__dirname, config.connection.database);
let nodeQuery = reload('../../lib/NodeQuery')(config);
let qb = null;
let qb = nodeQuery.getQuery();
// Skip on TravisCi
if (process.env.CI) {
return;
}
// 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);
});
test('insertBatch throws error', () => {
expect(() => {
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();
});
suite('Firebird adapter tests -', () => {
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
});
test('insertBatch throws error', () => {
expect(() => {
qb.driver.insertBatch('create_test', []);
}).to.throw(Error, 'Not Implemented');
});
//---------------------------------------------------------------------------
// 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();
});
}).catch(err => {
throw new Error(err);
});
})();

View File

@ -6,26 +6,19 @@ let configFile = (process.env.CI) ? '../config-travis.json' : '../config.json';
const reload = require('require-reload')(require);
reload.emptyCache();
const testBase = reload('../base');
const expect = testBase.expect,
promiseTestRunner = testBase.promiseTestRunner,
testRunner = testBase.testRunner;
const expect = testBase.expect;
const promiseTestRunner = testBase.promiseTestRunner;
const testRunner = testBase.testRunner;
// Load the test config file
let adapterName = 'pg';
let config = reload(configFile)[adapterName];
// Set up the connection
let pg = reload(adapterName);
let connection = new pg.Client(config.conn);
// Set up the query builder object
let nodeQuery = reload('../../lib/NodeQuery');
let qb = nodeQuery.init('pg', connection);
let nodeQuery = reload('../../lib/NodeQuery')(config);
let qb = nodeQuery.getQuery();
suite('Pg adapter tests -', () => {
suiteSetup(done => {
return connection.connect(done);
});
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);

View File

@ -3,7 +3,7 @@
let expect = require('chai').expect,
reload = require('require-reload')(require),
glob = require('glob'),
nodeQuery = reload('../lib/NodeQuery'),
nodeQuery = reload('../lib/NodeQuery')(),
Adapter = reload('../lib/Adapter');
suite('Base tests -', () => {

View File

@ -1,16 +1,7 @@
{
"mysql": {
"driver": "mysql",
"conn": {
"host": "localhost",
"user": "root",
"password": "",
"database": "test"
}
},
"mysql2": {
"driver": "mysql",
"conn": {
"connection": {
"host": "localhost",
"user": "root",
"password": "",
@ -21,6 +12,15 @@
"driver": "pg",
"conn": "postgres://postgres@localhost/test"
},
"pg-object": {
"driver": "pg",
"connection": {
"host": "localhost",
"user": "postgres",
"password": "",
"database": "test"
}
},
"dblite": {
"driver": "sqlite",
"conn": ":memory:"

View File

@ -1,16 +1,7 @@
{
"mysql": {
"driver": "mysql",
"conn": {
"host": "localhost",
"user": "test",
"password": "",
"database": "test"
}
},
"mysql2": {
"driver": "mysql",
"conn": {
"connection": {
"host": "localhost",
"user": "test",
"password": "",
@ -19,15 +10,24 @@
},
"pg": {
"driver": "pg",
"conn": "postgres://test:test@localhost/test"
"connection": "postgres://test:test@localhost/test"
},
"pg-object": {
"driver": "pg",
"connection": {
"host": "localhost",
"user": "test",
"password": "test",
"database": "test"
}
},
"dblite": {
"driver": "sqlite",
"conn": ":memory:"
"connection": ":memory:"
},
"node-firebird": {
"driver": "firebird",
"conn": {
"connection": {
"host": "127.0.0.1",
"database": "/../FB_TEST_DB.FDB",
"user": "SYSDBA",