From c3835d089b62334784cdf5ca78c95a3286c04a58 Mon Sep 17 00:00:00 2001 From: Anatoliy Chakkaev Date: Tue, 10 Jan 2012 19:43:32 +0400 Subject: [PATCH] Fix postgres adapter --- lib/abstract-class.js | 6 +++- lib/adapters/postgres.js | 59 +++++++++++++++++++++++++--------------- test/common_test.js | 4 ++- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/lib/abstract-class.js b/lib/abstract-class.js index 6528b560..511488c2 100644 --- a/lib/abstract-class.js +++ b/lib/abstract-class.js @@ -155,7 +155,11 @@ AbstractClass.create = function (data) { }; AbstractClass.exists = function exists(id, cb) { - this.schema.adapter.exists(this.modelName, id, cb); + if (id) { + this.schema.adapter.exists(this.modelName, id, cb); + } else { + cb(new Error('Model::exists requires positive id argument')); + } }; AbstractClass.find = function find(id, cb) { diff --git a/lib/adapters/postgres.js b/lib/adapters/postgres.js index 3c1e9f4a..ae163710 100644 --- a/lib/adapters/postgres.js +++ b/lib/adapters/postgres.js @@ -3,6 +3,7 @@ */ var Client = require('pg').Client; var Hash = require('hashish'); + exports.initialize = function initializeSchema(schema, callback) { var s = schema.settings; schema.client = new Client(s.url ? s.url : { @@ -38,7 +39,7 @@ PG.prototype.query = function (sql, callback) { var log = this.log; this.client.query(sql, function (err, data) { log(sql, time); - callback(err, Hash(data.rows)); + callback(err, data ? Hash(data.rows) : null); }); }; @@ -62,8 +63,10 @@ PG.prototype.create = function (model, data, callback) { } else { sql += ' VALUES ()'; } + sql += ' RETURNING id'; this.query(sql, function (err, info) { - callback(err, info && info.insertId); + if (err) return callback(err); + callback(err, info && info.items[0] && info.items[0].id); }); }; @@ -91,21 +94,21 @@ PG.prototype.toFields = function (model, data, forCreate) { }; PG.prototype.toDatabase = function (prop, val) { - if (prop.type.name === 'Number') return val; if (val === null) return 'NULL'; + if (prop.type.name === 'Number') return val; if (prop.type.name === 'Date') { if (!val) return 'NULL'; if (!val.toUTCString) { val = new Date(val); } val = [ - val.getFullYear(), - val.getMonth() + 1, - val.getDate() + val.getUTCFullYear(), + val.getUTCMonth() + 1, + val.getUTCDate() ].join('-') + ' ' + [ - val.getHours(), - val.getMinutes(), - val.getSeconds() + val.getUTCHours(), + val.getUTCMinutes(), + val.getUTCSeconds() ].join(':'); return escape(val); } @@ -129,24 +132,24 @@ PG.prototype.exists = function (model, id, callback) { var sql = 'SELECT 1 FROM "' + model + '" WHERE "id" = ' + id + ' LIMIT 1'; this.query(sql, function (err, data) { if (err) return callback(err); - callback(null, data.length === 1); + callback(null, data.items.length === 1); }); }; PG.prototype.find = function find(model, id, callback) { var sql = 'SELECT * FROM "' + model + '" WHERE "id" = ' + id + ' LIMIT 1'; this.query(sql, function (err, data) { - if (data && data.length === 1) { - data[0].id = id; + if (data && data.items && data.items.length === 1) { + data.items[0].id = id; } else { - data = [null]; + data = { items: [null] }; } - callback(err, this.fromDatabase(model, data[0])); + callback(err, this.fromDatabase(model, data.items[0])); }.bind(this)); }; PG.prototype.destroy = function destroy(model, id, callback) { - var sql = 'DELETE FROM "' + model + '" WHERE "id" = ' + id + ' LIMIT 1'; + var sql = 'DELETE FROM "' + model + '" WHERE "id" = ' + id; this.query(sql, function (err) { callback(err); }); @@ -154,28 +157,39 @@ PG.prototype.destroy = function destroy(model, id, callback) { // TODO: hook up where, order, limit and offset conditions PG.prototype.all = function all(model, filter, callback) { - this.query('SELECT * FROM "' + model + '"' + this.toFilter(model,filter), function (err, data) { + this.query('SELECT * FROM "' + model + '"' + this.toFilter(model, filter), function (err, data) { if (err) { return callback(err, []); } - callback(err, filter ? data.filter(applyFilter(filter)) : data); + callback(err, filter ? data.items.filter(applyFilter(filter)) : data.items); }.bind(this)); }; PG.prototype.toFilter = function (model, filter) { - if (typeof filter.where === 'function') { + if (filter && typeof filter.where === 'function') { return filter(); } + if (!filter) return ''; var props = this._models[model].properties; var out=''; - if(filter.where){ + if (filter.where) { var fields = []; Object.keys(filter.where).forEach(function (key) { + if (filter.where[key] && filter.where[key].constructor.name === 'RegExp') { + return; + } if (props[key]) { - fields.push('"' + key + '" = ' + this.toDatabase(props[key], filter.where[key])); + var filterValue = this.toDatabase(props[key], filter.where[key]); + if (filterValue === 'NULL') { + fields.push('"' + key + '" IS ' + filterValue); + } else { + fields.push('"' + key + '" = ' + filterValue); + } } }.bind(this)); - out += ' where ' + fields.join(' AND '); + if (fields.length) { + out += ' where ' + fields.join(' AND '); + } } return out; }; @@ -216,7 +230,8 @@ PG.prototype.destroyAll = function destroyAll(model, callback) { PG.prototype.count = function count(model, callback) { this.query('SELECT count(*) as cnt FROM "' + model + '"', function (err, res) { - callback(err, err ? null : res[0].cnt); + if (err) return callback(err); + callback(err, res && res.items[0] && res.items[0].cnt); }); }; diff --git a/test/common_test.js b/test/common_test.js index d31d1c28..62f361c5 100644 --- a/test/common_test.js +++ b/test/common_test.js @@ -34,6 +34,7 @@ Object.keys(schemas).forEach(function (schemaName) { if (process.env.ONLY && process.env.ONLY !== schemaName) return; context(schemaName, function () { var schema = new Schema(schemaName, schemas[schemaName]); + // schema.log = console.log; testOrm(schema); if (specificTest[schemaName]) specificTest[schemaName](schema); }); @@ -137,7 +138,7 @@ function testOrm(schema) { it('should create object', function (test) { Post.create(function (err, post) { if (err) throw err; - test.ok(post.id); + test.ok(post.id, 'Id present'); test.ok(!post.title, 'Title is blank'); Post.exists(post.id, function (err, exists) { if (err) throw err; @@ -315,6 +316,7 @@ function testOrm(schema) { // matching null Post.all({where: {title: null}}, function (err, res) { + var pass = true; res.forEach(function (r) { if (r.title != null) pass = false;