Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add initial library

  • Loading branch information...
commit 36c8869aaf814b81e2c38fc3d880904c61745ea4 0 parents
Alexandre Laurent authored
329 README.md
@@ -0,0 +1,329 @@
+node-mysql-ext
+==============
+
+Node.js Mysql extension to node-mysql
+
+## How to use it
+
+### Simple queries
+
+You have access to the following method through a client:
+- count
+- select
+- selectW
+- insert
+- remove
+- update
+- raw
+- query (alias to raw)
+
+
+If you add a 'p' prefix (pcount, pselect, pselectW, pinsert, premove, pupdate), a connection from the pool is requested and used.
+Else, you have to provide the connection yourself.
+
+```javascript
+var MysqlExtClient = require('mysql-ext').Client;
+
+var client = new MysqlExtClient({
+ host: '127.0.0.1',
+ port: 3306,
+ user: 'root',
+ password: '',
+ database: 'test'
+});
+
+var userObject = {
+ nickname: 'shaoner',
+ email_address: 'shaoner@gmail.com',
+ password: 'bisous',
+ enabled: true
+};
+
+client.pinsert('users', userObject, function(err, res) { });
+
+client.pool.getConnection(function(err, connection) {
+ if (err)
+ throw err;
+ client.insert(connection, 'users', function(err, res) {
+ if (err)
+ throw err;
+ if (res.affectedRows > 0) {
+ client.selectW('users', [ 'nickname', 'email_address' ], { id: 5 }, function(err, res) {
+ if (err)
+ throw err;
+ console.log(res);
+ });
+ }
+ });
+});
+
+```
+
+### Multiple statements
+
+You can build simple multiple statements queries or transactions using the Query object.
+The Query object contains exactly the same functions as the client to build a query:
+- count
+- select
+- selectW
+- insert
+- remove
+- update
+- raw
+
+```javascript
+var MysqlExtClient = require('mysql-ext').Client;
+var Query = require('mysql-ext').Query;
+
+var client = new MysqlExtClient({
+ host: '127.0.0.1',
+ port: 3306,
+ user: 'root',
+ password: '',
+ database: 'test'
+});
+
+var user1 = {
+ nickname: 'shaoner',
+ email_address: 'shaoner@gmail.com',
+ password: 'bisous',
+ enabled: true
+};
+
+var user2 = {
+ nickname: 'user2',
+ email_address: 'user2@mail.com',
+ password: 'mypassword',
+ enabled: true
+};
+
+
+client.ptransaction([
+ Query.insert('users', user1),
+ Query.insert('users', user2),
+ Query.raw('UPDATE otherTable SET uid = LAST_INSERT_ID() AND nickname = ?', [ user2.nickname ], true)
+], function(err) {
+ if (err)
+ throw err;
+ console.log('everything seems fine');
+});
+```
+
+## API
+
+### Query
+
+#### select
+
+```javascript
+/**
+ * Select elements
+ *
+ * @param {string} table
+ * @param {Array.string} fields
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+```
+
+#### selectW
+
+```javascript
+/**
+ * Select elements with a condition
+ *
+ * @param {string} table
+ * @param {Array.string} fields
+ * @param {Object<string, string>} where Build a key = element condition
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+```
+
+#### count
+
+```javascript
+/**
+ * Count elements
+ *
+ * @param {string} table
+ * @param {Object<string, string>} where Build a key = element condition
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+```
+
+#### insert
+
+```javascript
+/**
+ * Insert object
+ *
+ * @param {string} table
+ * @param {Object<string, ?>} values The object to insert
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+```
+
+#### remove
+
+```javascript
+/**
+ * Remove elements matching 'where' condition
+ *
+ * @param {string} table
+ * @param {Object<string, string>} where Build a key = element condition
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+```
+
+#### update
+
+```javascript
+/**
+ * Update a row
+ *
+ * @param {string} table
+ * @param {Object<string, string>} values The values to update in the matched element
+ * @param {Object<string, string>} where Build a key = element condition
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+```
+
+#### raw
+
+```javascript
+/**
+ * Simple raw query
+ *
+ * @param {string} statement
+ * @param {Array.<string>} args
+ * @param {Boolean} affect Tell if this query should affect some rows
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+```
+
+
+### Client
+
+Each of these methods can alternatively be called with a 'p' prefix without providing the connection.
+
+#### Create a new Client
+
+To create a new client, you need to pass it a config object see [node-mysql](https://github.com/felixge/node-mysql) for more details.
+
+#### select
+
+```javascript
+/**
+ * Select elements
+ *
+ * @param {mysql.Connection} connection
+ * @param {string} table
+ * @param {Array.string} fields
+ * @param {Function} callback
+ */
+```
+
+#### selectW
+
+```javascript
+/**
+ * Select elements with a condition
+ *
+ * @param {mysql.Connection} connection
+ * @param {string} table
+ * @param {Array.string} fields
+ * @param {Object<string, string>} where Build a key = element condition
+ * @param {Function} callback
+ */
+```
+
+#### count
+
+```javascript
+/**
+ * Count elements
+ *
+ * @param {mysql.Connection} connection
+ * @param {string} table
+ * @param {Object<string, string>} where Build a key = element condition
+ * @param {Function} callback
+ */
+```
+
+#### insert
+
+```javascript
+/**
+ * Insert object
+ *
+ * @param {mysql.Connection} connection
+ * @param {string} table
+ * @param {Object<string, ?>} values The object to insert
+ * @param {Function} callback
+ */
+```
+
+#### remove
+
+```javascript
+/**
+ * Remove elements matching 'where' condition
+ *
+ * @param {mysql.Connection} connection
+ * @param {string} table
+ * @param {Object<string, string>} where Build a key = element condition
+ * @param {Function} callback
+ */
+```
+
+#### update
+
+```javascript
+/**
+ * Update a row
+ *
+ * @param {mysql.Connection} connection
+ * @param {string} table
+ * @param {Object<string, string>} values The values to update in the matched element
+ * @param {Object<string, string>} where Build a key = element condition
+ * @param {Function} callback
+ */
+```
+
+#### query or raw
+
+```javascript
+/**
+ * Simple raw query
+ *
+ * @param {mysql.Connection} connection
+ * @param {string} statement
+ * @param {Array.<string>} args
+ * @param {Boolean} affect Tell if this query should affect some rows
+ * @param {Function} callback
+ */
+```
+
+#### multi
+
+```javascript
+/**
+ * Run multiple queries at once
+ * To use it, you have to explicitly enable multipleStatements in the config
+ * However this is not always recommanded
+ *
+ * @param {mysql.Connection} connection
+ * @param {Array.Query} queries
+ * @param {Function} callback
+ */
+```
+
+#### transaction
+```javascript
+/**
+ * Starts a transaction
+ *
+ * @param {mysql.Connection} connection
+ * @param {Array.Query} queries
+ * @param {Function} callback
+ */
+```
1  index.js
@@ -0,0 +1 @@
+module.exports = require('./lib');
149 lib/client.js
@@ -0,0 +1,149 @@
+var mysql = require('mysql');
+var Query = require('./query');
+
+/**
+ * A mysql client
+ *
+ * @constructor
+ * @param {Object<string,string>} config The mysql configuration
+ */
+var Client = function(config) {
+ this.pool = mysql.createPool(config);
+ // Directly extends Query object
+ // This is risky but this keeps client and query object coherent
+ // Moreover this is less code to maintain
+ var self = this;
+ for (var prop in Query) {
+ (function(prop) {
+ // This allows to call Query functions through the Client class
+ // Client.<query_method>(connection, ..., callback);
+ self[prop] = function() {
+ var args = Array.prototype.slice.call(arguments);
+ var connection = args.shift();
+ var callback = args.pop();
+ var query = Query[prop].apply(null, args);
+ connection.query(query.statement, query.args, callback);
+ };
+ // Same methods with 'p' prefix (that stands for 'pool')
+ // In this case, the connection is got from the pool
+ // Client.p<query_method>(..., callback);
+ self['p' + prop] = function() {
+ var callback = arguments[arguments.length - 1];
+ var query = Query[prop].apply(null, arguments);
+ self.pool.getConnection(function(err, connection) {
+ if (err)
+ return callback(err);
+ connection.query(query.statement, query.args, function(err, res) {
+ callback(err, res);
+ connection.release();
+ });
+ });
+ };
+ })(prop);
+ }
+ this.query = this.raw;
+ this.pquery = this.praw;
+};
+
+/**
+ * Run multiple queries at once
+ * To use it, you have to explicitly enable multipleStatements in the config
+ * However this is not always recommanded
+ *
+ * @param {mysql.Connection} connection
+ * @param {Array.Query} queries
+ * @param {Function} callback
+ */
+Client.prototype.multi = function(connection, queries, callback) {
+ var statement = 'BEGIN';
+ var args = [];
+ for (var i = 0, len = queries.length; i < len; ++i) {
+ var query = queries[i];
+ statement += ';' + query.statement;
+ args = args.concat(query.args);
+ }
+ statement += ';END;';
+ console.log(statement, args);
+ connection.query(statement, args, callback);
+};
+
+/**
+ * Run multiple queries at once using a connection from the pool
+ * To use it, you have to explicitly enable multipleStatements in the config
+ * However this is not always recommanded
+ *
+ * @param {Array.Query} queries
+ * @param {Function} callback
+ */
+Client.prototype.pmulti = function(queries, callback) {
+ var self = this;
+ this.pool.getConnection(function(err, connection) {
+ if (err)
+ return callback(err);
+ self.multi(connection, queries, function(err, res) {
+ callback(err, res);
+ connection.release();
+ });
+ });
+};
+
+/**
+ * Run recursively each request from a transaction
+ *
+ * @private
+ * @param {mysql.Connection} connection
+ * @param {Array.Query} queries
+ * @param {Function} callback
+ */
+Client.prototype._recTransaction = function(connection, queries, callback) {
+ var self = this;
+ var query = queries.shift();
+ connection.query(query.statement, query.args, function(err, res) {
+ if (err) {
+ connection.query('ROLLBACK');
+ return callback(err, res);
+ }
+ if (query.affect && res.affectedRows === 0) {
+ connection.query('ROLLBACK');
+ return callback('No affected: ' + query.statement);
+ }
+ if (queries.length > 0)
+ self._recTransaction(connection, queries, callback);
+ else
+ connection.query('COMMIT', callback);
+ });
+};
+
+/**
+ * Starts a transaction
+ *
+ * @param {mysql.Connection} connection
+ * @param {Array.Query} queries
+ * @param {Function} callback
+ */
+Client.prototype.transaction = function(connection, queries, callback) {
+ var self = this;
+ connection.query('START TRANSACTION', function(err) {
+ self._recTransaction(connection, queries, callback);
+ });
+};
+
+/**
+ * Starts a transaction with a connection from the pool
+ *
+ * @param {Array.Query} queries
+ * @param {Function} callback
+ */
+Client.prototype.ptransaction = function(queries, callback) {
+ var self = this;
+ this.pool.getConnection(function(err, connection) {
+ if (err)
+ return callback(err);
+ self.transaction(connection, queries, function(err, res) {
+ callback(err, res);
+ connection.release();
+ });
+ });
+};
+
+module.exports = Client;
2  lib/index.js
@@ -0,0 +1,2 @@
+module.exports.Client = require('./client');
+module.exports.Query = require('./query');
123 lib/query.js
@@ -0,0 +1,123 @@
+/**
+ * Query builder
+ */
+var Query = { };
+
+/**
+ * Build a string with placeholders and the relative values
+ * @return {Object<string, (string|Array.string)>}
+ */
+function hashToClause(hash, separator) {
+ var result = '';
+ var values = [];
+ var first = true;
+ for (var key in hash) {
+ result += (first ? '' : separator) + key + ' = ?';
+ values.push(hash[key]);
+ first = false;
+ }
+ return { placeholder: result, values: values };
+};
+
+/**
+ * Build a raw query
+ *
+ * @param {string} statement
+ * @param {Array.<string>} args
+ * @param {Boolean} affect Tell if this query should affect some rows
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+Query.raw = function(statement, args, affect) {
+ return { statement: statement, args: args, affect: affect };
+};
+
+/**
+ * Count elements
+ *
+ * @param {string} table
+ * @param {Object<string, string>} where Build a key = element condition
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+Query.count = function(table, where) {
+ var statement = 'SELECT COUNT(*) AS len FROM ' + table + ' WHERE ';
+ var clause = hashToClause(where, ' AND ');
+ statement += clause.placeholder;
+ return { statement: statement, args: clause.values, affect: false };
+};
+
+
+/**
+ * Select elements
+ *
+ * @param {string} table
+ * @param {Array.string} fields
+ * @param {Object<string, string>} where Build a key = element condition
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+Query.select = function(table, fields) {
+ var cols = fields.join(',');
+ var statement = 'SELECT ' + cols + ' FROM ' + table;
+ return { statement: statement, args: [], affect: false };
+};
+
+/**
+ * Select elements with a condition
+ *
+ * @param {string} table
+ * @param {Array.string} fields
+ * @param {Object<string, string>} where Build a key = element condition
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+Query.selectW = function(table, fields, where) {
+ var cols = fields.join(',');
+ var statement = 'SELECT ' + cols + ' FROM ' + table + ' WHERE '
+ var clause = hashToClause(where, ' AND ');
+ statement += clause.placeholder;
+ return { statement: statement, args: clause.values, affect: false };
+};
+
+/**
+ * Insert object
+ *
+ * @param {string} table
+ * @param {Object<string, ?>} values The object to insert
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+Query.insert = function(table, values) {
+ var statement = 'INSERT INTO ' + table + ' SET ';
+ var clause = hashToClause(values, ',');
+ statement += clause.placeholder;
+ return { statement: statement, args: clause.values, affect: true };
+};
+
+/**
+ * Remove elements matching 'where' condition
+ *
+ * @param {string} table
+ * @param {Object<string, string>} where Build a key = element condition
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+Query.remove = function(table, where) {
+ var statement = 'DELETE FROM ' + table + ' WHERE ';
+ var clause = hashToClause(where, ' AND ');
+ statement += clause.placeholder;
+ return { statement: statement, args: clause.values, affect: true };
+};
+
+/**
+ * Update a row
+ *
+ * @param {string} table
+ * @param {Object<string, string>} values The values to update in the matched element
+ * @param {Object<string, string>} where Build a key = element condition
+ * @returns {Object<string, (string|Array.string|boolean)>}
+ */
+Query.update = function(table, values, where) {
+ var valuesClause = hashToClause(values, ' AND ');
+ var whereClause = hashToClause(where, ' AND ');
+ var statement = 'UPDATE ' + table + ' SET ' + valuesClause.placeholder + ' WHERE ' +
+ whereClause.placeholder;
+ return { statement: statement, args: valuesClause.values.concat(whereClause.values), affect: true };
+};
+
+module.exports = Query;
37 package.json
@@ -0,0 +1,37 @@
+{
+ "name": "mysql-ext",
+ "version": "0.0.1",
+ "description": "Extension to mysql module abstracting some common SQL queries",
+ "main": "index.js",
+ "directories": {
+ "test": "test"
+ },
+ "scripts": {
+ "test": "node tests"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "dependencies": {
+ "mysql": "~2.0.0-alpha9"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/shaoner/node-mysql-ext.git"
+ },
+ "keywords": [
+ "mysql",
+ "helper",
+ "mysql-ext",
+ "extension"
+ ],
+ "author": {
+ "name": "Alexandre Laurent",
+ "email": "shaoner@gmail.com",
+ "url": "http://www.spe4k.com/"
+ },
+ "license": "BSD-2-Clause",
+ "bugs": {
+ "url": "https://github.com/shaoner/node-mysql-ext/issues"
+ }
+}
0  tests/index.js
No changes.
Please sign in to comment.
Something went wrong with that request. Please try again.