diff --git a/lib/model.js b/lib/model.js index 2f7f1e4..370fdb3 100644 --- a/lib/model.js +++ b/lib/model.js @@ -214,91 +214,63 @@ function compareThings (a, b) { // Updating documents // ============================================================== - -lastStepModifierFunctions.$set = function (obj, field, value) { - obj[field] = value; -}; - -function findLastModificationStep (modifier, obj, field, value) { - var fieldParts = typeof field === 'string' ? field.split('.') : field; - - if (fieldParts.length === 1) { - lastStepModifierFunctions[modifier](obj, field, value); - } else { - obj[fieldParts[0]] = obj[fieldParts[0]] || {}; - modifierFunctions[modifier](obj[fieldParts[0]], fieldParts.slice(1), value); - } -} - /** - * Set field to value in a model - * Create it if it doesn't exist - * @param {Object} obj The model to set a field for + * The signature of modifier functions is as follows + * Their structure is always the same: recursively follow the dot notation while creating + * the nested documents if needed, then apply the "last step modifier" + * @param {Object} obj The model to modify * @param {String} field Can contain dots, in that case that means we will set a subfield recursively * @param {Model} value */ -modifierFunctions.$set = function (obj, field, value) { - var fieldParts = typeof field === 'string' ? field.split('.') : field; - if (fieldParts.length === 1) { - obj[fieldParts[0]] = value; - } else { - obj[fieldParts[0]] = obj[fieldParts[0]] || {}; - modifierFunctions.$set(obj[fieldParts[0]], fieldParts.slice(1), value); - } +// Set a field to a new value +lastStepModifierFunctions.$set = function (obj, field, value) { + obj[field] = value; }; +// Push an element to the end of an array field +lastStepModifierFunctions.$push = function (obj, field, value) { + // Create the array if it doesn't exist + if (!obj.hasOwnProperty(field)) { obj[field] = []; } -/** - * 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); - } + if (!util.isArray(obj[field])) { throw "Can't $push an element on non-array values"; } + obj[field].push(value); }; - -/** - * Increase (or decrease) a 'number' field - * Create and initialize it if needed - * @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.$inc = function (obj, field, value) { - var fieldParts = typeof field === 'string' ? field.split('.') : field; - +// Increment a numeric field's value +lastStepModifierFunctions.$inc = function (obj, field, value) { if (typeof value !== 'number') { throw value + " must be a number"; } - if (fieldParts.length === 1) { - if (typeof obj[fieldParts[0]] !== 'number') { - if (!_.has(obj, fieldParts[0])) { - obj[fieldParts[0]] = value; - } else { - throw "Don't use the $inc modifier on non-number fields"; - } + if (typeof obj[field] !== 'number') { + if (!_.has(obj, field)) { + obj[field] = value; } else { - obj[fieldParts[0]] += value; + throw "Don't use the $inc modifier on non-number fields"; } } else { - obj[fieldParts[0]] = obj[fieldParts[0]] || {}; - modifierFunctions.$inc(obj[fieldParts[0]], fieldParts.slice(1), value); + obj[field] += value; } }; +// Given its name, create the complete modifier function +function createModifierFunction (modifier) { + return function (obj, field, value) { + var fieldParts = typeof field === 'string' ? field.split('.') : field; + + if (fieldParts.length === 1) { + lastStepModifierFunctions[modifier](obj, field, value); + } else { + obj[fieldParts[0]] = obj[fieldParts[0]] || {}; + modifierFunctions[modifier](obj[fieldParts[0]], fieldParts.slice(1), value); + } + }; +} + +// Actually create all modifier functions +Object.keys(lastStepModifierFunctions).forEach(function (modifier) { + modifierFunctions[modifier] = createModifierFunction(modifier); +}); + /** * Modify a DB object according to an update query diff --git a/test/model.test.js b/test/model.test.js index ba61728..06242b9 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -201,7 +201,7 @@ describe('Model', function () { }); // ==== End of 'Deep copying' ==== // - describe.only('Modifying documents', function () { + describe('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' }