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 Class for connection management
**Parameters**
- `config`
## constructor
Constructor
**Parameters**
- `config` **object** connection paramaters
## getQuery ## getQuery
Return an existing query builder instance Return an existing query builder instance

View File

@ -1,5 +1,9 @@
# Changelog # 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 ## 3.2.0
* Added public `query` method for making arbitrary sql calls * 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. * 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'> class='block bold'>
NodeQuery NodeQuery
</a> </a>
<a
href='#NodeQuery.constructor'
class='regular block'>
#constructor
</a>
<a <a
href='#NodeQuery.getQuery' href='#NodeQuery.getQuery'
class='regular block'> class='regular block'>
@ -244,11 +249,50 @@
<div class='px2'> <div class='px2'>
<div class='py1'><section class='py2 clearfix'> <div class='py1'><section class='py2 clearfix'>
<h2 id='NodeQuery' class='mt0'> <h2 id='NodeQuery' class='mt0'>
NodeQuery<span class='gray'></span> NodeQuery<span class='gray'>(config)</span>
</h2> </h2>
<p>Class for connection management</p> <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> <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'> <div class='collapsible' id='NodeQuery.getQuery'>
<a href='#NodeQuery.getQuery'> <a href='#NodeQuery.getQuery'>
<code> <code>

View File

@ -1,8 +1,22 @@
'use strict'; 'use strict';
let fs = require('fs'), const fs = require('fs');
helpers = require('./helpers'), const helpers = require('./helpers');
QueryBuilder = require('./QueryBuilder'); 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 * Class for connection management
@ -12,11 +26,20 @@ class NodeQuery {
/** /**
* Constructor * Constructor
* *
* @private * @param {object} config - connection paramaters
* @constructor * @constructor
*/ */
constructor() { constructor(config) {
this.instance = null; 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'; 'use strict';
let Adapter = require('../Adapter'), const Adapter = require('../Adapter');
getArgs = require('getargs'); 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 * Run the sql query as a prepared statement
* *
@ -40,4 +49,6 @@ module.exports = class nodefirebird extends Adapter {
close() { close() {
this.instance.detach(); this.instance.detach();
} }
}; }
module.exports = Firebird;

View File

@ -1,10 +1,17 @@
'use strict'; 'use strict';
let Adapter = require('../Adapter'), const Adapter = require('../Adapter');
getArgs = require('getargs'), const getArgs = require('getargs');
promisify = require('../promisify'); 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 * 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); return this.instance.execute(args.sql, args.params, args.callback);
} }
}; }
module.exports = Mysql;

View File

@ -1,9 +1,47 @@
'use strict'; 'use strict';
let Adapter = require('../Adapter'), const Adapter = require('../Adapter');
getArgs = require('getargs'); 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 * 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); return this.instance.query(args.sql, args.params, args.callback);
} }
}; }
module.exports = Pg;

View File

@ -1,10 +1,17 @@
'use strict'; 'use strict';
let Adapter = require('../Adapter'), const Adapter = require('../Adapter');
getArgs = require('getargs'), const getArgs = require('getargs');
promisify = require('../promisify'); 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 * Run the sql query as a prepared statement
* *
@ -31,4 +38,6 @@ module.exports = class dblite extends Adapter {
close() { close() {
this.instance.close(); this.instance.close();
} }
}; }
module.exports = Sqlite;

View File

@ -4,95 +4,80 @@
const reload = require('require-reload')(require); const reload = require('require-reload')(require);
reload.emptyCache(); reload.emptyCache();
const testBase = reload('../base'); const testBase = reload('../base');
const expect = testBase.expect, const expect = testBase.expect;
promiseTestRunner = testBase.promiseTestRunner, const promiseTestRunner = testBase.promiseTestRunner;
testRunner = testBase.testRunner; const testRunner = testBase.testRunner;
let tests = reload('../base/tests'); let tests = reload('../base/tests');
// Load the test config file // Load the test config file
let adapterName = 'dblite'; const configFile = (process.env.TRAVIS) ? '../config-travis.json' : '../config.json';
let sqlite = null; const config = reload(configFile);
let connection = null;
// Set up the connection // Set up the query builder object
try { let nodeQuery = require('../../lib/NodeQuery')(config.dblite);
sqlite = require(adapterName).withSQLite('3.7.11'); let qb = nodeQuery.getQuery();
connection = sqlite(':memory:');
} catch (e) {
// Export an empty testsuite if module not loaded
}
if (connection) { suite('Dblite adapter tests -', () => {
// Set up the query builder object suiteSetup(done => {
let nodeQuery = require('../../lib/NodeQuery'); // Set up the sqlite database
let qb = nodeQuery.init('sqlite', connection, adapterName); 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 -', () => { qb.query(sql, () => {
suiteSetup(done => { return 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);
}); });
});
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
Callback Tests Callback Tests
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
testRunner(qb, (err, done) => { testRunner(qb, (err, done) => {
expect(err).is.not.ok; expect(err).is.not.ok;
done(); done();
}); });
test('Callback - Select with function and argument in WHERE clause', done => { test('Callback - Select with function and argument in WHERE clause', done => {
qb.select('id') qb.select('id')
.from('create_test') .from('create_test')
.where('id', 'ABS(-88)') .where('id', 'ABS(-88)')
.get((err, rows) => { .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) => {
expect(err).is.not.ok; expect(err).is.not.ok;
return done(); 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) => {
Promise Tests expect(err).is.not.ok;
---------------------------------------------------------------------------*/ return done();
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;
}); });
}); });
}
/*---------------------------------------------------------------------------
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); const reload = require('require-reload')(require);
reload.emptyCache(); reload.emptyCache();
const testBase = reload('../base'); const testBase = reload('../base');
const expect = testBase.expect, const expect = testBase.expect;
promiseTestRunner = testBase.promiseTestRunner, const promiseTestRunner = testBase.promiseTestRunner;
testRunner = testBase.testRunner; const testRunner = testBase.testRunner;
let getArgs = reload('getargs'); let getArgs = reload('getargs');
@ -16,13 +16,9 @@ let getArgs = reload('getargs');
let adapterName = 'mysql2'; let adapterName = 'mysql2';
let config = reload(configFile)[adapterName]; 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 // Set up the query builder object
let nodeQuery = reload('../../lib/NodeQuery'); let nodeQuery = reload('../../lib/NodeQuery')(config);
let qb = nodeQuery.init('mysql', connection, adapterName); let qb = nodeQuery.getQuery();
qb.query(qb.driver.truncate('create_test')).then(() => { qb.query(qb.driver.truncate('create_test')).then(() => {
suite('Mysql2 adapter tests -', () => { suite('Mysql2 adapter tests -', () => {

View File

@ -14,48 +14,43 @@
let adapterName = 'node-firebird'; let adapterName = 'node-firebird';
let Firebird = reload(adapterName); let Firebird = reload(adapterName);
const config = reload('../config.json')[adapterName]; const config = reload('../config.json')[adapterName];
config.conn.database = path.join(__dirname, config.conn.database); config.connection.database = path.join(__dirname, config.connection.database);
let nodeQuery = reload('../../lib/NodeQuery'); let nodeQuery = reload('../../lib/NodeQuery')(config);
let qb = null; let qb = nodeQuery.getQuery();
// Skip on TravisCi // Skip on TravisCi
if (process.env.CI) { if (process.env.CI) {
return; return;
} }
// Promisifying the connection seems to be the only way to get suite('Firebird adapter tests -', () => {
// this test suite to run consistently. test('nodeQuery.getQuery = nodeQuery.init', () => {
promisify(Firebird.attach)(config.conn).then(db => { expect(nodeQuery.getQuery())
qb = nodeQuery.init('firebird', db, adapterName); .to.be.deep.equal(qb);
suite('Firebird adapter tests -', () => { });
test('nodeQuery.getQuery = nodeQuery.init', () => { test('insertBatch throws error', () => {
expect(nodeQuery.getQuery()) expect(() => {
.to.be.deep.equal(qb); qb.driver.insertBatch('create_test', []);
}); }).to.throw(Error, 'Not Implemented');
test('insertBatch throws error', () => { });
expect(() => {
qb.driver.insertBatch('create_test', []); //---------------------------------------------------------------------------
}).to.throw(Error, 'Not Implemented'); // Callback Tests
}); //---------------------------------------------------------------------------
/*--------------------------------------------------------------------------- testRunner(qb, (err, done) => {
Callback Tests expect(err).is.not.ok;
---------------------------------------------------------------------------*/ done();
testRunner(qb, (err, done) => { });
expect(err).is.not.ok;
done(); //---------------------------------------------------------------------------
}); // Promise Tests
/*--------------------------------------------------------------------------- //---------------------------------------------------------------------------
Promise Tests qb.adapter.execute(qb.driver.truncate('create_test')).then(() => {
---------------------------------------------------------------------------*/ promiseTestRunner(qb);
/*qb.adapter.execute(qb.driver.truncate('create_test')).then(() => { });
promiseTestRunner(qb); suiteTeardown(() => {
});*/ qb.end();
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); const reload = require('require-reload')(require);
reload.emptyCache(); reload.emptyCache();
const testBase = reload('../base'); const testBase = reload('../base');
const expect = testBase.expect, const expect = testBase.expect;
promiseTestRunner = testBase.promiseTestRunner, const promiseTestRunner = testBase.promiseTestRunner;
testRunner = testBase.testRunner; const testRunner = testBase.testRunner;
// Load the test config file // Load the test config file
let adapterName = 'pg'; let adapterName = 'pg';
let config = reload(configFile)[adapterName]; 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 // Set up the query builder object
let nodeQuery = reload('../../lib/NodeQuery'); let nodeQuery = reload('../../lib/NodeQuery')(config);
let qb = nodeQuery.init('pg', connection); let qb = nodeQuery.getQuery();
suite('Pg adapter tests -', () => { suite('Pg adapter tests -', () => {
suiteSetup(done => {
return connection.connect(done);
});
test('nodeQuery.getQuery = nodeQuery.init', () => { test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery()) expect(nodeQuery.getQuery())
.to.be.deep.equal(qb); .to.be.deep.equal(qb);

View File

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

View File

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

View File

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