Skip to content
Browse files

* initial check in.

  • Loading branch information...
1 parent 6fa4003 commit dae596371f846ac290d45279c0dd643fdc6e955c @redblaze committed Aug 28, 2013
Showing with 595 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +145 −0 lib/db.js
  3. +235 −0 lib/model.js
  4. +12 −0 lib/node-mysql.js
  5. +34 −0 package.json
  6. +108 −0 test/example_model.js
  7. +57 −0 test/test.js
View
4 .gitignore
@@ -0,0 +1,4 @@
+.idea
+*.iml
+npm-debug.log
+node_modules
View
145 lib/db.js
@@ -0,0 +1,145 @@
+
+var Class = require('better-js-class');
+
+var cps = require('cps');
+
+var mysql = require('mysql');
+
+var $U = require('underscore');
+
+module.exports = function() {
+ var DB = Class({
+ _init: function(cfg) {
+ this._cfg = cfg;
+ this._pool = mysql.createPool(cfg);
+ this._transactionPool = mysql.createPool(cfg);
+ },
+
+ connect: function(proc, cb) {
+ var me = this;
+ var conn;
+ cps.seq([
+ function(_, cb) {
+ me._pool.getConnection(cb);
+ },
+ function(res, cb) {
+ conn = res;
+ cps.rescue({
+ 'try': function(cb) {
+ proc(conn, cb);
+ },
+ 'finally': function(cb) {
+ conn.release();
+ cb();
+ }
+ }, cb);
+ }
+ ], cb);
+ },
+
+ transaction: function(conn, proc, cb) {
+ var me = this;
+ var txnConn;
+ var commitRes;
+
+ if (me._isTxnConnection(conn)) {
+ proc(conn, cb);
+ } else {
+ cps.seq([
+ function(_, cb) {
+ me._getTxnConnection(cb);
+ },
+ function(res, cb) {
+ txnConn = res;
+ cps.rescue({
+ 'try': function(cb) {
+ cps.seq([
+ function(_, cb) {
+ txnConn.query('START TRANSACTION', cb);
+ },
+ function(_, cb) {
+ cps.rescue({
+ 'try': function(cb) {
+ cps.seq([
+ function(_, cb) {
+ proc(txnConn, cb);
+ },
+ function(res, cb) {
+ commitRes = res;
+ conn.query('COMMIT', cb);
+ },
+ function(_, cb) {
+ cb(null, commitRes);
+ }
+ ], cb);
+ },
+ 'catch': function(err, cb) {
+ cps.seq([
+ function(_, cb) {
+ conn.query('ROLLBACK', cb);
+ },
+ function(_, cb) {
+ throw(err);
+ }
+ ], cb);
+ }
+ }, cb);
+ }
+ ], cb);
+ },
+ 'finally': function(cb) {
+ txnConn.release();
+ cb();
+ }
+ }, cb);
+ }
+ ], cb);
+ }
+ },
+
+ _isTxnConnection: function(conn) {
+ return conn != null && conn.__transaction__;
+ },
+
+ _getTxnConnection: function(cb) {
+ var me = this;
+
+ cps.seq([
+ function(_, cb) {
+ me._transactionPool.getConnection(cb);
+ },
+ function(conn, cb) {
+ conn.__transaction__ = true;
+ cb(null, conn);
+ }
+ ], cb);
+ },
+
+ end: function() {
+ this._pool.end();
+ }
+ });
+
+ $U.extend(DB, {
+ format: function(str, bindings) {
+ var l = str.split('?')
+
+ if (l.length - 1 != bindings.length) {
+ throw new Error('sql string format error');
+ }
+
+ var res = [];
+
+ for (var i = 0; i < bindings.length; i++) {
+ res.push(l[i]);
+ res.push(mysql.escape(bindings[i]));
+ }
+
+ res.push(l[l.length - 1]);
+
+ return res.join(' ');
+ }
+ });
+
+ return DB;
+}();
View
235 lib/model.js
@@ -0,0 +1,235 @@
+
+var Class = require('better-js-class');
+var cps = require('cps');
+var $U = require('underscore');
+
+var DB = require('./db.js');
+
+module.exports = function() {
+ var Model = {
+ OPTIMISTIC_LOCK_EXCEPTION: 'optimistic_lock_exception'
+ };
+
+ var Row = Class({
+ _init: function(data, cfg) {
+ this._table = cfg.table;
+ this._data = data;
+ },
+
+ getId: function() {
+ return this._data[this._table.getIdFieldName()];
+ },
+
+ _getVersion: function() {
+ return this._data[this._table.getVersionFieldName()];
+ },
+
+ _nextVersion: function() {
+ return this._data[this._table.getVersionFieldName()] + 1;
+ },
+
+ _updateLocalData: function(dto) {
+ for (var k in dto) {
+ var v = dto[k];
+ this._data[k] = v;
+ }
+ },
+
+ updateWithoutOptimisticLock: function(conn, dto, cb) {
+ this._update(conn, dto, null, cb);
+ },
+
+ update: function(conn, dto, cb) {
+ var me = this;
+
+ dto['version'] = this._nextVersion();
+ var cond = DB.format('version = ?', [this._getVersion()]);
+
+ cps.seq([
+ function(_, cb) {
+ me._update(conn, dto, cond, cb);
+ },
+ function(res, cb) {
+ if (res.changedRows === 0) {
+ throw new Error(Model.OPTIMISTIC_LOCK_EXCEPTION);
+ } else {
+ cb(null, res);
+ }
+ }
+ ], cb);
+ },
+
+ _update: function(conn, dto, conditions, cb) {
+ var me = this;
+
+ dto[this._table.getUpdatedFieldName()] = new Date();
+
+ var l = [
+ ' update ', this._table.getName(), ' set '
+ ];
+
+ var first = true;
+ for (var k in dto) {
+ var v = dto[k];
+ if (first) {
+ first = false;
+ } else {
+ l.push(', ');
+ }
+ l.push(
+ ' ', k, ' = ', conn.escape(v)
+ );
+ }
+
+ l.push(
+ ' where ', this._table.getIdFieldName(), ' = ', this.getId()
+ );
+
+ l.push(
+ ' and ', conditions
+ );
+
+ l.push(' ; ');
+
+ var q = l.join('');
+
+ console.log(q);
+
+ cps.seq([
+ function(_, cb) {
+ conn.query(q, cb);
+ },
+ function(res, cb) {
+ me._updateLocalData(dto);
+ cb(null, res);
+ }
+ ], cb);
+ },
+
+ get: function(fieldName) {
+ return this._data[fieldName]
+ }
+ });
+
+ var Table = Class({
+ _init: function(cfg) {
+ this._name = cfg.name;
+ this._idFieldName = cfg.idFieldName || 'id';
+ this._versionFieldName = cfg.versionFieldName || 'version';
+ this._createdFieldName = cfg.createdFieldName || 'date_created';
+ this._updatedFieldName = cfg.updatedFieldName || 'last_updated';
+
+ this._rowClass = cfg['rowClass'];
+ this._schema = cfg['schema'];
+ },
+
+ getName: function() {
+ return this._name;
+ },
+
+ getIdFieldName: function() {
+ return this._idFieldName;
+ },
+
+ getVersionFieldName: function() {
+ return this._versionFieldName;
+ },
+
+ getCreatedFieldName: function() {
+ return this._createdFieldName;
+ },
+
+ getUpdatedFieldName: function() {
+ return this._updatedFieldName;
+ },
+
+ create: function(conn, dto, cb) {
+ var me = this;
+
+ var d = new Date();
+ dto[this.getCreatedFieldName()] = d;
+ dto[this.getUpdatedFieldName()] = d;
+ dto[this.getVersionFieldName()] = 0;
+
+ $U.each(this._schema, function(field) {
+ if (dto[field] == null) {
+ dto[field] = null;
+ }
+ });
+
+ var l = [
+ ' insert into ' + this.getName() + ' set '
+ ];
+
+ var first = true;
+
+ $U.each(dto, function(v, k) {
+ if (first) {
+ first = false;
+ } else {
+ l.push(', ');
+ }
+ l.push(
+ ' ', k, ' = ', conn.escape(v)
+ );
+ });
+
+ l.push(' ; ');
+
+ var q = l.join('');
+
+ cps.seq([
+ function(_, cb) {
+ conn.query(q, cb);
+ },
+ function(res, cb) {
+ dto[me._idFieldName] = res.insertId;
+ cb(null, new me._rowClass(dto));
+ }
+ ], cb);
+ },
+
+ baseQuery: function() {
+ return ' select * from ' + this.getName() + ' ';
+ },
+
+ findById: function(conn, id, cb) {
+ var q = DB.format(this.baseQuery() + ' where ' + this.getIdFieldName() + ' = ?' , [id]);
+
+ cps.seq([
+ function(_, cb) {
+ this.find(conn, q, cb);
+ },
+ function(res) {
+ cb(null, res[0])
+ }
+ ], cb);
+ },
+
+ findAll: function(conn, cb) {
+ this.find(conn, this.baseQuery(), cb);
+ },
+
+ find: function(conn, q, cb) {
+ var me = this;
+
+ cps.seq([
+ function(_, cb) {
+ conn.query(q, cb);
+ },
+ function(res, cb) {
+ cb(null, $U.map(res, function(o) {
+ return new me._rowClass(o);
+ }));
+ }
+ ], cb);
+ }
+ });
+
+ $U.extend(Model, {
+ Row: Row,
+ Table: Table
+ });
+
+ return Model;
+}();
View
12 lib/node-mysql.js
@@ -0,0 +1,12 @@
+
+var DB = require('./db.js');
+var Model = require('./model.js');
+
+module.exports = {
+ DB: DB,
+ Row: Model.Row,
+ Table: Model.Table,
+ OPTIMISTIC_LOCK_EXCEPTION: Model.OPTIMISTIC_LOCK_EXCEPTION
+}
+
+
View
34 package.json
@@ -0,0 +1,34 @@
+{
+ "name": "node-mysql",
+ "description": "A wrapper of node.js mysql package to make it a bit easier to use.",
+ "main": "./lib/node-mysql",
+ "author": "Chiyan Chen",
+ "version": "0.1.1",
+ "repository" : {
+ "type" : "git",
+ "url" : "https://github.com/redblaze/node-mysql.git"
+ },
+ "bugs" : {
+ "url" : "https://github.com/redblaze/node-mysql/issues"
+ },
+ "licenses" : [
+ {
+ "type" : "MIT",
+ "url" : "https://github.com/redblaze/node-mysql/raw/master/LICENSE"
+ }
+ ],
+ "jam": {
+ "main": "lib/node-mysql.js",
+ "include": [
+ "lib/node-mysql.js",
+ "README.md",
+ "LICENSE"
+ ]
+ },
+ "dependencies": {
+ "better-js-class": "*",
+ "cps": "*",
+ "mysql": "*",
+ "underscore": "*"
+ }
+}
View
108 test/example_model.js
@@ -0,0 +1,108 @@
+
+var cps = require('cps');
+var Class = require('better-js-class');
+var $U = require('underscore');
+
+var db = require('../lib/node-mysql.js');
+var DB = db.DB;
+
+
+var cb = function() {
+ var handleError = function(e) {
+ if (e.stack) {
+ console.log(e.stack);
+ } else {
+ console.log(e);
+ }
+ };
+
+ var start = new Date();
+ return function(err, res) {
+ try {
+ var end = new Date();
+ console.log('time spent: ', end-start);
+ if (err) {
+ handleError(err);
+ } else {
+ console.log(res);
+ }
+ } catch(e) {
+ handleError(e);
+ } finally {
+ dw.end();
+ }
+ };
+}();
+
+
+var Model = function() {
+ var cls = {
+ };
+
+ var Row = Class(db.Row, {
+ _init: function(data) {
+ this.parent._init.call(this, data, {
+ table: Table
+ });
+ }
+ });
+
+ var TableClass = Class(db.Table, {
+ });
+
+ var Table = new TableClass({
+ 'name': 'subscription_initiation',
+ 'idFieldName': 'id',
+ 'rowClass': Row,
+ 'schema': [
+ 'id',
+ 'version',
+ 'date_created',
+ 'last_updated',
+ 'user_id',
+ 'subscription_id',
+ 'gift_id',
+ 'init_date',
+ 'subscription_status'
+ ]
+ });
+
+ $U.extend(cls, {
+ Row: Row,
+ Table: Table
+ });
+
+ return cls;
+}();
+
+var dw = new db.DB({
+ host : 'localhost',
+ user : 'root',
+ password : '',
+ database : 'data_warehouse_dev'
+});
+
+var findAndUpdateTest = function(cb) {
+ dw.connect(function(conn, cb) {
+ var o;
+ cps.seq([
+ function(_, cb) {
+ var q = Model.Table.baseQuery() + DB.format('limit ?', [1]);
+ Model.Table.find(conn, q, cb);
+ },
+ function(res, cb) {
+ o = res[0];
+ var dto = {
+ 'subscription_status': 'active'
+ };
+ o.update(conn, dto, cb);
+ },
+ function(res, cb) {
+ console.log(res);
+ cb();
+ }
+ ], cb);
+ }, cb);
+};
+
+findAndUpdateTest(cb);
View
57 test/test.js
@@ -0,0 +1,57 @@
+var cps = require('cps');
+
+var db = require('../lib/node-mysql.js');
+var DB = db.DB;
+var Row = db.Row;
+var Table = db.Table;
+
+var cb = function() {
+ var handleError = function(e) {
+ if (e.stack) {
+ console.log(e.stack);
+ } else {
+ console.log(e);
+ }
+ };
+
+ var start = new Date();
+ return function(err, res) {
+ try {
+ var end = new Date();
+ console.log('time spent: ', end-start);
+ if (err) {
+ handleError(err);
+ } else {
+ console.log(res);
+ }
+ box.end();
+ } catch(e) {
+ handleError(e);
+ box.end();
+ }
+ };
+}();
+
+var box = new DB({
+ host : 'localhost',
+ user : 'root',
+ password : '',
+ database : 'prod_clone'
+});
+
+var basicTest = function(cb) {
+ box.connect(function(conn, cb) {
+ cps.seq([
+ function(_, cb) {
+ conn.query('select * from users limit 1', cb);
+ },
+ function(res, cb) {
+ console.log(res);
+ cb();
+ }
+ ], cb);
+ }, cb);
+};
+
+
+basicTest(cb);

0 comments on commit dae5963

Please sign in to comment.
Something went wrong with that request. Please try again.