Skip to content

Commit

Permalink
Adds positional operator $
Browse files Browse the repository at this point in the history
  • Loading branch information
SReject committed Nov 11, 2021
1 parent 65ea0de commit de6d756
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 11 deletions.
6 changes: 2 additions & 4 deletions lib/datastore.js
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,6 @@ class Datastore extends EventEmitter {
const callback = cb || function () {};
const multi = options.multi !== undefined ? options.multi : false;
const upsert = options.upsert !== undefined ? options.upsert : false;
const position = options.position !== undefined ? options.position : false;

async.waterfall([
cb => {
Expand All @@ -604,7 +603,7 @@ class Datastore extends EventEmitter {
// updateQuery contains modifiers, use the find query as the base,
// strip it from all operators and update it according to updateQuery
try {
toBeInserted = model.modify(model.deepCopy(query, true), updateQuery, position);
toBeInserted = model.modify(model.deepCopy(query, true), updateQuery, options);
} catch (err) {
return callback(err);
}
Expand Down Expand Up @@ -640,10 +639,9 @@ class Datastore extends EventEmitter {
if (this.timestampData) {
createdAt = candidates[i].createdAt;
}
const modifiedDoc = model.modify(candidates[i], updateQuery, position);
const modifiedDoc = model.modify(candidates[i], updateQuery, options);
if (this.timestampData) {
modifiedDoc.createdAt = createdAt;
// modifiedDoc.updatedAt = new Date();
if (updateQuery.$set.updatedAt === undefined) {
modifiedDoc.updatedAt = new Date();
}
Expand Down
65 changes: 58 additions & 7 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,11 +647,12 @@ lastStepModifierFunctions.$min = function (obj, field, value) {

// Given its name, create the complete modifier function
function createModifierFunction (modifier) {
return function (obj, field, value, position) {
let fieldParts = typeof field === 'string' ? field.split('.') : field;
return function (obj, field, value, options) {
const fieldParts = typeof field === 'string' ? field.split('.') : field;

if (fieldParts.length === 1) {
lastStepModifierFunctions[modifier](obj, field, value, position);
lastStepModifierFunctions[modifier](obj, field, value, options);

} else {
if (obj[fieldParts[0]] === undefined) {
// Bad looking specific fix, needs to be generalized modifiers that behave like $unset are implemented
Expand All @@ -660,7 +661,28 @@ function createModifierFunction (modifier) {
}
obj[fieldParts[0]] = {};
}
modifierFunctions[modifier](obj[fieldParts[0]], fieldParts.slice(1), value, position);

if (fieldParts[1] === '$') {
const arrayKey = fieldParts[0];
const arrayObj = obj[arrayKey];
const query = options.query;

if (!Array.isArray) {
throw new Error("You cannot apply the positional ($) operator to a non-array field");
}

for (let i = arrayObj.length - 1; i >= 0; i -= 1) {
obj[arrayKey] = arrayObj[i];

if (match(obj, query)) {
obj[arrayKey] = arrayObj;
fieldParts[1] = i;
break;
}
}
}

modifierFunctions[modifier](obj[fieldParts[0]], fieldParts.slice(1), value, options);
}
};
}
Expand All @@ -671,7 +693,11 @@ Object.keys(lastStepModifierFunctions).forEach(function (modifier) {
});

/** Modify a DB object according to an update query */
function modify (obj, updateQuery, position) {
function modify (obj, updateQuery, options = {}) {
const position = options.position;
const query = options.query;


let keys = Object.keys(updateQuery),
firstChars = keys.map(item => item[0]),
dollarFirstChars = firstChars.filter(item => item === '$'),
Expand All @@ -690,6 +716,7 @@ function modify (obj, updateQuery, position) {
// Simply replace the object with the update query contents
newDoc = deepCopy(updateQuery);
newDoc._id = obj._id;

} else {
// Apply modifiers
modifiers = [...keys];
Expand All @@ -706,8 +733,32 @@ function modify (obj, updateQuery, position) {
}

const keys = Object.keys(updateQuery[m]);
keys.forEach(function (k) {
modifierFunctions[m](newDoc, k, updateQuery[m][k], position);
keys.forEach(k => {
let queryFields = k.split('.');
let index = queryFields.indexOf('$');

if (index === -1) {
const arrayField = queryFields[index - 1];
const queryKeys = Object.keys(query);

let i = queryKeys.length,
found = false;

while (i--) {
let fields = queryKeys[i].split('.');

if (fields.indexOf(arrayField) !== -1) {
found = true;
break;
}
}

if (!found) {
throw new Error("You must include the relevant array field in query when using the positional ($) operator");
}
}

modifierFunctions[m](newDoc, k, updateQuery[m][k], options);
});
});
}
Expand Down

0 comments on commit de6d756

Please sign in to comment.