Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit d1f7608fc58b90b154ed93d440f249881520e3ee 0 parents
@mscdex authored
1  .gitignore
@@ -0,0 +1 @@
+
3  AUTHORS
@@ -0,0 +1,3 @@
+# Authors ordered by first contribution.
+
+Brian White <mscdex@gmail.com>
7 LICENSE
@@ -0,0 +1,7 @@
+Copyright (C) 2010 Brian White <mscdex@gmail.com>. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
92 README.md
@@ -0,0 +1,92 @@
+# node-poormansmysql
+
+node-poormansmysql is a MySQL driver for [node.js](http://nodejs.org/) that executes queries using the mysql command-line client.
+
+
+# Requirements
+
+* [node.js](http://nodejs.org/) -- tested with [0.1.92](http://github.com/ry/node/commit/caa828a242f39b6158084ef4376355161c14fe34)
+* [libxmljs](http://github.com/polotek/libxmljs) -- tested with [7903666cd29001b19fb0](http://github.com/polotek/libxmljs/commit/7903666cd29001b19fb0821f62bcf50f6b5576b3)
+
+
+# Documentation
+
+MysqlConnection Methods:
+
+* (constructor) **MysqlConnection**(_config_)
+ * **Description**: Performs initialization and sets the connection configuration. All properties supplied in _config_ overwrite the defaults listed below.
+ * **Parameters**:
+ * _config_: (Object) An object containing the necessary connection information to connect to the MySQL server and perform queries. At least the user and password should be supplied. The default configuration is:
+
+ user: null,
+ password: null,
+ db: null,
+ host: 'localhost',
+ port: 3306,
+ connect_timeout: 0, // in seconds
+ query_timeout: 0 // in seconds (TODO)
+ * **Return Value**: (MysqlConnection) An instance of MysqlConnection.
+* **setConfig**(_config_)
+ * **Description**: Sets the connection configuration. This is only needed if you are reusing the instance and need to change the connection information. As with the constructor, all properties supplied in _config_ are merged with the defaults.
+ * **Parameters**:
+ * _config_: (Object) An object containing the necessary connection information to connect to the MySQL server and perform queries. At least the user and password should be supplied. See above for the default configuration.
+ * **Return Value**: None
+* **query**(_sql_)
+ * **Description**: Enqueues an SQL statement.
+ * **Parameters**:
+ * _sql_: (String) A valid SQL statement. Do not include a trailing semicolon at the end of the statement.
+ * **Return Value**: None
+* **execute**()
+ * **Description**: Begins executing the enqueued SQL statements all at once.
+ * **Parameters**: None
+ * **Return Value**: (Boolean) _true_ if there were statements to be executed and the 'user' and 'password' connection details have been supplied, _false_ otherwise.
+* (getter) **affectedRows**
+ * **Description**: Returns the number of rows updated, inserted, or deleted by the last SQL statement.
+ * **Return Value**: (Integer) The number of rows affected by the last SQL statement.
+* (getter) **lastInsertId**
+ * **Description**: Returns the first automatically generated value that was set for an AUTO_INCREMENT column by the most recent INSERT statement. See [here](http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id) for more details.
+ * **Return Value**: (Integer) The value of the AUTO_INCREMENT column for the last INSERTed row.
+
+MysqlConnection Events:
+
+* **error**
+ * **Description**: Fired when an error occurs. This can be either a MySQL error or a child process spawning error.
+ * **Parameters**:
+ * _err_: (String) The error details.
+* **row**
+ * **Description**: Fired when a row has been generated for the given query.
+ * **Parameters**:
+ * _rowdata_: (Object) A hash containing a single row from the results of a query.
+ * _sql_: (String) The original SQL (SELECT) statement that generated the row.
+* **queryDone**
+ * **Description**: Fired when the given query has completed and any/all resulting rows for the given query have been emitted.
+ * **Parameters**:
+ * _sql_: (String) The original SQL (SELECT) statement that generated the row.
+* **done**
+ * **Description**: Fired when <u>**all**</u> queries have completed and any/all resulting rows for each query have been emitted.
+ * **Parameters**: None
+
+# Example
+
+ var pmm = require('./node-poormansmysql'), sys = require('sys');
+
+ var conn = new pmm.MysqlConnection({user: 'foo', password: 'bar', db: 'baz'});
+ conn.addListener('error', function(err) {
+ sys.puts('Uh oh, ' + err);
+ });
+ conn.addListener('row', function(rowdata, sql) {
+ sys.puts("'" + sql + "' generated a row: " + sys.inspect(row));
+ });
+ conn.addListener('queryDone', function(sql) {
+ sys.puts("Done with query: " + sql);
+ });
+ conn.addListener('done', function() {
+ sys.puts('Done executing all SQL statements!');
+ });
+ conn.query("SELECT * FROM table");
+ conn.execute();
+
+
+# License
+
+See LICENSE file.
17 example.js
@@ -0,0 +1,17 @@
+var pmm = require('./node-poormansmysql'), sys = require('sys');
+
+var conn = new pmm.MysqlConnection({user: 'foo', password: 'bar', db: 'baz'});
+conn.addListener('error', function(err) {
+ sys.puts('Uh oh, ' + err);
+});
+conn.addListener('row', function(rowdata, sql) {
+ sys.puts("'" + sql + "' generated a row: " + sys.inspect(row));
+});
+conn.addListener('queryDone', function(sql) {
+ sys.puts("Done with query: " + sql);
+});
+conn.addListener('done', function() {
+ sys.puts('Done executing all SQL statements!');
+});
+conn.query("SELECT * FROM table");
+conn.execute();
146 node-poormansmysql.js
@@ -0,0 +1,146 @@
+var spawn = require('child_process').spawn;
+var libxml = require('./libxmljs');
+var inherits = require('sys').inherits;
+var EventEmitter = require('events').EventEmitter;
+
+function MysqlConnection(newconfig) {
+ var default_config = {
+ user: null,
+ password: null,
+ db: null,
+ host: 'localhost',
+ port: 3306,
+ connect_timeout: 0, // in seconds
+ query_timeout: 0 // in seconds (TODO)
+ };
+ var config;
+
+ var queries = [];
+
+ var _affectedRows = 0;
+ var _lastInsertId = 0; // 0 means no row(s) inserted
+ var isInserting = false;
+
+ /* Bookkeeping */
+ var curQuery = null;
+ var curRow = null;
+ var curField = null;
+ var queryTotal = 0;
+ var queryCount = 0;
+ var lastIndex = 0;
+
+ var lastError = null;
+
+ var proc = null;
+ var parser;
+
+ var self = this;
+
+ /* Public Methods */
+
+ this.setConfig = function(newconfig) {
+ config = {};
+ for (var option in default_config)
+ config[option] = (typeof newconfig[option] != "undefined" ? newconfig[option] : default_config[option]);
+ }
+
+ this.query = function(sql) {
+ sql = sql.replace(/^\s*/, "").replace(/\s*$/, "").replace('"', '\"');
+ queries.push(sql);
+ if (sql.substr(0, 6).toUpperCase() == "INSERT")
+ isInserting = true;
+ }
+
+ this.execute = function() {
+ if (queries.length > 0 && config.user != null && config.password != null) {
+ queries.push("SELECT ROW_COUNT() AS _node_poormansmysql_affectedRows");
+ if (isInserting) {
+ queries.push("SELECT LAST_INSERT_ID() AS _node_poormansmysql_lastInsertId");
+ lastIndex = queries.length-3;
+ } else
+ lastIndex = queries.length-2;
+
+ proc = spawn('/bin/sh', ['-c', 'mysql --xml --quick --disable-auto-rehash --connect_timeout=' + config.connect_timeout + ' --host=' + config.host + ' --port=' + config.port + ' --user=' + config.user + ' --password=' + config.password + (config.db != null ? ' --database=' + config.db : '') + ' --execute="' + queries.join('; ') + '"']);
+
+ proc.stdout.setEncoding('utf8');
+ proc.stderr.setEncoding('utf8');
+
+ proc.stdout.addListener('data', function(data) {
+ // UGLY HACK: There is one XML declaration for each MySQL query, so remove the extra ones where applicable, otherwise libxml throws a fit.
+ var header = "<?xml version=\"1.0\"?>\n";
+ if (queryCount == 0 && data.substr(0, header.length) == header)
+ data = header + "<results>\n" + data.substr(header.length);
+ data = data.replace("\n" + header, "");
+ parser.push(data);
+ });
+ proc.stderr.addListener('data', function(data) {
+ if (/^execvp\(\)/.test(data))
+ lastError = 'Spawn Error: Failed to start child process.';
+ else
+ lastError = 'MySQL Error: ' + data;
+
+ self.emit('error', lastError);
+ });
+ proc.addListener('exit', function(code) {
+ if (code == 0) {
+ parser.push("</results>");
+ queryCount = 0;
+ }
+ });
+
+ queryTotal = queries.length;
+ queries = [];
+ isInserting = false;
+ return true;
+ } else
+ return false;
+ }
+
+ this.__defineGetter__('affectedRows', function () { return _affectedRows; });
+ this.__defineGetter__('lastInsertId', function () { return _lastInsertId; });
+
+ /* Initialization */
+
+ this.setConfig(newconfig);
+ parser = new libxml.SaxPushParser(function(cb) {
+ cb.onStartElementNS(function(elem, attrs, prefix, uri, namespaces) {
+ if (elem == "resultset")
+ curQuery = attrs[0][3];
+ else if (elem == "row")
+ curRow = {};
+ else if (elem == "field") {
+ curField = attrs[0][3];
+ curRow[curField] = null;
+ }
+ });
+ cb.onEndElementNS(function(elem, prefix, uri) {
+ if (elem == "resultset") {
+ if (queryCount <= lastIndex)
+ self.emit('queryDone', curQuery);
+ curQuery = null;
+ if (++queryCount == queryTotal)
+ self.emit('done');
+ } else if (elem == "row") {
+ if (typeof curRow['_node_poormansmysql_lastInsertId'] != 'undefined')
+ _lastInsertId = curRow['_node_poormansmysql_lastInsertId'];
+ else if (typeof curRow['_node_poormansmysql_affectedRows'] != 'undefined')
+ _affectedRows = curRow['_node_poormansmysql_affectedRows'];
+ else
+ self.emit('row', curRow, curQuery);
+ curRow = null;
+ } else if (elem == "field")
+ curField = null;
+ });
+ cb.onCharacters(function(chars) {
+ if (curField != null) {
+ if (curRow[curField] == null)
+ curRow[curField] = chars;
+ else
+ curRow[curField] += chars;
+ }
+ });
+ });
+};
+inherits(MysqlConnection, EventEmitter);
+
+exports.MysqlConnection = MysqlConnection;
Please sign in to comment.
Something went wrong with that request. Please try again.