From 753035c0ef2bbdbc5a81aa27b0a6a77cd46c26a4 Mon Sep 17 00:00:00 2001 From: Louis Chatriot Date: Wed, 19 Jun 2013 17:43:47 +0200 Subject: [PATCH] Implemented modifier --- lib/model.js | 22 ++++++++++++++++++++ test/model.test.js | 52 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/lib/model.js b/lib/model.js index 22896bd..622977d 100644 --- a/lib/model.js +++ b/lib/model.js @@ -232,6 +232,28 @@ modifierFunctions.$set = function (obj, field, value) { }; +/** + * Push an element at the last place of an array + * @param {Object} obj The model to set a field for + * @param {String} field Can contain dots, in that case that means we will set a subfield recursively + * @param {Model} value + */ +modifierFunctions.$push = function (obj, field, value) { + var fieldParts = typeof field === 'string' ? field.split('.') : field; + + if (fieldParts.length === 1) { + // Create the array if it doesn't exist + if (!obj.hasOwnProperty(fieldParts[0])) { obj[fieldParts[0]] = []; } + + if (!util.isArray(obj[fieldParts[0]])) { throw "Can't $push an element on non-array values"; } + obj[fieldParts[0]].push(value); + } else { + obj[fieldParts[0]] = obj[fieldParts[0]] || {}; + modifierFunctions.$push(obj[fieldParts[0]], fieldParts.slice(1), value); + } +}; + + /** * Increase (or decrease) a 'number' field * Create and initialize it if needed diff --git a/test/model.test.js b/test/model.test.js index 30903f4..ba61728 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -201,7 +201,7 @@ describe('Model', function () { }); // ==== End of 'Deep copying' ==== // - describe('Modifying documents', function () { + describe.only('Modifying documents', function () { it('Queries not containing any modifier just replace the document by the contents of the query but keep its _id', function () { var obj = { some: 'thing', _id: 'keepit' } @@ -294,7 +294,7 @@ describe('Model', function () { _.isEqual(modified, { yup: { subfield: 'changed', yop: 'yes indeed' }, totally: { doesnt: { exist: 'now it does' } } }).should.equal(true); }); - }); + }); // End of '$set modifier' describe('$inc modifier', function () { it('Throw an error if you try to use it with a non-number or on a non number field', function () { @@ -330,7 +330,53 @@ describe('Model', function () { modified = model.modify(obj, { $inc: { "nay.nope": -2, "blip.blop": 123 } }); _.isEqual(modified, { some: 'thing', nay: { nope: 38 }, blip: { blop: 123 } }).should.equal(true); }); - }); + }); // End of '$inc modifier' + + describe('$push modifier', function () { + + it('Can push an element to the end of an array', function () { + var obj = { arr: ['hello'] } + , modified; + + modified = model.modify(obj, { $push: { arr: 'world' } }); + assert.deepEqual(modified, { arr: ['hello', 'world'] }); + }); + + it('Can push an element to a non-existent field and will create the array', function () { + var obj = { arr: [] } + , modified; + + modified = model.modify(obj, { $push: { arr: 'world' } }); + assert.deepEqual(modified, { arr: ['world'] }); + }); + + it('Can push on nested fields', function () { + var obj = { arr: { nested: ['hello'] } } + , modified; + + modified = model.modify(obj, { $push: { "arr.nested": 'world' } }); + assert.deepEqual(modified, { arr: { nested: ['hello', 'world'] } }); + + obj = { arr: { a: 2 }}; + modified = model.modify(obj, { $push: { "arr.nested": 'world' } }); + assert.deepEqual(modified, { arr: { a: 2, nested: ['world'] } }); + }); + + it('Throw if we try to push to a non-array', function () { + var obj = { arr: 'hello' } + , modified; + + (function () { + modified = model.modify(obj, { $push: { arr: 'world' } }); + }).should.throw(); + + obj = { arr: { nested: 45 } }; + (function () { + modified = model.modify(obj, { $push: { "arr.nested": 'world' } }); + }).should.throw(); + }); + + }); // End of '$push modifier' }); // ==== End of 'Modifying documents' ==== //