This commit is contained in:
Anatoliy Chakkaev 2011-10-23 23:43:53 +04:00
parent 8b6c608c6c
commit f251ac9a5b
4 changed files with 99 additions and 48 deletions

View File

@ -8,14 +8,12 @@ exports.initialize = function initializeSchema(schema, callback) {
schema.client = mysql.createClient({ schema.client = mysql.createClient({
host: s.host || 'localhost', host: s.host || 'localhost',
port: s.port || 3306, port: s.port || 3306,
user: s.user, user: s.username,
password: s.password, password: s.password,
database: s.database, database: s.database,
debug: s.debug debug: s.debug
}); });
schema.client.auth(schema.settings.password, callback);
schema.adapter = new MySQL(schema.client); schema.adapter = new MySQL(schema.client);
}; };
@ -29,57 +27,107 @@ MySQL.prototype.define = function (descr) {
}; };
MySQL.prototype.save = function (model, data, callback) { MySQL.prototype.save = function (model, data, callback) {
this.client.query() var sql = 'UPDATE ' + model + ' SET ' + this.toFields(model, data) +
this.client.hmset(model + ':' + data.id, data, callback); ' WHERE id = ' + data.id;
this.client.query(sql, function (err) {
callback(err);
});
}; };
/**
* Must invoke callback(err, id)
*/
MySQL.prototype.create = function (model, data, callback) { MySQL.prototype.create = function (model, data, callback) {
this.client.incr(model + ':id', function (err, id) { var fields = this.toFields(model, data);
data.id = id; var sql = 'INSERT ' + model;
this.save(model, data, function (err) { if (fields) {
if (callback) { sql += ' SET ' + fields;
callback(err, id); } else {
sql += ' VALUES ()';
} }
this.client.query(sql, function (err, info) {
callback(err, info && info.insertId);
}); });
};
MySQL.prototype.toFields = function (model, data) {
var fields = [];
var props = this._models[model].properties;
Object.keys(data).forEach(function (key) {
if (props[key]) {
fields.push(key + ' = ' + this.toDatabase(props[key], data[key]));
}
}.bind(this)); }.bind(this));
return fields.join(',');
};
MySQL.prototype.toDatabase = function (prop, val) {
if (prop.type.name === 'Number') return val;
if (val === null) return 'NULL';
if (prop.type.name === 'Date') {
if (!val.toUTCString) {
val = new Date(val);
}
val = [
val.getFullYear(),
val.getMonth() + 1,
val.getDate(),
val.getHours(),
val.getMinutes(),
val.getSeconds()
].join('-');
return this.client.escape(val);
}
return this.client.escape(val.toString());
};
MySQL.prototype.fromDatabase = function (model, data) {
if (!data) return null;
var props = this._models[model].properties;
Object.keys(data).forEach(function (key) {
var val = data[key];
if (props[key]) {
// if (props[key])
}
data[key] = val;
});
return data;
}; };
MySQL.prototype.exists = function (model, id, callback) { MySQL.prototype.exists = function (model, id, callback) {
this.client.exists(model + ':' + id, function (err, exists) { var sql = 'SELECT 1 FROM ' + model + ' WHERE id = ' + id + ' LIMIT 1';
if (callback) { this.client.query(sql, function (err, data) {
callback(err, exists); if (err) return callback(err);
} callback(null, data.length === 1);
}); });
}; };
MySQL.prototype.find = function find(model, id, callback) { MySQL.prototype.find = function find(model, id, callback) {
this.client.hgetall(model + ':' + id, function (err, data) { var sql = 'SELECT * FROM ' + model + ' WHERE id = ' + id + ' LIMIT 1';
if (data && data.id) { this.client.query(sql, function (err, data) {
data.id = id; if (data && data.length === 1) {
data[0].id = id;
} else { } else {
data = null; data = [null];
} }
callback(err, data); callback(err, this.fromDatabase(model, data[0]));
}); }.bind(this));
}; };
MySQL.prototype.destroy = function destroy(model, id, callback) { MySQL.prototype.destroy = function destroy(model, id, callback) {
this.client.del(model + ':' + id, function (err) { var sql = 'DELETE FROM ' + model + ' WHERE id = ' + id + ' LIMIT 1';
this.client.query(sql, function (err) {
callback(err); callback(err);
}); });
}; };
MySQL.prototype.all = function all(model, filter, callback) { MySQL.prototype.all = function all(model, filter, callback) {
this.client.keys(model + ':*', function (err, keys) { this.client.query('SELECT * FROM ' + model, function (err, data) {
if (err) { if (err) {
return callback(err, []); return callback(err, []);
} }
var query = keys.map(function (key) { callback(err, filter ? data.filter(applyFilter(filter)) : data);
return ['hgetall', key];
});
this.client.multi(query).exec(function (err, replies) {
callback(err, filter ? replies.filter(applyFilter(filter)) : replies);
});
}.bind(this)); }.bind(this));
}; };
@ -108,27 +156,22 @@ function applyFilter(filter) {
} }
MySQL.prototype.destroyAll = function destroyAll(model, callback) { MySQL.prototype.destroyAll = function destroyAll(model, callback) {
this.client.keys(model + ':*', function (err, keys) { this.client.query('DELETE FROM ' + model, function (err) {
if (err) { if (err) {
return callback(err, []); return callback(err, []);
} }
var query = keys.map(function (key) {
return ['del', key];
});
this.client.multi(query).exec(function (err, replies) {
callback(err); callback(err);
});
}.bind(this)); }.bind(this));
}; };
MySQL.prototype.count = function count(model, callback) { MySQL.prototype.count = function count(model, callback) {
this.client.keys(model + ':*', function (err, keys) { this.client.query('SELECT count(*) as cnt FROM ' + model, function (err, res) {
callback(err, err ? null : keys.length); callback(err, err ? null : res[0].cnt);
}); });
}; };
MySQL.prototype.updateAttributes = function updateAttrs(model, id, data, cb) { MySQL.prototype.updateAttributes = function updateAttrs(model, id, data, cb) {
this.client.hmset(model + ':' + id, data, cb); data.id = id;
this.save(model, data, cb);
}; };

View File

@ -3,6 +3,7 @@
*/ */
var AbstractClass = require('./abstract-class').AbstractClass; var AbstractClass = require('./abstract-class').AbstractClass;
var util = require('util'); var util = require('util');
var path = require('path');
/** /**
* Export public API * Export public API
@ -34,9 +35,9 @@ function Schema(name, settings) {
// this is only one initialization entry point of adapter // this is only one initialization entry point of adapter
// this module should define `adapter` member of `this` (schema) // this module should define `adapter` member of `this` (schema)
var adapter; var adapter;
try { if (path.existsSync(__dirname + '/adapters/' + name + '.js')) {
adapter = require('./adapters/' + name); adapter = require('./adapters/' + name);
} catch (e) { } else {
try { try {
adapter = require(name); adapter = require(name);
} catch (e) { } catch (e) {
@ -146,10 +147,10 @@ Schema.prototype.defineForeignKey = function defineForeignKey(className, key) {
if (this.adapter.defineForeignKey) { if (this.adapter.defineForeignKey) {
this.adapter.defineForeignKey(className, key, function (err, keyType) { this.adapter.defineForeignKey(className, key, function (err, keyType) {
if (err) throw err; if (err) throw err;
this.definitions[className].properties[key] = keyType; this.definitions[className].properties[key] = {type: keyType};
}.bind(this)); }.bind(this));
} else { } else {
this.definitions[className].properties[key] = Number; this.definitions[className].properties[key] = {type: Number};
} }
}; };

View File

@ -15,7 +15,8 @@
}, },
"dependencies": { "dependencies": {
"redis": ">= 0.6.7", "redis": ">= 0.6.7",
"mongoose": ">= 2.2.3" "mongoose": ">= 2.2.3",
"mysql": ">= 0.9.4"
}, },
"devDependencies": {} "devDependencies": {}
} }

View File

@ -11,6 +11,10 @@ var schemas = {
database: 'sequ-test', database: 'sequ-test',
username: 'root' username: 'root'
}, },
mysql: {
database: 'sequ-test',
username: 'root'
},
neo4j: { url: 'http://localhost:7474/' }, neo4j: { url: 'http://localhost:7474/' },
mongoose: { url: 'mongodb://localhost/test' }, mongoose: { url: 'mongodb://localhost/test' },
redis: {}, redis: {},
@ -128,7 +132,7 @@ function testOrm(schema) {
title: title, title: title,
date: date date: date
}, function (err, obj) { }, function (err, obj) {
test.ok(obj.id); test.ok(obj.id, 'Object id should present');
test.equals(obj.title, title); test.equals(obj.title, title);
// test.equals(obj.date, date); // test.equals(obj.date, date);
obj.title = title2; obj.title = title2;
@ -154,7 +158,8 @@ function testOrm(schema) {
test.equals(obj.date, date); test.equals(obj.date, date);
Post.find(obj.id, function () { Post.find(obj.id, function () {
test.equal(obj.title, title); test.equal(obj.title, title);
test.equal(obj.date, date.toString()); console.log(obj.date.toString());
test.equal(obj.date.toString(), date.toString());
test.done(); test.done();
}); });
}); });
@ -189,6 +194,7 @@ function testOrm(schema) {
test.ok(exists, 'Object exists'); test.ok(exists, 'Object exists');
post.destroy(function () { post.destroy(function () {
Post.exists(post.id, function (err, exists) { Post.exists(post.id, function (err, exists) {
if (err) console.log(err);
test.ok(!exists, 'Hey! ORM told me that object exists, but it looks like it doesn\'t. Something went wrong...'); test.ok(!exists, 'Hey! ORM told me that object exists, but it looks like it doesn\'t. Something went wrong...');
Post.find(post.id, function (err, obj) { Post.find(post.id, function (err, obj) {
test.equal(obj, null, 'Param obj should be null'); test.equal(obj, null, 'Param obj should be null');