Skip to content

Commit

Permalink
Model.count with params support, fix time in mysql
Browse files Browse the repository at this point in the history
  • Loading branch information
1602 committed Jan 30, 2012
1 parent b237b7b commit ad7d1d5
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 46 deletions.
8 changes: 6 additions & 2 deletions lib/abstract-class.js
Expand Up @@ -243,8 +243,12 @@ AbstractClass.destroyAll = function destroyAll(cb) {
}.bind(this));
};

AbstractClass.count = function (cb) {
this.schema.adapter.count(this.modelName, cb);
AbstractClass.count = function (where, cb) {
if (typeof where === 'function') {
cb = where;
where = null;
}
this.schema.adapter.count(this.modelName, cb, where);
};

AbstractClass.toString = function () {
Expand Down
17 changes: 15 additions & 2 deletions lib/adapters/memory.js
Expand Up @@ -119,8 +119,21 @@ Memory.prototype.destroyAll = function destroyAll(model, callback) {
callback();
};

Memory.prototype.count = function count(model, callback) {
callback(null, Object.keys(this.cache[model]).length);
Memory.prototype.count = function count(model, callback, where) {
var cache = this.cache[model];
var data = Object.keys(cache)
if (where) {
data = data.filter(function (id) {
var ok = true;
Object.keys(where).forEach(function (key) {
if (cache[id][key] != where[key]) {
ok = false;
}
});
return ok;
});
}
callback(null, data.length);
};

Memory.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
Expand Down
54 changes: 40 additions & 14 deletions lib/adapters/mysql.js
Expand Up @@ -15,7 +15,8 @@ exports.initialize = function initializeSchema(schema, callback) {
});

schema.adapter = new MySQL(schema.client);
process.nextTick(callback);
schema.client.query('SET TIME_ZONE = "+04:00"', callback);
// process.nextTick(callback);
};

function MySQL(client) {
Expand Down Expand Up @@ -77,6 +78,19 @@ MySQL.prototype.toFields = function (model, data) {
return fields.join(',');
};

function dateToMysql(val) {
return val.getUTCFullYear() + '-' +
fillZeros(val.getUTCMonth() + 1) + '-' +
fillZeros(val.getUTCDate()) + ' ' +
fillZeros(val.getUTCHours()) + ':' +
fillZeros(val.getUTCMinutes()) + ':' +
fillZeros(val.getUTCSeconds());

function fillZeros(v) {
return v < 10 ? '0' + v : v;
}
}

MySQL.prototype.toDatabase = function (prop, val) {
if (prop.type.name === 'Number') return val;
if (val === null) return 'NULL';
Expand All @@ -85,15 +99,7 @@ MySQL.prototype.toDatabase = function (prop, val) {
if (!val.toUTCString) {
val = new Date(val);
}
val = [
val.getFullYear(),
val.getMonth() + 1,
val.getDate(),
val.getHours(),
val.getMinutes(),
val.getSeconds()
].join('-');
return '"' + val + '"';
return '"' + dateToMysql(val) + '"';
}
if (prop.type.name == "Boolean") return val ? 1 : 0;
return this.client.escape(val.toString());
Expand All @@ -105,7 +111,9 @@ MySQL.prototype.fromDatabase = function (model, data) {
Object.keys(data).forEach(function (key) {
var val = data[key];
if (props[key]) {
// if (props[key])
if (props[key].type.name === 'Date') {
val = new Date(val.toString().replace(/GMT.*$/, 'GMT'));
}
}
data[key] = val;
});
Expand Down Expand Up @@ -165,7 +173,9 @@ MySQL.prototype.all = function all(model, filter, callback) {
if (err) {
return callback(err, []);
}
callback(null, data);
callback(null, data.map(function (obj) {
return self.fromDatabase(model, obj);
}));
}.bind(this));

return sql;
Expand Down Expand Up @@ -203,10 +213,26 @@ MySQL.prototype.destroyAll = function destroyAll(model, callback) {
}.bind(this));
};

MySQL.prototype.count = function count(model, callback) {
this.query('SELECT count(*) as cnt FROM ' + model, function (err, res) {
MySQL.prototype.count = function count(model, callback, where) {
var self = this;
var props = this._models[model].properties;

this.query('SELECT count(*) as cnt FROM ' + model + buildWhere(where), function (err, res) {
callback(err, err ? null : res[0].cnt);
});

function buildWhere(conds) {
var cs = [];
Object.keys(conds || {}).forEach(function (key) {
var keyEscaped = '`' + key.replace(/\./g, '`.`') + '`'
if (conds[key] === null) {
cs.push(keyEscaped + ' IS NULL');
} else {
cs.push(keyEscaped + ' = ' + self.toDatabase(props[key], conds[key]));
}
});
return cs.length ? ' WHERE ' + cs.join(' AND ') : '';
}
};

MySQL.prototype.updateAttributes = function updateAttrs(model, id, data, cb) {
Expand Down
25 changes: 20 additions & 5 deletions lib/adapters/neo4j.js
Expand Up @@ -254,10 +254,21 @@ Neo4j.prototype.destroy = function destroy(model, id, callback) {
Neo4j.prototype.all = function all(model, filter, callback) {
this.client.queryNodeIndex(model, 'id:*', function (err, nodes) {
if (nodes) {
nodes = nodes.map(function (s) { s.data.id = s.id; return s.data });
nodes = nodes.map(function (obj) {
obj.data.id = obj.id;
return this.readFromDb(model, obj.data);
}.bind(this));
}
callback(err, filter && nodes ? nodes.filter(applyFilter(filter)) : nodes);
});
if (filter) {
nodes = nodes ? nodes.filter(applyFilter(filter)) : nodes;
if (filter.order) {
nodes = nodes.sort(function (a, b) {
return a[filter.order] > b[filter.order];
});
}
}
callback(err, nodes);
}.bind(this));
};

Neo4j.prototype.allNodes = function all(model, callback) {
Expand Down Expand Up @@ -285,6 +296,10 @@ function applyFilter(filter) {
if (typeof value === 'string' && example && example.constructor.name === 'RegExp') {
return value.match(example);
}
if (typeof value === 'object' && value.constructor.name === 'Date' && typeof example === 'object' && example.constructor.name === 'Date') {
return example.toString() === value.toString();
}
console.log(example,'==', value, example == value);
// not strict equality
return example == value;
}
Expand All @@ -308,8 +323,8 @@ Neo4j.prototype.destroyAll = function destroyAll(model, callback) {
}
};

Neo4j.prototype.count = function count(model, callback) {
this.all(model, null, function (err, collection) {
Neo4j.prototype.count = function count(model, callback, conds) {
this.all(model, {where: conds}, function (err, collection) {
callback(err, collection ? collection.length : 0);
});
};
Expand Down
62 changes: 47 additions & 15 deletions lib/adapters/postgres.js
Expand Up @@ -93,6 +93,22 @@ PG.prototype.toFields = function (model, data, forCreate) {
}
};

function dateToPostgres(val) {
return [
val.getUTCFullYear(),
fz(val.getUTCMonth() + 1),
fz(val.getUTCDate())
].join('-') + ' ' + [
fz(val.getUTCHours()),
fz(val.getUTCMinutes()),
fz(val.getUTCSeconds())
].join(':');

function fz(v) {
return v < 10 ? '0' + v : v;
}
}

PG.prototype.toDatabase = function (prop, val) {
if (val === null) return 'NULL';
if (prop.type.name === 'Number') return val;
Expand All @@ -101,18 +117,10 @@ PG.prototype.toDatabase = function (prop, val) {
if (!val.toUTCString) {
val = new Date(val);
}
val = [
val.getUTCFullYear(),
val.getUTCMonth() + 1,
val.getUTCDate()
].join('-') + ' ' + [
val.getUTCHours(),
val.getUTCMinutes(),
val.getUTCSeconds()
].join(':');
return escape(val);
return escape(dateToPostgres(val));
}
return escape(val.toString());

};

PG.prototype.fromDatabase = function (model, data) {
Expand Down Expand Up @@ -161,7 +169,7 @@ PG.prototype.all = function all(model, filter, callback) {
if (err) {
return callback(err, []);
}
callback(err, filter ? data.items.filter(applyFilter(filter)) : data.items);
callback(err, filter && filter.where ? data.items.filter(applyFilter(filter)) : data.items);
}.bind(this));
};

Expand All @@ -171,7 +179,7 @@ PG.prototype.toFilter = function (model, filter) {
}
if (!filter) return '';
var props = this._models[model].properties;
var out='';
var out = '';
if (filter.where) {
var fields = [];
Object.keys(filter.where).forEach(function (key) {
Expand All @@ -188,9 +196,18 @@ PG.prototype.toFilter = function (model, filter) {
}
}.bind(this));
if (fields.length) {
out += ' where ' + fields.join(' AND ');
out += ' WHERE ' + fields.join(' AND ');
}
}

if (filter.order) {
out += ' ORDER BY ' + filter.order;
}

if (filter.limit) {
out += ' LIMIT ' + filter.limit + ' ' + (filter.offset || '');
}

return out;
};

Expand Down Expand Up @@ -228,11 +245,26 @@ PG.prototype.destroyAll = function destroyAll(model, callback) {
}.bind(this));
};

PG.prototype.count = function count(model, callback) {
this.query('SELECT count(*) as cnt FROM "' + model + '"', function (err, res) {
PG.prototype.count = function count(model, callback, where) {
var self = this;
var props = this._models[model].properties;

this.query('SELECT count(*) as cnt FROM "' + model + '"' + buildWhere(where), function (err, res) {
if (err) return callback(err);
callback(err, res && res.items[0] && res.items[0].cnt);
});

function buildWhere(conds) {
var cs = [];
Object.keys(conds || {}).forEach(function (key) {
if (conds[key] === null) {
cs.push(key + ' IS NULL');
} else {
cs.push(key + ' = ' + self.toDatabase(props[key], conds[key]));
}
});
return cs.length ? ' WHERE ' + cs.join(' AND ') : '';
}
};

PG.prototype.updateAttributes = function updateAttrs(model, id, data, cb) {
Expand Down
16 changes: 11 additions & 5 deletions lib/adapters/redis.js
Expand Up @@ -366,13 +366,19 @@ BridgeToRedis.prototype.destroyAll = function destroyAll(model, callback) {
}.bind(this));
};

BridgeToRedis.prototype.count = function count(model, callback) {
BridgeToRedis.prototype.count = function count(model, callback, where) {
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));
if (where && Object.keys(where).length) {
this.all(model, {where: where}, function (err, data) {
callback(err, err ? null : data.length);
});
} else {
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) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -8,7 +8,7 @@
},
"main": "index.js",
"scripts": {
"test": "ONLY=memory ./support/nodeunit/bin/nodeunit test/*_test.* && ONLY=redis nodeunit test/common_test.js && ONLY=mysql nodeunit test/common_test.js"
"test": "ONLY=memory ./support/nodeunit/bin/nodeunit test/*_test.* && ONLY=redis nodeunit test/common_test.js && ONLY=mysql nodeunit test/common_test.js && ONLY=postgres nodeunit test/common_test.js"
},
"engines": [
"node >= 0.4.0"
Expand Down
11 changes: 9 additions & 2 deletions test/common_test.js
Expand Up @@ -297,20 +297,26 @@ function testOrm(schema) {
});
});

var countOfposts;
var countOfposts, countOfpostsFiltered;
it('should fetch collection', function (test) {
Post.all(function (err, posts) {
countOfposts = posts.length;
test.ok(countOfposts > 0);
test.ok(posts[0] instanceof Post);
countOfpostsFiltered = posts.filter(function (p) {
return p.title === 'title';
}).length;
test.done();
});
});

it('should fetch count of records in collection', function (test) {
Post.count(function (err, count) {
test.equal(countOfposts, count);
test.done();
Post.count({title: 'title'}, function (err, count) {
test.equal(countOfpostsFiltered, count);
test.done();
});
});
});

Expand Down Expand Up @@ -481,6 +487,7 @@ function testOrm(schema) {
if (err) console.log(err);
test.equal(posts.length, 5);
dates.sort(numerically).forEach(function (d, i) {
// fix inappropriated tz convert
test.equal(posts[i].date.toString(), d.toString());
});
finished();
Expand Down

0 comments on commit ad7d1d5

Please sign in to comment.