Changeset: 6345f199614a for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=6345f199614a
Modified Files:
clients/nodejs/monetdb/README
clients/nodejs/monetdb/mapiclient.js
clients/nodejs/monetdb/package.json
Branch: default
Log Message:
Node.JS connector: standardized callback interface and disconnect fix
diffs (274 lines):
diff --git a/clients/nodejs/monetdb/README b/clients/nodejs/monetdb/README
--- a/clients/nodejs/monetdb/README
+++ b/clients/nodejs/monetdb/README
@@ -2,10 +2,17 @@ This package connects node.js and MonetD
Example usage:
-var conn = require('monetdb').connect({'dbname':'mydb'} , function(response) {
- if (response.success) console.log('connected');
+var conn = require('../monetdb').connect({'dbname':'mydb'} , function(err) {
+ if (!err) console.log('connected');
});
-conn.request('SELECT 1', function(response) {
- console.log(response);
-});
\ No newline at end of file
+conn.query('SELECT 1', function(err, res) {
+ if (!err) console.log(res);
+});
+
+conn.query('SELECT id FROM tables WHERE name=? and readonly=?',
+ ['connections', false], function(err, res) {
+ if (!err) console.log(res);
+});
+
+conn.close()
\ No newline at end of file
diff --git a/clients/nodejs/monetdb/mapiclient.js
b/clients/nodejs/monetdb/mapiclient.js
--- a/clients/nodejs/monetdb/mapiclient.js
+++ b/clients/nodejs/monetdb/mapiclient.js
@@ -11,6 +11,7 @@ function MonetDBConnection(options, conn
this.read_callback = undefined;
this.conn_callback = conncallback;
this.mapi_blocksize = 8192;
+ this.do_close = false;
this.queryqueue = [];
var thizz = this;
@@ -25,43 +26,96 @@ function MonetDBConnection(options, conn
});
this.socket.on('error', function(x) {
if (conncallback != undefined)
- conncallback({'success':false, 'message':x.toString()});
+ conncallback(x.toString());
});
/* some setup */
this.request('Xreply_size -1', undefined, true);
this.request('Xauto_commit 1', undefined, true);
/* get server environment into connector */
- this.request('SELECT * FROM env()', function(x) {
+ this.request('SELECT * FROM env()', function(err, resp) {
+ if (err) {
+ if (this.conn_callback != undefined)
+ this.conn_callback(err);
+ return;
+ }
thizz.env = {};
- x.data.forEach(function(l) {
+ resp.data.forEach(function(l) {
thizz.env[l.name] = l.value;
});
});
this.request('SELECT 42', function(x) {
if (this.conn_callback != undefined)
- this.conn_callback({'success':true, 'message':'ok'});
+ this.conn_callback(null);
});
}
MonetDBConnection.prototype.request =
-MonetDBConnection.prototype.query = function(message, callback, raw) {
- if (!raw) {
- message = 's'+message+';';
+MonetDBConnection.prototype.query = function() {
+ var message = arguments[0];
+
+ var params = [];
+ var callback = undefined;
+ var raw = false;
+
+ for (argi in arguments) {
+ if (typeof arguments[argi] == 'function') {
+ callback = arguments[argi];
+ }
+ if (Array.isArray(arguments[argi])) {
+ params = arguments[argi];
+ }
+ if (typeof arguments[argi] == 'boolean') {
+ raw = arguments[argi];
+ }
}
- this.queryqueue.push({'message' : message , 'callback' : callback})
+
+ if (Array.isArray(arguments[1])) {
+ params = arguments[1];
+ callback = arguments[2];
+ raw = arguments[3];
+
+ this.prepare(message, function(err, res) {
+ if (err) {
+ if (callback != undefined) {
+ callback(err);
+ }
+ return;
+ }
+ res.exec(params, function(err, res) {
+ if (err) {
+ if (callback != undefined) {
+ callback(err);
+ }
+ return;
+ }
+ if (callback != undefined) {
+ callback(null, res);
+ }
+ });
+ });
+ }
+ else {
+ callback = arguments[1];
+ raw = arguments[2];
+ if (!raw) {
+ message = 's' + message + ';';
+ }
+ this.queryqueue.push({'message' : message , 'callback' :
callback});
+ }
}
MonetDBConnection.prototype.prepare = function(query, callback) {
if (query.toUpperCase().trim().substring(0,7) != 'PREPARE')
query = 'PREPARE ' + query;
var thizz = this;
- thizz.query(query, function(resp) {
- if (resp.success) {
- var execfun = function() {
- /* last parameter is the callback on result */
- var ecallback = arguments[arguments.length-1];
- /* first n-1 parameters are the values to bind
*/
- var bindparams =
Array.prototype.slice.call(arguments, 0, arguments.length-1);
+ thizz.query(query, function(error, resp) {
+ if (!error) {
+ var execfun = function(bindparams, ecallback) {
+ /* the prepare response tells us how many
parameters we need to bind */
+ if (bindparams.length != resp.rows-1) {
+ ecallback('missing parameters');
+ return;
+ }
var quoted = bindparams.map(function(param) {
var type = typeof param;
switch(type) {
@@ -69,31 +123,36 @@ MonetDBConnection.prototype.prepare = fu
case 'number':
return ''+param;
break
- default:
+ case 'string':
/* escape single quotes except
if they are already escaped */
return "'" +
param.replace(/([^\\])'/g,"$1\\'") + "'";
break
+ default:
+ return param;
+ break;
}
}).join(', ');
var execquery = 'EXEC ' + resp.queryid + '(' +
quoted + ')';
thizz.query(execquery, ecallback);
}
- callback({'success' : true, 'message' : 'ok', 'prepare'
: resp, 'exec' : execfun});
+
+ var releasefun = function() {
+ thizz.query('Xrelease ' + resp.queryid,
undefined, true);
+ }
+
+ callback(null, {'message' : 'ok', 'prepare' : resp,
'exec' : execfun, 'release' : releasefun});
}
else {
- callback(resp);
+ callback(error);
}
});
}
+/* we need to wait till everything is done before we close the socket */
MonetDBConnection.prototype.disconnect =
MonetDBConnection.prototype.close = function() {
- var thizz = this;
- /* kills the connection after the query has been processed (will also
wait for all others) */
- this.request('SELECT 42', function(x) {
- thizz.socket.destroy();
- });
+ this.do_close = true;
}
exports.connect = exports.open = function() {
@@ -119,9 +178,9 @@ function handle_message(message) {
if (this.state == 'connected') {
/* error message during authentication? */
if (message.charAt(0) == '!') {
- message = 'Error:
'+message.substring(1,message.length-1);
+ message = 'Error: ' + message.substring(1,
message.length - 1);
if (this.conn_callback != undefined)
- this.conn_callback({'success':false,
'message':message});
+ this.conn_callback(message);
return;
}
@@ -137,22 +196,20 @@ function handle_message(message) {
}
var response = {};
+ var error = null;
/* error message */
if (message.charAt(0) == '!') {
- response.success = false;
- response.message = message.substring(1,message.length-1);
+ error = message.substring(1,message.length-1);
}
/* query result */
if (message.charAt(0) == '&') {
response = _parseresponse(message);
- response.success = true;
- response.message = 'ok';
}
if (this.read_callback != undefined) {
- this.read_callback(response);
+ this.read_callback(error, response);
this.read_callback = undefined;
}
next_op.call(this);
@@ -161,8 +218,12 @@ function handle_message(message) {
function next_op() {
if (this.queryqueue.length < 1) {
+ if (this.do_close) {
+ this.socket.destroy();
+ }
return;
}
+
var op = this.queryqueue.shift();
send_message.call(this, op.message);
this.read_callback = op.callback;
@@ -201,7 +262,6 @@ function handle_input(data) {
data.copy(leftover, 0, read_cnt, data.length);
handle_input.call(this, leftover);
}
-
};
function send_message(message) {
@@ -232,7 +292,6 @@ function __sha512(str) {
return crypto.createHash('sha512').update(str).digest('hex');
}
-
function _parsetuples(names, types, lines) {
var state = 'INCRAP';
var resultarr = [];
diff --git a/clients/nodejs/monetdb/package.json
b/clients/nodejs/monetdb/package.json
--- a/clients/nodejs/monetdb/package.json
+++ b/clients/nodejs/monetdb/package.json
@@ -1,6 +1,6 @@
{
"name": "monetdb",
- "version": "0.0.5",
+ "version": "0.0.7",
"description": "Connect MonetDB and node.js",
"main": "mapiclient.js",
"author": "Hannes Mühleisen <[email protected]>",
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list