diff --git a/README.md b/README.md index 1ee7398..30be692 100755 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ A node query builder for various SQL databases, based on CodeIgniter's query bui * pg * dblite * sqlite3 +* node-firebird ### Installation diff --git a/lib/adapters/node-firebird.js b/lib/adapters/node-firebird.js new file mode 100644 index 0000000..bd02b38 --- /dev/null +++ b/lib/adapters/node-firebird.js @@ -0,0 +1,29 @@ +'use strict'; + +var adapter = require('../adapter'), + getArgs = require('getargs'); + +/** @module adapters/node-firebird */ +var NodeFirebird = function(instance) { + + // That 'new' keyword is annoying + if ( ! (this instanceof NodeFirebird)) return new NodeFirebird(instance); + + /** + * Run the sql query as a prepared statement + * + * @param {String} sql - The sql with placeholders + * @param {Array} params - The values to insert into the query + * @param {Function} callback - Callback to run when a response is recieved + * @return void + */ + adapter.execute = function(sql, params, callback) { + var args = getArgs('sql:string, [params], callback:function', arguments); + + instance.execute(args.sql, args.params, args.callback); + }; + + return adapter; +} + +module.exports = NodeFirebird; \ No newline at end of file diff --git a/lib/drivers/firebird.js b/lib/drivers/firebird.js new file mode 100644 index 0000000..58abafa --- /dev/null +++ b/lib/drivers/firebird.js @@ -0,0 +1,47 @@ +"use strict"; + +var helpers = require('../helpers'); + +/** + * Driver for Firebird databases + * + * @module drivers/firebird + */ +module.exports = (function() { + delete require.cache[require.resolve('../driver')]; + var driver = require('../driver'); + + driver.hasTruncate = false; + + /** + * Generate a limit clause for firebird, which uses the syntax closest to the SQL standard + * + * @param {String} sql + * @param {Number} limit + * @param {Number} offset + * @return {String} + */ + driver.limit = function(origSql, limit, offset) { + var sql = 'FIRST ' + limit; + + if (helpers.isNumber(offset)) + { + sql += ' SKIP ' + offset; + } + + return origSql.replace(/SELECT/i, "SELECT " + sql);; + }; + + /** + * SQL to insert a group of rows + * + * @param {String} table - The table to insert to + * @param {Array} [data] - The array of object containing data to insert + * @return {String} + */ + driver.insertBatch = function(table, data) { + throw new Error("Not Implemented"); + }; + + return driver; +}()); \ No newline at end of file diff --git a/lib/query-builder.js b/lib/query-builder.js index 822cd3f..5c9afba 100755 --- a/lib/query-builder.js +++ b/lib/query-builder.js @@ -284,6 +284,7 @@ var QueryBuilder = function(driver, adapter) { //console.log(state.queryMap); //console.log(sql); //console.log(vals); +//console.log(callback); //console.log('------------------------'); // Reset the state so another query can be built @@ -768,13 +769,13 @@ var QueryBuilder = function(driver, adapter) { */ this.insert = function(/* table, data, callback */) { var args = getArgs('table:string, [data]:object, callback:function', arguments); - args.table = driver.quoteTable(args.table); + if (args.data) { this.set(args.data); } // Run the query - _p.run('insert', args.table, args.callback); + _p.run('insert', driver.quoteTable(args.table), args.callback); }; /** @@ -804,12 +805,13 @@ var QueryBuilder = function(driver, adapter) { */ this.update = function(/*table, data, callback*/) { var args = getArgs('table:string, [data]:object, callback:function', arguments); + if (args.data) { this.set(args.data); } // Run the query - _p.run('update', args.table, args.callback); + _p.run('update', driver.quoteTable(args.table), args.callback); }; /** @@ -829,7 +831,7 @@ var QueryBuilder = function(driver, adapter) { } // Run the query - _p.run('delete', args.table, args.callback); + _p.run('delete', driver.quoteTable(args.table), args.callback); }; // ------------------------------------------------------------------------ @@ -861,7 +863,7 @@ var QueryBuilder = function(driver, adapter) { * @return {String} */ this.getCompiledInsert = function(table, reset) { - return _p.getCompile('insert', table, reset); + return _p.getCompile('insert', driver.quoteTable(table), reset); }; /** @@ -872,7 +874,7 @@ var QueryBuilder = function(driver, adapter) { * @return {String} */ this.getCompiledUpdate = function(table, reset) { - return _p.getCompile('update', table, reset); + return _p.getCompile('update', driver.quoteTable(table), reset); }; /** @@ -883,7 +885,7 @@ var QueryBuilder = function(driver, adapter) { * @return {String} */ this.getCompiledDelete = function(table, reset) { - return _p.getCompile('delete', table, reset); + return _p.getCompile('delete', driver.quoteTable(table), reset); }; return this; diff --git a/package.json b/package.json index 5ee4ff1..bd21888 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ci-node-query", - "version": "1.0.0", + "version": "1.1.0", "description": "A query builder for node based on the one in CodeIgniter", "author": "Timothy J Warren ", "engines": { @@ -19,7 +19,9 @@ "postgres", "sqlite", "dblite", - "sqlite3" + "sqlite3", + "firebird", + "node-firebird" ], "bugs": { "url": "https://github.com/timw4mail/node-query/issues" @@ -44,7 +46,7 @@ "jsdoc": "^3.3.0-alpha9", "mysql": "^2.5.2", "mysql2": "^0.12.5", - "node-firebird": "^0.2.3", + "node-firebird": "^0.2.4", "nodeunit": "^0.9.0", "pg": "^3.6.2", "sqlite3": "^3.0.2" diff --git a/tests/adapters/node-firebird_test.js b/tests/adapters/node-firebird_test.js new file mode 100644 index 0000000..19c8644 --- /dev/null +++ b/tests/adapters/node-firebird_test.js @@ -0,0 +1,83 @@ +'use strict'; + +// Load the test base +var testBase = require('../query-builder-base'); + +// Load the test config file +var adapterName = 'node-firebird'; +var config = require('../config.json')[adapterName]; +config.conn.database = __dirname + config.conn.database; +var nodeQuery = require('../../lib/node-query'); + +// Set up the connection +try { + var Firebird = require(adapterName); + var conn = null; + var qb = null; +} catch (e) { + // Export an empty testBase.testsuite if module not loaded + console.log(e); + console.log("Database adapter firebird not found"); + module.exports = {}; +} + +// Setup testbase from the inside out +// Because the connection is async, utilize +// the setUp function from nodeunit to get the connection +testBase.tests.setUp = function(cb) { + if ( ! conn) + { + // Connect to the database + Firebird.attach(config.conn, function(err, db) { + if (err) { + throw new Error(err); + console.error(err); + } + conn = db; + + // Set up the query builder object + qb = nodeQuery.init('firebird', db, adapterName); + + testBase._setUp(qb, function(test, err, result) { + if (err) { + test.done(); + throw new Error(err); + } + + result = result || []; + + test.ok(result, 'firebird: Valid result for generated query'); + test.done(); + }); + + cb(); + }); + } + else + { + cb(); + } +}; + +//delete testBase.tests['DB update tests']; +testBase.tests['DB update tests']['Test Insert Batch'] = function(test) { + test.expect(1); + + test.throws(function() { + qb.insertBatch({}, (function() {})); + }, Error, "Insert Batch not implemented for firebird"); + + test.done(); +}; + +testBase.tests["firebird adapter with query builder"] = function(test) { + test.expect(1); + test.ok(testBase.qb); + + // Disconnect from the db + conn.detach(); + + test.done(); +}; + +module.exports = testBase.tests; \ No newline at end of file diff --git a/tests/config.json b/tests/config.json index 8988c22..8750235 100644 --- a/tests/config.json +++ b/tests/config.json @@ -24,5 +24,14 @@ "dblite": { "driver": "sqlite", "conn": ":memory:" + }, + "node-firebird": { + "driver": "firebird", + "conn": { + "host": "127.0.0.1", + "database": "/../FB_TEST_DB.FDB", + "user": "SYSDBA", + "password": "masterkey" + } } } \ No newline at end of file diff --git a/tests/query-builder-base.js b/tests/query-builder-base.js index d2711fe..11855d5 100644 --- a/tests/query-builder-base.js +++ b/tests/query-builder-base.js @@ -310,8 +310,8 @@ module.exports = (function QueryBuilderTestBase() { 'Test Insert': function(test) { test.expect(1); base.qb.set('id', 98) - .set('key', 84) - .set('val', 120) + .set('key', "84") + .set('val', new Buffer("120")) .insert('create_test', base.testCallback.bind(this, test)); }, 'Test Insert Object': function(test) { @@ -319,7 +319,7 @@ module.exports = (function QueryBuilderTestBase() { base.qb.insert('create_test', { id: 587, key: 1, - val: 2 + val: new Buffer('2') }, base.testCallback.bind(this, test)); }, 'Test Insert Batch': function(test) { @@ -327,15 +327,15 @@ module.exports = (function QueryBuilderTestBase() { var data = [{ id: 544, key: 3, - val: 7 + val: new Buffer('7') }, { id: 89, key: 34, - val: "10 o'clock" + val: new Buffer("10 o'clock") }, { id: 48, key: 403, - val: 97 + val: new Buffer('97') }]; base.qb.insertBatch('create_test', data, base.testCallback.bind(this, test)); @@ -346,7 +346,7 @@ module.exports = (function QueryBuilderTestBase() { .update('create_test', { id: 7, key: 'gogle', - val: 'non-word' + val: new Buffer('non-word') }, base.testCallback.bind(this, test)); }, 'Test set Array Update': function(test) { @@ -354,7 +354,7 @@ module.exports = (function QueryBuilderTestBase() { var object = { id: 22, key: 'gogle', - val: 'non-word' + val: new Buffer('non-word') }; base.qb.set(object) @@ -366,7 +366,7 @@ module.exports = (function QueryBuilderTestBase() { base.qb.where('id', 36) .set('id', 36) .set('key', 'gogle') - .set('val', 'non-word') + .set('val', new Buffer('non-word')) .update('create_test', base.testCallback.bind(this, test)); }, 'Test delete': function(test) {