Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of github.com:mde/model

  • Loading branch information...
commit 5734ff7abd71f30665d5fd8eb0072fbce60b4dcf 2 parents 8ee341a + 8d60236
@larzconwell larzconwell authored
View
333 lib/adapters/mongo/index.js
@@ -0,0 +1,333 @@
+var file = require('utilities').file
+ , driver = file.requireLocal('mongodb-wrapper')
+ , utils = require('utilities')
+ , operation = require('../../query/operation')
+ , comparison = require('../../query/comparison')
+ , Query = require('../../query/query').Query
+ , datatypes = require('../../datatypes')
+ , request = utils.request
+ , BaseAdapter = require('../base_adapter').BaseAdapter
+ , _baseConfig
+ , _comparisonTypeMap
+ , _collectionizeModelName;
+
+_baseConfig = {
+ username: null
+, dbname: null
+, prefix: null
+, password: null
+, host: 'localhost'
+, port: 27017
+};
+
+_comparisonTypeMap = {
+ 'NotEqualTo': '$ne'
+, 'In': '$in'
+, 'GreaterThan': '$gt'
+, 'LessThan': '$lt'
+, 'GreaterThanOrEqual': '$gte'
+, 'LessThanOrEqual': '$lte'
+};
+
+_collectionizeModelName = function (name) {
+ var collectionName = utils.inflection.pluralize(name);
+ collectionName = utils.string.snakeize(collectionName);
+ return collectionName;
+};
+
+var Adapter = function (options) {
+ var opts = options || {}
+ , config;
+
+ this.name = 'mongo';
+ this.config = _baseConfig;
+ this.client = null;
+
+ utils.mixin(this.config, opts);
+
+ this.init.apply(this, arguments);
+};
+
+Adapter.prototype = new BaseAdapter();
+Adapter.prototype.constructor = Adapter;
+
+utils.mixin(Adapter.prototype, new (function () {
+
+ this._serializeSortOrder = function (sort) {
+ var ret = {};
+ if (sort) {
+ for (var p in sort) {
+ ret[p] = (sort[p] == 'asc') ? 1 : -1;
+ }
+ }
+ return ret;
+ };
+
+ this._serializeConditions = function (conditions) {
+ return this._serializeOperation(conditions);
+ };
+
+ this._serializeOperation = function (op) {
+ var self = this
+ , ops = []
+ , ret = {};
+ if (!op.isEmpty()) {
+ if (op.type == 'not') {
+ ret = {'$nor': [self._serializeOperation(op.operand())]};
+ }
+ else {
+ // 'and' or 'or', ignore 'null' for now
+ ret['$' + op.type] = ops;
+ op.forEach(function (o) {
+ if (o instanceof operation.OperationBase) {
+ ops.push(self._serializeOperation(o));
+ }
+ else {
+ ops.push(self._serializeComparison(o));
+ }
+ });
+ }
+ }
+ return ret;
+ };
+
+ this._serializeComparison = function (comp) {
+ var ret = {}
+ , nocase = comp.opts.nocase
+ , complex
+ , re
+ , val = comp.value;
+
+ //if (comp.datatype == 'date' || comp.datetime == 'datetime') {
+ // val = JSON.stringify(val).replace(/"/g, '');
+ //}
+
+ switch (comp.type) {
+ case 'EqualTo':
+ // Case-insensitive equality via regex
+ if (nocase) {
+ val = val.toLowerCase();
+ re = new RegExp('^' + val + '$', 'i');
+ ret[comp.field] = re;
+ }
+ else {
+ ret[comp.field] = val;
+ }
+ break;
+ // Convert to regex
+ case 'Like':
+ if (nocase) {
+ val = val.toLowerCase();
+ re = new RegExp('^' + val, 'i');
+ }
+ else {
+ re = new RegExp('^' + val);
+ }
+ ret[comp.field] = re;
+ break;
+ default:
+ complex = {};
+ complex[_comparisonTypeMap[comp.type]] = val;
+ ret[comp.field] = complex;
+ }
+ return ret;
+ };
+
+ this.init = function () {
+ var config = this.config
+ , args = [];
+ ['host', 'port', 'dbname', 'prefix', 'username',
+ 'password'].forEach(function (c) {
+ args.push(config[c]);
+ });
+ this.client = driver.db.apply(driver, args);
+ };
+
+ this.load = function (query, callback) {
+ var collectionName = _collectionizeModelName(query.model.modelName)
+ , collection = this.client.collection(collectionName)
+ , id = query.byId
+ , conditions
+ , sort;
+
+ // Single instance-lookup by id
+ if (id) {
+ collection.findOne({id: id}, function (err, data) {
+ var inst
+ , res = [];
+ if (err) {
+ // Not found?
+ //if (err.statusCode == 404) {
+ // callback(null, null);
+ //}
+ //else {
+ callback(err, null);
+ //}
+ }
+ else {
+ if (data) {
+ inst = query.model.create(data);
+ inst.id = id;
+ inst._id = data._id;
+ inst._saved = true;
+ res.push(inst);
+ }
+ // If explicitly limited to one, just return the single instance
+ // This is also used by the `first` method
+ if (query.opts.limit == 1) {
+ res = res[0];
+ }
+ callback(null, res);
+ }
+ });
+ }
+ // Collection
+ else {
+ conditions = this._serializeConditions(query.conditions);
+ sort = this._serializeSortOrder(query.opts.sort);
+
+ //var util = require('util');
+ //console.log(util.inspect(conditions, false, null));
+
+ collection.find(conditions, {})
+ .sort(sort)
+ .toArray(function (err, data) {
+ var rows
+ , res = [];
+ if (err) {
+ callback(err, null);
+ }
+ else {
+ rows = data;
+ rows.forEach(function (row) {
+ var inst = query.model.create(row);
+ inst.id = row.id;
+ inst._id = row._id;
+ inst._saved = true;
+ res.push(inst);
+ });
+ // If explicitly limited to one, just return the single instance
+ // This is also used by the `first` method
+ if (query.opts.limit == 1) {
+ res = res[0];
+ }
+ callback(null, res);
+ }
+ });
+ }
+ };
+
+
+ this.update = function (data, query, opts, callback) {
+ var collectionName = _collectionizeModelName(query.model.modelName)
+ , collection = this.client.collection(collectionName)
+ , id = query.byId
+ , item = data;
+ // Single instance-lookup by id
+ if (id) {
+ // Bail out if instance isn't valid
+ if (!item.isValid()) {
+ return callback(data.errors, null);
+ }
+
+ item = item.toData({whitelist: ['_id', 'id', 'createdAt']});
+
+ collection.update({id: id}, item, function (err, data) {
+ if (err) {
+ callback(err, null);
+ }
+ else {
+ // FIXME: What is the right data to return here? Right now this
+ // is basically overwriting a doc, but we might be supporting
+ // bulk-updates at some point
+ callback(null, true);
+ }
+ });
+ }
+ // Bulk update?
+ else {
+ callback(new Error('Bulk update is not supported'), null);
+ }
+ };
+
+ this.remove = function (query, opts, callback) {
+ var collectionName = _collectionizeModelName(query.model.modelName)
+ , collection = this.client.collection(collectionName)
+ , id = query.byId
+ , conditions;
+
+ // Single instance-lookup by id
+ if (id) {
+ conditions = {id: id};
+ }
+ // Collection
+ else {
+ conditions = this._serializeConditions(query.conditions);
+ }
+ collection.remove(conditions, function (err, data) {
+ var inst
+ , res = [];
+ if (err) {
+ callback(err, null);
+ }
+ else {
+ callback(null, true);
+ }
+ });
+ };
+
+ this.insert = function (data, opts, callback) {
+ var self = this
+ , items = Array.isArray(data) ? data.slice() : [data]
+ , collectionName = _collectionizeModelName(items[0].type)
+ , collection = this.client.collection(collectionName)
+ , ret = []
+ , insert;
+
+ insert = function () {
+ var item;
+ if ((item = items.shift())) {
+ var id = utils.string.uuid()
+
+ item.id = id;
+ item = item.toData({whitelist: ['id', 'createdAt']});
+
+ collection.insert(item, function (err, res) {
+ if (err) {
+ callback(err, null);
+ }
+ else {
+ item.id = id;
+ item._id = res._id;
+ item._saved = true;
+ ret.push(data);
+ insert();
+ }
+ });
+ }
+ else {
+ callback(null, ret);
+ }
+ };
+ insert();
+ };
+
+ this.createTable = function (names, callback) {
+ var self = this
+ , collections = Array.isArray(names) ? names.slice() : [names]
+ , create = function () {
+ var c;
+ if ((c = collections.shift())) {
+ self.client.createCollection(c, {}, create);
+ }
+ else {
+ callback();
+ }
+ };
+ create();
+ };
+
+})());
+
+module.exports.Adapter = Adapter;
+
View
6 lib/adapters/riak/index.js
@@ -165,7 +165,7 @@ utils.mixin(Adapter.prototype, new (function () {
// Use bracket-notation, in case field-name has special chars
// or is a reserved word
var name = 'data[\'' + comp.field + '\']';
- if (comp.opts.lowercase) {
+ if (comp.opts.nocase) {
name += '.toLowerCase()';
}
return name;
@@ -354,13 +354,11 @@ utils.mixin(Adapter.prototype, new (function () {
this.insert = function (data, opts, callback) {
var self = this
- , items = Array.isArray(data) ? data : [data]
+ , items = Array.isArray(data) ? data.slice() : [data]
, bucket = _bucketizeModelName(items[0].type)
, ret = []
, insert;
- items = items.slice();
-
insert = function () {
var item;
if ((item = items.shift())) {
View
18 lib/adapters/sql/base.js
@@ -64,18 +64,18 @@ utils.mixin(Adapter.prototype, new (function () {
return '';
}
else {
- op.forEach(function (o) {
- if (o instanceof operation.OperationBase) {
- ops.push(self._serializeOperation(o));
- }
- else {
- ops.push(self._serializeComparison(o));
- }
- });
if (op.type == 'not') {
return 'NOT (' + self._serializeOperation(op.operand()) + ')';
}
else {
+ op.forEach(function (o) {
+ if (o instanceof operation.OperationBase) {
+ ops.push(self._serializeOperation(o));
+ }
+ else {
+ ops.push(self._serializeComparison(o));
+ }
+ });
return '(' + ops.join(' ' + op.type.toUpperCase() + ' ') + ')';
}
}
@@ -89,7 +89,7 @@ utils.mixin(Adapter.prototype, new (function () {
this._serializeComparisonFieldName = function (comp) {
var name = this._columnizePropertyName(comp.field);
- if (comp.opts.lowercase) {
+ if (comp.opts.nocase) {
name = 'LOWER(' + name + ')';
}
return name;
View
4 lib/adapters/sql/postgres.js
@@ -1,5 +1,5 @@
-
-var pg = require('pg')
+var file = require('utilities').file
+ , pg = file.requireLocal('pg')
, generator = require('../../../lib/generators/sql')
, utils = require('utilities')
, model = require('../../../lib')
View
7 lib/index.js
@@ -507,8 +507,11 @@ utils.mixin(model, new (function () {
return item;
};
- this.updateItem = function (item, params) {
- item = this.validateAndUpdateFromParams(item, params);
+ this.updateItem = function (item, params, opts) {
+ var data = {};
+ utils.mixin(data, item);
+ utils.mixin(data, params);
+ this.validateAndUpdateFromParams(item, data, opts);
// After-update hook
if (typeof item.afterUpdate === 'function') {
View
30 lib/query/query.js
@@ -12,20 +12,20 @@ Query = function (model, conditions, options) {
this.initialize.apply(this, arguments);
};
-Query.prototype = new (function () {
+Query.comparisonTypes = {
+ 'eql': 'EqualTo'
+, 'ne': 'NotEqualTo'
+, 'in': 'In'
+, 'like': 'Like'
+, 'gt': 'GreaterThan'
+, 'lt': 'LessThan'
+, 'gte': 'GreaterThanOrEqual'
+, 'lte': 'LessThanOrEqual'
+};
- var _comparisonCtorNames = {
- 'eql': 'EqualTo'
- , 'ne': 'NotEqualTo'
- , 'in': 'In'
- , 'like': 'Like'
- , 'gt': 'GreaterThan'
- , 'lt': 'LessThan'
- , 'gte': 'GreaterThanOrEqual'
- , 'lte': 'LessThanOrEqual'
- }
+Query.prototype = new (function () {
- , _operationTypes = {
+ var _operationTypes = {
'and': true
, 'or': true
, 'not': true
@@ -137,15 +137,15 @@ Query.prototype = new (function () {
// TODO: Validate the value for both the particular field
// (e.g., must be a numeric) and the type of comparison
// (e.g., 'IN' must be a collection, etc)
- return comparison.create(_comparisonCtorNames[type], key, val,
+ return comparison.create(Query.comparisonTypes[type], key, val,
datatype, opts);
}
, _createComparisonOpts = function (key) {
var opts = this.opts
- , lowercase = opts.lowercase
+ , nocase = opts.nocase
, ret = {};
- ['lowercase'].forEach(function (k) {
+ ['nocase'].forEach(function (k) {
var opt = opts[k]
, included;
if (opt) {
View
59 test/adapters/mongo/index.js
@@ -0,0 +1,59 @@
+var utils = require('utilities')
+ , model = require('../../../lib')
+ , Adapter = require('../../../lib/adapters/mongo').Adapter
+ , Query = require('../../../lib/query/query').Query
+ , generator = require('../../../lib/generators/sql')
+ , adapter
+ , assert = require('assert')
+ , currentId
+ , tests
+ , testItems = []
+ , Zooby = require('../../fixtures/zooby').Zooby
+ , User = require('../../fixtures/user').User
+ , Profile = require('../../fixtures/profile').Profile
+ , Account = require('../../fixtures/account').Account
+ , shared = require('../shared');
+
+tests = {
+ 'before': function (next) {
+ adapter = new Adapter({
+ dbname: 'model_test'
+ });
+
+ model.adapters = {
+ 'Zooby': adapter
+ , 'User': adapter
+ , 'Profile': adapter
+ , 'Account': adapter
+ };
+
+ Zooby.remove({}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'after': function (next) {
+ Zooby.remove({}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test create adapter': function () {
+ assert.ok(adapter instanceof Adapter);
+ }
+
+
+};
+
+for (var p in shared) {
+ tests[p + ' (Mongo)'] = shared[p];
+}
+
+module.exports = tests;
+
View
281 test/adapters/riak/index.js
@@ -11,7 +11,8 @@ var utils = require('utilities')
, Zooby = require('../../fixtures/zooby').Zooby
, User = require('../../fixtures/user').User
, Profile = require('../../fixtures/profile').Profile
- , Account = require('../../fixtures/account').Account;
+ , Account = require('../../fixtures/account').Account
+ , shared = require('../shared');
tests = {
'before': function () {
@@ -29,280 +30,10 @@ tests = {
assert.ok(adapter instanceof Adapter);
}
-, 'test save new, string UUID id': function (next) {
- var z = Zooby.create({foo: 'FOO'});
- z.save(function (err, data) {
- if (err) {
- throw err;
- }
- currentId = z.id;
- next();
- });
- }
-
-, 'test first via string id': function (next) {
- Zooby.first(currentId, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(currentId, data.id);
- next();
- });
- }
-
-, 'test save existing': function (next) {
- Zooby.first(currentId, {}, function (err, data) {
- if (err) {
- throw err;
- }
- var inst = data;
- data.updateProperties({
- foo: 'ZZZ'
- });
- inst.save(function (err, data) {
- if (err) {
- throw err;
- }
- Zooby.first(currentId, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal('ZZZ', data.foo);
- next();
- });
- });
- });
- }
-
-, 'test all, by id': function (next) {
- Zooby.all({id: currentId}, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(currentId, data[0].id);
- next();
- });
- }
-
-, 'test all, by map-reduce, equality': function (next) {
- Zooby.all({foo: 'ZZZ'}, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data[0].id, currentId);
- next();
- });
- }
-
-, 'test all, by map-reduce, like': function (next) {
- Zooby.all({foo: {like: 'Z'}}, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data[0].id, currentId);
- next();
- });
- }
-
-, 'test all, by map-reduce, like lowercased': function (next) {
- Zooby.all({foo: {like: 'z'}}, {lowercase: ['foo']}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data[0].id, currentId);
- next();
- });
- }
-
-, 'test all, by map-reduce, equality and like': function (next) {
- Zooby.all({createdAt: {ne: null}, foo: {like: 'Z'}}, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data[0].id, currentId);
- next();
- });
- }
-
-, 'test save collection': function (next) {
- var dt = new Date();
- testItems.push(Zooby.create({
- foo: 'FOO'
- , zong: utils.date.add(dt, 'day', -1)
- }));
- testItems.push(Zooby.create({
- foo: 'BAR'
- , zong: utils.date.add(dt, 'day', -2)
- }));
- testItems.push(Zooby.create({
- foo: 'BAZ'
- , zong: utils.date.add(dt, 'day', -3)
- }));
- Zooby.save(testItems, function (err, data) {
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all collection, by map-reduce, equality': function (next) {
- Zooby.all({foo: 'FOO'}, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.length, 1);
- assert.equal(testItems[0].foo, data[0].foo);
- next();
- });
- }
-
-, 'test all, by string LIKE case-sensitive': function (next) {
- Zooby.all({foo: {'like': 'B'}}, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.length, 2);
- next();
- });
- }
-
-, 'test all, by string LIKE case-insensitive bool': function (next) {
- Zooby.all({foo: {'like': 'b'}}, {lowercase: true}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.length, 2);
- next();
- });
- }
-
-, 'test all, by LIKE case-insensitive array': function (next) {
- Zooby.all({foo: {'like': 'b'}}, {lowercase: ['foo']}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.length, 2);
- next();
- });
- }
-
-, 'test all, sort string column name': function (next) {
- Zooby.all({}, {sort: 'zong'}, function (err, data) {
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, sort incorrect string column name': function () {
- assert.throws(function () {
- Zooby.all({}, {sort: 'zongX'}, function (err, data) {
- });
- }, Error);
- }
-
-, 'test all, sort array column names': function (next) {
- Zooby.all({}, {sort: ['foo', 'zong']}, function (err, data) {
- // Should be sorted BAR, BAZ, FOO
- assert.equal(data[0].id, testItems[1].id);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, sort object literal desc': function (next) {
- Zooby.all({}, {sort: {zong: 'desc'}}, function (err, data) {
- // Sort by datetime
- assert.equal(data[0].id, testItems[0].id);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-/*
-, 'test all, sort object literal asc': function (next) {
- Zooby.all({}, {sort: {zong: 'asc'}}, function (err, data) {
- // Sort by datetime reversed
- assert.equal(data[0].id, testItems[2].id);
- if (err) {
- throw err;
- }
- next();
- });
- }
-*/
-
-, 'test all, sort incorrect sort direction': function () {
- assert.throws(function () {
- Zooby.all({}, {sort: {foo: 'asc', bar: 'descX'}}, function (err, data) {
- });
- }, Error);
- }
-
-, 'test all, using or, simple equality': function (next) {
- Zooby.all({or: [{foo: 'BAR'}, {foo: 'BAZ'}]}, {}, function (err, data) {
- assert.equal(data.length, 2);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, using or, like comparison': function (next) {
- Zooby.all({or: [{foo: {'like': 'b'}}, {foo: 'foo'}]}, {lowercase: ['foo']},
- function (err, data) {
- assert.equal(data.length, 3);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, using or, like comparison with not': function (next) {
- Zooby.all({or: [{foo: {'like': 'b'}}, {foo: 'foo'}], not: {foo: 'baz'}},
- {lowercase: ['foo']}, function (err, data) {
- assert.equal(data.length, 2);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, using less-than createdAt': function (next) {
- Zooby.all({createdAt: {lt: new Date()}},
- {}, function (err, data) {
- assert.equal(data.length, 4);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test remove': function (next) {
- Zooby.remove(currentId, {}, function (err, data) {
- if (err) {
- throw err;
- }
- Zooby.first(currentId, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.ok(!data);
- next();
- });
- });
- }
-
};
+for (var p in shared) {
+ tests[p + ' (Riak)'] = shared[p];
+}
+
module.exports = tests;
View
254 test/adapters/shared.js
@@ -0,0 +1,254 @@
+var utils = require('utilities')
+ , assert = require('assert')
+ , currentId
+ , tests
+ , testItems = []
+ , Zooby = require('../fixtures/zooby').Zooby
+ , User = require('../fixtures/user').User
+ , Profile = require('../fixtures/profile').Profile
+ , Account = require('../fixtures/account').Account;
+
+tests = {
+
+ 'test save new, string UUID id': function (next) {
+ var z = Zooby.create({
+ foo: 'FOO'
+ , zong: new Date()
+ });
+ z.save(function (err, data) {
+ if (err) {
+ throw err;
+ }
+ currentId = z.id;
+ next();
+ });
+ }
+
+, 'test first via string id': function (next) {
+ Zooby.first(currentId, {}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ assert.equal(data.id, currentId);
+ next();
+ });
+ }
+
+// TODO: Load via array of ids
+
+, 'test first via object': function (next) {
+ Zooby.first({id: currentId}, {}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ assert.equal(data.id, currentId);
+ next();
+ });
+ }
+
+, 'test save existing': function (next) {
+ Zooby.first(currentId, {}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ var inst = data;
+ data.updateProperties({
+ foo: 'ZZZ'
+ });
+ inst.save(function (err, data) {
+ if (err) {
+ throw err;
+ }
+ Zooby.first(currentId, {}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ assert.ok(data);
+ assert.equal(data.foo, 'ZZZ');
+ next();
+ });
+ });
+ });
+ }
+
+, 'test save collection': function (next) {
+ var dt = new Date();
+ testItems.push(Zooby.create({
+ foo: 'FOO'
+ , zong: utils.date.add(dt, 'day', -1)
+ }));
+ testItems.push(Zooby.create({
+ foo: 'BAR'
+ , zong: utils.date.add(dt, 'day', -2)
+ }));
+ testItems.push(Zooby.create({
+ foo: 'BAZ'
+ , zong: utils.date.add(dt, 'day', -3)
+ }));
+ Zooby.save(testItems, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test all, by string equality': function (next) {
+ Zooby.all({foo: 'FOO'}, {}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ assert.equal(data.length, 1);
+ assert.equal(testItems[0].foo, data[0].foo);
+ next();
+ });
+ }
+
+, 'test all, by string LIKE case-sensitive': function (next) {
+ Zooby.all({foo: {'like': 'B'}}, {}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ assert.equal(data.length, 2);
+ next();
+ });
+ }
+
+, 'test all, by string LIKE case-insensitive bool': function (next) {
+ Zooby.all({foo: {'like': 'b'}}, {nocase: true}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ assert.equal(data.length, 2);
+ next();
+ });
+ }
+
+, 'test all, by LIKE case-insensitive array': function (next) {
+ Zooby.all({foo: {'like': 'b'}}, {nocase: ['foo']}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ assert.equal(data.length, 2);
+ next();
+ });
+ }
+
+, 'test all, sort string column name': function (next) {
+ Zooby.all({}, {sort: 'zong'}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test all, sort incorrect string column name': function () {
+ assert.throws(function () {
+ Zooby.all({}, {sort: 'zongX'}, function (err, data) {
+ });
+ }, Error);
+ }
+
+, 'test all, sort array column names': function (next) {
+ Zooby.all({}, {sort: ['foo', 'zong']}, function (err, data) {
+ // Should be BAR, BAZ, FOO, ZZZ
+ assert.equal(data[0].id, testItems[1].id);
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test all, sort object literal desc': function (next) {
+ Zooby.all({}, {sort: {zong: 'desc'}}, function (err, data) {
+ // Should be sorted ZZZ, FOO, BAR, BAZ
+ // Sort by datetime
+ assert.equal(data[0].id, currentId);
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test all, sort object literal asc': function (next) {
+ Zooby.all({}, {sort: {zong: 'asc'}}, function (err, data) {
+ // Sort by datetime reversed
+ assert.equal(data[0].id, testItems[2].id);
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test all, sort incorrect sort direction': function () {
+ assert.throws(function () {
+ Zooby.all({}, {sort: {foo: 'asc', bar: 'descX'}}, function (err, data) {
+ });
+ }, Error);
+ }
+
+, 'test all, using or, simple equality': function (next) {
+ Zooby.all({or: [{foo: 'BAR'}, {foo: 'BAZ'}]}, {}, function (err, data) {
+ assert.equal(2, data.length);
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test all, using or, like comparison': function (next) {
+ Zooby.all({or: [{foo: {'like': 'b'}}, {foo: 'foo'}]}, {nocase: ['foo']},
+ function (err, data) {
+ assert.equal(3, data.length);
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test all, using or, like comparison with not': function (next) {
+ Zooby.all({or: [{foo: {'like': 'b'}}, {foo: 'foo'}], not: {foo: 'baz'}},
+ {nocase: ['foo']}, function (err, data) {
+ assert.equal(data.length, 2);
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test all, using less-than createdAt': function (next) {
+ Zooby.all({createdAt: {lt: new Date()}},
+ {}, function (err, data) {
+ assert.equal(data.length, 4);
+ if (err) {
+ throw err;
+ }
+ next();
+ });
+ }
+
+, 'test remove': function (next) {
+ Zooby.remove(currentId, {}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ Zooby.first(currentId, {}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+ assert.ok(!data);
+ next();
+ });
+ });
+ }
+
+};
+
+module.exports = tests;
View
229 test/adapters/sql/postgres.js
@@ -17,11 +17,11 @@ var utils = require('utilities')
, assert = require('assert')
, currentId
, tests
- , testItems = []
, Zooby = require('../../fixtures/zooby').Zooby
, User = require('../../fixtures/user').User
, Profile = require('../../fixtures/profile').Profile
- , Account = require('../../fixtures/account').Account;
+ , Account = require('../../fixtures/account').Account
+ , shared = require('../shared');
tests = {
'before': function (next) {
@@ -202,64 +202,7 @@ tests = {
});
}
-, 'test save new, string UUID id': function (next) {
- var z = Zooby.create({foo: 'FOO'});
- z.save(function (err, data) {
- if (err) {
- throw err;
- }
- currentId = z.id;
- next();
- });
- }
-
-, 'test first via string id': function (next) {
- Zooby.first(currentId, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.id, currentId);
- next();
- });
- }
-
-// TODO: Load via array of ids
-
-, 'test first via object': function (next) {
- Zooby.first({id: currentId}, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.id, currentId);
- next();
- });
- }
-
-, 'test save existing': function (next) {
- Zooby.first(currentId, {}, function (err, data) {
- if (err) {
- throw err;
- }
- var inst = data;
- data.updateProperties({
- foo: 'BAR'
- });
- inst.save(function (err, data) {
- if (err) {
- throw err;
- }
- Zooby.first(currentId, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.foo, 'BAR');
- next();
- });
- });
- });
- }
-
-, 'test remove': function (next) {
+, 'test remove, auto-increment id': function (next) {
Zooby.remove(currentId, {}, function (err, data) {
if (err) {
throw err;
@@ -274,168 +217,10 @@ tests = {
});
}
-, 'test save collection': function (next) {
- var dt = new Date();
- testItems.push(Zooby.create({
- foo: 'FOO'
- , zong: utils.date.add(dt, 'day', -1)
- }));
- testItems.push(Zooby.create({
- foo: 'BAR'
- , zong: utils.date.add(dt, 'day', -2)
- }));
- testItems.push(Zooby.create({
- foo: 'BAZ'
- , zong: utils.date.add(dt, 'day', -3)
- }));
- Zooby.save(testItems, function (err, data) {
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, by string equality': function (next) {
- Zooby.all({foo: 'FOO'}, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.length, 1);
- assert.equal(testItems[0].foo, data[0].foo);
- next();
- });
- }
-
-, 'test all, by string LIKE case-sensitive': function (next) {
- Zooby.all({foo: {'like': 'B'}}, {}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.length, 2);
- next();
- });
- }
-
-, 'test all, by string LIKE case-insensitive bool': function (next) {
- Zooby.all({foo: {'like': 'b'}}, {lowercase: true}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.length, 2);
- next();
- });
- }
-
-, 'test all, by LIKE case-insensitive array': function (next) {
- Zooby.all({foo: {'like': 'b'}}, {lowercase: ['foo']}, function (err, data) {
- if (err) {
- throw err;
- }
- assert.equal(data.length, 2);
- next();
- });
- }
-
-, 'test all, sort string column name': function (next) {
- Zooby.all({}, {sort: 'zong'}, function (err, data) {
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, sort incorrect string column name': function () {
- assert.throws(function () {
- Zooby.all({}, {sort: 'zongX'}, function (err, data) {
- });
- }, Error);
- }
-
-, 'test all, sort array column names': function (next) {
- Zooby.all({}, {sort: ['foo', 'zong']}, function (err, data) {
- // Should be sorted BAR, BAZ, FOO
- assert.equal(data[0].id, testItems[1].id);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, sort object literal desc': function (next) {
- Zooby.all({}, {sort: {zong: 'desc'}}, function (err, data) {
- // Sort by datetime
- assert.equal(data[0].id, testItems[0].id);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, sort object literal asc': function (next) {
- Zooby.all({}, {sort: {zong: 'asc'}}, function (err, data) {
- // Sort by datetime reversed
- assert.equal(data[0].id, testItems[2].id);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, sort incorrect sort direction': function () {
- assert.throws(function () {
- Zooby.all({}, {sort: {foo: 'asc', bar: 'descX'}}, function (err, data) {
- });
- }, Error);
- }
-
-, 'test all, using or, simple equality': function (next) {
- Zooby.all({or: [{foo: 'BAR'}, {foo: 'BAZ'}]}, {}, function (err, data) {
- assert.equal(data.length, 2);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, using or, like comparison': function (next) {
- Zooby.all({or: [{foo: {'like': 'b'}}, {foo: 'foo'}]}, {lowercase: ['foo']},
- function (err, data) {
- assert.equal(data.length, 3);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, using or, like comparison with not': function (next) {
- Zooby.all({or: [{foo: {'like': 'b'}}, {foo: 'foo'}], not: {foo: 'baz'}},
- {lowercase: ['foo']}, function (err, data) {
- assert.equal(data.length, 2);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
-, 'test all, using less-than createdAt': function (next) {
- Zooby.all({createdAt: {lt: new Date()}},
- {}, function (err, data) {
- assert.equal(data.length, 3);
- if (err) {
- throw err;
- }
- next();
- });
- }
-
};
+for (var p in shared) {
+ tests[p + ' (Postgres)'] = shared[p];
+}
+
module.exports = tests;
View
20 test/query/query.js
@@ -32,7 +32,7 @@ var tests = {
, operands;
}
-, 'test not': function () {
+, 'test "not"': function () {
var conditions = {foo: 'bar', not: {bar: 'baz', baz: 'zoobie'}}
, query = new Query(Zooby, conditions, {})
, operands;
@@ -44,7 +44,7 @@ var tests = {
assert.ok(operands[0] instanceof operation.AndOperation);
}
-, 'test or': function () {
+, 'test simple "or"': function () {
var conditions = {or: [{foo: 'bar'}, {bar: 'baz'}]}
, query = new Query(Zooby, conditions, {})
, operands;
@@ -56,6 +56,22 @@ var tests = {
assert.ok(operands[1] instanceof operation.AndOperation);
}
+, 'test "and" with array of "or" sub-operations': function () {
+ var conditions = {and: [{or: [{foo: 'bar'}, {bar: 'baz'}]},
+ {or: [{foo: 'baz'}, {bar: 'quz'}]}]}
+ , query = new Query(Zooby, conditions, {})
+ , operands;
+
+ operands = query.conditions.operands;
+ assert.ok(operands[0] instanceof operation.OrOperation);
+ assert.ok(operands[1] instanceof operation.OrOperation);
+ operands = query.conditions.operands[0].operands;
+ assert.ok(operands[0] instanceof operation.AndOperation);
+ operands = query.conditions.operands[1].operands;
+ assert.ok(operands[0] instanceof operation.AndOperation);
+ }
+
+
};
module.exports = tests;
Please sign in to comment.
Something went wrong with that request. Please try again.