diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/lib/adapters/mysql.js b/lib/adapters/mysql.js index 0d955060..3de4efea 100644 --- a/lib/adapters/mysql.js +++ b/lib/adapters/mysql.js @@ -27,11 +27,20 @@ MySQL.prototype.define = function (descr) { this._models[descr.model.modelName] = descr; }; +MySQL.prototype.query = function (sql, callback) { + var time = Date.now(); + var log = this.log; + this.client.query(sql, function (err, data) { + log(sql, time); + callback(err, data); + }); +}; + MySQL.prototype.save = function (model, data, callback) { var sql = 'UPDATE ' + model + ' SET ' + this.toFields(model, data) + ' WHERE id = ' + data.id; - this.client.query(sql, function (err) { + this.query(sql, function (err) { callback(err); }); }; @@ -47,7 +56,7 @@ MySQL.prototype.create = function (model, data, callback) { } else { sql += ' VALUES ()'; } - this.client.query(sql, function (err, info) { + this.query(sql, function (err, info) { callback(err, info && info.insertId); }); }; @@ -98,7 +107,7 @@ MySQL.prototype.fromDatabase = function (model, data) { MySQL.prototype.exists = function (model, id, callback) { var sql = 'SELECT 1 FROM ' + model + ' WHERE id = ' + id + ' LIMIT 1'; - this.client.query(sql, function (err, data) { + this.query(sql, function (err, data) { if (err) return callback(err); callback(null, data.length === 1); }); @@ -106,7 +115,7 @@ MySQL.prototype.exists = function (model, id, callback) { MySQL.prototype.find = function find(model, id, callback) { var sql = 'SELECT * FROM ' + model + ' WHERE id = ' + id + ' LIMIT 1'; - this.client.query(sql, function (err, data) { + this.query(sql, function (err, data) { if (data && data.length === 1) { data[0].id = id; } else { @@ -118,14 +127,14 @@ MySQL.prototype.find = function find(model, id, callback) { MySQL.prototype.destroy = function destroy(model, id, callback) { var sql = 'DELETE FROM ' + model + ' WHERE id = ' + id + ' LIMIT 1'; - this.client.query(sql, function (err) { + this.query(sql, function (err) { callback(err); }); }; // TODO: hook up where, order, limit and offset conditions MySQL.prototype.all = function all(model, filter, callback) { - this.client.query('SELECT * FROM ' + model, function (err, data) { + this.query('SELECT * FROM ' + model, function (err, data) { if (err) { return callback(err, []); } @@ -158,7 +167,7 @@ function applyFilter(filter) { } MySQL.prototype.destroyAll = function destroyAll(model, callback) { - this.client.query('DELETE FROM ' + model, function (err) { + this.query('DELETE FROM ' + model, function (err) { if (err) { return callback(err, []); } @@ -167,7 +176,7 @@ MySQL.prototype.destroyAll = function destroyAll(model, callback) { }; MySQL.prototype.count = function count(model, callback) { - this.client.query('SELECT count(*) as cnt FROM ' + model, function (err, res) { + this.query('SELECT count(*) as cnt FROM ' + model, function (err, res) { callback(err, err ? null : res[0].cnt); }); }; @@ -177,3 +186,7 @@ MySQL.prototype.updateAttributes = function updateAttrs(model, id, data, cb) { this.save(model, data, cb); }; +MySQL.prototype.disconnect = function disconnect() { + this.client.end(); +}; + diff --git a/lib/adapters/redis.js b/lib/adapters/redis.js index 9e7179ca..d2a170a3 100644 --- a/lib/adapters/redis.js +++ b/lib/adapters/redis.js @@ -39,7 +39,9 @@ BridgeToRedis.prototype.defineForeignKey = function (model, key, cb) { }; BridgeToRedis.prototype.save = function (model, data, callback) { + var log = this.logger('HMSET ' + model + ':' + data.id + ' ...'); this.client.hmset(model + ':' + data.id, data, function (err) { + log(); if (err) return callback(err); this.updateIndexes(model, data.id, data, callback); }.bind(this)); @@ -68,7 +70,9 @@ BridgeToRedis.prototype.updateIndexes = function (model, id, data, callback) { }; BridgeToRedis.prototype.create = function (model, data, callback) { + var log = this.logger('INCR id:' + model); this.client.incr('id:' + model, function (err, id) { + log(); data.id = id; this.save(model, data, function (err) { if (callback) { @@ -79,7 +83,9 @@ BridgeToRedis.prototype.create = function (model, data, callback) { }; BridgeToRedis.prototype.exists = function (model, id, callback) { + var log = this.logger('EXISTS ' + model + ':' + id); this.client.exists(model + ':' + id, function (err, exists) { + log(); if (callback) { callback(err, exists); } @@ -87,20 +93,24 @@ BridgeToRedis.prototype.exists = function (model, id, callback) { }; BridgeToRedis.prototype.find = function find(model, id, callback) { + var t1 = Date.now(); this.client.hgetall(model + ':' + id, function (err, data) { + this.log('HGETALL ' + model + ':' + id, t1); if (data && data.id) { data.id = id; } else { data = null; } callback(err, data); - }); + }.bind(this)); }; BridgeToRedis.prototype.destroy = function destroy(model, id, callback) { + var t1 = Date.now(); this.client.del(model + ':' + id, function (err) { + this.log('DEL ' + model + ':' + id, t1); callback(err); - }); + }.bind(this)); }; BridgeToRedis.prototype.possibleIndexes = function (model, filter) { @@ -119,16 +129,23 @@ BridgeToRedis.prototype.possibleIndexes = function (model, filter) { BridgeToRedis.prototype.all = function all(model, filter, callback) { var ts = Date.now(); var client = this.client; + var log = this.log; + var t1 = Date.now(); + var cmd; var indexes = this.possibleIndexes(model, filter); if (indexes.length) { + cmd = 'SINTER "' + indexes.join('" "') + '"'; indexes.push(handleKeys); client.sinter.apply(client, indexes); } else { + cmd = 'KEYS ' + model + ':*'; client.keys(model + ':*', handleKeys); } function handleKeys(err, keys) { + log(cmd, t1); + var t2 = Date.now(); if (err) { return callback(err, []); } @@ -136,6 +153,7 @@ BridgeToRedis.prototype.all = function all(model, filter, callback) { return ['hgetall', key]; }); client.multi(query).exec(function (err, replies) { + log(query, t2); // console.log('Redis time: %dms', Date.now() - ts); callback(err, filter ? replies.filter(applyFilter(filter)) : replies); }); @@ -167,32 +185,43 @@ function applyFilter(filter) { } BridgeToRedis.prototype.destroyAll = function destroyAll(model, callback) { - this.client.keys(model + ':*', function (err, keys) { + var keysQuery = model + ':*'; + var t1 = Date.now(); + this.client.keys(keysQuery, function (err, keys) { + this.log('KEYS ' + keysQuery, t1); if (err) { return callback(err, []); } var query = keys.map(function (key) { return ['del', key]; }); + var t2 = Date.now(); this.client.multi(query).exec(function (err, replies) { + this.log(query, t2); callback(err); - }); + }.bind(this)); }.bind(this)); }; BridgeToRedis.prototype.count = function count(model, callback) { - this.client.keys(model + ':*', function (err, keys) { + var keysQuery = model + ':*'; + var t1 = Date.now(); + this.client.keys(keysQuery, function (err, keys) { + this.log('KEYS ' + keysQuery, t1); callback(err, err ? null : keys.length); - }); + }.bind(this)); }; BridgeToRedis.prototype.updateAttributes = function updateAttrs(model, id, data, cb) { + var t1 = Date.now(); this.client.hmset(model + ':' + id, data, function () { + this.log('HMSET ' + model + ':' + id, t1); this.updateIndexes(model, id, data, cb); }.bind(this)); }; BridgeToRedis.prototype.disconnect = function disconnect() { + this.log('QUIT', Date.now()); this.client.quit(); }; diff --git a/lib/schema.js b/lib/schema.js index b2fa18e6..336d4d91 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -23,6 +23,7 @@ var slice = Array.prototype.slice; * establish connection (of course it depends on specific adapter) */ function Schema(name, settings) { + var schema = this; // just save everything we get this.name = name; this.settings = settings; @@ -54,6 +55,18 @@ function Schema(name, settings) { if (!this.adapter) { throw new Error('Adapter is not defined correctly: it should create `adapter` member of schema'); } + + this.adapter.log = function (query, start) { + schema.log(query, start); + }; + + this.adapter.logger = function (query) { + var t1 = Date.now(); + var log = this.log; + return function (q) { + log(q || query, t1); + }; + }; }; util.inherits(Schema, process.EventEmitter); @@ -71,6 +84,9 @@ Schema.prototype.automigrate = function (cb) { } }; +Schema.prototype.log = function () { +}; + Schema.prototype.freeze = function freeze() { if (this.adapter.freezeSchema) { this.adapter.freezeSchema(); diff --git a/package.json b/package.json index 56e3a83e..41089094 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Anatoliy Chakkaev", "name": "jugglingdb", "description": "ORM for every database: redis, mysql, neo4j, mongodb", - "version": "0.0.4", + "version": "0.0.5", "repository": { "url": "https://github.com/1602/jugglingdb" },