mongo-dot-notation
Version:
Transform objects to MongoDB update instructions
324 lines (323 loc) • 11.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.$sort = exports.$slice = exports.$push = exports.$pull = exports.$pullAll = exports.$pop = exports.$addToSet = exports.$ = void 0;
const field_1 = require("./field");
const operator_1 = require("./operator");
const positional = (field) => {
if (typeof field === 'undefined') {
return '$';
}
const isIndex = typeof field === 'number' || /^\d+/.test(field);
if (isIndex) {
return field.toString();
}
const isAll = field.startsWith('[');
if (isAll) {
return `$${field}`;
}
if (field === '') {
return '$';
}
return `$.${field}`;
};
const combine = (value, chain1, chain2) => (0, operator_1.create)('$push', value, Object.assign(Object.assign({}, chain1 === null || chain1 === void 0 ? void 0 : chain1(value)), chain2 === null || chain2 === void 0 ? void 0 : chain2(value)));
const position = (chain1, chain2) => (value) => (0, operator_1.create)('$push', value, {
/**
* Specifies the location in the array at which the `$push` operator inserts elements.
* @see https://www.mongodb.com/docs/manual/reference/operator/update/position/
* @param index zero-based index
*
* @example
* ```ts
* // insert element `10` at position 1 in the array
* flatten({ scores: $push(10).$each().$position(1) });
* ```
*/
$position: (index) => combine(Object.assign(Object.assign({}, value), { $position: index }), chain1, chain2),
});
const slice = (chain1, chain2) => (value) => (0, operator_1.create)('$push', value, {
/**
* Limits the number of array elements.
* @see https://www.mongodb.com/docs/manual/reference/operator/update/slice/
*
* @example
* ```ts
* // leave only the first 3 elements
* flatten({ grades: $push().$each().$slice(3) });
*
* // leave only the last element
* flatten({ grades: $push().$each().$slice(-1) });
*
* // empty the array
* flatten({ grades: $push().$each().$slice(0) });
* ```
*/
$slice: (count) => combine(Object.assign(Object.assign({}, value), { $slice: count }), chain1, chain2),
});
const sort = (chain1, chain2) => (value) => (0, operator_1.create)('$push', value, {
/**
* Orders the elements of an array.
* @param value sort specification (default `1`)
* @see https://www.mongodb.com/docs/manual/reference/operator/update/sort/
*
* @example
* ```ts
* // sort ascending an array of numbers
* flatten({ scores: $push().$each().$sort(1) });
*
* // sort descending an array of numbers
* flatten({ scores: $push().$each().$sort(-1) });
*
* // sort ascending an array of documents with `name` field
* flatten({ users: $push().$each().$sort({ name: 1 }) });
* ```
*/
$sort: (specification) => combine(Object.assign(Object.assign({}, value), { $sort: specification !== null && specification !== void 0 ? specification : 1 }), chain1, chain2),
});
/**
* The positional operator identifies **an element** or **multiple elements** matching a
* given query condition to be updated in an array.
* @param field _(optional)_ field of the array document to update.
*
* @see https://www.mongodb.com/docs/manual/reference/operator/update/positional/
* @see https://www.mongodb.com/docs/manual/reference/operator/update/positional-all/
*
* @example
* ```ts
* // Increment by one the first element that matches the update query
* $().$inc(1);
*
* // Increment by one the first element's `score` field that matches the update query
* $('score').$inc(1);
*
* // Increment all elements by one
* $('[]').$inc(1);
*
* // Increment all elements' `score` field by one
* $('[].score').$inc(1);
*
* // Find all `grades` documents that have the `std` lower than seven
* // and increment their `grade` by ten.
* collection.updateOne(
* criteria,
* flatten({ grades: $('[element].grade').$inc(10) }),
* { arrayFilters: [{ 'element.std': { $lt: 7 } }] }
* );
* ```
*/
const $ = (field) => {
const key = positional(field);
return (0, operator_1.create)(key, undefined, {
/**
* Merges the array element(s) identified by the current positional operator
* with the given object.
* @see https://www.mongodb.com/docs/manual/reference/operator/update/positional-all/#nested-arrays
* @param value object to merge
*
* @example
* ```ts
* flatten({ points: $('[]').merge({ x: 0, y: 1 }) });
*
* // {
* // $set: {
* // 'points.$[].x': 1,
* // 'points.$[].y': 2,
* // }
* // }
* ```
*/
merge: (value) => (0, operator_1.create)(key, (0, operator_1.create)('merge', value)),
/**
* @see {@link $inc}
*/
$inc: (value) => (0, operator_1.create)(key, (0, field_1.$inc)(value)),
/**
* @see {@link $mul}
*/
$mul: (value) => (0, operator_1.create)(key, (0, field_1.$mul)(value)),
/**
* @see {@link $set}
*/
$set: (value) => (0, operator_1.create)(key, (0, field_1.$set)(value)),
/**
* @see {@link $unset}
*/
$unset: () => (0, operator_1.create)(key, (0, field_1.$unset)()),
/**
* @see {@link $rename}
*/
$rename: (field) => (0, operator_1.create)(key, (0, field_1.$rename)(field)),
/**
* @see {@link $min}
*/
$min: (value) => (0, operator_1.create)(key, (0, field_1.$min)(value)),
/**
* @see {@link $max}
*/
$max: (value) => (0, operator_1.create)(key, (0, field_1.$max)(value)),
/**
* @see {@link $currentDate}
*/
$currentDate: (type) => (0, operator_1.create)(key, (0, field_1.$currentDate)(type)),
/**
* @see {@link $timestamp}
*/
$timestamp: () => (0, operator_1.create)(key, (0, field_1.$timestamp)()),
});
};
exports.$ = $;
/**
* Adds a value to an array unless the value is already present.
* To add multiple values, chain with `$each` operator.
* @param value the value to add
* @see https://www.mongodb.com/docs/manual/reference/operator/update/addToSet/
*
* @example
* ```ts
* // add just one element
* flatten({ permissions: $addToSet('admin') });
*
* // add multiple elements
* flatten({ permissions: $addToSet(['read', 'write']).$each() });
* ```
*/
const $addToSet = (value) => (0, operator_1.create)('$addToSet', value, {
/**
* Specifies that value to add is an array and that each element should be added.
* @see https://www.mongodb.com/docs/manual/reference/operator/update/each/
*/
$each: () => (0, operator_1.create)('$addToSet', { $each: Array.isArray(value) ? value : [value] }),
});
exports.$addToSet = $addToSet;
/**
* Removes the first or last element of an array.
* @param value specify `-1` to remove the first element, `1` to remove the last element
* @see https://www.mongodb.com/docs/manual/reference/operator/update/pop/
*
* @example
* ```ts
* // remove the first element from the array
* flatten({ grades: $pop(-1) });
* // same as:
* flatten({ grades: $pop().first() });
* ```
*/
const $pop = (value = 1) => (0, operator_1.create)('$pop', value, {
/**
* Removes the first element from the array.
*/
first: () => (0, operator_1.create)('$pop', -1),
/**
* Removes the last element from the array.
*/
last: () => (0, operator_1.create)('$pop', 1),
});
exports.$pop = $pop;
/**
* Removes all instances of the specified values from an existing array.
* @param value the value(s) to remove from the array
* @see https://www.mongodb.com/docs/manual/reference/operator/update/pullAll/
*
* @example
* ```ts
* // remove all instances of the value `1` and `2` from the array
* flatten({ score: $pullAll([1, 2]) });
* ```
*/
const $pullAll = (value) => (0, operator_1.create)('$pullAll', Array.isArray(value) ? value : [value]);
exports.$pullAll = $pullAll;
/**
* Removes from an existing array all instances of a value or values that match a specified condition.
* Unlike the {@link $pullAll} operator, this operator can be used to remove all instances that match a query.
* @param value the value(s) or condition to match to remove from the array
* @see https://www.mongodb.com/docs/manual/reference/operator/update/pull/
*
* @example
* ```ts
* // remove all instances of the value `0` and `1` from the array;
* // same as using $pullAll
* flatten({ scores: $pull([0, 1]) });
*
* // remove all instances lower than or equal to `3`
* flatten({ scores: $pull({ $lte: 3 }) })
*
* // remove all documents with the field `name` equal to `Test`
* flatten({ users: $pull({ name: { $eq: 'Test' } }) })
* ```
*/
const $pull = (value) => (0, operator_1.create)('$pull', Array.isArray(value) ? { $in: value } : value);
exports.$pull = $pull;
/**
* Appends a specified value to an array.
* @param value the value(s) to append to the array
* @see https://www.mongodb.com/docs/manual/reference/operator/update/push/
*
* @example
* ```ts
* // append one element
* flatten({ scores: $push(1) });
*
* // append multiple elements
* flatten({ scores: $push([1, 2, 3]).$each() });
*
* // append an element and update to leave only the last ten
* flatten({ scores: $push(7).$each().$slice(-10) });
*
* // append an element and update to leave only the last ten sorted by value
* flatten({ scores: $push(7).$each().$sort(1).$slice(-10) });
*
* // append an element at position three in the array
* flatten({ scores: $push(7).$each().$position(2) });
* ```
*/
const $push = (value) => (0, operator_1.create)('$push', value, {
/**
* Specifies that value to add is an array and that each element should be added.
* @see https://www.mongodb.com/docs/manual/reference/operator/update/each/
*/
$each: () => {
const arr = typeof value === 'undefined' ? [] : Array.isArray(value) ? value : [value];
const eachValue = { $each: arr };
return (0, operator_1.create)('$push', eachValue, Object.assign(Object.assign(Object.assign({}, position(sort(slice()), slice(sort()))(eachValue)), slice(position(sort()), sort(position()))(eachValue)), sort(slice(position()), position(slice()))(eachValue)));
},
});
exports.$push = $push;
/**
* Limits the number of array elements.
* Alias for `$push().$each().$slice()`.
* @see https://www.mongodb.com/docs/manual/reference/operator/update/slice/
*
* @example
* ```ts
* // leave only the first 3 elements
* flatten({ grades: $slice(3) });
*
* // leave only the last element
* flatten({ grades: $slice(-1) });
*
* // empty the array
* flatten({ grades: $slice(0) });
* ```
*/
const $slice = (count) => (0, exports.$push)().$each().$slice(count);
exports.$slice = $slice;
/**
* Orders the elements of an array.
* Alias for `$push().$each().$sort()`.
* @param value sort specification (default `1`)
* @see https://www.mongodb.com/docs/manual/reference/operator/update/sort/
*
* @example
* ```ts
* // sort ascending an array of numbers
* flatten({ scores: $sort(1) });
*
* // sort descending an array of numbers
* flatten({ scores: $sort(-1) });
*
* // sort ascending an array of documents with `name` field
* flatten({ users: $sort({ name: 1 }) });
* ```
*/
const $sort = (specification) => (0, exports.$push)().$each().$sort(specification);
exports.$sort = $sort;