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

@ -26,6 +26,11 @@
href='#NodeQuery' href='#NodeQuery'
class='block bold'> class='block bold'>
NodeQuery NodeQuery
</a>
<a
href='#NodeQuery.constructor'
class='regular block'>
#constructor
</a> </a>
<a <a
href='#NodeQuery.getQuery' href='#NodeQuery.getQuery'
@ -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,43 +4,29 @@
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
try {
sqlite = require(adapterName).withSQLite('3.7.11');
connection = sqlite(':memory:');
} catch (e) {
// Export an empty testsuite if module not loaded
}
if (connection) {
// Set up the query builder object // Set up the query builder object
let nodeQuery = require('../../lib/NodeQuery'); let nodeQuery = require('../../lib/NodeQuery')(config.dblite);
let qb = nodeQuery.init('sqlite', connection, adapterName); let qb = nodeQuery.getQuery();
suite('Dblite adapter tests -', () => { suite('Dblite adapter tests -', () => {
suiteSetup(done => { suiteSetup(done => {
// Set up the sqlite database // Set up the sqlite database
let sql = 'CREATE TABLE IF NOT EXISTS "create_test" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);' + 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);'; CREATE TABLE IF NOT EXISTS "create_join" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);`;
connection.query(sql, () => {
qb.query(sql, () => {
return done(); return done();
}); });
}); });
test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery())
.to.be.deep.equal(qb);
});
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
Callback Tests Callback Tests
@ -95,4 +81,3 @@ if (connection) {
expect(promise).to.be.fulfilled; 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,20 +14,16 @@
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
// this test suite to run consistently.
promisify(Firebird.attach)(config.conn).then(db => {
qb = nodeQuery.init('firebird', db, adapterName);
suite('Firebird adapter tests -', () => { suite('Firebird adapter tests -', () => {
test('nodeQuery.getQuery = nodeQuery.init', () => { test('nodeQuery.getQuery = nodeQuery.init', () => {
expect(nodeQuery.getQuery()) expect(nodeQuery.getQuery())
@ -38,24 +34,23 @@
qb.driver.insertBatch('create_test', []); qb.driver.insertBatch('create_test', []);
}).to.throw(Error, 'Not Implemented'); }).to.throw(Error, 'Not Implemented');
}); });
/*---------------------------------------------------------------------------
Callback Tests //---------------------------------------------------------------------------
---------------------------------------------------------------------------*/ // Callback Tests
//---------------------------------------------------------------------------
testRunner(qb, (err, done) => { testRunner(qb, (err, done) => {
expect(err).is.not.ok; expect(err).is.not.ok;
done(); done();
}); });
/*---------------------------------------------------------------------------
Promise Tests //---------------------------------------------------------------------------
---------------------------------------------------------------------------*/ // Promise Tests
/*qb.adapter.execute(qb.driver.truncate('create_test')).then(() => { //---------------------------------------------------------------------------
qb.adapter.execute(qb.driver.truncate('create_test')).then(() => {
promiseTestRunner(qb); promiseTestRunner(qb);
});*/ });
suiteTeardown(() => { suiteTeardown(() => {
qb.end(); 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",