diff --git a/.cupboard b/.cupboard new file mode 100644 index 0000000..73d6ec5 --- /dev/null +++ b/.cupboard @@ -0,0 +1,5 @@ +[project] +name = dbslayer +[commands] +publish = git add ., git commit -m "$@", git push origin master +ignore = echo $@ >> .gitignore diff --git a/README.md b/README.md old mode 100644 new mode 100755 index d927fd5..f12f193 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ node.dbslayer.js ================= -node.dbslayer.js is a very basic and easy-to-use library to connect to a DBSlayer server, which effectively provides non-blocking and scalable MySQL support for Node.JS. +node.dbslayer.js is a very basic and easy-to-use library to connect to a DBSlayer server, which effectively provides non-blocking and scalable MySQL support for Node.JS. DBSlayer benefits include: @@ -12,40 +12,80 @@ DBSlayer benefits include: Requirements ------------ -* [Node.js](http://nodejs.org/) (tested with v0.1.21) +* [Node.js](http://nodejs.org/) (tested with v0.1.90) * [DBSlayer](http://code.nytimes.com/projects/dbslayer/) (tested with beta-12) +How to Install ![New!](http://i.imgur.com/XSqxQs.jpg) +-------------- + +From your npm equipped command line: + + npm install dbslayer + How to Use ---------- - + From your node.js script, require the `dbslayer` package - var db = require('dbslayer'); + var db = require('dbslayer'); Initialize a connection - var connection = db.Server('localhost', 9090); - + var connection = db.Server('localhost', 9090); + and then perform a query: - connection.query("SELECT * FROM table"); - -To be truly non-blocking, `Server::fetch` has to return a promise and not the result immediately. This means that in order to be able to perform queries in a designated order or access the result, you'll have to use callbacks: - - connection.query("SELECT * FROM TABLE").addCallback(function(result){ - for (var i = 0, l = result.ROWS.length; i < l; i++){ - var row = result.ROWS[i]; - // do something with the data - } - }); - + connection.query("SELECT * FROM table"); + +To be truly non-blocking, you must use listeners. This means that in order to be able to perform queries in a designated order or access the result, you'll have to use callbacks: + + connection.query("SELECT * FROM TABLE"); + connection.on('result', function(result) { + for (var i = 0, l = result.ROWS.length; i < l; i++){ + var row = result.ROWS[i]; + // do something with the data + } + + connection.removeListener('result', arguments.callee); + }); + +You **must** remember to remove your listener, otherwise it will be called along with any new listeners you create. + If you want to capture MySQL errors, subscribe to the 'error' event - connection.query("SELECT * FROM inexistent_table").addErrback(function(error, errno){ - alert('mysql error! + ' error); - }); - -Aside from query, the commands `stat`, `client_info`, `host_info`, `server_version` and `client_version` are available, which provide the respective information about the server. + connection.query("SELECT * FROM inexistent_table") + connection.on('error', function(error, errno){ + sys.puts('mysql error! + ' error); + }); + +Aside from query, the commands `stat`, `client_info`, `host_info`, `server_version` and `client_version` are available, which provide the respective information about the server. In order to preserve somewhat backwards compatibility, these have seperate events per function. + +More Examples +------------- + + mysql.on('result', function(result) { + this.fetch_object(result, function(obj) { + node.log(obj.Field); + }); + }).query('DESCRIBE `stock`;'); + +You can use the fetch_object, fetch_array or fetch_args functions as shorthand to return either an object, an array or function callback arguments to retrieve your data. + + mysql.on('result', function(result) { + this.fetch_array(result, function(arr) { + node.log(arr[0]); + }); + }).query('DESCRIBE `stock`;'); + +Or + + mysql.on('result', function(result) { + this.fetch_args(result, function(field, type) { + node.log(field); + }); + }).query('DESCRIBE `stock`;'); + +Will produce the same output as the first example. Installing DBSlayer ------------------- @@ -54,23 +94,32 @@ Compile it according to the instructions [here](http://code.nytimes.com/projects Then create a /etc/dbslayer.conf file defining a database. Here I'm defining the `cool` server which connects to my `mysql` database - [cool] - database=mysql - host=localhost - user=root - pass=1234 - + [cool] + database=mysql + host=localhost + user=root + pass=1234 + Then run DBSlayer for that connection: - dbslayer -c /etc/dbslayer.conf -s cool - + dbslayer -c /etc/dbslayer.conf -s cool + Test it by running test.js like this: - node test.js "SELECT * FROM help_category" - + node test.js "SELECT * FROM help_category" + If you get a bunch of entries like in this [screenshot](http://cld.ly/9aosh) then dbslayer (and node.dbslayer.js) work! -Author ------- +Authors +------- + +Guillermo Rauch <[http://devthought.com](http://devthought.com)> + +Robin Duckett <[http://www.twitter.com/robinduckett](http://www.twitter.com/robinduckett)> + +Barry Ezell <[http://twitter.com/barryezl](http://twitter.com/barryezl)> + +Contributors +------------ -Guillermo Rauch <[http://devthought.com](http://devthought.com)> \ No newline at end of file +Craig Condon <[http://spiceapps.com](http://spiceapps.com)> \ No newline at end of file diff --git a/dbslayer.js b/dbslayer.js old mode 100644 new mode 100755 index 706b6ad..6445632 --- a/dbslayer.js +++ b/dbslayer.js @@ -1,54 +1,62 @@ /* --- name: dbslayer.js - description: Interface to DBSlayer for Node.JS - +version: 0.2 author: [Guillermo Rauch](http://devthought.com) +updaters: [Robin Duckett](http://www.twitter.com/robinduckett), + [Barry Ezell](http://twitter.com/barryezl) ... */ - -var sys = require('sys'), +var util = require('util'), http = require('http'), - - booleanCommands = ['STAT', 'CLIENT_INFO', 'HOST_INFO', 'SERVER_VERSION', 'CLIENT_VERSION'], + events = require('events'), + booleanCommands = ['STAT', 'CLIENT_INFO', 'HOST_INFO', 'SERVER_VERSION', 'CLIENT_VERSION']; -Server = this.Server = function(host, port, timeout){ +var Server = function(host, port, timeout) { this.host = host || 'localhost'; this.port = port || 9090; this.timeout = timeout; }; -Server.prototype.fetch = function(object, key){ - var connection = http.createClient(this.port, this.host), - request = connection[connection.get ? 'get' : 'request']('/db?' + escape(JSON.stringify(object)), {'host': this.host}), - promise = new process.Promise(); - - promise.timeout(this.timeout); +util.inherits(Server, events.EventEmitter); +Server.prototype.fetch = function(object, key) { + var connection = http.createClient(this.port, this.host); + var request = connection.request('GET', '/db?' + escape(JSON.stringify(object)), {'host': this.host}); + var server = this; + + request.on('response', function(response) { + var allData = ""; + response.setEncoding('utf8'); + response.on('data', function(data) { + allData += data; + }); - request.finish(function(response){ - response.addListener('body', function(data){ + response.on('end', function() { try { - var object = JSON.parse(data); - } catch(e){ - return promise.emitError(e); - } - - if (object.MYSQL_ERROR !== undefined){ - promise.emitError(object.MYSQL_ERROR, object.MYSQL_ERRNO); - } else if (object.ERROR !== undefined){ - promise.emitError(object.ERROR); - } else { - promise.emitSuccess(key ? object[key] : object); - } + var object = JSON.parse(allData); + } catch(e) { + server.emit('error', e); + } + + if (object !== undefined) { + if (object.MYSQL_ERROR !== undefined) { + server.emit('error', object.MYSQL_ERROR, object.MYSQL_ERRNO); + } else if (object.ERROR !== undefined) { + server.emit('error', object.ERROR); + } else { + server.emit(key.toLowerCase(), key ? object[key] : object); + } + } }); }); - - return promise; + + request.end(); }; Server.prototype.query = function(query){ - return this.fetch({SQL: query}, 'RESULT'); + this.fetch({SQL: query}, 'RESULT') + return this; }; for (var i = 0, l = booleanCommands.length; i < l; i++){ @@ -59,4 +67,45 @@ for (var i = 0, l = booleanCommands.length; i < l; i++){ return this.fetch(obj, command); }; })(booleanCommands[i]); -} \ No newline at end of file +} + +Server.prototype.fetch_object = function(res, callback) { + for (var row, i = 0; i < res.ROWS.length; row = res.ROWS[i], i++) { + var ret = {}; + if (typeof row !== "undefined") { + for (var j = 0; j < res.HEADER.length; j ++) { + ret[res.HEADER[j]] = row[j]; + } + + callback.apply(this, [ret]); + } + } +}; + +Server.prototype.fetch_array = function(res, callback) { + for (var row, i = 0; i < res.ROWS.length; row = res.ROWS[i], i++) { + var ret = []; + if (typeof row !== "undefined") { + for (var j = 0; j < res.HEADER.length; j ++) { + ret[j] = row[j]; + } + + callback.apply(this, [ret]); + } + } +}; + +Server.prototype.fetch_args = function(res, callback) { + for (var row, i = 0; i < res.ROWS.length; row = res.ROWS[i], i++) { + var ret = []; + if (typeof row !== "undefined") { + for (var j = 0; j < res.HEADER.length; j ++) { + ret[j] = row[j]; + } + + callback.apply(this, ret); + } + } +}; + +exports.Server = Server; diff --git a/package.json b/package.json new file mode 100644 index 0000000..ba36a9e --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "name": "dbslayer", + "description": "mysql api for node.js", + "version": "0.2.0", + "main": "dbslayer.js", + "dependencies": {}, + "devDependencies": {} +} diff --git a/test.js b/test.js old mode 100644 new mode 100755 index 8ab8c6e..28f9303 --- a/test.js +++ b/test.js @@ -7,6 +7,7 @@ description: < It takes three parameters from the SQL query, a host author: [Guillermo Rauch](http://devthought.com) +updaters: [Robin Duckett](http://www.twitter.com/robinduckett) ... */ @@ -20,24 +21,25 @@ if (!sql){ return; } -db.query(sql) - // on success - .addCallback(function(result){ - sys.puts('-------------------------'); - for (var i = 0, l = result.ROWS.length; i < l; i++){ - sys.puts('Row ' + i + ': ' + result.ROWS[i].join(' ')); - } - }) - - // on error :( - .addErrback(function(error, errno){ - sys.puts('-------------------------'); - sys.puts('MySQL error (' + (errno || '') + '): ' + error); - }); +db.addListener('result', function(result) { + sys.puts('-------------------------'); + for (var i = 0, l = result.ROWS.length; i < l; i++){ + sys.puts('Row ' + i + ': ' + result.ROWS[i].join(' ')); + } +}); + +db.addListener('error', function(error, errno) { + sys.puts('-------------------------'); + sys.puts('MySQL error (' + (errno || '') + '): ' + error); +}); -['stat', 'client_info', 'host_info', 'server_version', 'client_version'].forEach(function(command){ - db[command]().addCallback(function(result){ - sys.puts('-------------------------'); +db.query(sql); + +['stat', 'client_info', 'host_info', 'server_version', 'client_version'].forEach(function(command) { + db.addListener(command, function(result) { + sys.puts('-------------------------'); sys.puts(command.toUpperCase() + ' ' + result); }); -}); \ No newline at end of file + db[command](); +}); +