@depup/mongoose 9.1.3-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +22 -0
- package/README.md +397 -0
- package/SECURITY.md +1 -0
- package/eslint.config.mjs +198 -0
- package/index.js +64 -0
- package/lib/aggregate.js +1189 -0
- package/lib/cast/bigint.js +46 -0
- package/lib/cast/boolean.js +32 -0
- package/lib/cast/date.js +41 -0
- package/lib/cast/decimal128.js +39 -0
- package/lib/cast/double.js +50 -0
- package/lib/cast/int32.js +36 -0
- package/lib/cast/number.js +42 -0
- package/lib/cast/objectid.js +29 -0
- package/lib/cast/string.js +37 -0
- package/lib/cast/uuid.js +35 -0
- package/lib/cast.js +436 -0
- package/lib/collection.js +321 -0
- package/lib/connection.js +1855 -0
- package/lib/connectionState.js +26 -0
- package/lib/constants.js +73 -0
- package/lib/cursor/aggregationCursor.js +466 -0
- package/lib/cursor/changeStream.js +198 -0
- package/lib/cursor/queryCursor.js +622 -0
- package/lib/document.js +5521 -0
- package/lib/driver.js +15 -0
- package/lib/drivers/SPEC.md +4 -0
- package/lib/drivers/node-mongodb-native/bulkWriteResult.js +5 -0
- package/lib/drivers/node-mongodb-native/collection.js +393 -0
- package/lib/drivers/node-mongodb-native/connection.js +506 -0
- package/lib/drivers/node-mongodb-native/index.js +10 -0
- package/lib/error/browserMissingSchema.js +29 -0
- package/lib/error/bulkSaveIncompleteError.js +44 -0
- package/lib/error/bulkWriteError.js +41 -0
- package/lib/error/cast.js +158 -0
- package/lib/error/createCollectionsError.js +26 -0
- package/lib/error/divergentArray.js +40 -0
- package/lib/error/eachAsyncMultiError.js +41 -0
- package/lib/error/index.js +237 -0
- package/lib/error/invalidSchemaOption.js +32 -0
- package/lib/error/messages.js +47 -0
- package/lib/error/missingSchema.js +33 -0
- package/lib/error/mongooseError.js +13 -0
- package/lib/error/notFound.js +47 -0
- package/lib/error/objectExpected.js +31 -0
- package/lib/error/objectParameter.js +31 -0
- package/lib/error/overwriteModel.js +31 -0
- package/lib/error/parallelSave.js +33 -0
- package/lib/error/parallelValidate.js +33 -0
- package/lib/error/serverSelection.js +62 -0
- package/lib/error/setOptionError.js +103 -0
- package/lib/error/strict.js +35 -0
- package/lib/error/strictPopulate.js +31 -0
- package/lib/error/syncIndexes.js +30 -0
- package/lib/error/validation.js +97 -0
- package/lib/error/validator.js +100 -0
- package/lib/error/version.js +38 -0
- package/lib/helpers/aggregate/prepareDiscriminatorPipeline.js +39 -0
- package/lib/helpers/aggregate/stringifyFunctionOperators.js +50 -0
- package/lib/helpers/arrayDepth.js +33 -0
- package/lib/helpers/clone.js +204 -0
- package/lib/helpers/common.js +127 -0
- package/lib/helpers/createJSONSchemaTypeDefinition.js +24 -0
- package/lib/helpers/cursor/eachAsync.js +225 -0
- package/lib/helpers/discriminator/applyEmbeddedDiscriminators.js +36 -0
- package/lib/helpers/discriminator/areDiscriminatorValuesEqual.js +16 -0
- package/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js +12 -0
- package/lib/helpers/discriminator/getConstructor.js +29 -0
- package/lib/helpers/discriminator/getDiscriminatorByValue.js +28 -0
- package/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js +27 -0
- package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +91 -0
- package/lib/helpers/document/applyDefaults.js +132 -0
- package/lib/helpers/document/applyTimestamps.js +106 -0
- package/lib/helpers/document/applyVirtuals.js +147 -0
- package/lib/helpers/document/cleanModifiedSubpaths.js +45 -0
- package/lib/helpers/document/compile.js +238 -0
- package/lib/helpers/document/getDeepestSubdocumentForPath.js +38 -0
- package/lib/helpers/document/getEmbeddedDiscriminatorPath.js +53 -0
- package/lib/helpers/document/handleSpreadDoc.js +35 -0
- package/lib/helpers/each.js +25 -0
- package/lib/helpers/error/combinePathErrors.js +22 -0
- package/lib/helpers/firstKey.js +8 -0
- package/lib/helpers/get.js +65 -0
- package/lib/helpers/getConstructorName.js +16 -0
- package/lib/helpers/getDefaultBulkwriteResult.js +18 -0
- package/lib/helpers/getFunctionName.js +10 -0
- package/lib/helpers/immediate.js +16 -0
- package/lib/helpers/indexes/applySchemaCollation.js +13 -0
- package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +14 -0
- package/lib/helpers/indexes/getRelatedIndexes.js +63 -0
- package/lib/helpers/indexes/isDefaultIdIndex.js +18 -0
- package/lib/helpers/indexes/isIndexEqual.js +95 -0
- package/lib/helpers/indexes/isIndexSpecEqual.js +32 -0
- package/lib/helpers/indexes/isTextIndex.js +16 -0
- package/lib/helpers/indexes/isTimeseriesIndex.js +16 -0
- package/lib/helpers/isAsyncFunction.js +9 -0
- package/lib/helpers/isBsonType.js +15 -0
- package/lib/helpers/isMongooseObject.js +22 -0
- package/lib/helpers/isObject.js +16 -0
- package/lib/helpers/isPOJO.js +12 -0
- package/lib/helpers/isPromise.js +6 -0
- package/lib/helpers/isSimpleValidator.js +22 -0
- package/lib/helpers/minimize.js +41 -0
- package/lib/helpers/model/applyDefaultsToPOJO.js +52 -0
- package/lib/helpers/model/applyHooks.js +140 -0
- package/lib/helpers/model/applyMethods.js +70 -0
- package/lib/helpers/model/applyStaticHooks.js +33 -0
- package/lib/helpers/model/applyStatics.js +13 -0
- package/lib/helpers/model/castBulkWrite.js +316 -0
- package/lib/helpers/model/decorateBulkWriteResult.js +8 -0
- package/lib/helpers/model/discriminator.js +265 -0
- package/lib/helpers/model/pushNestedArrayPaths.js +15 -0
- package/lib/helpers/omitUndefined.js +20 -0
- package/lib/helpers/once.js +12 -0
- package/lib/helpers/parallelLimit.js +37 -0
- package/lib/helpers/path/parentPaths.js +18 -0
- package/lib/helpers/path/setDottedPath.js +33 -0
- package/lib/helpers/pluralize.js +95 -0
- package/lib/helpers/populate/assignRawDocsToIdStructure.js +129 -0
- package/lib/helpers/populate/assignVals.js +360 -0
- package/lib/helpers/populate/createPopulateQueryFilter.js +97 -0
- package/lib/helpers/populate/getModelsMapForPopulate.js +776 -0
- package/lib/helpers/populate/getSchemaTypes.js +228 -0
- package/lib/helpers/populate/getVirtual.js +103 -0
- package/lib/helpers/populate/leanPopulateMap.js +7 -0
- package/lib/helpers/populate/lookupLocalFields.js +40 -0
- package/lib/helpers/populate/markArraySubdocsPopulated.js +49 -0
- package/lib/helpers/populate/modelNamesFromRefPath.js +66 -0
- package/lib/helpers/populate/removeDeselectedForeignField.js +31 -0
- package/lib/helpers/populate/setPopulatedVirtualValue.js +33 -0
- package/lib/helpers/populate/skipPopulateValue.js +10 -0
- package/lib/helpers/populate/validateRef.js +19 -0
- package/lib/helpers/printJestWarning.js +21 -0
- package/lib/helpers/processConnectionOptions.js +65 -0
- package/lib/helpers/projection/applyProjection.js +83 -0
- package/lib/helpers/projection/hasIncludedChildren.js +41 -0
- package/lib/helpers/projection/isDefiningProjection.js +18 -0
- package/lib/helpers/projection/isExclusive.js +37 -0
- package/lib/helpers/projection/isInclusive.js +39 -0
- package/lib/helpers/projection/isNestedProjection.js +8 -0
- package/lib/helpers/projection/isPathExcluded.js +40 -0
- package/lib/helpers/projection/isPathSelectedInclusive.js +28 -0
- package/lib/helpers/projection/isSubpath.js +14 -0
- package/lib/helpers/projection/parseProjection.js +33 -0
- package/lib/helpers/query/applyGlobalOption.js +29 -0
- package/lib/helpers/query/cast$expr.js +287 -0
- package/lib/helpers/query/castFilterPath.js +54 -0
- package/lib/helpers/query/castUpdate.js +643 -0
- package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +103 -0
- package/lib/helpers/query/handleImmutable.js +44 -0
- package/lib/helpers/query/handleReadPreferenceAliases.js +23 -0
- package/lib/helpers/query/hasDollarKeys.js +23 -0
- package/lib/helpers/query/isOperator.js +14 -0
- package/lib/helpers/query/sanitizeFilter.js +38 -0
- package/lib/helpers/query/sanitizeProjection.js +14 -0
- package/lib/helpers/query/selectPopulatedFields.js +62 -0
- package/lib/helpers/query/trusted.js +13 -0
- package/lib/helpers/query/validOps.js +3 -0
- package/lib/helpers/schema/addAutoId.js +7 -0
- package/lib/helpers/schema/applyBuiltinPlugins.js +12 -0
- package/lib/helpers/schema/applyPlugins.js +55 -0
- package/lib/helpers/schema/applyReadConcern.js +20 -0
- package/lib/helpers/schema/applyWriteConcern.js +39 -0
- package/lib/helpers/schema/cleanPositionalOperators.js +12 -0
- package/lib/helpers/schema/getIndexes.js +171 -0
- package/lib/helpers/schema/getKeysInSchemaOrder.js +28 -0
- package/lib/helpers/schema/getPath.js +43 -0
- package/lib/helpers/schema/getSubdocumentStrictValue.js +32 -0
- package/lib/helpers/schema/handleIdOption.js +20 -0
- package/lib/helpers/schema/handleTimestampOption.js +24 -0
- package/lib/helpers/schema/idGetter.js +34 -0
- package/lib/helpers/schema/merge.js +36 -0
- package/lib/helpers/schematype/handleImmutable.js +50 -0
- package/lib/helpers/setDefaultsOnInsert.js +158 -0
- package/lib/helpers/specialProperties.js +3 -0
- package/lib/helpers/symbols.js +20 -0
- package/lib/helpers/timers.js +3 -0
- package/lib/helpers/timestamps/setDocumentTimestamps.js +26 -0
- package/lib/helpers/timestamps/setupTimestamps.js +116 -0
- package/lib/helpers/topology/allServersUnknown.js +12 -0
- package/lib/helpers/topology/isAtlas.js +31 -0
- package/lib/helpers/topology/isSSLError.js +16 -0
- package/lib/helpers/update/applyTimestampsToChildren.js +193 -0
- package/lib/helpers/update/applyTimestampsToUpdate.js +131 -0
- package/lib/helpers/update/castArrayFilters.js +113 -0
- package/lib/helpers/update/decorateUpdateWithVersionKey.js +35 -0
- package/lib/helpers/update/modifiedPaths.js +33 -0
- package/lib/helpers/update/moveImmutableProperties.js +53 -0
- package/lib/helpers/update/removeUnusedArrayFilters.js +32 -0
- package/lib/helpers/update/updatedPathsByArrayFilter.js +27 -0
- package/lib/helpers/updateValidators.js +193 -0
- package/lib/index.js +17 -0
- package/lib/internal.js +46 -0
- package/lib/model.js +5010 -0
- package/lib/modifiedPathsSnapshot.js +9 -0
- package/lib/mongoose.js +1411 -0
- package/lib/options/populateOptions.js +36 -0
- package/lib/options/propertyOptions.js +8 -0
- package/lib/options/saveOptions.js +16 -0
- package/lib/options/schemaArrayOptions.js +78 -0
- package/lib/options/schemaBufferOptions.js +38 -0
- package/lib/options/schemaDateOptions.js +71 -0
- package/lib/options/schemaDocumentArrayOptions.js +68 -0
- package/lib/options/schemaMapOptions.js +43 -0
- package/lib/options/schemaNumberOptions.js +101 -0
- package/lib/options/schemaObjectIdOptions.js +64 -0
- package/lib/options/schemaStringOptions.js +138 -0
- package/lib/options/schemaSubdocumentOptions.js +66 -0
- package/lib/options/schemaTypeOptions.js +244 -0
- package/lib/options/schemaUnionOptions.js +32 -0
- package/lib/options/virtualOptions.js +164 -0
- package/lib/options.js +17 -0
- package/lib/plugins/index.js +6 -0
- package/lib/plugins/saveSubdocs.js +76 -0
- package/lib/plugins/sharding.js +84 -0
- package/lib/plugins/trackTransaction.js +84 -0
- package/lib/plugins/validateBeforeSave.js +41 -0
- package/lib/query.js +5673 -0
- package/lib/queryHelpers.js +387 -0
- package/lib/schema/array.js +699 -0
- package/lib/schema/bigint.js +282 -0
- package/lib/schema/boolean.js +332 -0
- package/lib/schema/buffer.js +343 -0
- package/lib/schema/date.js +467 -0
- package/lib/schema/decimal128.js +263 -0
- package/lib/schema/documentArray.js +656 -0
- package/lib/schema/documentArrayElement.js +137 -0
- package/lib/schema/double.js +246 -0
- package/lib/schema/index.js +32 -0
- package/lib/schema/int32.js +289 -0
- package/lib/schema/map.js +201 -0
- package/lib/schema/mixed.js +146 -0
- package/lib/schema/number.js +510 -0
- package/lib/schema/objectId.js +333 -0
- package/lib/schema/operators/bitwise.js +38 -0
- package/lib/schema/operators/exists.js +12 -0
- package/lib/schema/operators/geospatial.js +107 -0
- package/lib/schema/operators/helpers.js +32 -0
- package/lib/schema/operators/text.js +39 -0
- package/lib/schema/operators/type.js +20 -0
- package/lib/schema/string.js +733 -0
- package/lib/schema/subdocument.js +436 -0
- package/lib/schema/symbols.js +5 -0
- package/lib/schema/union.js +113 -0
- package/lib/schema/uuid.js +305 -0
- package/lib/schema.js +3226 -0
- package/lib/schemaType.js +1835 -0
- package/lib/stateMachine.js +232 -0
- package/lib/types/array/index.js +119 -0
- package/lib/types/array/isMongooseArray.js +5 -0
- package/lib/types/array/methods/index.js +1095 -0
- package/lib/types/arraySubdocument.js +207 -0
- package/lib/types/buffer.js +294 -0
- package/lib/types/decimal128.js +13 -0
- package/lib/types/documentArray/index.js +113 -0
- package/lib/types/documentArray/isMongooseDocumentArray.js +5 -0
- package/lib/types/documentArray/methods/index.js +415 -0
- package/lib/types/double.js +13 -0
- package/lib/types/index.js +23 -0
- package/lib/types/map.js +419 -0
- package/lib/types/objectid.js +41 -0
- package/lib/types/subdocument.js +464 -0
- package/lib/types/uuid.js +13 -0
- package/lib/utils.js +1054 -0
- package/lib/validOptions.js +42 -0
- package/lib/virtualType.js +204 -0
- package/package.json +148 -0
- package/types/aggregate.d.ts +180 -0
- package/types/augmentations.d.ts +9 -0
- package/types/callback.d.ts +8 -0
- package/types/collection.d.ts +49 -0
- package/types/connection.d.ts +297 -0
- package/types/cursor.d.ts +67 -0
- package/types/document.d.ts +374 -0
- package/types/error.d.ts +143 -0
- package/types/expressions.d.ts +3053 -0
- package/types/helpers.d.ts +32 -0
- package/types/index.d.ts +1056 -0
- package/types/indexes.d.ts +97 -0
- package/types/inferhydrateddoctype.d.ts +115 -0
- package/types/inferrawdoctype.d.ts +135 -0
- package/types/inferschematype.d.ts +337 -0
- package/types/middlewares.d.ts +59 -0
- package/types/models.d.ts +1306 -0
- package/types/mongooseoptions.d.ts +228 -0
- package/types/pipelinestage.d.ts +333 -0
- package/types/populate.d.ts +53 -0
- package/types/query.d.ts +934 -0
- package/types/schemaoptions.d.ts +282 -0
- package/types/schematypes.d.ts +654 -0
- package/types/session.d.ts +32 -0
- package/types/types.d.ts +109 -0
- package/types/utility.d.ts +175 -0
- package/types/validation.d.ts +39 -0
- package/types/virtuals.d.ts +14 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
|
|
4
|
+
const handleTimestampOption = require('../schema/handleTimestampOption');
|
|
5
|
+
|
|
6
|
+
module.exports = applyTimestampsToChildren;
|
|
7
|
+
|
|
8
|
+
/*!
|
|
9
|
+
* ignore
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
function applyTimestampsToChildren(now, update, schema) {
|
|
13
|
+
if (update == null) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const keys = Object.keys(update);
|
|
18
|
+
const hasDollarKey = keys.some(key => key[0] === '$');
|
|
19
|
+
|
|
20
|
+
if (hasDollarKey) {
|
|
21
|
+
if (update.$push) {
|
|
22
|
+
_applyTimestampToUpdateOperator(update.$push);
|
|
23
|
+
}
|
|
24
|
+
if (update.$addToSet) {
|
|
25
|
+
_applyTimestampToUpdateOperator(update.$addToSet);
|
|
26
|
+
}
|
|
27
|
+
if (update.$set != null) {
|
|
28
|
+
const keys = Object.keys(update.$set);
|
|
29
|
+
for (const key of keys) {
|
|
30
|
+
applyTimestampsToUpdateKey(schema, key, update.$set, now);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (update.$setOnInsert != null) {
|
|
34
|
+
const keys = Object.keys(update.$setOnInsert);
|
|
35
|
+
for (const key of keys) {
|
|
36
|
+
applyTimestampsToUpdateKey(schema, key, update.$setOnInsert, now);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const updateKeys = Object.keys(update).filter(key => key[0] !== '$');
|
|
42
|
+
for (const key of updateKeys) {
|
|
43
|
+
applyTimestampsToUpdateKey(schema, key, update, now);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function _applyTimestampToUpdateOperator(op) {
|
|
47
|
+
for (const key of Object.keys(op)) {
|
|
48
|
+
const $path = schema.path(key.replace(/\.\$\./i, '.').replace(/.\$$/, ''));
|
|
49
|
+
if (op[key] &&
|
|
50
|
+
$path &&
|
|
51
|
+
$path.$isMongooseDocumentArray &&
|
|
52
|
+
$path.schema.options.timestamps) {
|
|
53
|
+
const timestamps = $path.schema.options.timestamps;
|
|
54
|
+
const createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
55
|
+
const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
56
|
+
if (op[key].$each) {
|
|
57
|
+
op[key].$each.forEach(function(subdoc) {
|
|
58
|
+
if (updatedAt != null) {
|
|
59
|
+
subdoc[updatedAt] = now;
|
|
60
|
+
}
|
|
61
|
+
if (createdAt != null) {
|
|
62
|
+
subdoc[createdAt] = now;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
applyTimestampsToChildren(now, subdoc, $path.schema);
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
if (updatedAt != null) {
|
|
69
|
+
op[key][updatedAt] = now;
|
|
70
|
+
}
|
|
71
|
+
if (createdAt != null) {
|
|
72
|
+
op[key][createdAt] = now;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
applyTimestampsToChildren(now, op[key], $path.schema);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function applyTimestampsToDocumentArray(arr, schematype, now) {
|
|
83
|
+
const timestamps = schematype.schema.options.timestamps;
|
|
84
|
+
|
|
85
|
+
const len = arr.length;
|
|
86
|
+
|
|
87
|
+
if (!timestamps) {
|
|
88
|
+
for (let i = 0; i < len; ++i) {
|
|
89
|
+
applyTimestampsToChildren(now, arr[i], schematype.schema);
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
95
|
+
const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
96
|
+
for (let i = 0; i < len; ++i) {
|
|
97
|
+
if (updatedAt != null) {
|
|
98
|
+
arr[i][updatedAt] = now;
|
|
99
|
+
}
|
|
100
|
+
if (createdAt != null) {
|
|
101
|
+
arr[i][createdAt] = now;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
applyTimestampsToChildren(now, arr[i], schematype.schema);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function applyTimestampsToSingleNested(subdoc, schematype, now) {
|
|
109
|
+
const timestamps = schematype.schema.options.timestamps;
|
|
110
|
+
if (!timestamps) {
|
|
111
|
+
applyTimestampsToChildren(now, subdoc, schematype.schema);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
116
|
+
const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
117
|
+
if (updatedAt != null) {
|
|
118
|
+
subdoc[updatedAt] = now;
|
|
119
|
+
}
|
|
120
|
+
if (createdAt != null) {
|
|
121
|
+
subdoc[createdAt] = now;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
applyTimestampsToChildren(now, subdoc, schematype.schema);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function applyTimestampsToUpdateKey(schema, key, update, now) {
|
|
128
|
+
// Replace positional operator `$` and array filters `$[]` and `$[.*]`
|
|
129
|
+
const keyToSearch = cleanPositionalOperators(key);
|
|
130
|
+
const path = schema.path(keyToSearch);
|
|
131
|
+
if (!path) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const parentSchemaTypes = [];
|
|
136
|
+
const pieces = keyToSearch.split('.');
|
|
137
|
+
for (let i = pieces.length - 1; i > 0; --i) {
|
|
138
|
+
const s = schema.path(pieces.slice(0, i).join('.'));
|
|
139
|
+
if (s != null &&
|
|
140
|
+
(s.$isMongooseDocumentArray || s.$isSingleNested)) {
|
|
141
|
+
parentSchemaTypes.push({ parentPath: key.split('.').slice(0, i).join('.'), parentSchemaType: s });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (Array.isArray(update[key]) && path.$isMongooseDocumentArray) {
|
|
146
|
+
applyTimestampsToDocumentArray(update[key], path, now);
|
|
147
|
+
} else if (update[key] && path.$isSingleNested) {
|
|
148
|
+
applyTimestampsToSingleNested(update[key], path, now);
|
|
149
|
+
} else if (parentSchemaTypes.length > 0) {
|
|
150
|
+
for (const item of parentSchemaTypes) {
|
|
151
|
+
const parentPath = item.parentPath;
|
|
152
|
+
const parentSchemaType = item.parentSchemaType;
|
|
153
|
+
const timestamps = parentSchemaType.schema.options.timestamps;
|
|
154
|
+
const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
155
|
+
|
|
156
|
+
if (!timestamps || updatedAt == null) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (parentSchemaType.$isSingleNested) {
|
|
161
|
+
// Single nested is easy
|
|
162
|
+
update[parentPath + '.' + updatedAt] = now;
|
|
163
|
+
} else if (parentSchemaType.$isMongooseDocumentArray) {
|
|
164
|
+
let childPath = key.substring(parentPath.length + 1);
|
|
165
|
+
|
|
166
|
+
if (/^\d+$/.test(childPath)) {
|
|
167
|
+
update[parentPath + '.' + childPath][updatedAt] = now;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const firstDot = childPath.indexOf('.');
|
|
172
|
+
childPath = firstDot !== -1 ? childPath.substring(0, firstDot) : childPath;
|
|
173
|
+
|
|
174
|
+
update[parentPath + '.' + childPath + '.' + updatedAt] = now;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} else if (path.schema != null && path.schema != schema && update[key]) {
|
|
178
|
+
const timestamps = path.schema.options.timestamps;
|
|
179
|
+
const createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
180
|
+
const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
181
|
+
|
|
182
|
+
if (!timestamps) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (updatedAt != null) {
|
|
187
|
+
update[key][updatedAt] = now;
|
|
188
|
+
}
|
|
189
|
+
if (createdAt != null) {
|
|
190
|
+
update[key][createdAt] = now;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* ignore
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const get = require('../get');
|
|
8
|
+
const utils = require('../../utils');
|
|
9
|
+
|
|
10
|
+
module.exports = applyTimestampsToUpdate;
|
|
11
|
+
|
|
12
|
+
/*!
|
|
13
|
+
* ignore
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, options, isReplace) {
|
|
17
|
+
const updates = currentUpdate;
|
|
18
|
+
let _updates = updates;
|
|
19
|
+
const timestamps = get(options, 'timestamps', true);
|
|
20
|
+
|
|
21
|
+
// Support skipping timestamps at the query level, see gh-6980
|
|
22
|
+
if (!timestamps || updates == null) {
|
|
23
|
+
return currentUpdate;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const skipCreatedAt = timestamps?.createdAt === false;
|
|
27
|
+
const skipUpdatedAt = timestamps?.updatedAt === false;
|
|
28
|
+
|
|
29
|
+
if (isReplace) {
|
|
30
|
+
if (currentUpdate?.$set) {
|
|
31
|
+
currentUpdate = currentUpdate.$set;
|
|
32
|
+
updates.$set = {};
|
|
33
|
+
_updates = updates.$set;
|
|
34
|
+
}
|
|
35
|
+
if (!skipUpdatedAt && updatedAt && !currentUpdate[updatedAt]) {
|
|
36
|
+
_updates[updatedAt] = now;
|
|
37
|
+
}
|
|
38
|
+
if (!skipCreatedAt && createdAt && !currentUpdate[createdAt]) {
|
|
39
|
+
_updates[createdAt] = now;
|
|
40
|
+
}
|
|
41
|
+
return updates;
|
|
42
|
+
}
|
|
43
|
+
currentUpdate = currentUpdate || {};
|
|
44
|
+
|
|
45
|
+
if (Array.isArray(updates)) {
|
|
46
|
+
// Update with aggregation pipeline
|
|
47
|
+
if (updatedAt == null) {
|
|
48
|
+
return updates;
|
|
49
|
+
}
|
|
50
|
+
updates.push({ $set: { [updatedAt]: now } });
|
|
51
|
+
return updates;
|
|
52
|
+
}
|
|
53
|
+
updates.$set = updates.$set || {};
|
|
54
|
+
if (!skipUpdatedAt && updatedAt &&
|
|
55
|
+
!currentUpdate.$currentDate?.[updatedAt]) {
|
|
56
|
+
let timestampSet = false;
|
|
57
|
+
if (updatedAt.indexOf('.') !== -1) {
|
|
58
|
+
const pieces = updatedAt.split('.');
|
|
59
|
+
for (let i = 1; i < pieces.length; ++i) {
|
|
60
|
+
const remnant = pieces.slice(-i).join('.');
|
|
61
|
+
const start = pieces.slice(0, -i).join('.');
|
|
62
|
+
if (currentUpdate[start] != null) {
|
|
63
|
+
currentUpdate[start][remnant] = now;
|
|
64
|
+
timestampSet = true;
|
|
65
|
+
break;
|
|
66
|
+
} else if (currentUpdate.$set?.[start]) {
|
|
67
|
+
currentUpdate.$set[start][remnant] = now;
|
|
68
|
+
timestampSet = true;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!timestampSet) {
|
|
75
|
+
updates.$set[updatedAt] = now;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (Object.hasOwn(updates, updatedAt)) {
|
|
79
|
+
delete updates[updatedAt];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!skipCreatedAt && createdAt) {
|
|
84
|
+
const overwriteImmutable = get(options, 'overwriteImmutable', false);
|
|
85
|
+
const hasUserCreatedAt = currentUpdate[createdAt] != null || currentUpdate.$set?.[createdAt] != null;
|
|
86
|
+
|
|
87
|
+
// If overwriteImmutable is true and user provided createdAt, keep their value
|
|
88
|
+
if (overwriteImmutable && hasUserCreatedAt) {
|
|
89
|
+
// Move createdAt from top-level to $set if needed
|
|
90
|
+
if (currentUpdate[createdAt] != null) {
|
|
91
|
+
updates.$set[createdAt] = currentUpdate[createdAt];
|
|
92
|
+
delete currentUpdate[createdAt];
|
|
93
|
+
}
|
|
94
|
+
// User's value is already in $set, nothing more to do
|
|
95
|
+
} else {
|
|
96
|
+
if (currentUpdate[createdAt]) {
|
|
97
|
+
delete currentUpdate[createdAt];
|
|
98
|
+
}
|
|
99
|
+
if (currentUpdate.$set?.[createdAt]) {
|
|
100
|
+
delete currentUpdate.$set[createdAt];
|
|
101
|
+
}
|
|
102
|
+
let timestampSet = false;
|
|
103
|
+
if (createdAt.indexOf('.') !== -1) {
|
|
104
|
+
const pieces = createdAt.split('.');
|
|
105
|
+
for (let i = 1; i < pieces.length; ++i) {
|
|
106
|
+
const remnant = pieces.slice(-i).join('.');
|
|
107
|
+
const start = pieces.slice(0, -i).join('.');
|
|
108
|
+
if (currentUpdate[start] != null) {
|
|
109
|
+
currentUpdate[start][remnant] = now;
|
|
110
|
+
timestampSet = true;
|
|
111
|
+
break;
|
|
112
|
+
} else if (currentUpdate.$set?.[start]) {
|
|
113
|
+
currentUpdate.$set[start][remnant] = now;
|
|
114
|
+
timestampSet = true;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!timestampSet) {
|
|
121
|
+
updates.$setOnInsert = updates.$setOnInsert || {};
|
|
122
|
+
updates.$setOnInsert[createdAt] = now;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (utils.hasOwnKeys(updates.$set) === false) {
|
|
128
|
+
delete updates.$set;
|
|
129
|
+
}
|
|
130
|
+
return updates;
|
|
131
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const castFilterPath = require('../query/castFilterPath');
|
|
4
|
+
const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
|
|
5
|
+
const getPath = require('../schema/getPath');
|
|
6
|
+
const updatedPathsByArrayFilter = require('./updatedPathsByArrayFilter');
|
|
7
|
+
const utils = require('../../utils');
|
|
8
|
+
|
|
9
|
+
module.exports = function castArrayFilters(query) {
|
|
10
|
+
const arrayFilters = query.options.arrayFilters;
|
|
11
|
+
if (!Array.isArray(arrayFilters)) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const update = query.getUpdate();
|
|
15
|
+
const schema = query.schema;
|
|
16
|
+
const updatedPathsByFilter = updatedPathsByArrayFilter(update);
|
|
17
|
+
|
|
18
|
+
let strictQuery = schema.options.strict;
|
|
19
|
+
if (query._mongooseOptions.strict != null) {
|
|
20
|
+
strictQuery = query._mongooseOptions.strict;
|
|
21
|
+
}
|
|
22
|
+
if (query.model?.base.options.strictQuery != null) {
|
|
23
|
+
strictQuery = query.model.base.options.strictQuery;
|
|
24
|
+
}
|
|
25
|
+
if (schema._userProvidedOptions.strictQuery != null) {
|
|
26
|
+
strictQuery = schema._userProvidedOptions.strictQuery;
|
|
27
|
+
}
|
|
28
|
+
if (query._mongooseOptions.strictQuery != null) {
|
|
29
|
+
strictQuery = query._mongooseOptions.strictQuery;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
_castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilter, query);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilter, query) {
|
|
36
|
+
// Map to store discriminator values for embedded documents in the array filters.
|
|
37
|
+
// This is used to handle cases where array filters target specific embedded document types.
|
|
38
|
+
const discriminatorValueMap = {};
|
|
39
|
+
|
|
40
|
+
for (const filter of arrayFilters) {
|
|
41
|
+
if (filter == null) {
|
|
42
|
+
throw new Error(`Got null array filter in ${arrayFilters}`);
|
|
43
|
+
}
|
|
44
|
+
const keys = Object.keys(filter).filter(key => filter[key] != null);
|
|
45
|
+
if (keys.length === 0) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const firstKey = keys[0];
|
|
50
|
+
if (firstKey === '$and' || firstKey === '$or') {
|
|
51
|
+
for (const key of keys) {
|
|
52
|
+
_castArrayFilters(filter[key], schema, strictQuery, updatedPathsByFilter, query);
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const dot = firstKey.indexOf('.');
|
|
57
|
+
const filterWildcardPath = dot === -1 ? firstKey : firstKey.substring(0, dot);
|
|
58
|
+
if (updatedPathsByFilter[filterWildcardPath] == null) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const baseFilterPath = cleanPositionalOperators(
|
|
62
|
+
updatedPathsByFilter[filterWildcardPath]
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const baseSchematype = getPath(schema, baseFilterPath, discriminatorValueMap);
|
|
66
|
+
let filterBaseSchema = baseSchematype != null ? baseSchematype.schema : null;
|
|
67
|
+
if (filterBaseSchema?.discriminators != null &&
|
|
68
|
+
filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]) {
|
|
69
|
+
filterBaseSchema = filterBaseSchema.discriminators[filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]] || filterBaseSchema;
|
|
70
|
+
discriminatorValueMap[baseFilterPath] = filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const key of keys) {
|
|
74
|
+
if (updatedPathsByFilter[key] === null) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (utils.hasOwnKeys(updatedPathsByFilter) === false) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const dot = key.indexOf('.');
|
|
81
|
+
|
|
82
|
+
let filterPathRelativeToBase = dot === -1 ? null : key.substring(dot);
|
|
83
|
+
let schematype;
|
|
84
|
+
if (filterPathRelativeToBase == null || filterBaseSchema == null) {
|
|
85
|
+
schematype = baseSchematype;
|
|
86
|
+
} else {
|
|
87
|
+
// If there are multiple array filters in the path being updated, make sure
|
|
88
|
+
// to replace them so we can get the schema path.
|
|
89
|
+
filterPathRelativeToBase = cleanPositionalOperators(filterPathRelativeToBase);
|
|
90
|
+
schematype = getPath(filterBaseSchema, filterPathRelativeToBase, discriminatorValueMap);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (schematype == null) {
|
|
94
|
+
if (!strictQuery) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const filterPath = filterPathRelativeToBase == null ?
|
|
98
|
+
baseFilterPath + '.0' :
|
|
99
|
+
baseFilterPath + '.0' + filterPathRelativeToBase;
|
|
100
|
+
// For now, treat `strictQuery = true` and `strictQuery = 'throw'` as
|
|
101
|
+
// equivalent for casting array filters. `strictQuery = true` doesn't
|
|
102
|
+
// quite work in this context because we never want to silently strip out
|
|
103
|
+
// array filters, even if the path isn't in the schema.
|
|
104
|
+
throw new Error(`Could not find path "${filterPath}" in schema`);
|
|
105
|
+
}
|
|
106
|
+
if (typeof filter[key] === 'object') {
|
|
107
|
+
filter[key] = castFilterPath(query, schematype, filter[key]);
|
|
108
|
+
} else {
|
|
109
|
+
filter[key] = schematype.castForQuery(null, filter[key]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Decorate the update with a version key, if necessary
|
|
5
|
+
* @api private
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
module.exports = function decorateUpdateWithVersionKey(update, options, versionKey) {
|
|
9
|
+
if (!versionKey || !options?.upsert) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (options.overwrite) {
|
|
14
|
+
if (!hasKey(update, versionKey)) {
|
|
15
|
+
update[versionKey] = 0;
|
|
16
|
+
}
|
|
17
|
+
} else if (
|
|
18
|
+
!hasKey(update, versionKey) &&
|
|
19
|
+
!hasKey(update?.$set, versionKey) &&
|
|
20
|
+
!hasKey(update?.$inc, versionKey) &&
|
|
21
|
+
!hasKey(update?.$setOnInsert, versionKey)
|
|
22
|
+
) {
|
|
23
|
+
if (!update.$setOnInsert) {
|
|
24
|
+
update.$setOnInsert = {};
|
|
25
|
+
}
|
|
26
|
+
update.$setOnInsert[versionKey] = 0;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function hasKey(obj, key) {
|
|
31
|
+
if (obj == null || typeof obj !== 'object') {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return Object.hasOwn(obj, key);
|
|
35
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _modifiedPaths = require('../common').modifiedPaths;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Given an update document with potential update operators (`$set`, etc.)
|
|
7
|
+
* returns an object whose keys are the directly modified paths.
|
|
8
|
+
*
|
|
9
|
+
* If there are any top-level keys that don't start with `$`, we assume those
|
|
10
|
+
* will get wrapped in a `$set`. The Mongoose Query is responsible for wrapping
|
|
11
|
+
* top-level keys in `$set`.
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} update
|
|
14
|
+
* @return {Object} modified
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
module.exports = function modifiedPaths(update) {
|
|
18
|
+
const keys = Object.keys(update);
|
|
19
|
+
const res = {};
|
|
20
|
+
|
|
21
|
+
const withoutDollarKeys = {};
|
|
22
|
+
for (const key of keys) {
|
|
23
|
+
if (key.startsWith('$')) {
|
|
24
|
+
_modifiedPaths(update[key], '', res);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
withoutDollarKeys[key] = update[key];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_modifiedPaths(withoutDollarKeys, '', res);
|
|
31
|
+
|
|
32
|
+
return res;
|
|
33
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const get = require('../get');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Given an update, move all $set on immutable properties to $setOnInsert.
|
|
7
|
+
* This should only be called for upserts, because $setOnInsert bypasses the
|
|
8
|
+
* strictness check for immutable properties.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
module.exports = function moveImmutableProperties(schema, update, ctx) {
|
|
12
|
+
if (update == null) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const keys = Object.keys(update);
|
|
17
|
+
for (const key of keys) {
|
|
18
|
+
const isDollarKey = key.startsWith('$');
|
|
19
|
+
|
|
20
|
+
if (key === '$set') {
|
|
21
|
+
const updatedPaths = Object.keys(update[key]);
|
|
22
|
+
for (const path of updatedPaths) {
|
|
23
|
+
_walkUpdatePath(schema, update[key], path, update, ctx);
|
|
24
|
+
}
|
|
25
|
+
} else if (!isDollarKey) {
|
|
26
|
+
_walkUpdatePath(schema, update, key, update, ctx);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function _walkUpdatePath(schema, op, path, update, ctx) {
|
|
33
|
+
const schematype = schema.path(path);
|
|
34
|
+
if (schematype == null) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let immutable = get(schematype, 'options.immutable', null);
|
|
39
|
+
if (immutable == null) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (typeof immutable === 'function') {
|
|
43
|
+
immutable = immutable.call(ctx, ctx);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!immutable) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
update.$setOnInsert = update.$setOnInsert || {};
|
|
51
|
+
update.$setOnInsert[path] = op[path];
|
|
52
|
+
delete op[path];
|
|
53
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MongoDB throws an error if there's unused array filters. That is, if `options.arrayFilters` defines
|
|
5
|
+
* a filter, but none of the `update` keys use it. This should be enough to filter out all unused array
|
|
6
|
+
* filters.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
module.exports = function removeUnusedArrayFilters(update, arrayFilters) {
|
|
10
|
+
const updateKeys = Object.keys(update).
|
|
11
|
+
map(key => Object.keys(update[key])).
|
|
12
|
+
reduce((cur, arr) => cur.concat(arr), []);
|
|
13
|
+
return arrayFilters.filter(obj => {
|
|
14
|
+
return _checkSingleFilterKey(obj, updateKeys);
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function _checkSingleFilterKey(arrayFilter, updateKeys) {
|
|
19
|
+
const firstKey = Object.keys(arrayFilter)[0];
|
|
20
|
+
|
|
21
|
+
if (firstKey === '$and' || firstKey === '$or') {
|
|
22
|
+
if (!Array.isArray(arrayFilter[firstKey])) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return arrayFilter[firstKey].find(filter => _checkSingleFilterKey(filter, updateKeys)) != null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const firstDot = firstKey.indexOf('.');
|
|
29
|
+
const arrayFilterKey = firstDot === -1 ? firstKey : firstKey.slice(0, firstDot);
|
|
30
|
+
|
|
31
|
+
return updateKeys.find(key => key.includes('$[' + arrayFilterKey + ']')) != null;
|
|
32
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const modifiedPaths = require('./modifiedPaths');
|
|
4
|
+
|
|
5
|
+
module.exports = function updatedPathsByArrayFilter(update) {
|
|
6
|
+
if (update == null) {
|
|
7
|
+
return {};
|
|
8
|
+
}
|
|
9
|
+
const updatedPaths = modifiedPaths(update);
|
|
10
|
+
|
|
11
|
+
return Object.keys(updatedPaths).reduce((cur, path) => {
|
|
12
|
+
const matches = path.match(/\$\[[^\]]+\]/g);
|
|
13
|
+
if (matches == null) {
|
|
14
|
+
return cur;
|
|
15
|
+
}
|
|
16
|
+
for (const match of matches) {
|
|
17
|
+
const firstMatch = path.indexOf(match);
|
|
18
|
+
if (firstMatch !== path.lastIndexOf(match)) {
|
|
19
|
+
throw new Error(`Path '${path}' contains the same array filter multiple times`);
|
|
20
|
+
}
|
|
21
|
+
cur[match.substring(2, match.length - 1)] = path.
|
|
22
|
+
substring(0, firstMatch - 1).
|
|
23
|
+
replace(/\$\[[^\]]+\]/g, '0');
|
|
24
|
+
}
|
|
25
|
+
return cur;
|
|
26
|
+
}, {});
|
|
27
|
+
};
|