diff --git a/lib/model.js b/lib/model.js index 64dfb64..2ba7454 100644 --- a/lib/model.js +++ b/lib/model.js @@ -230,6 +230,50 @@ function modify (obj, updateQuery) { // Finding documents // ============================================================== +/** + * Check whether things are equal + * Returns true if they are, false otherwise + */ +function areThingsEqual (a, b) { + var aKeys , bKeys , i; + + // Strings, booleans, numbers, null, undefined + if (a === null || a === undefined || typeof a === 'string' || typeof a === 'boolean' || typeof a === 'number' || + b === null || b === undefined || typeof b === 'string' || typeof b === 'boolean' || typeof b === 'number') { return a === b; } + + // Dates + if (util.isDate(a) || util.isDate(b)) { return util.isDate(a) && util.isDate(b) && a.getTime() === b.getTime(); } + + // Arrays (no match since arrays are used as a $in) + if (util.isArray(a) || util.isArray(b)) { return false; } + + // a and b should be objects + try { + aKeys = Object.keys(a); + bKeys = Object.keys(b); + } catch (e) { + return false; + } + + // Objects + if (aKeys.length !== bKeys.length) { return false; } + for (i = 0; i < aKeys.length; i += 1) { + if (bKeys.indexOf(aKeys[i]) === -1) { return false; } + if (!areThingsEqual(a[aKeys[i]], b[aKeys[i]])) { return false; } + } + return true; +} + + +/** + * Compare two things. That can be any serialized data: strings, booleans, numbers, dates, null, undefined, objects + * Returns -1 if a is less than b + * 0 if equal + * 1 if greater + */ + + + /** * Test for field equality * @param {Object} obj The model to check @@ -272,3 +316,4 @@ module.exports.deepCopy = deepCopy; module.exports.checkObject = checkObject; module.exports.modify = modify; module.exports.match = match; +module.exports.areThingsEqual = areThingsEqual; diff --git a/test/db.test.js b/test/db.test.js index 9b2fa54..3020faa 100644 --- a/test/db.test.js +++ b/test/db.test.js @@ -155,7 +155,7 @@ describe('Database', function () { describe('Find', function () { - it('Can find all documents an empty query is used', function (done) { + it('Can find all documents if an empty query is used', function (done) { async.waterfall([ function (cb) { d.insert({ somedata: 'ok' }, function (err) { @@ -233,6 +233,19 @@ describe('Database', function () { ], done); }); + it('Can find dates and objects', function (done) { + var now = new Date(); + + d.insert({ now: now, sth: { name: 'nedb' } }, function () { + d.findOne({ now: now }, function (err, doc) { + //console.log(doc); + // TODO + + done(); + }); + }); + }); + it('Can use dot-notation to query subfields', function (done) { d.insert({ greeting: { english: 'hello' } }, function () { d.findOne({ "greeting.english": 'hello' }, function (err, doc) { diff --git a/test/model.test.js b/test/model.test.js index b1178f9..d70d19c 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -330,6 +330,52 @@ describe('Model', function () { describe('Finding documents', function () { + describe.only('Comparing things', function () { + + it('Two things of different types cannot be equal, two identical native things are equal', function () { + var toTest = [null, undefined, 'somestring', 42, true, new Date(72998322), { hello: 'world' }] + , toTestAgainst = [null, undefined, 'somestring', 42, true, new Date(72998322), { hello: 'world' }] // Use another array so that we don't test pointer equality + , i, j + ; + + for (i = 0; i < toTest.length; i += 1) { + for (j = 0; j < toTestAgainst.length; j += 1) { + model.areThingsEqual(toTest[i], toTestAgainst[j]).should.equal(i === j); + } + } + }); + + it('Can test native types null undefined string number boolean date equality', function () { + var toTest = [null, undefined, 'somestring', 42, true, new Date(72998322), { hello: 'world' }] + , toTestAgainst = [undefined, null, 'someotherstring', 5, false, new Date(111111), { hello: 'mars' }] + , i + ; + + for (i = 0; i < toTest.length; i += 1) { + model.areThingsEqual(toTest[i], toTestAgainst[i]).should.equal(false); + } + }); + + it('If one side is an array, comparison fails', function () { + var toTestAgainst = [null, undefined, 'somestring', 42, true, new Date(72998322), { hello: 'world' }] + , i + ; + + for (i = 0; i < toTestAgainst.length; i += 1) { + model.areThingsEqual([1, 2, 3], toTestAgainst[i]).should.equal(false); + model.areThingsEqual(toTestAgainst[i], []).should.equal(false); + } + }); + + it('Can test objects equality', function () { + model.areThingsEqual({ hello: 'world' }, {}).should.equal(false); + model.areThingsEqual({ hello: 'world' }, { hello: 'mars' }).should.equal(false); + model.areThingsEqual({ hello: 'world' }, { hello: 'world', temperature: 42 }).should.equal(false); + model.areThingsEqual({ hello: 'world', other: { temperature: 42 }}, { hello: 'world', other: { temperature: 42 }}).should.equal(true); + }); + + }); + describe('$eq', function () { it('Can find documents with simple fields', function () {