|
|
|
@ -214,90 +214,62 @@ 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 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) { |
|
|
|
|
// 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(fieldParts[0])) { obj[fieldParts[0]] = []; } |
|
|
|
|
if (!obj.hasOwnProperty(field)) { obj[field] = []; } |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
if (typeof obj[field] !== 'number') { |
|
|
|
|
if (!_.has(obj, field)) { |
|
|
|
|
obj[field] = value; |
|
|
|
|
} else { |
|
|
|
|
throw "Don't use the $inc modifier on non-number fields"; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
obj[fieldParts[0]] += 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.$inc(obj[fieldParts[0]], fieldParts.slice(1), value); |
|
|
|
|
modifierFunctions[modifier](obj[fieldParts[0]], fieldParts.slice(1), value); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Actually create all modifier functions
|
|
|
|
|
Object.keys(lastStepModifierFunctions).forEach(function (modifier) { |
|
|
|
|
modifierFunctions[modifier] = createModifierFunction(modifier); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|