diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..ed1280b --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,28 @@ +{ + "env": { + "es6": true, + "node": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "always" + ] + } +} \ No newline at end of file diff --git a/package.json b/package.json index d268ee9..7de997d 100644 --- a/package.json +++ b/package.json @@ -1,34 +1,40 @@ { - "name": "voltjs", - "version": "2.0.0", - "description": "VoltDB binary driver", - "keywords": [ - "voltdb", - "client", - "driver", - "binary driver" - ], - "bugs": { - "url": "https://github.com/VoltDB/voltdb-client-nodejs/issues", - "email": "support@voltdb.com" - }, - "license": "MIT", - "author": "VoltDB", - "engines": { - "node": ">= 6.11.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/VoltDB/voltdb-client-nodejs.git" - }, - "dependencies": { - "bignumber": "^1.1.0", - "ctype": "^0.5.0", - "cli": "^1.0.0", - "debug": "^3.0.1", - "supports-color": "^4.4.0" - }, - "devDependencies": { - "nodeunit": "^0.11.0" - } + "name": "voltjs", + "version": "2.0.0", + "description": "VoltDB binary driver", + "keywords": [ + "voltdb", + "client", + "driver", + "binary driver" + ], + "bugs": { + "url": "https://github.com/VoltDB/voltdb-client-nodejs/issues", + "email": "support@voltdb.com" + }, + "license": "MIT", + "author": "VoltDB", + "engines": { + "node": ">= 6.11.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/VoltDB/voltdb-client-nodejs.git" + }, + "dependencies": { + "bignumber": "^1.1.0", + "ctype": "^0.5.0", + "cli": "^1.0.0", + "debug": "^3.0.1", + "supports-color": "^4.4.0" + }, + "devDependencies": { + "eslint": "^4.7.1", + "eslint-config-standard": "^10.2.1", + "eslint-plugin-import": "^2.7.0", + "eslint-plugin-node": "^5.1.1", + "eslint-plugin-promise": "^3.5.0", + "eslint-plugin-standard": "^3.0.1", + "nodeunit": "^0.11.0" + } } diff --git a/test/cases/bufferTest.js b/test/cases/bufferTest.js new file mode 100644 index 0000000..58b8dc9 --- /dev/null +++ b/test/cases/bufferTest.js @@ -0,0 +1,236 @@ +!(function (global) { // eslint-disable-line no-unused-vars + + "use strict"; + + const VoltClient = require("../../lib/client"); + const VoltConfiguration = require("../../lib/configuration"); + const VoltConstants = require("../../lib/voltconstants"); + const VoltProcedure = require("../../lib/query"); + + + require("nodeunit"); + const debug = require("debug")("voltdb-client-nodejs:BufferTest"); + + /** + * A "good" client config that points to a volt instance on localhost + */ + function configs() { + + const configs = []; + + const config = new VoltConfiguration(); + config.host = "localhost"; + + configs.push(config); + + return configs; + } + + /** + * Promise style function for connecting to a Volt instance + */ + function connect(client){ + + const p = new Promise(function(resolve, reject) { + client.connect(function(code, event, results) { + if(code === VoltConstants.STATUS_CODES.SUCCESS){ + resolve({errorCode: code, eventCode: event, results: results}); + } + else{ + debug("Connect Failure | Code: %o, Event: %o", code, event); + reject({errorCode: code, eventCode: event, results: results}); + } + }); + }); + + return p; + } + + /** + * Promise style function for calling a procedure. An alternative to the old + * callback style functions that returns both a write and a read promise. + */ + function query(query, client){ + + var writeResolve = null; + var writeReject = null; + + const writePromise = new Promise(function(resolve, reject){ + writeResolve = resolve; + writeReject = reject; + }); + + const readPromise = new Promise(function(resolve, reject){ + + client.callProcedure(query, function read(code, event, results) { + // debug("AdHocQuery Complete | errorCode: %o, eventCode: %o, results: + // %O", code, event, results); + if(code === VoltConstants.STATUS_CODES.SUCCESS){ + // The results code is 1 for SUCCESS so can't use voltconstants + if(results.status === PROC_STATUS_CODE_SUCCESS){ + resolve({errorCode: code, eventCode: event, results: results}); + } + else{ + debug("AdHocQuery Failure | Read Error. errorCode: %o, eventCode: %o, results: %O", statusCodeToString(code), event, results); + reject({errorCode: code, eventCode: event, results: results}); + } + } + else{ + debug("AdHocQuery Failure | Read Error. errorCode: %o, eventCode: %o, results: %O", statusCodeToString(code), event, results); + reject({errorCode: code, eventCode: event, results: results}); + } + + }, function write(code, event, results) { + if(code === VoltConstants.STATUS_CODES.SUCCESS){ + writeResolve({errorCode: code, eventCode: event, results: results}); + } + else{ + debug("AdHocQuery Failure | Write Error. errorCode: %o, eventCode: %o, results: %O", statusCodeToString(code), event, results); + writeReject({errorCode: code, eventCode: event, results: results}); + } + }); + }); + + return { writePromise: writePromise, readPromise: readPromise }; + } + + /** + * Sugar for running an adhoc query + */ + function adHocQuery(queryString, client){ + + debug("Query | query: %o", queryString); + + const p = new VoltProcedure("@AdHoc", [ "string" ]); + + const q = p.getQuery(); + q.setParameters([queryString]); + + return query(q, client); + } + + /** + * + */ + function statusCodeToString(code){ + return code === null ? VoltConstants.STATUS_CODE_STRINGS[PROC_STATUS_CODE_SUCCESS] : VoltConstants.STATUS_CODE_STRINGS[code]; + } + + /** + * Utility method for volt queries that return a write and a read promise. + * Useful for when you want to fire off a bunch of writes and then wait on the + * read at the end. Executes the query and collects the read promises in the + * given array. Returns both the write and read promise. + */ + function queryCollect(queryString, readPromises, client){ + const p = adHocQuery(queryString, client); + readPromises.push(p.readPromise); + return p; + } + + /** + * + */ + const PROC_STATUS_CODE_SUCCESS = 1; + + // Exports + module.exports = { + setUp : function(callback){ + callback(); + }, + tearDown : function(callback){ + callback(); + }, + readTest : function(test){ + + debug("readTest"); + + const client = new VoltClient(configs()); + + debug("Connecting"); + + connect(client) + .then(function(value){ + test.ok(value.errorCode === VoltConstants.STATUS_CODES.SUCCESS); + return Promise.resolve(null); + }) + .then(function(){ + return adHocQuery("DROP TABLE PLAYERS IF EXISTS;", client).readPromise; + }) + .then(function(){ + return adHocQuery("CREATE TABLE PLAYERS (" + + "playerID integer NOT NULL, " + + "teamid varchar(100) NOT NULL " + + ");", client).readPromise; + }) + .then(function(){ + return adHocQuery("DROP TABLE TEAM_PLAYERS IF EXISTS;", client).readPromise; + }) + .then(function(){ + return adHocQuery("CREATE TABLE TEAM_PLAYERS (" + + "id integer NOT NULL, " + + "uid varchar(100) NOT NULL, " + + "name varchar(100) NOT NULL, " + + "avatar varbinary(12000) NOT NULL" + + ");", client).readPromise; + }) + .then(function(){ + + const readPromises = []; + + return Promise.resolve() + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (0, 'TeamA');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (1, 'TeamA');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (2, 'TeamA');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (3, 'TeamA');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (4, 'TeamA');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (5, 'TeamB');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (6, 'TeamB');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (7, 'TeamB');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (8, 'TeamB');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (9, 'TeamB');", readPromises, client).writePromise; }) + .then(function() { return Promise.all(readPromises); }); + + }) + .then(function(){ + + const readPromises = []; + + return Promise.resolve() + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (0, 'GameA', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (1, 'GameB', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (2, 'GameC', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (3, 'GameD', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (4, 'GameE', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (5, 'GameA', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (6, 'GameB', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (7, 'GameC', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (8, 'GameD', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (9, 'GameE', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; }) + .then(function() { return Promise.all(readPromises); }); + + }) + .then(function(){ + return adHocQuery("select A.*, " + + "B.name as name, " + + "B.avatar as avatar " + + "from PLAYERS as A left join TEAM_PLAYERS as B on A.playerID=B.id " + + "where uID='GameA' and A.teamID='TeamA';", client).readPromise; + }) + .then(function(value){ + debug("Result Count: %O", value.results.table.length); + debug("Results: %O", value.results.table[0][0]); + client.exit(); + test.done(); + return Promise.resolve(null); + }) + .catch(function(value){ + debug("Test Failed | Results: %O", value); + client.exit(); + test.ok(false, "Test failed, see previous messages"); + test.done(); + }); + } + }; + +}(this));