diff --git a/lib/model.js b/lib/model.js index 70f7d6e..cb20c09 100644 --- a/lib/model.js +++ b/lib/model.js @@ -129,13 +129,18 @@ function deepCopy (obj) { * Set field to value in a model * Create it if it doesn't exist * @param {Object} obj The model to set a field for - * @param {Object} mod mod is of the form { k: v }. k is the field, v its value - * k can contain dots, in that case that means we will set a subfield + * @param {String} field Can contain dots, in that case that means we will set a subfield recursively + * @param {Model} value */ -modifierFunctions.$set = function (obj, mod) { - var field, value; - +modifierFunctions.$set = function (obj, field, value) { + var fieldParts = field.split('.'); + if (fieldParts.length === 1) { + obj[field] = value; + } else { + obj[fieldParts[0]] = obj[fieldParts[0]] || {}; + modifierFunctions.$set(obj[fieldParts[0]], fieldParts.slice(1).join('.'), value); + } }; modifierFunctions.$inc = function () {}; @@ -176,8 +181,9 @@ function modify (obj, updateQuery) { throw "Modifier " + m + "'s argument must be an object"; } + newDoc = deepCopy(obj); keys.forEach(function (k) { - modifierFunctions[m](obj, k, updateQuery[m][k]); + modifierFunctions[m](newDoc, k, updateQuery[m][k]); }); }); } diff --git a/test/model.test.js b/test/model.test.js index e2fc1dd..57d6c02 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -249,6 +249,45 @@ describe('Model', function () { }).should.throw(); }); + describe('$set modifier', function () { + + it('Can change already set fields without modfifying the underlying object', function () { + var obj = { some: 'thing', yup: 'yes', nay: 'noes' } + , updateQuery = { $set: { some: 'changed', nay: 'yes indeed' } } + , modified = model.modify(obj, updateQuery); + + Object.keys(modified).length.should.equal(3); + modified.some.should.equal('changed'); + modified.yup.should.equal('yes'); + modified.nay.should.equal('yes indeed'); + + Object.keys(obj).length.should.equal(3); + obj.some.should.equal('thing'); + obj.yup.should.equal('yes'); + obj.nay.should.equal('noes'); + }); + + it('Creates fields to set if they dont exist yet', function () { + var obj = { yup: 'yes' } + , updateQuery = { $set: { some: 'changed', nay: 'yes indeed' } } + , modified = model.modify(obj, updateQuery); + + Object.keys(modified).length.should.equal(3); + modified.some.should.equal('changed'); + modified.yup.should.equal('yes'); + modified.nay.should.equal('yes indeed'); + }); + + it('Can set sub-fields and create them if necessary', function () { + var obj = { yup: { subfield: 'bloup' } } + , updateQuery = { $set: { "yup.subfield": 'changed', "yup.yop": 'yes indeed', "totally.doesnt.exist": 'now it does' } } + , modified = model.modify(obj, updateQuery); + + _.isEqual(modified, { yup: { subfield: 'changed', yop: 'yes indeed' }, totally: { doesnt: { exist: 'now it does' } } }).should.equal(true); + }); + + }); + }); // ==== End of 'Modifying documents' ==== // });