@nullix/zod-mongoose-studio 1.0.13 → 2.1.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/.output/nitro.json +1 -1
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/8b851c04-1848-472a-b5cd-0727aaaf90f4.json +1 -0
- package/.output/server/chunks/nitro/nitro.mjs +232 -232
- package/.output/server/chunks/routes/api/parse.post.mjs +54 -11
- package/.output/server/chunks/routes/api/parse.post.mjs.map +1 -1
- package/.output/server/node_modules/bson/lib/bson.cjs +157 -48
- package/.output/server/node_modules/bson/package.json +9 -11
- package/.output/server/node_modules/kareem/index.js +228 -343
- package/.output/server/node_modules/kareem/package.json +3 -3
- package/.output/server/node_modules/mongodb/lib/bson.js +27 -5
- package/.output/server/node_modules/mongodb/lib/bulk/common.js +7 -9
- package/.output/server/node_modules/mongodb/lib/change_stream.js +91 -39
- package/.output/server/node_modules/mongodb/lib/client-side-encryption/auto_encrypter.js +21 -14
- package/.output/server/node_modules/mongodb/lib/client-side-encryption/client_encryption.js +2 -5
- package/.output/server/node_modules/mongodb/lib/client-side-encryption/errors.js +3 -1
- package/.output/server/node_modules/mongodb/lib/client-side-encryption/mongocryptd_manager.js +1 -1
- package/.output/server/node_modules/mongodb/lib/client-side-encryption/state_machine.js +1 -0
- package/.output/server/node_modules/mongodb/lib/cmap/auth/aws4.js +161 -0
- package/.output/server/node_modules/mongodb/lib/cmap/auth/aws_temporary_credentials.js +11 -58
- package/.output/server/node_modules/mongodb/lib/cmap/auth/gssapi.js +4 -6
- package/.output/server/node_modules/mongodb/lib/cmap/auth/mongo_credentials.js +2 -16
- package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_aws.js +14 -23
- package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc/azure_machine_workflow.js +3 -3
- package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc/gcp_machine_workflow.js +3 -3
- package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc/k8s_machine_workflow.js +4 -3
- package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc/token_machine_workflow.js +4 -3
- package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc.js +4 -4
- package/.output/server/node_modules/mongodb/lib/cmap/auth/plain.js +1 -1
- package/.output/server/node_modules/mongodb/lib/cmap/auth/providers.js +0 -1
- package/.output/server/node_modules/mongodb/lib/cmap/auth/scram.js +53 -40
- package/.output/server/node_modules/mongodb/lib/cmap/commands.js +46 -39
- package/.output/server/node_modules/mongodb/lib/cmap/connect.js +35 -3
- package/.output/server/node_modules/mongodb/lib/cmap/connection.js +36 -32
- package/.output/server/node_modules/mongodb/lib/cmap/connection_pool.js +67 -67
- package/.output/server/node_modules/mongodb/lib/cmap/connection_pool_events.js +3 -3
- package/.output/server/node_modules/mongodb/lib/cmap/errors.js +1 -1
- package/.output/server/node_modules/mongodb/lib/cmap/handshake/client_metadata.js +15 -13
- package/.output/server/node_modules/mongodb/lib/cmap/metrics.js +3 -3
- package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/compression.js +26 -10
- package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/constants.js +3 -1
- package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/on_data.js +0 -1
- package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/on_demand/document.js +9 -9
- package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/responses.js +2 -2
- package/.output/server/node_modules/mongodb/lib/collection.js +1 -1
- package/.output/server/node_modules/mongodb/lib/connection_string.js +30 -15
- package/.output/server/node_modules/mongodb/lib/cursor/abstract_cursor.js +17 -34
- package/.output/server/node_modules/mongodb/lib/cursor/change_stream_cursor.js +2 -2
- package/.output/server/node_modules/mongodb/lib/cursor/find_cursor.js +37 -26
- package/.output/server/node_modules/mongodb/lib/cursor/run_command_cursor.js +1 -1
- package/.output/server/node_modules/mongodb/lib/db.js +6 -7
- package/.output/server/node_modules/mongodb/lib/deps.js +0 -13
- package/.output/server/node_modules/mongodb/lib/error.js +7 -10
- package/.output/server/node_modules/mongodb/lib/gridfs/download.js +7 -6
- package/.output/server/node_modules/mongodb/lib/gridfs/index.js +9 -9
- package/.output/server/node_modules/mongodb/lib/gridfs/upload.js +17 -23
- package/.output/server/node_modules/mongodb/lib/index.js +2 -4
- package/.output/server/node_modules/mongodb/lib/mongo_client.js +58 -67
- package/.output/server/node_modules/mongodb/lib/mongo_client_auth_providers.js +0 -6
- package/.output/server/node_modules/mongodb/lib/mongo_logger.js +11 -5
- package/.output/server/node_modules/mongodb/lib/mongo_types.js +1 -2
- package/.output/server/node_modules/mongodb/lib/operations/aggregate.js +0 -3
- package/.output/server/node_modules/mongodb/lib/operations/create_collection.js +0 -1
- package/.output/server/node_modules/mongodb/lib/operations/drop.js +8 -9
- package/.output/server/node_modules/mongodb/lib/operations/end_sessions.js +34 -0
- package/.output/server/node_modules/mongodb/lib/operations/execute_operation.js +121 -45
- package/.output/server/node_modules/mongodb/lib/operations/operation.js +1 -0
- package/.output/server/node_modules/mongodb/lib/read_preference.js +10 -14
- package/.output/server/node_modules/mongodb/lib/runtime_adapters.js +32 -0
- package/.output/server/node_modules/mongodb/lib/sdam/monitor.js +8 -8
- package/.output/server/node_modules/mongodb/lib/sdam/server.js +55 -43
- package/.output/server/node_modules/mongodb/lib/sdam/server_description.js +1 -1
- package/.output/server/node_modules/mongodb/lib/sdam/server_selection.js +135 -72
- package/.output/server/node_modules/mongodb/lib/sdam/srv_polling.js +3 -3
- package/.output/server/node_modules/mongodb/lib/sdam/topology.js +37 -77
- package/.output/server/node_modules/mongodb/lib/sdam/topology_description.js +1 -1
- package/.output/server/node_modules/mongodb/lib/sessions.js +150 -40
- package/.output/server/node_modules/mongodb/lib/transactions.js +2 -13
- package/.output/server/node_modules/mongodb/lib/utils.js +42 -90
- package/.output/server/node_modules/mongodb/package.json +49 -45
- package/.output/server/node_modules/mongodb-connection-string-url/lib/index.js +45 -19
- package/.output/server/node_modules/mongodb-connection-string-url/lib/redact.js +30 -19
- package/.output/server/node_modules/mongodb-connection-string-url/package.json +25 -16
- package/.output/server/node_modules/mongoose/lib/aggregate.js +108 -127
- package/.output/server/node_modules/mongoose/lib/cast/bigint.js +3 -3
- package/.output/server/node_modules/mongoose/lib/cast/boolean.js +3 -3
- package/.output/server/node_modules/mongoose/lib/cast/double.js +4 -4
- package/.output/server/node_modules/mongoose/lib/cast/int32.js +2 -2
- package/.output/server/node_modules/mongoose/lib/cast/number.js +6 -6
- package/.output/server/node_modules/mongoose/lib/cast/string.js +3 -3
- package/.output/server/node_modules/mongoose/lib/cast/uuid.js +5 -48
- package/.output/server/node_modules/mongoose/lib/cast.js +16 -24
- package/.output/server/node_modules/mongoose/lib/collection.js +6 -6
- package/.output/server/node_modules/mongoose/lib/connection.js +108 -105
- package/.output/server/node_modules/mongoose/lib/cursor/aggregationCursor.js +23 -33
- package/.output/server/node_modules/mongoose/lib/cursor/changeStream.js +60 -40
- package/.output/server/node_modules/mongoose/lib/cursor/queryCursor.js +21 -25
- package/.output/server/node_modules/mongoose/lib/document.js +712 -531
- package/.output/server/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js +85 -130
- package/.output/server/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js +32 -41
- package/.output/server/node_modules/mongoose/lib/error/cast.js +21 -12
- package/.output/server/node_modules/mongoose/lib/error/createCollectionsError.js +2 -2
- package/.output/server/node_modules/mongoose/lib/error/divergentArray.js +1 -1
- package/.output/server/node_modules/mongoose/lib/error/eachAsyncMultiError.js +1 -1
- package/.output/server/node_modules/mongoose/lib/error/index.js +3 -3
- package/.output/server/node_modules/mongoose/lib/error/invalidSchemaOption.js +1 -1
- package/.output/server/node_modules/mongoose/lib/error/messages.js +1 -0
- package/.output/server/node_modules/mongoose/lib/error/missingSchema.js +1 -1
- package/.output/server/node_modules/mongoose/lib/error/objectParameter.js +4 -5
- package/.output/server/node_modules/mongoose/lib/error/overwriteModel.js +1 -1
- package/.output/server/node_modules/mongoose/lib/error/setOptionError.js +3 -3
- package/.output/server/node_modules/mongoose/lib/error/strict.js +3 -3
- package/.output/server/node_modules/mongoose/lib/error/strictPopulate.js +2 -2
- package/.output/server/node_modules/mongoose/lib/error/syncIndexes.js +2 -2
- package/.output/server/node_modules/mongoose/lib/error/validation.js +2 -10
- package/.output/server/node_modules/mongoose/lib/error/validator.js +1 -1
- package/.output/server/node_modules/mongoose/lib/error/version.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/aggregate/prepareDiscriminatorPipeline.js +4 -4
- package/.output/server/node_modules/mongoose/lib/helpers/buildMiddlewareFilter.js +24 -0
- package/.output/server/node_modules/mongoose/lib/helpers/clone.js +35 -18
- package/.output/server/node_modules/mongoose/lib/helpers/common.js +5 -5
- package/.output/server/node_modules/mongoose/lib/helpers/cursor/eachAsync.js +4 -4
- package/.output/server/node_modules/mongoose/lib/helpers/discriminator/getConstructor.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/discriminator/getDiscriminatorByValue.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/discriminator/mergeDiscriminatorSchema.js +10 -5
- package/.output/server/node_modules/mongoose/lib/helpers/document/applyDefaults.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/document/applyTimestamps.js +11 -10
- package/.output/server/node_modules/mongoose/lib/helpers/document/applyVirtuals.js +10 -9
- package/.output/server/node_modules/mongoose/lib/helpers/document/cleanModifiedSubpaths.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/document/compile.js +17 -14
- package/.output/server/node_modules/mongoose/lib/helpers/document/getDeepestSubdocumentForPath.js +3 -3
- package/.output/server/node_modules/mongoose/lib/helpers/document/getEmbeddedDiscriminatorPath.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/document/isInPathsToSave.js +24 -0
- package/.output/server/node_modules/mongoose/lib/helpers/get.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/indexes/getRelatedIndexes.js +3 -3
- package/.output/server/node_modules/mongoose/lib/helpers/indexes/isIndexEqual.js +3 -4
- package/.output/server/node_modules/mongoose/lib/helpers/indexes/isIndexSpecEqual.js +3 -3
- package/.output/server/node_modules/mongoose/lib/helpers/isBsonType.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/isMongooseObject.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/isObject.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/isSimpleValidator.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/minimize.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/model/applyDefaultsToPOJO.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/model/applyHooks.js +55 -54
- package/.output/server/node_modules/mongoose/lib/helpers/model/applyMethods.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js +1 -48
- package/.output/server/node_modules/mongoose/lib/helpers/model/castBulkWrite.js +8 -12
- package/.output/server/node_modules/mongoose/lib/helpers/model/discriminator.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/parallelLimit.js +18 -36
- package/.output/server/node_modules/mongoose/lib/helpers/pluralize.js +4 -4
- package/.output/server/node_modules/mongoose/lib/helpers/populate/assignRawDocsToIdStructure.js +4 -11
- package/.output/server/node_modules/mongoose/lib/helpers/populate/assignVals.js +10 -10
- package/.output/server/node_modules/mongoose/lib/helpers/populate/createPopulateQueryFilter.js +3 -3
- package/.output/server/node_modules/mongoose/lib/helpers/populate/getModelsMapForPopulate.js +197 -69
- package/.output/server/node_modules/mongoose/lib/helpers/populate/getSchemaTypes.js +15 -15
- package/.output/server/node_modules/mongoose/lib/helpers/populate/markArraySubdocsPopulated.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/populate/modelNamesFromRefPath.js +10 -2
- package/.output/server/node_modules/mongoose/lib/helpers/populate/setPopulatedVirtualValue.js +5 -5
- package/.output/server/node_modules/mongoose/lib/helpers/printJestWarning.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/processConnectionOptions.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/projection/hasIncludedChildren.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/projection/isPathExcluded.js +3 -3
- package/.output/server/node_modules/mongoose/lib/helpers/projection/isSubpath.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/projection/parseProjection.js +9 -4
- package/.output/server/node_modules/mongoose/lib/helpers/query/cast$expr.js +8 -10
- package/.output/server/node_modules/mongoose/lib/helpers/query/castFilterPath.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/query/castUpdate.js +44 -38
- package/.output/server/node_modules/mongoose/lib/helpers/query/getEmbeddedDiscriminatorPath.js +8 -8
- package/.output/server/node_modules/mongoose/lib/helpers/query/handleImmutable.js +8 -8
- package/.output/server/node_modules/mongoose/lib/helpers/schema/applyPlugins.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/schema/applyReadConcern.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/schema/applyWriteConcern.js +4 -2
- package/.output/server/node_modules/mongoose/lib/helpers/schema/getIndexes.js +5 -11
- package/.output/server/node_modules/mongoose/lib/helpers/schema/getSubdocumentStrictValue.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/schema/handleIdOption.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/schema/idGetter.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/schematype/handleImmutable.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/setDefaultsOnInsert.js +26 -13
- package/.output/server/node_modules/mongoose/lib/helpers/timestamps/setDocumentTimestamps.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/timestamps/setupTimestamps.js +60 -38
- package/.output/server/node_modules/mongoose/lib/helpers/update/applyTimestampsToUpdate.js +13 -10
- package/.output/server/node_modules/mongoose/lib/helpers/update/castArrayFilters.js +4 -4
- package/.output/server/node_modules/mongoose/lib/helpers/update/decorateUpdateWithVersionKey.js +1 -1
- package/.output/server/node_modules/mongoose/lib/helpers/update/modifiedPaths.js +2 -2
- package/.output/server/node_modules/mongoose/lib/helpers/update/removeUnusedArrayFilters.js +7 -2
- package/.output/server/node_modules/mongoose/lib/helpers/updateValidators.js +58 -119
- package/.output/server/node_modules/mongoose/lib/model.js +940 -946
- package/.output/server/node_modules/mongoose/lib/mongoose.js +131 -79
- package/.output/server/node_modules/mongoose/lib/options/schemaArrayOptions.js +2 -2
- package/.output/server/node_modules/mongoose/lib/options/schemaBufferOptions.js +1 -1
- package/.output/server/node_modules/mongoose/lib/options/schemaDocumentArrayOptions.js +23 -0
- package/.output/server/node_modules/mongoose/lib/options/schemaNumberOptions.js +3 -3
- package/.output/server/node_modules/mongoose/lib/options/schemaObjectIdOptions.js +2 -2
- package/.output/server/node_modules/mongoose/lib/options/schemaStringOptions.js +6 -6
- package/.output/server/node_modules/mongoose/lib/options/schemaSubdocumentOptions.js +23 -0
- package/.output/server/node_modules/mongoose/lib/options/schemaTypeOptions.js +27 -13
- package/.output/server/node_modules/mongoose/lib/options/virtualOptions.js +12 -12
- package/.output/server/node_modules/mongoose/lib/plugins/index.js +0 -1
- package/.output/server/node_modules/mongoose/lib/plugins/saveSubdocs.js +84 -92
- package/.output/server/node_modules/mongoose/lib/plugins/sharding.js +33 -15
- package/.output/server/node_modules/mongoose/lib/plugins/trackTransaction.js +29 -25
- package/.output/server/node_modules/mongoose/lib/query.js +700 -548
- package/.output/server/node_modules/mongoose/lib/queryHelpers.js +34 -32
- package/.output/server/node_modules/mongoose/lib/schema/array.js +69 -113
- package/.output/server/node_modules/mongoose/lib/schema/bigint.js +18 -20
- package/.output/server/node_modules/mongoose/lib/schema/boolean.js +20 -22
- package/.output/server/node_modules/mongoose/lib/schema/buffer.js +23 -25
- package/.output/server/node_modules/mongoose/lib/schema/date.js +19 -21
- package/.output/server/node_modules/mongoose/lib/schema/decimal128.js +16 -18
- package/.output/server/node_modules/mongoose/lib/schema/documentArray.js +94 -131
- package/.output/server/node_modules/mongoose/lib/schema/documentArrayElement.js +50 -16
- package/.output/server/node_modules/mongoose/lib/schema/double.js +16 -18
- package/.output/server/node_modules/mongoose/lib/schema/index.js +1 -0
- package/.output/server/node_modules/mongoose/lib/schema/int32.js +17 -19
- package/.output/server/node_modules/mongoose/lib/schema/map.js +17 -24
- package/.output/server/node_modules/mongoose/lib/schema/mixed.js +14 -14
- package/.output/server/node_modules/mongoose/lib/schema/number.js +38 -28
- package/.output/server/node_modules/mongoose/lib/schema/objectId.js +18 -20
- package/.output/server/node_modules/mongoose/lib/schema/operators/exists.js +1 -1
- package/.output/server/node_modules/mongoose/lib/schema/operators/geospatial.js +1 -1
- package/.output/server/node_modules/mongoose/lib/schema/operators/text.js +4 -4
- package/.output/server/node_modules/mongoose/lib/schema/string.js +42 -27
- package/.output/server/node_modules/mongoose/lib/schema/subdocument.js +47 -58
- package/.output/server/node_modules/mongoose/lib/schema/union.js +54 -4
- package/.output/server/node_modules/mongoose/lib/schema/uuid.js +17 -40
- package/.output/server/node_modules/mongoose/lib/schema.js +235 -176
- package/.output/server/node_modules/mongoose/lib/schemaType.js +227 -158
- package/.output/server/node_modules/mongoose/lib/stateMachine.js +5 -8
- package/.output/server/node_modules/mongoose/lib/types/array/index.js +5 -5
- package/.output/server/node_modules/mongoose/lib/types/array/methods/index.js +27 -28
- package/.output/server/node_modules/mongoose/lib/types/arraySubdocument.js +11 -11
- package/.output/server/node_modules/mongoose/lib/types/buffer.js +15 -15
- package/.output/server/node_modules/mongoose/lib/types/decimal128.js +1 -1
- package/.output/server/node_modules/mongoose/lib/types/documentArray/index.js +4 -4
- package/.output/server/node_modules/mongoose/lib/types/documentArray/methods/index.js +15 -13
- package/.output/server/node_modules/mongoose/lib/types/double.js +1 -1
- package/.output/server/node_modules/mongoose/lib/types/map.js +20 -71
- package/.output/server/node_modules/mongoose/lib/types/objectid.js +1 -1
- package/.output/server/node_modules/mongoose/lib/types/subdocument.js +32 -81
- package/.output/server/node_modules/mongoose/lib/types/uuid.js +1 -1
- package/.output/server/node_modules/mongoose/lib/utils.js +91 -70
- package/.output/server/node_modules/mongoose/lib/validOptions.js +4 -3
- package/.output/server/node_modules/mongoose/lib/virtualType.js +18 -18
- package/.output/server/node_modules/mongoose/package.json +46 -63
- package/.output/server/node_modules/mquery/lib/collection/collection.js +3 -1
- package/.output/server/node_modules/mquery/lib/collection/node.js +17 -3
- package/.output/server/node_modules/mquery/lib/mquery.js +136 -93
- package/.output/server/node_modules/mquery/lib/permissions.js +21 -6
- package/.output/server/node_modules/mquery/package.json +4 -7
- package/.output/server/package.json +7 -9
- package/package.json +3 -3
- package/.output/public/_nuxt/builds/meta/0d6006db-fbb0-4297-85cf-bf92ceafcb79.json +0 -1
- package/.output/server/node_modules/debug/package.json +0 -64
- package/.output/server/node_modules/debug/src/browser.js +0 -272
- package/.output/server/node_modules/debug/src/common.js +0 -292
- package/.output/server/node_modules/debug/src/index.js +0 -10
- package/.output/server/node_modules/debug/src/node.js +0 -263
- package/.output/server/node_modules/mongodb/lib/client-side-encryption/crypto_callbacks.js +0 -81
- package/.output/server/node_modules/mongodb/lib/resource_management.js +0 -58
- package/.output/server/node_modules/mongoose/lib/browserDocument.js +0 -101
- package/.output/server/node_modules/mongoose/lib/documentProvider.js +0 -30
- package/.output/server/node_modules/mongoose/lib/helpers/createJSONSchemaTypeDefinition.js +0 -24
- package/.output/server/node_modules/mongoose/lib/helpers/promiseOrCallback.js +0 -54
- package/.output/server/node_modules/mongoose/lib/plugins/validateBeforeSave.js +0 -51
- package/.output/server/node_modules/supports-color/index.js +0 -202
- package/.output/server/node_modules/supports-color/package.json +0 -64
|
@@ -22,6 +22,7 @@ const $__hasIncludedChildren = require('./helpers/projection/hasIncludedChildren
|
|
|
22
22
|
const applyDefaults = require('./helpers/document/applyDefaults');
|
|
23
23
|
const cleanModifiedSubpaths = require('./helpers/document/cleanModifiedSubpaths');
|
|
24
24
|
const clone = require('./helpers/clone');
|
|
25
|
+
const isInPathsToSave = require('./helpers/document/isInPathsToSave');
|
|
25
26
|
const compile = require('./helpers/document/compile').compile;
|
|
26
27
|
const defineKey = require('./helpers/document/compile').defineKey;
|
|
27
28
|
const firstKey = require('./helpers/firstKey');
|
|
@@ -30,7 +31,6 @@ const getEmbeddedDiscriminatorPath = require('./helpers/document/getEmbeddedDisc
|
|
|
30
31
|
const getKeysInSchemaOrder = require('./helpers/schema/getKeysInSchemaOrder');
|
|
31
32
|
const getSubdocumentStrictValue = require('./helpers/schema/getSubdocumentStrictValue');
|
|
32
33
|
const handleSpreadDoc = require('./helpers/document/handleSpreadDoc');
|
|
33
|
-
const immediate = require('./helpers/immediate');
|
|
34
34
|
const isBsonType = require('./helpers/isBsonType');
|
|
35
35
|
const isDefiningProjection = require('./helpers/projection/isDefiningProjection');
|
|
36
36
|
const isExclusive = require('./helpers/projection/isExclusive');
|
|
@@ -42,6 +42,7 @@ const minimize = require('./helpers/minimize');
|
|
|
42
42
|
const mpath = require('mpath');
|
|
43
43
|
const parentPaths = require('./helpers/path/parentPaths');
|
|
44
44
|
const queryhelpers = require('./queryHelpers');
|
|
45
|
+
const { buildMiddlewareFilter } = require('./helpers/buildMiddlewareFilter');
|
|
45
46
|
const utils = require('./utils');
|
|
46
47
|
const isPromise = require('./helpers/isPromise');
|
|
47
48
|
|
|
@@ -63,7 +64,6 @@ const getDeepestSubdocumentForPath = require('./helpers/document/getDeepestSubdo
|
|
|
63
64
|
const sessionNewDocuments = require('./helpers/symbols').sessionNewDocuments;
|
|
64
65
|
|
|
65
66
|
let DocumentArray;
|
|
66
|
-
let MongooseArray;
|
|
67
67
|
let Embedded;
|
|
68
68
|
|
|
69
69
|
const specialProperties = utils.specialProperties;
|
|
@@ -76,36 +76,37 @@ const VERSION_ALL = VERSION_WHERE | VERSION_INC;
|
|
|
76
76
|
* The core Mongoose document constructor. You should not call this directly,
|
|
77
77
|
* the Mongoose [Model constructor](./api/model.html#Model) calls this for you.
|
|
78
78
|
*
|
|
79
|
-
* @param {
|
|
80
|
-
* @param {
|
|
81
|
-
* @param {
|
|
82
|
-
* @param {
|
|
79
|
+
* @param {object} obj the values to set
|
|
80
|
+
* @param {object} [fields] optional object containing the fields which were selected in the query returning this document and any populated paths data
|
|
81
|
+
* @param {object} [options] various configuration options for the document
|
|
82
|
+
* @param {boolean} [options.defaults=true] if `false`, skip applying default values to this document.
|
|
83
|
+
* @param {boolean} [options.skipId=false] By default, Mongoose document if one is not provided and the document's schema does not override Mongoose's default `_id`. Set `skipId` to `true` to skip this generation step.
|
|
83
84
|
* @inherits NodeJS EventEmitter https://nodejs.org/api/events.html#class-eventemitter
|
|
84
85
|
* @event `init`: Emitted on a document after it has been retrieved from the db and fully hydrated by Mongoose.
|
|
85
86
|
* @event `save`: Emitted when the document is successfully saved
|
|
86
87
|
* @api private
|
|
87
88
|
*/
|
|
88
89
|
|
|
89
|
-
function Document(obj, fields,
|
|
90
|
-
if (typeof
|
|
91
|
-
options
|
|
92
|
-
skipId = options.skipId;
|
|
90
|
+
function Document(obj, fields, options) {
|
|
91
|
+
if (typeof options === 'boolean') {
|
|
92
|
+
throw new Error('The skipId parameter has been removed. Use { skipId: true } in the options parameter instead.');
|
|
93
93
|
}
|
|
94
94
|
options = Object.assign({}, options);
|
|
95
|
+
let skipId = options.skipId;
|
|
96
|
+
|
|
97
|
+
this.$__ = new InternalCache();
|
|
95
98
|
|
|
96
99
|
// Support `browserDocument.js` syntax
|
|
97
100
|
if (this.$__schema == null) {
|
|
98
101
|
const _schema = utils.isObject(fields) && !fields.instanceOfSchema ?
|
|
99
102
|
new Schema(fields) :
|
|
100
103
|
fields;
|
|
104
|
+
|
|
101
105
|
this.$__setSchema(_schema);
|
|
102
|
-
fields =
|
|
103
|
-
skipId = options;
|
|
104
|
-
options = arguments[4] || {};
|
|
106
|
+
fields = options;
|
|
107
|
+
skipId = options.skipId;
|
|
105
108
|
}
|
|
106
109
|
|
|
107
|
-
this.$__ = new InternalCache();
|
|
108
|
-
|
|
109
110
|
// Avoid setting `isNew` to `true`, because it is `true` by default
|
|
110
111
|
if (options.isNew != null && options.isNew !== true) {
|
|
111
112
|
this.$isNew = options.isNew;
|
|
@@ -151,7 +152,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
151
152
|
|
|
152
153
|
// determine if this doc is a result of a query with
|
|
153
154
|
// excluded fields
|
|
154
|
-
if (utils.isPOJO(fields) &&
|
|
155
|
+
if (utils.isPOJO(fields) && utils.hasOwnKeys(fields)) {
|
|
155
156
|
exclude = isExclusive(fields);
|
|
156
157
|
this.$__.selected = fields;
|
|
157
158
|
this.$__.exclude = exclude;
|
|
@@ -547,11 +548,11 @@ function $applyDefaultsToNested(val, path, doc) {
|
|
|
547
548
|
/**
|
|
548
549
|
* Builds the default doc structure
|
|
549
550
|
*
|
|
550
|
-
* @param {
|
|
551
|
-
* @param {
|
|
552
|
-
* @param {
|
|
553
|
-
* @param {
|
|
554
|
-
* @param {
|
|
551
|
+
* @param {object} obj
|
|
552
|
+
* @param {object} [fields]
|
|
553
|
+
* @param {boolean} [skipId]
|
|
554
|
+
* @param {boolean} [exclude]
|
|
555
|
+
* @param {object} [hasIncludedChildren]
|
|
555
556
|
* @api private
|
|
556
557
|
* @method $__buildDoc
|
|
557
558
|
* @memberOf Document
|
|
@@ -635,9 +636,9 @@ Document.prototype.toBSON = function() {
|
|
|
635
636
|
* This function triggers `init` [middleware](https://mongoosejs.com/docs/middleware.html).
|
|
636
637
|
* Note that `init` hooks are [synchronous](https://mongoosejs.com/docs/middleware.html#synchronous).
|
|
637
638
|
*
|
|
638
|
-
* @param {
|
|
639
|
-
* @param {
|
|
640
|
-
* @param {
|
|
639
|
+
* @param {object} doc raw document returned by mongo
|
|
640
|
+
* @param {object} [opts]
|
|
641
|
+
* @param {boolean} [opts.hydratedPopulatedDocs=false] If true, hydrate and mark as populated any paths that are populated in the raw document
|
|
641
642
|
* @param {Function} [fn]
|
|
642
643
|
* @api public
|
|
643
644
|
* @memberOf Document
|
|
@@ -677,12 +678,15 @@ Document.prototype.$init = function() {
|
|
|
677
678
|
* Internal "init" function
|
|
678
679
|
*
|
|
679
680
|
* @param {Document} doc
|
|
680
|
-
* @param {
|
|
681
|
+
* @param {object} [opts]
|
|
681
682
|
* @returns {Document} this
|
|
682
683
|
* @api private
|
|
683
684
|
*/
|
|
684
685
|
|
|
685
686
|
Document.prototype.$__init = function(doc, opts) {
|
|
687
|
+
if (doc == null) {
|
|
688
|
+
throw new ObjectParameterError(doc, 'doc', 'init');
|
|
689
|
+
}
|
|
686
690
|
this.$isNew = false;
|
|
687
691
|
opts = opts || {};
|
|
688
692
|
|
|
@@ -701,7 +705,7 @@ Document.prototype.$__init = function(doc, opts) {
|
|
|
701
705
|
continue;
|
|
702
706
|
}
|
|
703
707
|
for (const child of item._childDocs) {
|
|
704
|
-
if (child
|
|
708
|
+
if (child?.$__ == null) {
|
|
705
709
|
continue;
|
|
706
710
|
}
|
|
707
711
|
child.$__.parent = this;
|
|
@@ -727,18 +731,22 @@ Document.prototype.$__init = function(doc, opts) {
|
|
|
727
731
|
/**
|
|
728
732
|
* Init helper.
|
|
729
733
|
*
|
|
730
|
-
* @param {
|
|
731
|
-
* @param {
|
|
732
|
-
* @param {
|
|
733
|
-
* @param {
|
|
734
|
-
* @param {
|
|
735
|
-
* @param {
|
|
734
|
+
* @param {object} self document instance
|
|
735
|
+
* @param {object} obj raw mongodb doc
|
|
736
|
+
* @param {object} doc object we are initializing
|
|
737
|
+
* @param {object} [opts] Optional Options
|
|
738
|
+
* @param {boolean} [opts.setters] Call `applySetters` instead of `cast`
|
|
739
|
+
* @param {string} [prefix] Prefix to add to each path
|
|
736
740
|
* @api private
|
|
737
741
|
*/
|
|
738
742
|
|
|
739
743
|
function init(self, obj, doc, opts, prefix) {
|
|
740
744
|
prefix = prefix || '';
|
|
741
745
|
|
|
746
|
+
if (typeof obj !== 'object' || Array.isArray(obj)) {
|
|
747
|
+
throw new ObjectExpectedError(self.$basePath, obj);
|
|
748
|
+
}
|
|
749
|
+
|
|
742
750
|
if (obj.$__ != null) {
|
|
743
751
|
obj = obj._doc;
|
|
744
752
|
}
|
|
@@ -802,7 +810,7 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
802
810
|
|
|
803
811
|
if (schemaType && !wasPopulated && !opts.hydratedPopulatedDocs) {
|
|
804
812
|
try {
|
|
805
|
-
if (opts
|
|
813
|
+
if (opts?.setters) {
|
|
806
814
|
// Call applySetters with `init = false` because otherwise setters are a noop
|
|
807
815
|
const overrideInit = false;
|
|
808
816
|
doc[i] = schemaType.applySetters(value, self, overrideInit, null, opts);
|
|
@@ -821,7 +829,7 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
821
829
|
} else if (schemaType && opts.hydratedPopulatedDocs) {
|
|
822
830
|
doc[i] = schemaType.cast(value, self, true, undefined, { hydratedPopulatedDocs: true });
|
|
823
831
|
|
|
824
|
-
if (doc[i]
|
|
832
|
+
if (doc[i]?.$__?.wasPopulated) {
|
|
825
833
|
self.$populated(path, doc[i].$__.wasPopulated.value, doc[i].$__.wasPopulated.options);
|
|
826
834
|
} else if (Array.isArray(doc[i]) && doc[i].length && doc[i][0]?.$__?.wasPopulated) {
|
|
827
835
|
self.$populated(path, doc[i].map(populatedDoc => populatedDoc?.$__?.wasPopulated?.value).filter(val => val != null), doc[i][0].$__.wasPopulated.options);
|
|
@@ -850,39 +858,47 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
850
858
|
* - same as in [Model.updateOne](https://mongoosejs.com/docs/api/model.html#Model.updateOne)
|
|
851
859
|
*
|
|
852
860
|
* @see Model.updateOne https://mongoosejs.com/docs/api/model.html#Model.updateOne
|
|
853
|
-
* @param {
|
|
854
|
-
* @param {
|
|
855
|
-
* @param {
|
|
856
|
-
* @param {
|
|
857
|
-
* @param {
|
|
861
|
+
* @param {object} update
|
|
862
|
+
* @param {object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
863
|
+
* @param {object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.lean()) and the [Mongoose lean tutorial](https://mongoosejs.com/docs/tutorials/lean.html).
|
|
864
|
+
* @param {boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
865
|
+
* @param {boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
|
|
866
|
+
* @param {boolean|object} [options.middleware=true] set to `false` to skip all user-defined middleware
|
|
867
|
+
* @param {boolean} [options.middleware.pre=true] set to `false` to skip only pre hooks
|
|
868
|
+
* @param {boolean} [options.middleware.post=true] set to `false` to skip only post hooks
|
|
858
869
|
* @return {Query}
|
|
859
870
|
* @api public
|
|
860
871
|
* @memberOf Document
|
|
861
872
|
* @instance
|
|
862
873
|
*/
|
|
863
874
|
|
|
864
|
-
Document.prototype.updateOne = function updateOne(update, options
|
|
875
|
+
Document.prototype.updateOne = function updateOne(update, options) {
|
|
865
876
|
const query = this.constructor.updateOne();
|
|
866
877
|
const self = this;
|
|
867
|
-
query.pre(function queryPreUpdateOne(
|
|
868
|
-
self.
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
878
|
+
query.pre(async function queryPreUpdateOne() {
|
|
879
|
+
const res = await self._execDocumentPreHooks('updateOne', options, [self, update, options]);
|
|
880
|
+
// `self` is passed to pre hooks as argument for backwards compatibility, but that
|
|
881
|
+
// isn't the actual arguments passed to the wrapped function.
|
|
882
|
+
if (res[0] !== self || res[1] !== update || res[2] !== options) {
|
|
883
|
+
throw new Error('Document updateOne pre hooks cannot overwrite arguments');
|
|
884
|
+
}
|
|
885
|
+
query.updateOne({ _id: self._doc._id }, update, options);
|
|
886
|
+
// Apply custom where conditions _after_ document updateOne middleware for
|
|
887
|
+
// consistency with save() - sharding plugin needs to set $where
|
|
888
|
+
if (self.$where != null) {
|
|
889
|
+
this.where(self.$where);
|
|
890
|
+
}
|
|
891
|
+
if (self.$session() != null) {
|
|
892
|
+
if (!('session' in query.options)) {
|
|
893
|
+
query.options.session = self.$session();
|
|
874
894
|
}
|
|
875
|
-
|
|
876
|
-
|
|
895
|
+
}
|
|
896
|
+
return res;
|
|
877
897
|
});
|
|
878
|
-
query.post(function queryPostUpdateOne(
|
|
879
|
-
self.
|
|
898
|
+
query.post(function queryPostUpdateOne() {
|
|
899
|
+
return self._execDocumentPostHooks('updateOne', options);
|
|
880
900
|
});
|
|
881
901
|
|
|
882
|
-
if (callback != null) {
|
|
883
|
-
return query.exec(callback);
|
|
884
|
-
}
|
|
885
|
-
|
|
886
902
|
return query;
|
|
887
903
|
};
|
|
888
904
|
|
|
@@ -894,8 +910,8 @@ Document.prototype.updateOne = function updateOne(update, options, callback) {
|
|
|
894
910
|
* - same as in [Model.replaceOne](https://mongoosejs.com/docs/api/model.html#Model.replaceOne())
|
|
895
911
|
*
|
|
896
912
|
* @see Model.replaceOne https://mongoosejs.com/docs/api/model.html#Model.replaceOne()
|
|
897
|
-
* @param {
|
|
898
|
-
* @param {
|
|
913
|
+
* @param {object} doc
|
|
914
|
+
* @param {object} [options]
|
|
899
915
|
* @param {Function} [callback]
|
|
900
916
|
* @return {Query}
|
|
901
917
|
* @api public
|
|
@@ -934,14 +950,14 @@ Document.prototype.replaceOne = function replaceOne() {
|
|
|
934
950
|
|
|
935
951
|
Document.prototype.$session = function $session(session) {
|
|
936
952
|
if (arguments.length === 0) {
|
|
937
|
-
if (this.$__.session
|
|
953
|
+
if (this.$__.session?.hasEnded) {
|
|
938
954
|
this.$__.session = null;
|
|
939
955
|
return null;
|
|
940
956
|
}
|
|
941
957
|
return this.$__.session;
|
|
942
958
|
}
|
|
943
959
|
|
|
944
|
-
if (session
|
|
960
|
+
if (session?.hasEnded) {
|
|
945
961
|
throw new MongooseError('Cannot set a document\'s session to a session that has ended. Make sure you haven\'t ' +
|
|
946
962
|
'called `endSession()` on the session you are passing to `$session()`.');
|
|
947
963
|
}
|
|
@@ -976,7 +992,7 @@ Document.prototype.$session = function $session(session) {
|
|
|
976
992
|
* doc.$timestamps(false);
|
|
977
993
|
* await doc.save(); // Does **not** apply timestamps
|
|
978
994
|
*
|
|
979
|
-
* @param {
|
|
995
|
+
* @param {boolean} [value] overwrite the current session
|
|
980
996
|
* @return {Document|boolean|undefined} When used as a getter (no argument), a boolean will be returned indicating the timestamps option state or if unset "undefined" will be used, otherwise will return "this"
|
|
981
997
|
* @method $timestamps
|
|
982
998
|
* @api public
|
|
@@ -1009,7 +1025,7 @@ Document.prototype.$timestamps = function $timestamps(value) {
|
|
|
1009
1025
|
* for immutable properties. Behaves similarly to `set()`, except for it
|
|
1010
1026
|
* unsets all properties that aren't in `obj`.
|
|
1011
1027
|
*
|
|
1012
|
-
* @param {
|
|
1028
|
+
* @param {object} obj the object to overwrite this document with
|
|
1013
1029
|
* @method overwrite
|
|
1014
1030
|
* @memberOf Document
|
|
1015
1031
|
* @instance
|
|
@@ -1018,17 +1034,21 @@ Document.prototype.$timestamps = function $timestamps(value) {
|
|
|
1018
1034
|
*/
|
|
1019
1035
|
|
|
1020
1036
|
Document.prototype.overwrite = function overwrite(obj) {
|
|
1021
|
-
const keys =
|
|
1037
|
+
const keys = new Set(Object.keys(this._doc));
|
|
1038
|
+
for (const key of Object.keys(obj)) {
|
|
1039
|
+
keys.add(key);
|
|
1040
|
+
}
|
|
1022
1041
|
|
|
1042
|
+
const schemaOptions = this.$__schema.options;
|
|
1023
1043
|
for (const key of keys) {
|
|
1024
1044
|
if (key === '_id') {
|
|
1025
1045
|
continue;
|
|
1026
1046
|
}
|
|
1027
1047
|
// Explicitly skip version key
|
|
1028
|
-
if (
|
|
1048
|
+
if (schemaOptions.versionKey && key === schemaOptions.versionKey) {
|
|
1029
1049
|
continue;
|
|
1030
1050
|
}
|
|
1031
|
-
if (
|
|
1051
|
+
if (schemaOptions.discriminatorKey && key === schemaOptions.discriminatorKey) {
|
|
1032
1052
|
continue;
|
|
1033
1053
|
}
|
|
1034
1054
|
this.$set(key, obj[key]);
|
|
@@ -1040,11 +1060,11 @@ Document.prototype.overwrite = function overwrite(obj) {
|
|
|
1040
1060
|
/**
|
|
1041
1061
|
* Alias for `set()`, used internally to avoid conflicts
|
|
1042
1062
|
*
|
|
1043
|
-
* @param {
|
|
1044
|
-
* @param {
|
|
1045
|
-
* @param {Schema|
|
|
1046
|
-
* @param {
|
|
1047
|
-
* @param {
|
|
1063
|
+
* @param {string|object} path path or object of key/vals to set
|
|
1064
|
+
* @param {any} val the value to set
|
|
1065
|
+
* @param {Schema|string|number|Buffer|any} [type] optionally specify a type for "on-the-fly" attributes
|
|
1066
|
+
* @param {object} [options] optionally specify options that modify the behavior of the set
|
|
1067
|
+
* @param {boolean} [options.merge=false] if true, setting a [nested path](https://mongoosejs.com/docs/subdocs.html#subdocuments-versus-nested-paths) will merge existing values rather than overwrite the whole object. So `doc.set('nested', { a: 1, b: 2 })` becomes `doc.set('nested.a', 1); doc.set('nested.b', 2);`
|
|
1048
1068
|
* @return {Document} this
|
|
1049
1069
|
* @method $set
|
|
1050
1070
|
* @memberOf Document
|
|
@@ -1058,7 +1078,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1058
1078
|
type = undefined;
|
|
1059
1079
|
}
|
|
1060
1080
|
|
|
1061
|
-
const merge = options
|
|
1081
|
+
const merge = options?.merge;
|
|
1062
1082
|
const adhoc = type && type !== true;
|
|
1063
1083
|
const constructing = type === true;
|
|
1064
1084
|
let adhocs;
|
|
@@ -1104,7 +1124,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1104
1124
|
|
|
1105
1125
|
// `_skipMinimizeTopLevel` is because we may have deleted the top-level
|
|
1106
1126
|
// nested key to ensure key order.
|
|
1107
|
-
const _skipMinimizeTopLevel = options
|
|
1127
|
+
const _skipMinimizeTopLevel = options?._skipMinimizeTopLevel || false;
|
|
1108
1128
|
if (len === 0 && _skipMinimizeTopLevel) {
|
|
1109
1129
|
delete options._skipMinimizeTopLevel;
|
|
1110
1130
|
if (val) {
|
|
@@ -1408,17 +1428,31 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1408
1428
|
}
|
|
1409
1429
|
|
|
1410
1430
|
// Check refPath
|
|
1411
|
-
|
|
1431
|
+
let refPath = schema.options.refPath;
|
|
1412
1432
|
if (refPath == null) {
|
|
1413
1433
|
return false;
|
|
1414
1434
|
}
|
|
1415
|
-
|
|
1435
|
+
|
|
1436
|
+
if (typeof refPath === 'function' && !refPath[modelSymbol]) {
|
|
1437
|
+
let fullPath = path;
|
|
1438
|
+
const fullPathWithIndexes = this.$__fullPathWithIndexes?.();
|
|
1439
|
+
if (fullPathWithIndexes?.length) {
|
|
1440
|
+
fullPath = fullPathWithIndexes + '.' + path;
|
|
1441
|
+
}
|
|
1442
|
+
refPath = refPath.call(this, this, fullPath);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
if (typeof refPath !== 'string') {
|
|
1446
|
+
throw new MongooseError('`refPath` must be a string or a function that returns a string, got ' + inspect(refPath));
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
const modelName = this.ownerDocument().get(refPath);
|
|
1416
1450
|
return modelName === model.modelName || modelName === model.baseModelName;
|
|
1417
1451
|
})();
|
|
1418
1452
|
|
|
1419
1453
|
let didPopulate = false;
|
|
1420
1454
|
if (refMatches && val instanceof Document && (!val.$__.wasPopulated || utils.deepEqual(val.$__.wasPopulated.value, val._doc._id))) {
|
|
1421
|
-
const unpopulatedValue =
|
|
1455
|
+
const unpopulatedValue = schema?.$isSingleNested ? schema.cast(val, this) : val._doc._id;
|
|
1422
1456
|
this.$populated(path, unpopulatedValue, { [populateModelSymbol]: val.constructor });
|
|
1423
1457
|
val.$__.wasPopulated = { value: unpopulatedValue };
|
|
1424
1458
|
didPopulate = true;
|
|
@@ -1450,7 +1484,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1450
1484
|
if (this.$__schema.singleNestedPaths[path] != null && parts.length > 1) {
|
|
1451
1485
|
setterContext = getDeepestSubdocumentForPath(this, parts, this.schema);
|
|
1452
1486
|
}
|
|
1453
|
-
if (options
|
|
1487
|
+
if (options?.overwriteImmutable) {
|
|
1454
1488
|
val = schema.applySetters(val, setterContext, false, priorVal, { path, overwriteImmutable: true });
|
|
1455
1489
|
} else {
|
|
1456
1490
|
val = schema.applySetters(val, setterContext, false, priorVal, { path });
|
|
@@ -1461,9 +1495,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1461
1495
|
!Array.isArray(schema) &&
|
|
1462
1496
|
schema.$isMongooseDocumentArray &&
|
|
1463
1497
|
val.length !== 0 &&
|
|
1464
|
-
val[0] != null
|
|
1465
|
-
val[0].$__ != null &&
|
|
1466
|
-
val[0].$__.populated != null) {
|
|
1498
|
+
val[0]?.$__?.populated != null) {
|
|
1467
1499
|
const populatedPaths = Object.keys(val[0].$__.populated);
|
|
1468
1500
|
for (const populatedPath of populatedPaths) {
|
|
1469
1501
|
this.$populated(path + '.' + populatedPath,
|
|
@@ -1596,10 +1628,10 @@ function _isManuallyPopulatedArray(val, ref) {
|
|
|
1596
1628
|
* // changing strict mode behavior
|
|
1597
1629
|
* doc.set(path, value, { strict: false });
|
|
1598
1630
|
*
|
|
1599
|
-
* @param {
|
|
1600
|
-
* @param {
|
|
1601
|
-
* @param {Schema|
|
|
1602
|
-
* @param {
|
|
1631
|
+
* @param {string|object} path path or object of key/vals to set
|
|
1632
|
+
* @param {any} val the value to set
|
|
1633
|
+
* @param {Schema|string|number|Buffer|any} [type] optionally specify a type for "on-the-fly" attributes
|
|
1634
|
+
* @param {object} [options] optionally specify options that modify the behavior of the set
|
|
1603
1635
|
* @return {Document} this
|
|
1604
1636
|
* @api public
|
|
1605
1637
|
* @method set
|
|
@@ -1613,14 +1645,14 @@ Document.prototype.set = Document.prototype.$set;
|
|
|
1613
1645
|
* Determine if we should mark this change as modified.
|
|
1614
1646
|
*
|
|
1615
1647
|
* @param {never} pathToMark UNUSED
|
|
1616
|
-
* @param {
|
|
1617
|
-
* @param {
|
|
1618
|
-
* @param {
|
|
1648
|
+
* @param {string|symbol} path
|
|
1649
|
+
* @param {object} options
|
|
1650
|
+
* @param {any} constructing
|
|
1619
1651
|
* @param {never} parts UNUSED
|
|
1620
1652
|
* @param {Schema} schema
|
|
1621
|
-
* @param {
|
|
1622
|
-
* @param {
|
|
1623
|
-
* @return {
|
|
1653
|
+
* @param {any} val
|
|
1654
|
+
* @param {any} priorVal
|
|
1655
|
+
* @return {boolean}
|
|
1624
1656
|
* @api private
|
|
1625
1657
|
* @method $__shouldModify
|
|
1626
1658
|
* @memberOf Document
|
|
@@ -1628,7 +1660,7 @@ Document.prototype.set = Document.prototype.$set;
|
|
|
1628
1660
|
*/
|
|
1629
1661
|
|
|
1630
1662
|
Document.prototype.$__shouldModify = function(pathToMark, path, options, constructing, parts, schema, val, priorVal) {
|
|
1631
|
-
if (options
|
|
1663
|
+
if (options?._skipMarkModified) {
|
|
1632
1664
|
return false;
|
|
1633
1665
|
}
|
|
1634
1666
|
if (this.$isNew) {
|
|
@@ -1677,14 +1709,14 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru
|
|
|
1677
1709
|
/**
|
|
1678
1710
|
* Handles the actual setting of the value and marking the path modified if appropriate.
|
|
1679
1711
|
*
|
|
1680
|
-
* @param {
|
|
1681
|
-
* @param {
|
|
1682
|
-
* @param {
|
|
1683
|
-
* @param {
|
|
1712
|
+
* @param {string} pathToMark
|
|
1713
|
+
* @param {string|symbol} path
|
|
1714
|
+
* @param {object} options
|
|
1715
|
+
* @param {any} constructing
|
|
1684
1716
|
* @param {Array} parts
|
|
1685
1717
|
* @param {Schema} schema
|
|
1686
|
-
* @param {
|
|
1687
|
-
* @param {
|
|
1718
|
+
* @param {any} val
|
|
1719
|
+
* @param {any} priorVal
|
|
1688
1720
|
* @api private
|
|
1689
1721
|
* @method $__set
|
|
1690
1722
|
* @memberOf Document
|
|
@@ -1694,20 +1726,20 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru
|
|
|
1694
1726
|
Document.prototype.$__set = function(pathToMark, path, options, constructing, parts, schema, val, priorVal) {
|
|
1695
1727
|
Embedded = Embedded || require('./types/arraySubdocument');
|
|
1696
1728
|
|
|
1697
|
-
const shouldModify = this.$
|
|
1698
|
-
|
|
1729
|
+
const shouldModify = this.$isNew && !options?._skipMarkModified ?
|
|
1730
|
+
true :
|
|
1731
|
+
this.$__shouldModify(pathToMark, path, options, constructing, parts, schema, val, priorVal);
|
|
1699
1732
|
|
|
1700
1733
|
if (shouldModify) {
|
|
1701
|
-
if (this.$__.primitiveAtomics
|
|
1734
|
+
if (this.$__.primitiveAtomics?.[path]) {
|
|
1702
1735
|
delete this.$__.primitiveAtomics[path];
|
|
1703
|
-
if (
|
|
1736
|
+
if (utils.hasOwnKeys(this.$__.primitiveAtomics) === false) {
|
|
1704
1737
|
delete this.$__.primitiveAtomics;
|
|
1705
1738
|
}
|
|
1706
1739
|
}
|
|
1707
1740
|
this.markModified(pathToMark);
|
|
1708
1741
|
|
|
1709
1742
|
// handle directly setting arrays (gh-1126)
|
|
1710
|
-
MongooseArray || (MongooseArray = require('./types/array'));
|
|
1711
1743
|
if (val && utils.isMongooseArray(val)) {
|
|
1712
1744
|
val._registerAtomic('$set', val);
|
|
1713
1745
|
|
|
@@ -1788,8 +1820,8 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
|
|
|
1788
1820
|
/**
|
|
1789
1821
|
* Gets a raw value from a path (no getters)
|
|
1790
1822
|
*
|
|
1791
|
-
* @param {
|
|
1792
|
-
* @return {
|
|
1823
|
+
* @param {string} path
|
|
1824
|
+
* @return {any} Returns the value from the given `path`.
|
|
1793
1825
|
* @api private
|
|
1794
1826
|
*/
|
|
1795
1827
|
|
|
@@ -1821,8 +1853,8 @@ Document.prototype.$__getValue = function(path) {
|
|
|
1821
1853
|
* doc.counter += 2;
|
|
1822
1854
|
* await doc.save(); // Sends a `{ $set: { counter: 2 } }` to MongoDB
|
|
1823
1855
|
*
|
|
1824
|
-
* @param {
|
|
1825
|
-
* @param {
|
|
1856
|
+
* @param {string|Array} path path or paths to update
|
|
1857
|
+
* @param {number} val increment `path` by this value
|
|
1826
1858
|
* @return {Document} this
|
|
1827
1859
|
*/
|
|
1828
1860
|
|
|
@@ -1879,8 +1911,8 @@ Document.prototype.$inc = function $inc(path, val) {
|
|
|
1879
1911
|
/**
|
|
1880
1912
|
* Sets a raw value for a path (no casting, setters, transformations)
|
|
1881
1913
|
*
|
|
1882
|
-
* @param {
|
|
1883
|
-
* @param {
|
|
1914
|
+
* @param {string} path
|
|
1915
|
+
* @param {object} value
|
|
1884
1916
|
* @return {Document} this
|
|
1885
1917
|
* @api private
|
|
1886
1918
|
*/
|
|
@@ -1901,12 +1933,12 @@ Document.prototype.$__setValue = function(path, val) {
|
|
|
1901
1933
|
* // dynamic casting to a string
|
|
1902
1934
|
* doc.get('age', String) // "47"
|
|
1903
1935
|
*
|
|
1904
|
-
* @param {
|
|
1905
|
-
* @param {Schema|
|
|
1906
|
-
* @param {
|
|
1907
|
-
* @param {
|
|
1908
|
-
* @param {
|
|
1909
|
-
* @return {
|
|
1936
|
+
* @param {string} path
|
|
1937
|
+
* @param {Schema|string|number|Buffer|any} [type] optionally specify a type for on-the-fly attributes
|
|
1938
|
+
* @param {object} [options]
|
|
1939
|
+
* @param {boolean} [options.virtuals=false] Apply virtuals before getting this path
|
|
1940
|
+
* @param {boolean} [options.getters=true] If false, skip applying getters and just get the raw value
|
|
1941
|
+
* @return {any}
|
|
1910
1942
|
* @api public
|
|
1911
1943
|
*/
|
|
1912
1944
|
|
|
@@ -1942,7 +1974,7 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1942
1974
|
return obj;
|
|
1943
1975
|
}
|
|
1944
1976
|
|
|
1945
|
-
if (schema
|
|
1977
|
+
if (schema?.instance === 'Mixed') {
|
|
1946
1978
|
const virtual = this.$__schema.virtualpath(path);
|
|
1947
1979
|
if (virtual != null) {
|
|
1948
1980
|
schema = virtual;
|
|
@@ -1959,7 +1991,7 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1959
1991
|
}
|
|
1960
1992
|
|
|
1961
1993
|
for (let i = 0, l = pieces.length; i < l; i++) {
|
|
1962
|
-
if (obj
|
|
1994
|
+
if (obj?._doc) {
|
|
1963
1995
|
obj = obj._doc;
|
|
1964
1996
|
}
|
|
1965
1997
|
|
|
@@ -1998,7 +2030,7 @@ Document.prototype.$get = Document.prototype.get;
|
|
|
1998
2030
|
/**
|
|
1999
2031
|
* Returns the schematype for the given `path`.
|
|
2000
2032
|
*
|
|
2001
|
-
* @param {
|
|
2033
|
+
* @param {string} path
|
|
2002
2034
|
* @return {SchemaPath}
|
|
2003
2035
|
* @api private
|
|
2004
2036
|
* @method $__path
|
|
@@ -2027,7 +2059,7 @@ Document.prototype.$__path = function(path) {
|
|
|
2027
2059
|
* doc.markModified('mixed.type');
|
|
2028
2060
|
* doc.save() // changes to mixed.type are now persisted
|
|
2029
2061
|
*
|
|
2030
|
-
* @param {
|
|
2062
|
+
* @param {string} path the path to mark modified
|
|
2031
2063
|
* @param {Document} [scope] the scope to run validators with
|
|
2032
2064
|
* @api public
|
|
2033
2065
|
*/
|
|
@@ -2067,7 +2099,7 @@ Document.prototype.$__saveInitialState = function $__saveInitialState(path) {
|
|
|
2067
2099
|
* doc.unmarkModified('foo');
|
|
2068
2100
|
* doc.save(); // changes to foo will not be persisted
|
|
2069
2101
|
*
|
|
2070
|
-
* @param {
|
|
2102
|
+
* @param {string} path the path to unmark modified
|
|
2071
2103
|
* @api public
|
|
2072
2104
|
*/
|
|
2073
2105
|
|
|
@@ -2090,7 +2122,7 @@ Document.prototype.unmarkModified = function(path) {
|
|
|
2090
2122
|
* @memberOf Document
|
|
2091
2123
|
* @instance
|
|
2092
2124
|
* @method $ignore
|
|
2093
|
-
* @param {
|
|
2125
|
+
* @param {string} path the path to ignore
|
|
2094
2126
|
* @api public
|
|
2095
2127
|
*/
|
|
2096
2128
|
|
|
@@ -2117,7 +2149,7 @@ Document.prototype.$ignore = function(path) {
|
|
|
2117
2149
|
* doc.directModifiedPaths(); // ['nested.bar']
|
|
2118
2150
|
* doc.modifiedPaths(); // ['nested', 'nested.bar']
|
|
2119
2151
|
*
|
|
2120
|
-
* @return {
|
|
2152
|
+
* @return {string[]}
|
|
2121
2153
|
* @api public
|
|
2122
2154
|
*/
|
|
2123
2155
|
|
|
@@ -2142,12 +2174,12 @@ Document.prototype.directModifiedPaths = function() {
|
|
|
2142
2174
|
* doc.$isEmpty('nested'); // false
|
|
2143
2175
|
* doc.nested.$isEmpty(); // false
|
|
2144
2176
|
*
|
|
2145
|
-
* @param {
|
|
2177
|
+
* @param {string} [path]
|
|
2146
2178
|
* @memberOf Document
|
|
2147
2179
|
* @instance
|
|
2148
2180
|
* @api public
|
|
2149
2181
|
* @method $isEmpty
|
|
2150
|
-
* @return {
|
|
2182
|
+
* @return {boolean}
|
|
2151
2183
|
*/
|
|
2152
2184
|
|
|
2153
2185
|
Document.prototype.$isEmpty = function(path) {
|
|
@@ -2197,9 +2229,9 @@ function _isEmpty(v) {
|
|
|
2197
2229
|
/**
|
|
2198
2230
|
* Returns the list of paths that have been modified.
|
|
2199
2231
|
*
|
|
2200
|
-
* @param {
|
|
2201
|
-
* @param {
|
|
2202
|
-
* @return {
|
|
2232
|
+
* @param {object} [options]
|
|
2233
|
+
* @param {boolean} [options.includeChildren=false] if true, returns children of modified paths as well. For example, if false, the list of modified paths for `doc.colors = { primary: 'blue' };` will **not** contain `colors.primary`. If true, `modifiedPaths()` will return an array that contains `colors.primary`.
|
|
2234
|
+
* @return {string[]}
|
|
2203
2235
|
* @api public
|
|
2204
2236
|
*/
|
|
2205
2237
|
|
|
@@ -2278,16 +2310,16 @@ Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;
|
|
|
2278
2310
|
* doc.isModified('documents otherProp') // true
|
|
2279
2311
|
* doc.isDirectModified('documents') // false
|
|
2280
2312
|
*
|
|
2281
|
-
* @param {
|
|
2282
|
-
* @param {
|
|
2283
|
-
* @param {
|
|
2284
|
-
* @return {
|
|
2313
|
+
* @param {string} [path] optional
|
|
2314
|
+
* @param {object} [options]
|
|
2315
|
+
* @param {boolean} [options.ignoreAtomics=false] If true, doesn't return true if path is underneath an array that was modified with atomic operations like `push()`
|
|
2316
|
+
* @return {boolean}
|
|
2285
2317
|
* @api public
|
|
2286
2318
|
*/
|
|
2287
2319
|
|
|
2288
2320
|
Document.prototype.isModified = function(paths, options, modifiedPaths) {
|
|
2289
2321
|
if (paths) {
|
|
2290
|
-
const ignoreAtomics = options
|
|
2322
|
+
const ignoreAtomics = options?.ignoreAtomics;
|
|
2291
2323
|
const directModifiedPathsObj = this.$__.activePaths.states.modify;
|
|
2292
2324
|
if (directModifiedPathsObj == null) {
|
|
2293
2325
|
return false;
|
|
@@ -2312,7 +2344,7 @@ Document.prototype.isModified = function(paths, options, modifiedPaths) {
|
|
|
2312
2344
|
if (ignoreAtomics) {
|
|
2313
2345
|
directModifiedPaths = directModifiedPaths.filter(path => {
|
|
2314
2346
|
const value = this.$__getValue(path);
|
|
2315
|
-
if (value
|
|
2347
|
+
if (value?.[arrayAtomicsSymbol] != null && value[arrayAtomicsSymbol].$set === undefined) {
|
|
2316
2348
|
return false;
|
|
2317
2349
|
}
|
|
2318
2350
|
return true;
|
|
@@ -2352,8 +2384,8 @@ Document.prototype[documentIsModified] = Document.prototype.isModified;
|
|
|
2352
2384
|
* @memberOf Document
|
|
2353
2385
|
* @instance
|
|
2354
2386
|
* @method $isDefault
|
|
2355
|
-
* @param {
|
|
2356
|
-
* @return {
|
|
2387
|
+
* @param {string} [path]
|
|
2388
|
+
* @return {boolean}
|
|
2357
2389
|
* @api public
|
|
2358
2390
|
*/
|
|
2359
2391
|
|
|
@@ -2388,8 +2420,8 @@ Document.prototype.$isDefault = function(path) {
|
|
|
2388
2420
|
* product.deleteOne(); // will execute a remove against the db
|
|
2389
2421
|
*
|
|
2390
2422
|
*
|
|
2391
|
-
* @param {
|
|
2392
|
-
* @return {
|
|
2423
|
+
* @param {boolean} [val] optional, overrides whether mongoose thinks the doc is deleted
|
|
2424
|
+
* @return {boolean|Document} whether mongoose thinks this doc is deleted.
|
|
2393
2425
|
* @method $isDeleted
|
|
2394
2426
|
* @memberOf Document
|
|
2395
2427
|
* @instance
|
|
@@ -2414,8 +2446,8 @@ Document.prototype.$isDeleted = function(val) {
|
|
|
2414
2446
|
* doc.isDirectModified('documents.0.title') // true
|
|
2415
2447
|
* doc.isDirectModified('documents') // false
|
|
2416
2448
|
*
|
|
2417
|
-
* @param {
|
|
2418
|
-
* @return {
|
|
2449
|
+
* @param {string|string[]} [path]
|
|
2450
|
+
* @return {boolean}
|
|
2419
2451
|
* @api public
|
|
2420
2452
|
*/
|
|
2421
2453
|
|
|
@@ -2434,7 +2466,7 @@ Document.prototype.isDirectModified = function(path) {
|
|
|
2434
2466
|
for (let i = 0; i < pieces.length - 1; ++i) {
|
|
2435
2467
|
const subpath = pieces.slice(0, i + 1).join('.');
|
|
2436
2468
|
const subdoc = this.$get(subpath);
|
|
2437
|
-
if (subdoc
|
|
2469
|
+
if (subdoc?.$__ != null && subdoc.isDirectModified(pieces.slice(i + 1).join('.'))) {
|
|
2438
2470
|
return true;
|
|
2439
2471
|
}
|
|
2440
2472
|
}
|
|
@@ -2453,8 +2485,8 @@ Document.prototype.isDirectModified = function(path) {
|
|
|
2453
2485
|
/**
|
|
2454
2486
|
* Checks if `path` is in the `init` state, that is, it was set by `Document#init()` and not modified since.
|
|
2455
2487
|
*
|
|
2456
|
-
* @param {
|
|
2457
|
-
* @return {
|
|
2488
|
+
* @param {string} [path]
|
|
2489
|
+
* @return {boolean}
|
|
2458
2490
|
* @api public
|
|
2459
2491
|
*/
|
|
2460
2492
|
|
|
@@ -2484,8 +2516,8 @@ Document.prototype.isInit = function(path) {
|
|
|
2484
2516
|
* doc.isSelected('name') // true
|
|
2485
2517
|
* doc.isSelected('age') // false
|
|
2486
2518
|
*
|
|
2487
|
-
* @param {
|
|
2488
|
-
* @return {
|
|
2519
|
+
* @param {string|string[]} path
|
|
2520
|
+
* @return {boolean}
|
|
2489
2521
|
* @api public
|
|
2490
2522
|
*/
|
|
2491
2523
|
|
|
@@ -2566,8 +2598,8 @@ Document.prototype.$__isSelected = Document.prototype.isSelected;
|
|
|
2566
2598
|
* doc.isDirectSelected('nested') // false
|
|
2567
2599
|
* })
|
|
2568
2600
|
*
|
|
2569
|
-
* @param {
|
|
2570
|
-
* @return {
|
|
2601
|
+
* @param {string} path
|
|
2602
|
+
* @return {boolean}
|
|
2571
2603
|
* @api public
|
|
2572
2604
|
*/
|
|
2573
2605
|
|
|
@@ -2628,10 +2660,13 @@ Document.prototype.isDirectSelected = function isDirectSelected(path) {
|
|
|
2628
2660
|
*
|
|
2629
2661
|
* await doc.validate({ validateModifiedOnly: false, pathsToSkip: ['name', 'email']});
|
|
2630
2662
|
*
|
|
2631
|
-
* @param {Array|
|
|
2632
|
-
* @param {
|
|
2633
|
-
* @param {
|
|
2663
|
+
* @param {Array|string} [pathsToValidate] list of paths to validate. If set, Mongoose will validate only the modified paths that are in the given list.
|
|
2664
|
+
* @param {object} [options] internal options
|
|
2665
|
+
* @param {boolean} [options.validateModifiedOnly=false] if `true` mongoose validates only modified paths.
|
|
2634
2666
|
* @param {Array|string} [options.pathsToSkip] list of paths to skip. If set, Mongoose will validate every modified path that is not in this list.
|
|
2667
|
+
* @param {boolean|object} [options.middleware=true] set to `false` to skip all user-defined middleware
|
|
2668
|
+
* @param {boolean} [options.middleware.pre=true] set to `false` to skip only pre hooks
|
|
2669
|
+
* @param {boolean} [options.middleware.post=true] set to `false` to skip only post hooks
|
|
2635
2670
|
* @return {Promise} Returns a Promise.
|
|
2636
2671
|
* @api public
|
|
2637
2672
|
*/
|
|
@@ -2652,7 +2687,7 @@ Document.prototype.validate = async function validate(pathsToValidate, options)
|
|
|
2652
2687
|
const isOnePathOnly = options.pathsToSkip.indexOf(' ') === -1;
|
|
2653
2688
|
options.pathsToSkip = isOnePathOnly ? [options.pathsToSkip] : options.pathsToSkip.split(' ');
|
|
2654
2689
|
}
|
|
2655
|
-
const _skipParallelValidateCheck = options
|
|
2690
|
+
const _skipParallelValidateCheck = options?._skipParallelValidateCheck;
|
|
2656
2691
|
|
|
2657
2692
|
if (this.$isSubdocument != null) {
|
|
2658
2693
|
// Skip parallel validate check for subdocuments
|
|
@@ -2662,16 +2697,183 @@ Document.prototype.validate = async function validate(pathsToValidate, options)
|
|
|
2662
2697
|
this.$__.validating = true;
|
|
2663
2698
|
}
|
|
2664
2699
|
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2700
|
+
try {
|
|
2701
|
+
try {
|
|
2702
|
+
[options] = await this._execDocumentPreHooks('validate', options, [options]);
|
|
2703
|
+
} catch (error) {
|
|
2704
|
+
await this._execDocumentPostHooks('validate', options, error);
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
if (this.$__.saveOptions && this.$__.saveOptions.pathsToSave && !pathsToValidate) {
|
|
2709
|
+
pathsToValidate = [...this.$__.saveOptions.pathsToSave];
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
const hasValidateModifiedOnlyOption = options &&
|
|
2713
|
+
(typeof options === 'object') &&
|
|
2714
|
+
('validateModifiedOnly' in options);
|
|
2715
|
+
|
|
2716
|
+
const pathsToSkip = options?.pathsToSkip || null;
|
|
2717
|
+
|
|
2718
|
+
let shouldValidateModifiedOnly;
|
|
2719
|
+
if (hasValidateModifiedOnlyOption) {
|
|
2720
|
+
shouldValidateModifiedOnly = !!options.validateModifiedOnly;
|
|
2721
|
+
} else {
|
|
2722
|
+
shouldValidateModifiedOnly = this.$__schema.options.validateModifiedOnly;
|
|
2723
|
+
}
|
|
2724
|
+
this.$__.validateModifiedOnly = shouldValidateModifiedOnly;
|
|
2725
|
+
|
|
2726
|
+
const validateAllPaths = options?.validateAllPaths;
|
|
2727
|
+
if (validateAllPaths) {
|
|
2728
|
+
if (pathsToSkip) {
|
|
2729
|
+
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToSkip`');
|
|
2671
2730
|
}
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2731
|
+
if (pathsToValidate) {
|
|
2732
|
+
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToValidate`');
|
|
2733
|
+
}
|
|
2734
|
+
if (hasValidateModifiedOnlyOption && shouldValidateModifiedOnly) {
|
|
2735
|
+
throw new TypeError('Cannot set both `validateAllPaths` and `validateModifiedOnly`');
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
const _this = this;
|
|
2740
|
+
|
|
2741
|
+
// only validate required fields when necessary
|
|
2742
|
+
let paths;
|
|
2743
|
+
let doValidateOptionsByPath;
|
|
2744
|
+
if (validateAllPaths) {
|
|
2745
|
+
paths = new Set(Object.keys(this.$__schema.paths));
|
|
2746
|
+
// gh-661: if a whole array is modified, make sure to run validation on all
|
|
2747
|
+
// the children as well
|
|
2748
|
+
for (const path of paths) {
|
|
2749
|
+
const schemaType = this.$__schema.path(path);
|
|
2750
|
+
if (!schemaType?.$isMongooseArray) {
|
|
2751
|
+
continue;
|
|
2752
|
+
}
|
|
2753
|
+
const val = this.$__getValue(path);
|
|
2754
|
+
if (!val) {
|
|
2755
|
+
continue;
|
|
2756
|
+
}
|
|
2757
|
+
_pushNestedArrayPaths(val, paths, path);
|
|
2758
|
+
}
|
|
2759
|
+
paths = [...paths];
|
|
2760
|
+
doValidateOptionsByPath = {};
|
|
2761
|
+
} else {
|
|
2762
|
+
const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip, options?._nestedValidate);
|
|
2763
|
+
paths = shouldValidateModifiedOnly ?
|
|
2764
|
+
pathDetails[0].filter((path) => this.$isModified(path)) :
|
|
2765
|
+
pathDetails[0];
|
|
2766
|
+
doValidateOptionsByPath = pathDetails[1];
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
if (typeof pathsToValidate === 'string') {
|
|
2770
|
+
pathsToValidate = pathsToValidate.split(' ');
|
|
2771
|
+
}
|
|
2772
|
+
|
|
2773
|
+
if (paths.length === 0) {
|
|
2774
|
+
const error = _completeValidate(this);
|
|
2775
|
+
|
|
2776
|
+
await this._execDocumentPostHooks('validate', options, error);
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
const validated = {};
|
|
2781
|
+
|
|
2782
|
+
const pathsToSave = Array.isArray(this.$__.saveOptions?.pathsToSave) ?
|
|
2783
|
+
new Set(this.$__.saveOptions.pathsToSave) :
|
|
2784
|
+
null;
|
|
2785
|
+
const promises = [];
|
|
2786
|
+
for (let i = 0; i < paths.length; ++i) {
|
|
2787
|
+
const path = paths[i];
|
|
2788
|
+
if (pathsToSave != null && !pathsToSave.has(path)) {
|
|
2789
|
+
promises.push(Promise.resolve(null));
|
|
2790
|
+
continue;
|
|
2791
|
+
}
|
|
2792
|
+
if (path == null || validated[path]) {
|
|
2793
|
+
promises.push(Promise.resolve(null));
|
|
2794
|
+
continue;
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
validated[path] = true;
|
|
2798
|
+
const schemaType = _this.$__schema.path(path);
|
|
2799
|
+
|
|
2800
|
+
if (!schemaType) {
|
|
2801
|
+
promises.push(Promise.resolve(null));
|
|
2802
|
+
continue;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
// If user marked as invalid or there was a cast error, don't validate
|
|
2806
|
+
if (!_this.$isValid(path)) {
|
|
2807
|
+
promises.push(Promise.resolve(null));
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
// If setting a path under a mixed path, avoid using the mixed path validator (gh-10141)
|
|
2812
|
+
if (schemaType[schemaMixedSymbol] != null && path !== schemaType.path) {
|
|
2813
|
+
promises.push(Promise.resolve(null));
|
|
2814
|
+
continue;
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
let val = _this.$__getValue(path);
|
|
2818
|
+
|
|
2819
|
+
// If you `populate()` and get back a null value, required validators
|
|
2820
|
+
// shouldn't fail (gh-8018). We should always fall back to the populated
|
|
2821
|
+
// value.
|
|
2822
|
+
let pop;
|
|
2823
|
+
if ((pop = _this.$populated(path))) {
|
|
2824
|
+
val = pop;
|
|
2825
|
+
} else if (val?.$__?.wasPopulated) {
|
|
2826
|
+
// Array paths, like `somearray.1`, do not show up as populated with `$populated()`,
|
|
2827
|
+
// so in that case pull out the document's id
|
|
2828
|
+
val = val._doc._id;
|
|
2829
|
+
}
|
|
2830
|
+
const scope = _this.$__.pathsToScopes != null && path in _this.$__.pathsToScopes ?
|
|
2831
|
+
_this.$__.pathsToScopes[path] :
|
|
2832
|
+
_this;
|
|
2833
|
+
|
|
2834
|
+
const doValidateOptions = {
|
|
2835
|
+
...doValidateOptionsByPath[path],
|
|
2836
|
+
path: path,
|
|
2837
|
+
validateAllPaths,
|
|
2838
|
+
_nestedValidate: true
|
|
2839
|
+
};
|
|
2840
|
+
|
|
2841
|
+
promises.push(
|
|
2842
|
+
schemaType.doValidate(val, scope, doValidateOptions).then(
|
|
2843
|
+
() => null,
|
|
2844
|
+
err => {
|
|
2845
|
+
const isSubdoc = schemaType.$isSingleNested ||
|
|
2846
|
+
schemaType.$isArraySubdocument ||
|
|
2847
|
+
schemaType.$isMongooseDocumentArray;
|
|
2848
|
+
if (isSubdoc && err instanceof ValidationError) {
|
|
2849
|
+
return null;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
return err;
|
|
2853
|
+
}
|
|
2854
|
+
)
|
|
2855
|
+
);
|
|
2856
|
+
}
|
|
2857
|
+
const validationErrors = await Promise.all(promises);
|
|
2858
|
+
for (let i = 0; i < validationErrors.length; ++i) {
|
|
2859
|
+
const validationError = validationErrors[i];
|
|
2860
|
+
if (validationError == null) {
|
|
2861
|
+
continue;
|
|
2862
|
+
}
|
|
2863
|
+
if (this.$__.validationError == null) {
|
|
2864
|
+
this.$__.validationError = new ValidationError(this);
|
|
2865
|
+
}
|
|
2866
|
+
_this.invalidate(paths[i], validationError, undefined, true);
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
const error = _completeValidate(this);
|
|
2870
|
+
|
|
2871
|
+
await this._execDocumentPostHooks('validate', options, error);
|
|
2872
|
+
} finally {
|
|
2873
|
+
delete this.$__.validateModifiedOnly;
|
|
2874
|
+
this.$op = null;
|
|
2875
|
+
this.$__.validating = null;
|
|
2876
|
+
}
|
|
2675
2877
|
};
|
|
2676
2878
|
|
|
2677
2879
|
/**
|
|
@@ -2685,9 +2887,49 @@ Document.prototype.validate = async function validate(pathsToValidate, options)
|
|
|
2685
2887
|
Document.prototype.$validate = Document.prototype.validate;
|
|
2686
2888
|
|
|
2687
2889
|
/*!
|
|
2688
|
-
*
|
|
2890
|
+
* Event emitting and error persisting logic that needs to happen in both the `paths.length === 0`
|
|
2891
|
+
* and `paths.length > 0` cases in `Document.prototype.validate()`.
|
|
2892
|
+
*
|
|
2893
|
+
* @param {Document} doc
|
|
2894
|
+
* @return {Error}
|
|
2895
|
+
* @private
|
|
2689
2896
|
*/
|
|
2690
2897
|
|
|
2898
|
+
function _completeValidate(doc) {
|
|
2899
|
+
let error = doc.$__.validationError;
|
|
2900
|
+
doc.$__.validationError = null;
|
|
2901
|
+
doc.$__.validating = null;
|
|
2902
|
+
|
|
2903
|
+
if (doc.$__.validateModifiedOnly && error != null) {
|
|
2904
|
+
// Remove any validation errors that aren't from modified paths
|
|
2905
|
+
const errors = Object.keys(error.errors);
|
|
2906
|
+
for (const errPath of errors) {
|
|
2907
|
+
if (!doc.$isModified(errPath)) {
|
|
2908
|
+
delete error.errors[errPath];
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
if (utils.hasOwnKeys(error.errors) === false) {
|
|
2912
|
+
error = void 0;
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
doc.$__.cachedRequired = {};
|
|
2917
|
+
doc.$emit('validate', doc);
|
|
2918
|
+
doc.constructor.emit('validate', doc);
|
|
2919
|
+
|
|
2920
|
+
if (error) {
|
|
2921
|
+
for (const key in error.errors) {
|
|
2922
|
+
// Make sure cast errors persist
|
|
2923
|
+
if (!doc[documentArrayParent] &&
|
|
2924
|
+
error.errors[key] instanceof MongooseError.CastError) {
|
|
2925
|
+
doc.invalidate(key, error.errors[key]);
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
return error;
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2691
2933
|
function _evaluateRequiredFunctions(doc) {
|
|
2692
2934
|
const requiredFields = Object.keys(doc.$__.activePaths.getStatePaths('require'));
|
|
2693
2935
|
let i = 0;
|
|
@@ -2697,7 +2939,7 @@ function _evaluateRequiredFunctions(doc) {
|
|
|
2697
2939
|
|
|
2698
2940
|
const p = doc.$__schema.path(path);
|
|
2699
2941
|
|
|
2700
|
-
if (
|
|
2942
|
+
if (typeof p?.originalRequiredValue === 'function') {
|
|
2701
2943
|
doc.$__.cachedRequired = doc.$__.cachedRequired || {};
|
|
2702
2944
|
try {
|
|
2703
2945
|
doc.$__.cachedRequired[path] = p.originalRequiredValue.call(doc, doc);
|
|
@@ -2739,9 +2981,40 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
2739
2981
|
// Skip $* paths - they represent map schemas, not actual document paths
|
|
2740
2982
|
return;
|
|
2741
2983
|
}
|
|
2984
|
+
|
|
2985
|
+
const _pathType = doc.$__schema.path(p);
|
|
2986
|
+
|
|
2987
|
+
// Optimization: if primitive path with no validators, or array of primitives
|
|
2988
|
+
// with no validators, skip validating this path entirely.
|
|
2989
|
+
// Note: paths with no _pathType (e.g. sub-paths under Mixed) must still be
|
|
2990
|
+
// added, as they trigger validation of the parent Mixed path.
|
|
2991
|
+
if (_pathType) {
|
|
2992
|
+
if (!_pathType.schema &&
|
|
2993
|
+
!_pathType.embeddedSchemaType &&
|
|
2994
|
+
_pathType.validators.length === 0 &&
|
|
2995
|
+
!_pathType.$parentSchemaDocArray &&
|
|
2996
|
+
// gh-15957: skip this optimization for SchemaMap as maps can contain subdocuments
|
|
2997
|
+
// that need validation even if the map itself has no validators
|
|
2998
|
+
!_pathType.$isSchemaMap &&
|
|
2999
|
+
!_pathType.$isSchemaUnion) {
|
|
3000
|
+
return;
|
|
3001
|
+
} else if (_pathType.$isMongooseArray &&
|
|
3002
|
+
!_pathType.$isMongooseDocumentArray && // Skip document arrays...
|
|
3003
|
+
!_pathType.embeddedSchemaType.$isMongooseArray && // and arrays of arrays
|
|
3004
|
+
_pathType.validators.length === 0 && // and arrays with top-level validators
|
|
3005
|
+
_pathType.embeddedSchemaType.validators.length === 0) {
|
|
3006
|
+
return;
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
|
|
2742
3010
|
paths.add(p);
|
|
2743
3011
|
}
|
|
2744
3012
|
|
|
3013
|
+
const onlyPrimitiveValues = doc.$__hasOnlyPrimitiveValues();
|
|
3014
|
+
if (onlyPrimitiveValues && paths.size === 0) {
|
|
3015
|
+
return [[], doValidateOptions];
|
|
3016
|
+
}
|
|
3017
|
+
|
|
2745
3018
|
if (!isNestedValidate) {
|
|
2746
3019
|
// If we're validating a subdocument, all this logic will run anyway on the top-level document, so skip for subdocuments.
|
|
2747
3020
|
// But only run for top-level subdocuments, because we're looking for subdocuments that are not modified at top-level but
|
|
@@ -2757,7 +3030,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
2757
3030
|
}
|
|
2758
3031
|
} else if (schemaType.$isMongooseDocumentArray) {
|
|
2759
3032
|
const arr = doc.$get(path);
|
|
2760
|
-
if (arr
|
|
3033
|
+
if (arr?.length) {
|
|
2761
3034
|
for (const subdoc of arr) {
|
|
2762
3035
|
if (subdoc) {
|
|
2763
3036
|
topLevelSubdocs.push(subdoc);
|
|
@@ -2806,31 +3079,17 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
2806
3079
|
}
|
|
2807
3080
|
}
|
|
2808
3081
|
|
|
2809
|
-
|
|
2810
|
-
const
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
if (p == null || p.startsWith(_pathType.path + '.')) {
|
|
2818
|
-
paths.delete(p);
|
|
3082
|
+
if (!onlyPrimitiveValues) {
|
|
3083
|
+
for (const path of paths) {
|
|
3084
|
+
const _pathType = doc.$__schema.path(path);
|
|
3085
|
+
if (_pathType && _pathType.$isMongooseDocumentArray) {
|
|
3086
|
+
for (const p of paths) {
|
|
3087
|
+
if (p == null || p.startsWith(_pathType.path + '.')) {
|
|
3088
|
+
paths.delete(p);
|
|
3089
|
+
}
|
|
2819
3090
|
}
|
|
2820
3091
|
}
|
|
2821
3092
|
}
|
|
2822
|
-
|
|
2823
|
-
// Optimization: if primitive path with no validators, or array of primitives
|
|
2824
|
-
// with no validators, skip validating this path entirely.
|
|
2825
|
-
if (!_pathType.caster && _pathType.validators.length === 0 && !_pathType.$parentSchemaDocArray) {
|
|
2826
|
-
paths.delete(path);
|
|
2827
|
-
} else if (_pathType.$isMongooseArray &&
|
|
2828
|
-
!_pathType.$isMongooseDocumentArray && // Skip document arrays...
|
|
2829
|
-
!_pathType.$embeddedSchemaType.$isMongooseArray && // and arrays of arrays
|
|
2830
|
-
_pathType.validators.length === 0 && // and arrays with top-level validators
|
|
2831
|
-
_pathType.$embeddedSchemaType.validators.length === 0) {
|
|
2832
|
-
paths.delete(path);
|
|
2833
|
-
}
|
|
2834
3093
|
}
|
|
2835
3094
|
|
|
2836
3095
|
|
|
@@ -2910,7 +3169,7 @@ function _addArrayPathsToValidate(doc, paths) {
|
|
|
2910
3169
|
// it unless we have a case of #6364
|
|
2911
3170
|
(!Array.isArray(_pathType) &&
|
|
2912
3171
|
_pathType.$isMongooseDocumentArray &&
|
|
2913
|
-
!
|
|
3172
|
+
!_pathType?.schemaOptions?.required)) {
|
|
2914
3173
|
continue;
|
|
2915
3174
|
}
|
|
2916
3175
|
|
|
@@ -2918,8 +3177,8 @@ function _addArrayPathsToValidate(doc, paths) {
|
|
|
2918
3177
|
// on the array type, there's no need to run validation on the individual array elements.
|
|
2919
3178
|
if (_pathType.$isMongooseArray &&
|
|
2920
3179
|
!_pathType.$isMongooseDocumentArray && // Skip document arrays...
|
|
2921
|
-
!_pathType
|
|
2922
|
-
_pathType
|
|
3180
|
+
!_pathType.embeddedSchemaType.$isMongooseArray && // and arrays of arrays
|
|
3181
|
+
_pathType.embeddedSchemaType.validators.length === 0) {
|
|
2923
3182
|
continue;
|
|
2924
3183
|
}
|
|
2925
3184
|
|
|
@@ -2945,217 +3204,18 @@ function _pushNestedArrayPaths(val, paths, path) {
|
|
|
2945
3204
|
* ignore
|
|
2946
3205
|
*/
|
|
2947
3206
|
|
|
2948
|
-
Document.prototype
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
callback = pathsToValidate;
|
|
2953
|
-
options = null;
|
|
2954
|
-
pathsToValidate = null;
|
|
2955
|
-
} else if (typeof options === 'function') {
|
|
2956
|
-
callback = options;
|
|
2957
|
-
options = null;
|
|
2958
|
-
}
|
|
2959
|
-
|
|
2960
|
-
const hasValidateModifiedOnlyOption = options &&
|
|
2961
|
-
(typeof options === 'object') &&
|
|
2962
|
-
('validateModifiedOnly' in options);
|
|
2963
|
-
|
|
2964
|
-
const pathsToSkip = (options && options.pathsToSkip) || null;
|
|
2965
|
-
|
|
2966
|
-
let shouldValidateModifiedOnly;
|
|
2967
|
-
if (hasValidateModifiedOnlyOption) {
|
|
2968
|
-
shouldValidateModifiedOnly = !!options.validateModifiedOnly;
|
|
2969
|
-
} else {
|
|
2970
|
-
shouldValidateModifiedOnly = this.$__schema.options.validateModifiedOnly;
|
|
2971
|
-
}
|
|
2972
|
-
|
|
2973
|
-
const validateAllPaths = options && options.validateAllPaths;
|
|
2974
|
-
if (validateAllPaths) {
|
|
2975
|
-
if (pathsToSkip) {
|
|
2976
|
-
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToSkip`');
|
|
2977
|
-
}
|
|
2978
|
-
if (pathsToValidate) {
|
|
2979
|
-
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToValidate`');
|
|
2980
|
-
}
|
|
2981
|
-
if (hasValidateModifiedOnlyOption && shouldValidateModifiedOnly) {
|
|
2982
|
-
throw new TypeError('Cannot set both `validateAllPaths` and `validateModifiedOnly`');
|
|
2983
|
-
}
|
|
2984
|
-
}
|
|
2985
|
-
|
|
2986
|
-
const _this = this;
|
|
2987
|
-
const _complete = () => {
|
|
2988
|
-
let validationError = this.$__.validationError;
|
|
2989
|
-
this.$__.validationError = null;
|
|
2990
|
-
this.$__.validating = null;
|
|
2991
|
-
|
|
2992
|
-
if (shouldValidateModifiedOnly && validationError != null) {
|
|
2993
|
-
// Remove any validation errors that aren't from modified paths
|
|
2994
|
-
const errors = Object.keys(validationError.errors);
|
|
2995
|
-
for (const errPath of errors) {
|
|
2996
|
-
if (!this.$isModified(errPath)) {
|
|
2997
|
-
delete validationError.errors[errPath];
|
|
2998
|
-
}
|
|
2999
|
-
}
|
|
3000
|
-
if (Object.keys(validationError.errors).length === 0) {
|
|
3001
|
-
validationError = void 0;
|
|
3002
|
-
}
|
|
3003
|
-
}
|
|
3004
|
-
|
|
3005
|
-
this.$__.cachedRequired = {};
|
|
3006
|
-
this.$emit('validate', _this);
|
|
3007
|
-
this.constructor.emit('validate', _this);
|
|
3008
|
-
|
|
3009
|
-
if (validationError) {
|
|
3010
|
-
for (const key in validationError.errors) {
|
|
3011
|
-
// Make sure cast errors persist
|
|
3012
|
-
if (!this[documentArrayParent] &&
|
|
3013
|
-
validationError.errors[key] instanceof MongooseError.CastError) {
|
|
3014
|
-
this.invalidate(key, validationError.errors[key]);
|
|
3015
|
-
}
|
|
3016
|
-
}
|
|
3017
|
-
|
|
3018
|
-
return validationError;
|
|
3019
|
-
}
|
|
3020
|
-
};
|
|
3021
|
-
|
|
3022
|
-
// only validate required fields when necessary
|
|
3023
|
-
let paths;
|
|
3024
|
-
let doValidateOptionsByPath;
|
|
3025
|
-
if (validateAllPaths) {
|
|
3026
|
-
paths = new Set(Object.keys(this.$__schema.paths));
|
|
3027
|
-
// gh-661: if a whole array is modified, make sure to run validation on all
|
|
3028
|
-
// the children as well
|
|
3029
|
-
for (const path of paths) {
|
|
3030
|
-
const schemaType = this.$__schema.path(path);
|
|
3031
|
-
if (!schemaType || !schemaType.$isMongooseArray) {
|
|
3032
|
-
continue;
|
|
3033
|
-
}
|
|
3034
|
-
const val = this.$__getValue(path);
|
|
3035
|
-
if (!val) {
|
|
3036
|
-
continue;
|
|
3037
|
-
}
|
|
3038
|
-
_pushNestedArrayPaths(val, paths, path);
|
|
3039
|
-
}
|
|
3040
|
-
paths = [...paths];
|
|
3041
|
-
doValidateOptionsByPath = {};
|
|
3042
|
-
} else {
|
|
3043
|
-
const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip, options && options._nestedValidate);
|
|
3044
|
-
paths = shouldValidateModifiedOnly ?
|
|
3045
|
-
pathDetails[0].filter((path) => this.$isModified(path)) :
|
|
3046
|
-
pathDetails[0];
|
|
3047
|
-
doValidateOptionsByPath = pathDetails[1];
|
|
3048
|
-
}
|
|
3049
|
-
|
|
3050
|
-
if (typeof pathsToValidate === 'string') {
|
|
3051
|
-
pathsToValidate = pathsToValidate.split(' ');
|
|
3052
|
-
}
|
|
3053
|
-
|
|
3054
|
-
if (paths.length === 0) {
|
|
3055
|
-
return immediate(function() {
|
|
3056
|
-
const error = _complete();
|
|
3057
|
-
if (error) {
|
|
3058
|
-
return _this.$__schema.s.hooks.execPost('validate:error', _this, [_this], { error: error }, function(error) {
|
|
3059
|
-
callback(error);
|
|
3060
|
-
});
|
|
3061
|
-
}
|
|
3062
|
-
callback(null, _this);
|
|
3063
|
-
});
|
|
3064
|
-
}
|
|
3065
|
-
|
|
3066
|
-
const validated = {};
|
|
3067
|
-
let total = 0;
|
|
3068
|
-
|
|
3069
|
-
let pathsToSave = this.$__.saveOptions?.pathsToSave;
|
|
3070
|
-
if (Array.isArray(pathsToSave)) {
|
|
3071
|
-
pathsToSave = new Set(pathsToSave);
|
|
3072
|
-
for (const path of paths) {
|
|
3073
|
-
if (!pathsToSave.has(path)) {
|
|
3074
|
-
continue;
|
|
3075
|
-
}
|
|
3076
|
-
validatePath(path);
|
|
3077
|
-
}
|
|
3078
|
-
} else {
|
|
3079
|
-
for (const path of paths) {
|
|
3080
|
-
validatePath(path);
|
|
3081
|
-
}
|
|
3082
|
-
}
|
|
3083
|
-
|
|
3084
|
-
function validatePath(path) {
|
|
3085
|
-
if (path == null || validated[path]) {
|
|
3086
|
-
return;
|
|
3087
|
-
}
|
|
3088
|
-
|
|
3089
|
-
validated[path] = true;
|
|
3090
|
-
total++;
|
|
3091
|
-
|
|
3092
|
-
immediate(function() {
|
|
3093
|
-
const schemaType = _this.$__schema.path(path);
|
|
3094
|
-
|
|
3095
|
-
if (!schemaType) {
|
|
3096
|
-
return --total || complete();
|
|
3097
|
-
}
|
|
3098
|
-
|
|
3099
|
-
// If user marked as invalid or there was a cast error, don't validate
|
|
3100
|
-
if (!_this.$isValid(path)) {
|
|
3101
|
-
--total || complete();
|
|
3102
|
-
return;
|
|
3103
|
-
}
|
|
3104
|
-
|
|
3105
|
-
// If setting a path under a mixed path, avoid using the mixed path validator (gh-10141)
|
|
3106
|
-
if (schemaType[schemaMixedSymbol] != null && path !== schemaType.path) {
|
|
3107
|
-
return --total || complete();
|
|
3108
|
-
}
|
|
3109
|
-
|
|
3110
|
-
let val = _this.$__getValue(path);
|
|
3111
|
-
|
|
3112
|
-
// If you `populate()` and get back a null value, required validators
|
|
3113
|
-
// shouldn't fail (gh-8018). We should always fall back to the populated
|
|
3114
|
-
// value.
|
|
3115
|
-
let pop;
|
|
3116
|
-
if ((pop = _this.$populated(path))) {
|
|
3117
|
-
val = pop;
|
|
3118
|
-
} else if (val != null && val.$__ != null && val.$__.wasPopulated) {
|
|
3119
|
-
// Array paths, like `somearray.1`, do not show up as populated with `$populated()`,
|
|
3120
|
-
// so in that case pull out the document's id
|
|
3121
|
-
val = val._doc._id;
|
|
3122
|
-
}
|
|
3123
|
-
const scope = _this.$__.pathsToScopes != null && path in _this.$__.pathsToScopes ?
|
|
3124
|
-
_this.$__.pathsToScopes[path] :
|
|
3125
|
-
_this;
|
|
3126
|
-
|
|
3127
|
-
const doValidateOptions = {
|
|
3128
|
-
...doValidateOptionsByPath[path],
|
|
3129
|
-
path: path,
|
|
3130
|
-
validateAllPaths,
|
|
3131
|
-
_nestedValidate: true
|
|
3132
|
-
};
|
|
3133
|
-
|
|
3134
|
-
schemaType.doValidate(val, function(err) {
|
|
3135
|
-
if (err) {
|
|
3136
|
-
const isSubdoc = schemaType.$isSingleNested ||
|
|
3137
|
-
schemaType.$isArraySubdocument ||
|
|
3138
|
-
schemaType.$isMongooseDocumentArray;
|
|
3139
|
-
if (isSubdoc && err instanceof ValidationError) {
|
|
3140
|
-
return --total || complete();
|
|
3141
|
-
}
|
|
3142
|
-
_this.invalidate(path, err, undefined, true);
|
|
3143
|
-
}
|
|
3144
|
-
--total || complete();
|
|
3145
|
-
}, scope, doValidateOptions);
|
|
3146
|
-
});
|
|
3147
|
-
}
|
|
3207
|
+
Document.prototype._execDocumentPreHooks = async function _execDocumentPreHooks(opName, options, argsForHooks) {
|
|
3208
|
+
const filter = buildMiddlewareFilter(options, 'pre');
|
|
3209
|
+
return this.$__middleware.execPre(opName, this, argsForHooks || [], { filter });
|
|
3210
|
+
};
|
|
3148
3211
|
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
return _this.$__schema.s.hooks.execPost('validate:error', _this, [_this], { error: error }, function(error) {
|
|
3153
|
-
callback(error);
|
|
3154
|
-
});
|
|
3155
|
-
}
|
|
3156
|
-
callback(null, _this);
|
|
3157
|
-
}
|
|
3212
|
+
/*!
|
|
3213
|
+
* ignore
|
|
3214
|
+
*/
|
|
3158
3215
|
|
|
3216
|
+
Document.prototype._execDocumentPostHooks = async function _execDocumentPostHooks(opName, options, error) {
|
|
3217
|
+
const filter = buildMiddlewareFilter(options, 'post');
|
|
3218
|
+
return this.$__middleware.execPost(opName, this, [this], { error, filter });
|
|
3159
3219
|
};
|
|
3160
3220
|
|
|
3161
3221
|
/*!
|
|
@@ -3218,9 +3278,12 @@ function _handlePathsToSkip(paths, pathsToSkip) {
|
|
|
3218
3278
|
* }
|
|
3219
3279
|
*
|
|
3220
3280
|
* @param {Array|string} [pathsToValidate] only validate the given paths
|
|
3221
|
-
* @param {
|
|
3222
|
-
* @param {
|
|
3281
|
+
* @param {object} [options] options for validation
|
|
3282
|
+
* @param {boolean} [options.validateModifiedOnly=false] If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
|
|
3223
3283
|
* @param {Array|string} [options.pathsToSkip] list of paths to skip. If set, Mongoose will validate every modified path that is not in this list.
|
|
3284
|
+
* @param {boolean|object} [options.middleware=true] set to `false` to skip all user-defined middleware
|
|
3285
|
+
* @param {boolean} [options.middleware.pre=true] set to `false` to skip only pre hooks
|
|
3286
|
+
* @param {boolean} [options.middleware.post=true] set to `false` to skip only post hooks
|
|
3224
3287
|
* @return {ValidationError|undefined} ValidationError if there are errors during validation, or undefined if there is no error.
|
|
3225
3288
|
* @api public
|
|
3226
3289
|
*/
|
|
@@ -3244,9 +3307,9 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
3244
3307
|
shouldValidateModifiedOnly = this.$__schema.options.validateModifiedOnly;
|
|
3245
3308
|
}
|
|
3246
3309
|
|
|
3247
|
-
let pathsToSkip = options
|
|
3310
|
+
let pathsToSkip = options?.pathsToSkip;
|
|
3248
3311
|
|
|
3249
|
-
const validateAllPaths = options
|
|
3312
|
+
const validateAllPaths = options?.validateAllPaths;
|
|
3250
3313
|
if (validateAllPaths) {
|
|
3251
3314
|
if (pathsToSkip) {
|
|
3252
3315
|
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToSkip`');
|
|
@@ -3272,7 +3335,7 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
3272
3335
|
// the children as well
|
|
3273
3336
|
for (const path of paths) {
|
|
3274
3337
|
const schemaType = this.$__schema.path(path);
|
|
3275
|
-
if (!schemaType
|
|
3338
|
+
if (!schemaType?.$isMongooseArray) {
|
|
3276
3339
|
continue;
|
|
3277
3340
|
}
|
|
3278
3341
|
const val = this.$__getValue(path);
|
|
@@ -3368,10 +3431,10 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
3368
3431
|
* value: 14 } } }
|
|
3369
3432
|
* })
|
|
3370
3433
|
*
|
|
3371
|
-
* @param {
|
|
3372
|
-
* @param {
|
|
3373
|
-
* @param {
|
|
3374
|
-
* @param {
|
|
3434
|
+
* @param {string} path the field to invalidate. For array elements, use the `array.i.field` syntax, where `i` is the 0-based index in the array.
|
|
3435
|
+
* @param {string|Error} err the error which states the reason `path` was invalid
|
|
3436
|
+
* @param {object|string|number|any} val optional invalid value
|
|
3437
|
+
* @param {string} [kind] optional `kind` property for the error
|
|
3375
3438
|
* @return {ValidationError} the current ValidationError, with all currently invalidated paths
|
|
3376
3439
|
* @api public
|
|
3377
3440
|
*/
|
|
@@ -3405,7 +3468,7 @@ Document.prototype.invalidate = function(path, err, val, kind) {
|
|
|
3405
3468
|
/**
|
|
3406
3469
|
* Marks a path as valid, removing existing validation errors.
|
|
3407
3470
|
*
|
|
3408
|
-
* @param {
|
|
3471
|
+
* @param {string} path the field to mark as valid
|
|
3409
3472
|
* @api public
|
|
3410
3473
|
* @memberOf Document
|
|
3411
3474
|
* @instance
|
|
@@ -3413,12 +3476,12 @@ Document.prototype.invalidate = function(path, err, val, kind) {
|
|
|
3413
3476
|
*/
|
|
3414
3477
|
|
|
3415
3478
|
Document.prototype.$markValid = function(path) {
|
|
3416
|
-
if (!this.$__.validationError
|
|
3479
|
+
if (!this.$__.validationError?.errors[path]) {
|
|
3417
3480
|
return;
|
|
3418
3481
|
}
|
|
3419
3482
|
|
|
3420
3483
|
delete this.$__.validationError.errors[path];
|
|
3421
|
-
if (
|
|
3484
|
+
if (utils.hasOwnKeys(this.$__.validationError.errors) === false) {
|
|
3422
3485
|
this.$__.validationError = null;
|
|
3423
3486
|
}
|
|
3424
3487
|
};
|
|
@@ -3438,7 +3501,7 @@ function _markValidSubpaths(doc, path) {
|
|
|
3438
3501
|
delete doc.$__.validationError.errors[key];
|
|
3439
3502
|
}
|
|
3440
3503
|
}
|
|
3441
|
-
if (
|
|
3504
|
+
if (utils.hasOwnKeys(doc.$__.validationError.errors) === false) {
|
|
3442
3505
|
doc.$__.validationError = null;
|
|
3443
3506
|
}
|
|
3444
3507
|
}
|
|
@@ -3483,16 +3546,16 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3483
3546
|
* const newProduct = await product.save();
|
|
3484
3547
|
* newProduct === product; // true
|
|
3485
3548
|
*
|
|
3486
|
-
* @param {
|
|
3549
|
+
* @param {object} [options] options optional options
|
|
3487
3550
|
* @param {Session} [options.session=null] the [session](https://www.mongodb.com/docs/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](https://mongoosejs.com/docs/api/document.html#Document.prototype.$session()).
|
|
3488
|
-
* @param {
|
|
3489
|
-
* @param {
|
|
3490
|
-
* @param {
|
|
3491
|
-
* @param {
|
|
3492
|
-
* @param {
|
|
3493
|
-
* @param {
|
|
3494
|
-
* @param {
|
|
3495
|
-
* @param {
|
|
3551
|
+
* @param {object} [options.safe] (DEPRECATED) overrides [schema's safe option](https://mongoosejs.com/docs/guide.html#safe). Use the `w` option instead.
|
|
3552
|
+
* @param {boolean} [options.validateBeforeSave] set to false to save without validating.
|
|
3553
|
+
* @param {boolean} [options.validateModifiedOnly=false] If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
|
|
3554
|
+
* @param {number|string} [options.w] set the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/#w-option). Overrides the [schema-level `writeConcern` option](https://mongoosejs.com/docs/guide.html#writeConcern)
|
|
3555
|
+
* @param {boolean} [options.j] set to true for MongoDB to wait until this `save()` has been [journaled before resolving the returned promise](https://www.mongodb.com/docs/manual/reference/write-concern/#j-option). Overrides the [schema-level `writeConcern` option](https://mongoosejs.com/docs/guide.html#writeConcern)
|
|
3556
|
+
* @param {number} [options.wtimeout] sets a [timeout for the write concern](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](https://mongoosejs.com/docs/guide.html#writeConcern).
|
|
3557
|
+
* @param {boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://www.mongodb.com/docs/manual/reference/limits/#Restrictions-on-Field-Names)
|
|
3558
|
+
* @param {boolean} [options.timestamps=true] if `false` and [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this `save()`.
|
|
3496
3559
|
* @method save
|
|
3497
3560
|
* @memberOf Document
|
|
3498
3561
|
* @instance
|
|
@@ -3505,7 +3568,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3505
3568
|
/**
|
|
3506
3569
|
* Checks if a path is invalid
|
|
3507
3570
|
*
|
|
3508
|
-
* @param {
|
|
3571
|
+
* @param {string|string[]} [path] the field to check. If unset will always return "false"
|
|
3509
3572
|
* @method $isValid
|
|
3510
3573
|
* @memberOf Document
|
|
3511
3574
|
* @instance
|
|
@@ -3513,7 +3576,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3513
3576
|
*/
|
|
3514
3577
|
|
|
3515
3578
|
Document.prototype.$isValid = function(path) {
|
|
3516
|
-
if (this.$__.validationError == null ||
|
|
3579
|
+
if (this.$__.validationError == null || utils.hasOwnKeys(this.$__.validationError.errors) === false) {
|
|
3517
3580
|
return true;
|
|
3518
3581
|
}
|
|
3519
3582
|
if (path == null) {
|
|
@@ -3543,25 +3606,21 @@ Document.prototype.$isValid = function(path) {
|
|
|
3543
3606
|
Document.prototype.$__reset = function reset() {
|
|
3544
3607
|
let _this = this;
|
|
3545
3608
|
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3609
|
+
const onlyPrimitiveValues = this.$__hasOnlyPrimitiveValues();
|
|
3610
|
+
|
|
3611
|
+
// Skip for subdocuments. Also skip if doc only has primitive values,
|
|
3612
|
+
// because primitives can't be subdocs.
|
|
3613
|
+
const subdocs = !this.$isSubdocument && !onlyPrimitiveValues ? this.$getAllSubdocs({ useCache: true }) : null;
|
|
3614
|
+
if (subdocs?.length > 0) {
|
|
3549
3615
|
for (const subdoc of subdocs) {
|
|
3550
3616
|
subdoc.$__reset();
|
|
3551
3617
|
}
|
|
3552
3618
|
}
|
|
3553
3619
|
|
|
3554
|
-
//
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
if (type && typeof type.clearAtomics === 'function') {
|
|
3559
|
-
type.clearAtomics();
|
|
3560
|
-
} else if (type && type[arrayAtomicsSymbol]) {
|
|
3561
|
-
type[arrayAtomicsBackupSymbol] = type[arrayAtomicsSymbol];
|
|
3562
|
-
type[arrayAtomicsSymbol] = {};
|
|
3563
|
-
}
|
|
3564
|
-
});
|
|
3620
|
+
// Clear atomics on dirty paths. Walk the modified and default paths
|
|
3621
|
+
// directly instead of calling $__dirty(), which builds intermediate
|
|
3622
|
+
// arrays, a Map, and does parent-path deduplication we don't need here.
|
|
3623
|
+
this.$__resetAtomics();
|
|
3565
3624
|
|
|
3566
3625
|
this.$__.backup = {};
|
|
3567
3626
|
this.$__.backup.activePaths = {
|
|
@@ -3584,12 +3643,46 @@ Document.prototype.$__reset = function reset() {
|
|
|
3584
3643
|
return this;
|
|
3585
3644
|
};
|
|
3586
3645
|
|
|
3646
|
+
/*!
|
|
3647
|
+
* Clear atomics on all dirty (modified + default) paths. This is a lighter
|
|
3648
|
+
* alternative to calling `$__dirty()` when we only need to clear atomics
|
|
3649
|
+
* and don't need the full {path, value, schema} objects or parent-path
|
|
3650
|
+
* deduplication.
|
|
3651
|
+
*/
|
|
3652
|
+
|
|
3653
|
+
Document.prototype.$__resetAtomics = function $__resetAtomics() {
|
|
3654
|
+
const activePaths = this.$__.activePaths;
|
|
3655
|
+
const modifyPaths = activePaths.getStatePaths('modify');
|
|
3656
|
+
const defaultPaths = activePaths.getStatePaths('default');
|
|
3657
|
+
|
|
3658
|
+
_clearAtomicsOnPaths(this, modifyPaths);
|
|
3659
|
+
_clearAtomicsOnPaths(this, defaultPaths);
|
|
3660
|
+
};
|
|
3661
|
+
|
|
3662
|
+
function _clearAtomicsOnPaths(doc, paths) {
|
|
3663
|
+
if (paths == null) {
|
|
3664
|
+
return;
|
|
3665
|
+
}
|
|
3666
|
+
const keys = Object.keys(paths);
|
|
3667
|
+
for (let i = 0; i < keys.length; ++i) {
|
|
3668
|
+
const type = doc.$__getValue(keys[i]);
|
|
3669
|
+
if (type != null) {
|
|
3670
|
+
if (typeof type.clearAtomics === 'function') {
|
|
3671
|
+
type.clearAtomics();
|
|
3672
|
+
} else if (type[arrayAtomicsSymbol]) {
|
|
3673
|
+
type[arrayAtomicsBackupSymbol] = type[arrayAtomicsSymbol];
|
|
3674
|
+
type[arrayAtomicsSymbol] = {};
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3587
3680
|
/*!
|
|
3588
3681
|
* ignore
|
|
3589
3682
|
*/
|
|
3590
3683
|
|
|
3591
3684
|
Document.prototype.$__undoReset = function $__undoReset() {
|
|
3592
|
-
if (this.$__.backup
|
|
3685
|
+
if (this.$__.backup?.activePaths == null) {
|
|
3593
3686
|
return;
|
|
3594
3687
|
}
|
|
3595
3688
|
|
|
@@ -3602,7 +3695,7 @@ Document.prototype.$__undoReset = function $__undoReset() {
|
|
|
3602
3695
|
for (const dirt of this.$__dirty()) {
|
|
3603
3696
|
const type = dirt.value;
|
|
3604
3697
|
|
|
3605
|
-
if (type
|
|
3698
|
+
if (type?.[arrayAtomicsSymbol] && type[arrayAtomicsBackupSymbol]) {
|
|
3606
3699
|
type[arrayAtomicsSymbol] = type[arrayAtomicsBackupSymbol];
|
|
3607
3700
|
}
|
|
3608
3701
|
}
|
|
@@ -3657,15 +3750,17 @@ Document.prototype.$__dirty = function() {
|
|
|
3657
3750
|
}
|
|
3658
3751
|
|
|
3659
3752
|
let top = null;
|
|
3753
|
+
let foundParent = false;
|
|
3660
3754
|
|
|
3661
3755
|
const array = parentPaths(item.path);
|
|
3662
3756
|
for (let i = 0; i < array.length - 1; i++) {
|
|
3663
3757
|
if (allPaths.has(array[i])) {
|
|
3664
3758
|
top = allPaths.get(array[i]);
|
|
3759
|
+
foundParent = true;
|
|
3665
3760
|
break;
|
|
3666
3761
|
}
|
|
3667
3762
|
}
|
|
3668
|
-
if (
|
|
3763
|
+
if (!foundParent) {
|
|
3669
3764
|
minimal.push(item);
|
|
3670
3765
|
} else if (top != null &&
|
|
3671
3766
|
top[arrayAtomicsSymbol] != null &&
|
|
@@ -3702,6 +3797,7 @@ Document.prototype.$__setSchema = function(schema) {
|
|
|
3702
3797
|
this.schema = schema;
|
|
3703
3798
|
}
|
|
3704
3799
|
this.$__schema = schema;
|
|
3800
|
+
this.$__middleware = schema._getDocumentMiddleware();
|
|
3705
3801
|
this[documentSchemaSymbol] = schema;
|
|
3706
3802
|
};
|
|
3707
3803
|
|
|
@@ -3738,7 +3834,7 @@ Document.prototype.$__getArrayPathsToValidate = function() {
|
|
|
3738
3834
|
/**
|
|
3739
3835
|
* Get all subdocs (by bfs)
|
|
3740
3836
|
*
|
|
3741
|
-
* @param {
|
|
3837
|
+
* @param {object} [options] options. Currently for internal use.
|
|
3742
3838
|
* @return {Array}
|
|
3743
3839
|
* @api public
|
|
3744
3840
|
* @method $getAllSubdocs
|
|
@@ -3769,14 +3865,14 @@ Document.prototype.$getAllSubdocs = function(options) {
|
|
|
3769
3865
|
}
|
|
3770
3866
|
if (Array.isArray(val)) {
|
|
3771
3867
|
for (const el of val) {
|
|
3772
|
-
if (el
|
|
3868
|
+
if (el?.$__) {
|
|
3773
3869
|
newSubdocs.push(el);
|
|
3774
3870
|
}
|
|
3775
3871
|
}
|
|
3776
3872
|
}
|
|
3777
3873
|
if (val instanceof Map) {
|
|
3778
3874
|
for (const el of val.values()) {
|
|
3779
|
-
if (el
|
|
3875
|
+
if (el?.$__) {
|
|
3780
3876
|
newSubdocs.push(el);
|
|
3781
3877
|
}
|
|
3782
3878
|
}
|
|
@@ -3823,7 +3919,7 @@ Document.prototype.$__handleReject = function handleReject(err) {
|
|
|
3823
3919
|
// emit on the Model if listening
|
|
3824
3920
|
if (this.$listeners('error').length) {
|
|
3825
3921
|
this.$emit('error', err);
|
|
3826
|
-
} else if (this.constructor.listeners
|
|
3922
|
+
} else if (this.constructor.listeners?.('error').length) {
|
|
3827
3923
|
this.constructor.emit('error', err);
|
|
3828
3924
|
}
|
|
3829
3925
|
};
|
|
@@ -3831,7 +3927,7 @@ Document.prototype.$__handleReject = function handleReject(err) {
|
|
|
3831
3927
|
/**
|
|
3832
3928
|
* Internal common logic for toObject() and toJSON()
|
|
3833
3929
|
*
|
|
3834
|
-
* @return {
|
|
3930
|
+
* @return {object}
|
|
3835
3931
|
* @api private
|
|
3836
3932
|
* @method $toObject
|
|
3837
3933
|
* @memberOf Document
|
|
@@ -3852,7 +3948,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3852
3948
|
_minimize = options.minimize;
|
|
3853
3949
|
} else if (this.$__schemaTypeOptions?.minimize != null) {
|
|
3854
3950
|
_minimize = this.$__schemaTypeOptions.minimize;
|
|
3855
|
-
} else if (defaultOptions
|
|
3951
|
+
} else if (defaultOptions?.minimize != null) {
|
|
3856
3952
|
_minimize = defaultOptions.minimize;
|
|
3857
3953
|
} else {
|
|
3858
3954
|
_minimize = this.$__schema.options.minimize;
|
|
@@ -4011,7 +4107,7 @@ Document.prototype.$__toObjectShallow = function $__toObjectShallow(schemaFields
|
|
|
4011
4107
|
/**
|
|
4012
4108
|
* Converts this document into a plain-old JavaScript object ([POJO](https://masteringjs.io/tutorials/fundamentals/pojo)).
|
|
4013
4109
|
*
|
|
4014
|
-
* Buffers are converted to instances of [mongodb.Binary](https://mongodb.github.io/node-mongodb-native/
|
|
4110
|
+
* Buffers are converted to instances of [mongodb.Binary](https://mongodb.github.io/node-mongodb-native/7.0/classes/BSON.Binary.html) for proper storage.
|
|
4015
4111
|
*
|
|
4016
4112
|
* #### Getters/Virtuals
|
|
4017
4113
|
*
|
|
@@ -4139,21 +4235,21 @@ Document.prototype.$__toObjectShallow = function $__toObjectShallow(schemaFields
|
|
|
4139
4235
|
*
|
|
4140
4236
|
* _During save, no custom options are applied to the document before being sent to the database._
|
|
4141
4237
|
*
|
|
4142
|
-
* @param {
|
|
4143
|
-
* @param {
|
|
4144
|
-
* @param {
|
|
4145
|
-
* @param {
|
|
4146
|
-
* @param {
|
|
4238
|
+
* @param {object} [options]
|
|
4239
|
+
* @param {boolean} [options.getters=false] if true, apply all getters, including virtuals
|
|
4240
|
+
* @param {boolean|object} [options.virtuals=false] if true, apply virtuals, including aliases. Use `{ getters: true, virtuals: false }` to just apply getters, not virtuals. An object of the form `{ pathsToSkip: ['someVirtual'] }` may also be used to omit specific virtuals.
|
|
4241
|
+
* @param {boolean} [options.aliases=true] if `options.virtuals = true`, you can set `options.aliases = false` to skip applying aliases. This option is a no-op if `options.virtuals = false`.
|
|
4242
|
+
* @param {boolean} [options.minimize=true] if true, omit any empty objects from the output
|
|
4147
4243
|
* @param {Function|null} [options.transform=null] if set, mongoose will call this function to allow you to transform the returned object
|
|
4148
|
-
* @param {
|
|
4149
|
-
* @param {
|
|
4150
|
-
* @param {
|
|
4151
|
-
* @param {
|
|
4152
|
-
* @param {
|
|
4153
|
-
* @param {
|
|
4154
|
-
* @param {
|
|
4155
|
-
* @return {
|
|
4156
|
-
* @see mongodb.Binary https://mongodb.github.io/node-mongodb-native/
|
|
4244
|
+
* @param {boolean} [options.depopulate=false] if true, replace any conventionally populated paths with the original id in the output. Has no affect on virtual populated paths.
|
|
4245
|
+
* @param {boolean} [options.versionKey=true] if false, exclude the version key (`__v` by default) from the output
|
|
4246
|
+
* @param {boolean} [options.flattenMaps=false] if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`.
|
|
4247
|
+
* @param {boolean} [options.flattenObjectIds=false] if true, convert any ObjectIds in the result to 24 character hex strings.
|
|
4248
|
+
* @param {boolean} [options.flattenUUIDs=false] if true, convert any UUIDs in the result to 36-character UUID strings in 8-4-4-4-12 format.
|
|
4249
|
+
* @param {boolean} [options.useProjection=false] - If true, omits fields that are excluded in this document's projection. Unless you specified a projection, this will omit any field that has `select: false` in the schema.
|
|
4250
|
+
* @param {boolean} [options.schemaFieldsOnly=false] - If true, the resulting object will only have fields that are defined in the document's schema. By default, `toObject()` returns all fields in the underlying document from MongoDB, including ones that are not listed in the schema.
|
|
4251
|
+
* @return {object} document as a plain old JavaScript object (POJO). This object may contain ObjectIds, Maps, Dates, mongodb.Binary, Buffers, and other non-POJO values.
|
|
4252
|
+
* @see mongodb.Binary https://mongodb.github.io/node-mongodb-native/7.0/classes/BSON.Binary.html
|
|
4157
4253
|
* @api public
|
|
4158
4254
|
* @memberOf Document
|
|
4159
4255
|
* @instance
|
|
@@ -4177,7 +4273,7 @@ function applyVirtuals(self, json, options, toObjectOptions) {
|
|
|
4177
4273
|
let assignPath;
|
|
4178
4274
|
let cur = self._doc;
|
|
4179
4275
|
let v;
|
|
4180
|
-
const aliases = typeof
|
|
4276
|
+
const aliases = typeof toObjectOptions?.aliases === 'boolean'
|
|
4181
4277
|
? toObjectOptions.aliases
|
|
4182
4278
|
: true;
|
|
4183
4279
|
|
|
@@ -4185,7 +4281,7 @@ function applyVirtuals(self, json, options, toObjectOptions) {
|
|
|
4185
4281
|
let virtualsToApply = null;
|
|
4186
4282
|
if (Array.isArray(options.virtuals)) {
|
|
4187
4283
|
virtualsToApply = new Set(options.virtuals);
|
|
4188
|
-
} else if (options.virtuals
|
|
4284
|
+
} else if (options.virtuals?.pathsToSkip) {
|
|
4189
4285
|
virtualsToApply = new Set(paths);
|
|
4190
4286
|
for (let i = 0; i < options.virtuals.pathsToSkip.length; i++) {
|
|
4191
4287
|
if (virtualsToApply.has(options.virtuals.pathsToSkip[i])) {
|
|
@@ -4251,8 +4347,8 @@ function applyVirtuals(self, json, options, toObjectOptions) {
|
|
|
4251
4347
|
* Applies virtuals properties to `json`.
|
|
4252
4348
|
*
|
|
4253
4349
|
* @param {Document} self
|
|
4254
|
-
* @param {
|
|
4255
|
-
* @return {
|
|
4350
|
+
* @param {object} json
|
|
4351
|
+
* @return {object} `json`
|
|
4256
4352
|
* @api private
|
|
4257
4353
|
*/
|
|
4258
4354
|
|
|
@@ -4296,9 +4392,9 @@ function applyGetters(self, json) {
|
|
|
4296
4392
|
branch[part],
|
|
4297
4393
|
self
|
|
4298
4394
|
);
|
|
4299
|
-
if (Array.isArray(branch[part]) && schema.paths[path]
|
|
4395
|
+
if (Array.isArray(branch[part]) && schema.paths[path].embeddedSchemaType) {
|
|
4300
4396
|
for (let i = 0; i < branch[part].length; ++i) {
|
|
4301
|
-
branch[part][i] = schema.paths[path]
|
|
4397
|
+
branch[part][i] = schema.paths[path].embeddedSchemaType.applyGetters(
|
|
4302
4398
|
branch[part][i],
|
|
4303
4399
|
self
|
|
4304
4400
|
);
|
|
@@ -4323,8 +4419,8 @@ function applyGetters(self, json) {
|
|
|
4323
4419
|
* Applies schema type transforms to `json`.
|
|
4324
4420
|
*
|
|
4325
4421
|
* @param {Document} self
|
|
4326
|
-
* @param {
|
|
4327
|
-
* @return {
|
|
4422
|
+
* @param {object} json
|
|
4423
|
+
* @return {object} `json`
|
|
4328
4424
|
* @api private
|
|
4329
4425
|
*/
|
|
4330
4426
|
|
|
@@ -4340,8 +4436,8 @@ function applySchemaTypeTransforms(self, json) {
|
|
|
4340
4436
|
for (const path of paths) {
|
|
4341
4437
|
const schematype = schema.paths[path];
|
|
4342
4438
|
const topLevelTransformFunction = schematype.options.transform ?? schematype.constructor?.defaultOptions?.transform;
|
|
4343
|
-
const embeddedSchemaTypeTransformFunction = schematype
|
|
4344
|
-
?? schematype
|
|
4439
|
+
const embeddedSchemaTypeTransformFunction = schematype.embeddedSchemaType?.options?.transform
|
|
4440
|
+
?? schematype.embeddedSchemaType?.constructor?.defaultOptions?.transform;
|
|
4345
4441
|
if (typeof topLevelTransformFunction === 'function') {
|
|
4346
4442
|
const val = self.$get(path);
|
|
4347
4443
|
if (val === undefined) {
|
|
@@ -4393,7 +4489,7 @@ function omitDeselectedFields(self, json) {
|
|
|
4393
4489
|
selected = {};
|
|
4394
4490
|
queryhelpers.applyPaths(selected, schema);
|
|
4395
4491
|
}
|
|
4396
|
-
if (selected == null ||
|
|
4492
|
+
if (selected == null || utils.hasOwnKeys(selected) === false) {
|
|
4397
4493
|
return json;
|
|
4398
4494
|
}
|
|
4399
4495
|
|
|
@@ -4419,12 +4515,12 @@ function omitDeselectedFields(self, json) {
|
|
|
4419
4515
|
*
|
|
4420
4516
|
* See [schema options](https://mongoosejs.com/docs/guide.html#toJSON) for more information on setting `toJSON` option defaults.
|
|
4421
4517
|
*
|
|
4422
|
-
* @param {
|
|
4423
|
-
* @param {
|
|
4424
|
-
* @param {
|
|
4425
|
-
* @param {
|
|
4426
|
-
* @param {
|
|
4427
|
-
* @return {
|
|
4518
|
+
* @param {object} options
|
|
4519
|
+
* @param {boolean} [options.flattenMaps=true] if true, convert Maps to [POJOs](https://masteringjs.io/tutorials/fundamentals/pojo). Useful if you want to `JSON.stringify()` the result.
|
|
4520
|
+
* @param {boolean} [options.flattenObjectIds=false] if true, convert any ObjectIds in the result to 24 character hex strings.
|
|
4521
|
+
* @param {boolean} [options.flattenUUIDs=false] if true, convert any UUIDs in the result to 36-character UUID strings in 8-4-4-4-12 format.
|
|
4522
|
+
* @param {boolean} [options.schemaFieldsOnly=false] - If true, the resulting object will only have fields that are defined in the document's schema. By default, `toJSON()` returns all fields in the underlying document from MongoDB, including ones that are not listed in the schema.
|
|
4523
|
+
* @return {object}
|
|
4428
4524
|
* @see Document#toObject https://mongoosejs.com/docs/api/document.html#Document.prototype.toObject()
|
|
4429
4525
|
* @see JSON.stringify() in JavaScript https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html
|
|
4430
4526
|
* @api public
|
|
@@ -4494,7 +4590,7 @@ Document.prototype.$__setParent = function $__setParent(parent) {
|
|
|
4494
4590
|
/**
|
|
4495
4591
|
* Helper for console.log
|
|
4496
4592
|
*
|
|
4497
|
-
* @return {
|
|
4593
|
+
* @return {string}
|
|
4498
4594
|
* @api public
|
|
4499
4595
|
* @method inspect
|
|
4500
4596
|
* @memberOf Document
|
|
@@ -4528,7 +4624,7 @@ if (inspect.custom) {
|
|
|
4528
4624
|
/**
|
|
4529
4625
|
* Helper for console.log
|
|
4530
4626
|
*
|
|
4531
|
-
* @return {
|
|
4627
|
+
* @return {string}
|
|
4532
4628
|
* @api public
|
|
4533
4629
|
* @method toString
|
|
4534
4630
|
* @memberOf Document
|
|
@@ -4551,7 +4647,7 @@ Document.prototype.toString = function() {
|
|
|
4551
4647
|
* `deepEqual()`.
|
|
4552
4648
|
*
|
|
4553
4649
|
* @param {Document} [doc] a document to compare. If falsy, will always return "false".
|
|
4554
|
-
* @return {
|
|
4650
|
+
* @return {boolean}
|
|
4555
4651
|
* @api public
|
|
4556
4652
|
* @memberOf Document
|
|
4557
4653
|
* @instance
|
|
@@ -4596,21 +4692,21 @@ Document.prototype.equals = function(doc) {
|
|
|
4596
4692
|
* await doc.populate('fans', '-email');
|
|
4597
4693
|
* doc.fans[0].email // undefined because of 2nd param `select`
|
|
4598
4694
|
*
|
|
4599
|
-
* @param {
|
|
4600
|
-
* @param {
|
|
4695
|
+
* @param {string|object|Array} path either the path to populate or an object specifying all parameters, or either an array of those
|
|
4696
|
+
* @param {object|string} [select] Field selection for the population query
|
|
4601
4697
|
* @param {Model} [model] The model you wish to use for population. If not specified, populate will look up the model by the name in the Schema's `ref` field.
|
|
4602
|
-
* @param {
|
|
4603
|
-
* @param {
|
|
4604
|
-
* @param {
|
|
4698
|
+
* @param {object} [match] Conditions for the population query
|
|
4699
|
+
* @param {object} [options] Options for the population query (sort, etc)
|
|
4700
|
+
* @param {string} [options.path=null] The path to populate.
|
|
4605
4701
|
* @param {string|PopulateOptions} [options.populate=null] Recursively populate paths in the populated documents. See [deep populate docs](https://mongoosejs.com/docs/populate.html#deep-populate).
|
|
4606
4702
|
* @param {boolean} [options.retainNullValues=false] by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
|
|
4607
4703
|
* @param {boolean} [options.getters=false] if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](https://mongoosejs.com/docs/schematypes.html#schematype-options).
|
|
4608
4704
|
* @param {boolean} [options.clone=false] When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
|
|
4609
|
-
* @param {
|
|
4705
|
+
* @param {object|Function} [options.match=null] Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/), or a function that returns a filter object.
|
|
4610
4706
|
* @param {Function} [options.transform=null] Function that Mongoose will call on every populated document that allows you to transform the populated document.
|
|
4611
|
-
* @param {
|
|
4612
|
-
* @param {
|
|
4613
|
-
* @param {
|
|
4707
|
+
* @param {object} [options.options=null] Additional options like `limit` and `lean`.
|
|
4708
|
+
* @param {boolean} [options.forceRepopulate=true] Set to `false` to prevent Mongoose from repopulating paths that are already populated
|
|
4709
|
+
* @param {boolean} [options.ordered=false] Set to `true` to execute any populate queries one at a time, as opposed to in parallel. We recommend setting this option to `true` if using transactions, especially if also populating multiple paths or paths with multiple models. MongoDB server does **not** support multiple operations in parallel on a single transaction.
|
|
4614
4710
|
* @param {Function} [callback] Callback
|
|
4615
4711
|
* @see population https://mongoosejs.com/docs/populate.html
|
|
4616
4712
|
* @see Query#select https://mongoosejs.com/docs/api/query.html#Query.prototype.select()
|
|
@@ -4708,10 +4804,10 @@ Document.prototype.$getPopulatedDocs = function $getPopulatedDocs() {
|
|
|
4708
4804
|
*
|
|
4709
4805
|
* If the path was not populated, returns `undefined`.
|
|
4710
4806
|
*
|
|
4711
|
-
* @param {
|
|
4712
|
-
* @param {
|
|
4713
|
-
* @param {
|
|
4714
|
-
* @return {Array|ObjectId|
|
|
4807
|
+
* @param {string} path
|
|
4808
|
+
* @param {any} [val]
|
|
4809
|
+
* @param {object} [options]
|
|
4810
|
+
* @return {Array|ObjectId|number|Buffer|string|undefined}
|
|
4715
4811
|
* @memberOf Document
|
|
4716
4812
|
* @instance
|
|
4717
4813
|
* @api public
|
|
@@ -4746,7 +4842,7 @@ Document.prototype.populated = function(path, val, options) {
|
|
|
4746
4842
|
for (let i = 0; i < pieces.length - 1; ++i) {
|
|
4747
4843
|
const subpath = pieces.slice(0, i + 1).join('.');
|
|
4748
4844
|
const subdoc = this.$get(subpath);
|
|
4749
|
-
if (subdoc
|
|
4845
|
+
if (subdoc?.$__ != null && this.$populated(subpath)) {
|
|
4750
4846
|
const rest = pieces.slice(i + 1).join('.');
|
|
4751
4847
|
subdoc.$populated(rest, val, options);
|
|
4752
4848
|
// No need to continue because the above recursion should take care of
|
|
@@ -4783,8 +4879,8 @@ Document.prototype.$populated = Document.prototype.populated;
|
|
|
4783
4879
|
* doc.$assertPopulated('likes', { likes });
|
|
4784
4880
|
*
|
|
4785
4881
|
*
|
|
4786
|
-
* @param {
|
|
4787
|
-
* @param {
|
|
4882
|
+
* @param {string|string[]} path path or array of paths to check. `$assertPopulated` throws if any of the given paths is not populated.
|
|
4883
|
+
* @param {object} [values] optional values to `$set()`. Convenient if you want to manually populate a path and assert that the path was populated in 1 call.
|
|
4788
4884
|
* @return {Document} this
|
|
4789
4885
|
* @memberOf Document
|
|
4790
4886
|
* @method $assertPopulated
|
|
@@ -4822,7 +4918,7 @@ Document.prototype.$assertPopulated = function $assertPopulated(path, values) {
|
|
|
4822
4918
|
*
|
|
4823
4919
|
* If the path was not provided, then all populated fields are returned to their unpopulated state.
|
|
4824
4920
|
*
|
|
4825
|
-
* @param {
|
|
4921
|
+
* @param {string|string[]} [path] Specific Path to depopulate. If unset, will depopulate all paths on the Document. Or multiple space-delimited paths.
|
|
4826
4922
|
* @return {Document} this
|
|
4827
4923
|
* @see Document.populate https://mongoosejs.com/docs/api/document.html#Document.prototype.populate()
|
|
4828
4924
|
* @api public
|
|
@@ -4837,7 +4933,7 @@ Document.prototype.depopulate = function(path) {
|
|
|
4837
4933
|
|
|
4838
4934
|
let populatedIds;
|
|
4839
4935
|
const virtualKeys = this.$$populatedVirtuals ? Object.keys(this.$$populatedVirtuals) : [];
|
|
4840
|
-
const populated = this.$__
|
|
4936
|
+
const populated = this.$__?.populated || {};
|
|
4841
4937
|
|
|
4842
4938
|
if (arguments.length === 0) {
|
|
4843
4939
|
// Depopulate all
|
|
@@ -4910,8 +5006,8 @@ Document.prototype.depopulate = function(path) {
|
|
|
4910
5006
|
/**
|
|
4911
5007
|
* Returns the full path to this document.
|
|
4912
5008
|
*
|
|
4913
|
-
* @param {
|
|
4914
|
-
* @return {
|
|
5009
|
+
* @param {string} [path]
|
|
5010
|
+
* @return {string}
|
|
4915
5011
|
* @api private
|
|
4916
5012
|
* @method $__fullPath
|
|
4917
5013
|
* @memberOf Document
|
|
@@ -4942,51 +5038,103 @@ Document.prototype.$__fullPath = function(path) {
|
|
|
4942
5038
|
* });
|
|
4943
5039
|
*
|
|
4944
5040
|
* // returns an empty object, no changes happened yet
|
|
4945
|
-
* user
|
|
5041
|
+
* user.$getChanges(); // { }
|
|
4946
5042
|
*
|
|
4947
5043
|
* user.country = undefined;
|
|
4948
5044
|
* user.age = 26;
|
|
4949
5045
|
*
|
|
4950
|
-
* user
|
|
5046
|
+
* user.$getChanges(); // { $set: { age: 26 }, { $unset: { country: 1 } } }
|
|
4951
5047
|
*
|
|
4952
5048
|
* await user.save();
|
|
4953
5049
|
*
|
|
4954
|
-
* user
|
|
5050
|
+
* user.$getChanges(); // { }
|
|
4955
5051
|
*
|
|
4956
|
-
* Modifying the object that
|
|
4957
|
-
* change tracking state. Even if you `delete user
|
|
5052
|
+
* Modifying the object that `$getChanges()` returns does not affect the document's
|
|
5053
|
+
* change tracking state. Even if you `delete user.$getChanges().$set`, Mongoose
|
|
4958
5054
|
* will still send a `$set` to the server.
|
|
4959
5055
|
*
|
|
4960
|
-
* @return {
|
|
5056
|
+
* @return {object}
|
|
4961
5057
|
* @api public
|
|
4962
|
-
* @method getChanges
|
|
5058
|
+
* @method $getChanges
|
|
4963
5059
|
* @memberOf Document
|
|
4964
5060
|
* @instance
|
|
4965
5061
|
*/
|
|
4966
5062
|
|
|
4967
|
-
Document.prototype
|
|
5063
|
+
Document.prototype.$getChanges = function() {
|
|
4968
5064
|
const delta = this.$__delta();
|
|
4969
5065
|
const changes = delta ? delta[1] : {};
|
|
4970
5066
|
return changes;
|
|
4971
5067
|
};
|
|
4972
5068
|
|
|
5069
|
+
/**
|
|
5070
|
+
* **Deprecated.** Use `$getChanges()` instead.
|
|
5071
|
+
*
|
|
5072
|
+
* Returns the changes that happened to the document
|
|
5073
|
+
* in the format that will be sent to MongoDB.
|
|
5074
|
+
*
|
|
5075
|
+
* @return {Object}
|
|
5076
|
+
* @deprecated Use `$getChanges()` instead. `getChanges` does not use the `$` prefix convention and may conflict with user-defined schema methods/properties.
|
|
5077
|
+
* @api public
|
|
5078
|
+
* @method getChanges
|
|
5079
|
+
* @memberOf Document
|
|
5080
|
+
* @instance
|
|
5081
|
+
*/
|
|
5082
|
+
|
|
5083
|
+
Document.prototype.getChanges = function() {
|
|
5084
|
+
utils.warn('`getChanges()` is deprecated, use `$getChanges()` instead.');
|
|
5085
|
+
return this.$getChanges();
|
|
5086
|
+
};
|
|
5087
|
+
|
|
4973
5088
|
/**
|
|
4974
5089
|
* Produces a special query document of the modified properties used in updates.
|
|
4975
5090
|
*
|
|
5091
|
+
* @param {string[]|null} [pathsToSave] paths to include in delta generation
|
|
5092
|
+
* @param {Set<string>|null} [pathsToSaveSet] pre-built Set of pathsToSave for O(1) exact lookup
|
|
4976
5093
|
* @api private
|
|
4977
5094
|
* @method $__delta
|
|
4978
5095
|
* @memberOf Document
|
|
4979
5096
|
* @instance
|
|
4980
5097
|
*/
|
|
4981
5098
|
|
|
4982
|
-
Document.prototype.$__delta = function $__delta() {
|
|
4983
|
-
const
|
|
5099
|
+
Document.prototype.$__delta = function $__delta(pathsToSave, pathsToSaveSet) {
|
|
5100
|
+
const allDirty = this.$__dirty();
|
|
5101
|
+
let dirty = allDirty;
|
|
5102
|
+
let unsavedDirty = null;
|
|
5103
|
+
if (pathsToSave != null) {
|
|
5104
|
+
dirty = [];
|
|
5105
|
+
unsavedDirty = [];
|
|
5106
|
+
for (const data of allDirty) {
|
|
5107
|
+
if (isInPathsToSave(data.path, pathsToSaveSet, pathsToSave)) {
|
|
5108
|
+
dirty.push(data);
|
|
5109
|
+
} else {
|
|
5110
|
+
unsavedDirty.push(data);
|
|
5111
|
+
}
|
|
5112
|
+
}
|
|
5113
|
+
}
|
|
4984
5114
|
const optimisticConcurrency = this.$__schema.options.optimisticConcurrency;
|
|
4985
5115
|
if (optimisticConcurrency) {
|
|
4986
5116
|
if (Array.isArray(optimisticConcurrency)) {
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
5117
|
+
if (!this.$__schema.options._optimisticConcurrencySet) {
|
|
5118
|
+
this.$__schema.options._optimisticConcurrencySet = new Set(optimisticConcurrency);
|
|
5119
|
+
}
|
|
5120
|
+
const optimisticConcurrencySet = this.$__schema.options._optimisticConcurrencySet;
|
|
5121
|
+
const modPaths = this.directModifiedPaths();
|
|
5122
|
+
const hasRelevantModPaths = pathsToSave == null ?
|
|
5123
|
+
modPaths.find(path => _pathOverlapsSet(path, optimisticConcurrencySet)) :
|
|
5124
|
+
modPaths.find(path => _pathOverlapsSet(path, optimisticConcurrencySet) && isInPathsToSave(path, pathsToSaveSet, pathsToSave));
|
|
5125
|
+
if (hasRelevantModPaths) {
|
|
5126
|
+
this.$__.version = dirty.length ? VERSION_ALL : VERSION_WHERE;
|
|
5127
|
+
}
|
|
5128
|
+
} else if (Array.isArray(optimisticConcurrency?.exclude)) {
|
|
5129
|
+
if (!this.$__schema.options._optimisticConcurrencyExcludeSet) {
|
|
5130
|
+
this.$__schema.options._optimisticConcurrencyExcludeSet = new Set(optimisticConcurrency.exclude);
|
|
5131
|
+
}
|
|
5132
|
+
const optimisticConcurrencyExcludeSet = this.$__schema.options._optimisticConcurrencyExcludeSet;
|
|
5133
|
+
const modPaths = this.directModifiedPaths();
|
|
5134
|
+
const hasRelevantModPaths = pathsToSave == null ?
|
|
5135
|
+
modPaths.find(path => !_pathOverlapsSet(path, optimisticConcurrencyExcludeSet)) :
|
|
5136
|
+
modPaths.find(path => !_pathOverlapsSet(path, optimisticConcurrencyExcludeSet) && isInPathsToSave(path, pathsToSaveSet, pathsToSave));
|
|
5137
|
+
if (hasRelevantModPaths) {
|
|
4990
5138
|
this.$__.version = dirty.length ? VERSION_ALL : VERSION_WHERE;
|
|
4991
5139
|
}
|
|
4992
5140
|
} else {
|
|
@@ -5006,7 +5154,7 @@ Document.prototype.$__delta = function $__delta() {
|
|
|
5006
5154
|
where._id = this._doc._id;
|
|
5007
5155
|
// If `_id` is an object, need to depopulate, but also need to be careful
|
|
5008
5156
|
// because `_id` can technically be null (see gh-6406)
|
|
5009
|
-
if (
|
|
5157
|
+
if (where?._id?.$__ != null) {
|
|
5010
5158
|
where._id = where._id.toObject({ transform: false, depopulate: true });
|
|
5011
5159
|
}
|
|
5012
5160
|
for (; d < len; ++d) {
|
|
@@ -5065,7 +5213,7 @@ Document.prototype.$__delta = function $__delta() {
|
|
|
5065
5213
|
value = value.toObject();
|
|
5066
5214
|
operand(this, where, delta, data, value);
|
|
5067
5215
|
} else {
|
|
5068
|
-
if (this.$__.primitiveAtomics
|
|
5216
|
+
if (this.$__.primitiveAtomics?.[data.path] != null) {
|
|
5069
5217
|
const val = this.$__.primitiveAtomics[data.path];
|
|
5070
5218
|
const op = firstKey(val);
|
|
5071
5219
|
operand(this, where, delta, data, val[op], op);
|
|
@@ -5084,18 +5232,18 @@ Document.prototype.$__delta = function $__delta() {
|
|
|
5084
5232
|
}
|
|
5085
5233
|
|
|
5086
5234
|
if (divergent.length) {
|
|
5087
|
-
|
|
5235
|
+
throw new DivergentArrayError(divergent);
|
|
5088
5236
|
}
|
|
5089
5237
|
|
|
5090
5238
|
if (this.$__.version) {
|
|
5091
5239
|
this.$__version(where, delta);
|
|
5092
5240
|
}
|
|
5093
5241
|
|
|
5094
|
-
if (
|
|
5095
|
-
return [where, null];
|
|
5242
|
+
if (utils.hasOwnKeys(delta) === false) {
|
|
5243
|
+
return [where, null, unsavedDirty];
|
|
5096
5244
|
}
|
|
5097
5245
|
|
|
5098
|
-
return [where, delta];
|
|
5246
|
+
return [where, delta, unsavedDirty];
|
|
5099
5247
|
};
|
|
5100
5248
|
|
|
5101
5249
|
/**
|
|
@@ -5104,9 +5252,9 @@ Document.prototype.$__delta = function $__delta() {
|
|
|
5104
5252
|
*
|
|
5105
5253
|
* @see https://github.com/Automattic/mongoose/issues/1334
|
|
5106
5254
|
* @param {Document} doc
|
|
5107
|
-
* @param {
|
|
5108
|
-
* @param {
|
|
5109
|
-
* @return {
|
|
5255
|
+
* @param {string} path
|
|
5256
|
+
* @param {any} array
|
|
5257
|
+
* @return {string|undefined}
|
|
5110
5258
|
* @api private
|
|
5111
5259
|
*/
|
|
5112
5260
|
|
|
@@ -5136,14 +5284,14 @@ function checkDivergentArray(doc, path, array) {
|
|
|
5136
5284
|
// elements of the array and potentially would overwrite data.
|
|
5137
5285
|
const check = pop.options.match ||
|
|
5138
5286
|
pop.options.options && Object.hasOwn(pop.options.options, 'limit') || // 0 is not permitted
|
|
5139
|
-
pop.options.options
|
|
5287
|
+
pop.options.options?.skip || // 0 is permitted
|
|
5140
5288
|
pop.options.select && // deselected _id?
|
|
5141
5289
|
(pop.options.select._id === 0 ||
|
|
5142
5290
|
/\s?-_id\s?/.test(pop.options.select));
|
|
5143
5291
|
|
|
5144
5292
|
if (check) {
|
|
5145
5293
|
const atomics = array[arrayAtomicsSymbol];
|
|
5146
|
-
if (
|
|
5294
|
+
if (utils.hasOwnKeys(atomics) === false || atomics.$set || atomics.$pop) {
|
|
5147
5295
|
return path;
|
|
5148
5296
|
}
|
|
5149
5297
|
}
|
|
@@ -5154,11 +5302,11 @@ function checkDivergentArray(doc, path, array) {
|
|
|
5154
5302
|
* well as track versioning for our where clause.
|
|
5155
5303
|
*
|
|
5156
5304
|
* @param {Document} self
|
|
5157
|
-
* @param {
|
|
5158
|
-
* @param {
|
|
5159
|
-
* @param {
|
|
5305
|
+
* @param {object} where Unused
|
|
5306
|
+
* @param {object} delta
|
|
5307
|
+
* @param {object} data
|
|
5160
5308
|
* @param {Mixed} val
|
|
5161
|
-
* @param {
|
|
5309
|
+
* @param {string} [op]
|
|
5162
5310
|
* @api private
|
|
5163
5311
|
*/
|
|
5164
5312
|
|
|
@@ -5176,7 +5324,11 @@ function operand(self, where, delta, data, val, op) {
|
|
|
5176
5324
|
// already marked for versioning?
|
|
5177
5325
|
if (VERSION_ALL === (VERSION_ALL & self.$__.version)) return;
|
|
5178
5326
|
|
|
5179
|
-
if (
|
|
5327
|
+
if (
|
|
5328
|
+
self.$__schema.options.optimisticConcurrency === true ||
|
|
5329
|
+
Array.isArray(self.$__schema.options.optimisticConcurrency) ||
|
|
5330
|
+
Array.isArray(self.$__schema.options.optimisticConcurrency?.exclude)
|
|
5331
|
+
) {
|
|
5180
5332
|
return;
|
|
5181
5333
|
}
|
|
5182
5334
|
|
|
@@ -5222,15 +5374,15 @@ function operand(self, where, delta, data, val, op) {
|
|
|
5222
5374
|
* Compiles an update and where clause for a `val` with _atomics.
|
|
5223
5375
|
*
|
|
5224
5376
|
* @param {Document} self
|
|
5225
|
-
* @param {
|
|
5226
|
-
* @param {
|
|
5227
|
-
* @param {
|
|
5377
|
+
* @param {object} where
|
|
5378
|
+
* @param {object} delta
|
|
5379
|
+
* @param {object} data
|
|
5228
5380
|
* @param {Array} value
|
|
5229
5381
|
* @api private
|
|
5230
5382
|
*/
|
|
5231
5383
|
|
|
5232
5384
|
function handleAtomics(self, where, delta, data, value) {
|
|
5233
|
-
if (delta.$set
|
|
5385
|
+
if (delta.$set?.[data.path]) {
|
|
5234
5386
|
// $set has precedence over other atomics
|
|
5235
5387
|
return;
|
|
5236
5388
|
}
|
|
@@ -5303,8 +5455,8 @@ function handleAtomics(self, where, delta, data, value) {
|
|
|
5303
5455
|
* Determines whether versioning should be skipped for the given path
|
|
5304
5456
|
*
|
|
5305
5457
|
* @param {Document} self
|
|
5306
|
-
* @param {
|
|
5307
|
-
* @return {
|
|
5458
|
+
* @param {string} path
|
|
5459
|
+
* @return {boolean} true if versioning should be skipped for the given path
|
|
5308
5460
|
* @api private
|
|
5309
5461
|
*/
|
|
5310
5462
|
function shouldSkipVersioning(self, path) {
|
|
@@ -5343,7 +5495,10 @@ Document.prototype.$clone = function() {
|
|
|
5343
5495
|
}
|
|
5344
5496
|
clonedCache[key] = clone(this.$__[key]);
|
|
5345
5497
|
}
|
|
5346
|
-
Object.assign(
|
|
5498
|
+
Object.assign(
|
|
5499
|
+
clonedCache.activePaths,
|
|
5500
|
+
clone({ ...this.$__.activePaths })
|
|
5501
|
+
);
|
|
5347
5502
|
clonedDoc.$__ = clonedCache;
|
|
5348
5503
|
}
|
|
5349
5504
|
return clonedDoc;
|
|
@@ -5505,6 +5660,32 @@ Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
|
|
|
5505
5660
|
* Module exports.
|
|
5506
5661
|
*/
|
|
5507
5662
|
|
|
5663
|
+
/*!
|
|
5664
|
+
* Check if `path`, any of its ancestor paths, or any of its descendant paths
|
|
5665
|
+
* exist in `pathSet`.
|
|
5666
|
+
* For example:
|
|
5667
|
+
* _pathOverlapsSet('profile.firstName', Set(['profile'])) === true
|
|
5668
|
+
* _pathOverlapsSet('profile', Set(['profile.firstName'])) === true
|
|
5669
|
+
*/
|
|
5670
|
+
function _pathOverlapsSet(path, pathSet) {
|
|
5671
|
+
if (pathSet.has(path)) {
|
|
5672
|
+
return true;
|
|
5673
|
+
}
|
|
5674
|
+
let idx = path.indexOf('.');
|
|
5675
|
+
while (idx !== -1) {
|
|
5676
|
+
if (pathSet.has(path.substring(0, idx))) {
|
|
5677
|
+
return true;
|
|
5678
|
+
}
|
|
5679
|
+
idx = path.indexOf('.', idx + 1);
|
|
5680
|
+
}
|
|
5681
|
+
for (const p of pathSet) {
|
|
5682
|
+
if (p.length > path.length + 1 && p[path.length] === '.' && p.slice(0, path.length) === path) {
|
|
5683
|
+
return true;
|
|
5684
|
+
}
|
|
5685
|
+
}
|
|
5686
|
+
return false;
|
|
5687
|
+
}
|
|
5688
|
+
|
|
5508
5689
|
Document.VERSION_WHERE = VERSION_WHERE;
|
|
5509
5690
|
Document.VERSION_INC = VERSION_INC;
|
|
5510
5691
|
Document.VERSION_ALL = VERSION_ALL;
|