@nullix/zod-mongoose-studio 1.0.13 → 2.0.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.
Files changed (314) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/{Db4IAypj.js → 0J_bLG6U.js} +1 -1
  3. package/.output/public/_nuxt/{Y39o1QEi.js → 5KLjKHc1.js} +1 -1
  4. package/.output/public/_nuxt/{B4zoPYF-.js → B2UrsJHg.js} +1 -1
  5. package/.output/public/_nuxt/{BSqjh6Vk.js → BC5hGokz.js} +1 -1
  6. package/.output/public/_nuxt/{BS4yU4O0.js → BJwN20Xm.js} +1 -1
  7. package/.output/public/_nuxt/{D8_n84hl.js → BMgDPqps.js} +1 -1
  8. package/.output/public/_nuxt/{CqNsQbt9.js → B_sGF2qN.js} +1 -1
  9. package/.output/public/_nuxt/{NAqlztEN.js → BeaJ7I-K.js} +10 -10
  10. package/.output/public/_nuxt/{WZ0WK9cR.js → BkE1sm_1.js} +1 -1
  11. package/.output/public/_nuxt/{kBtP64Rx.js → CADbZwE5.js} +1 -1
  12. package/.output/public/_nuxt/{B8qGaxNm.js → CB0WRoVi.js} +1 -1
  13. package/.output/public/_nuxt/{BV6uALfO.js → CCh0PVV0.js} +1 -1
  14. package/.output/public/_nuxt/{CP9Z7-_9.js → Cr0GW7rA.js} +1 -1
  15. package/.output/public/_nuxt/{DeCqoVOS.js → DJe7Wxdv.js} +1 -1
  16. package/.output/public/_nuxt/{dBZQW7JD.js → DRBrUaE5.js} +1 -1
  17. package/.output/public/_nuxt/{Db19R32y.js → DV2n9B6m.js} +1 -1
  18. package/.output/public/_nuxt/{CvnpbYw0.js → DVD-jGiv.js} +1 -1
  19. package/.output/public/_nuxt/{BWajNATZ.js → Dk9qGA5X.js} +3 -3
  20. package/.output/public/_nuxt/builds/latest.json +1 -1
  21. package/.output/public/_nuxt/builds/meta/dc761332-547d-4953-b51d-b2d453009b48.json +1 -0
  22. package/.output/public/_nuxt/error-404.64pZEiDn.css +1 -0
  23. package/.output/public/_nuxt/error-500.DHOpI0Ir.css +1 -0
  24. package/.output/public/_nuxt/{BoHhCIKW.js → koEZfutw.js} +3 -3
  25. package/.output/public/_nuxt/{B_782F4p.js → r6LdR7DN.js} +1 -1
  26. package/.output/public/_nuxt/{BEI71c6K.js → rEfOp38p.js} +1 -1
  27. package/.output/server/chunks/_/error-500.mjs.map +1 -1
  28. package/.output/server/chunks/build/client.precomputed.mjs +1 -1
  29. package/.output/server/chunks/build/{error-404-8tbBXju4.mjs → error-404-BN-7rNE4.mjs} +4 -4
  30. package/.output/server/chunks/build/error-404-BN-7rNE4.mjs.map +1 -0
  31. package/.output/server/chunks/build/error-404-styles.Byx46oLR.mjs +8 -0
  32. package/.output/server/chunks/build/error-404-styles.Byx46oLR.mjs.map +1 -0
  33. package/.output/server/chunks/build/{error-500-DxFsom1i.mjs → error-500-DhIQ-2yt.mjs} +4 -4
  34. package/.output/server/chunks/build/error-500-DhIQ-2yt.mjs.map +1 -0
  35. package/.output/server/chunks/build/error-500-styles.BL3UT0Wa.mjs +8 -0
  36. package/.output/server/chunks/build/error-500-styles.BL3UT0Wa.mjs.map +1 -0
  37. package/.output/server/chunks/build/{index-BB-Clavm.mjs → index-Dnrh1ePF.mjs} +1 -1
  38. package/.output/server/chunks/build/index-Dnrh1ePF.mjs.map +1 -0
  39. package/.output/server/chunks/build/server.mjs +9 -9
  40. package/.output/server/chunks/build/styles.mjs +4 -4
  41. package/.output/server/chunks/nitro/nitro.mjs +333 -333
  42. package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
  43. package/.output/server/chunks/routes/renderer.mjs.map +1 -1
  44. package/.output/server/node_modules/bson/lib/bson.cjs +157 -48
  45. package/.output/server/node_modules/bson/package.json +9 -11
  46. package/.output/server/node_modules/kareem/index.js +228 -343
  47. package/.output/server/node_modules/kareem/package.json +3 -3
  48. package/.output/server/node_modules/mongodb/lib/bson.js +27 -5
  49. package/.output/server/node_modules/mongodb/lib/bulk/common.js +7 -9
  50. package/.output/server/node_modules/mongodb/lib/change_stream.js +91 -39
  51. package/.output/server/node_modules/mongodb/lib/client-side-encryption/auto_encrypter.js +21 -14
  52. package/.output/server/node_modules/mongodb/lib/client-side-encryption/client_encryption.js +2 -5
  53. package/.output/server/node_modules/mongodb/lib/client-side-encryption/errors.js +3 -1
  54. package/.output/server/node_modules/mongodb/lib/client-side-encryption/mongocryptd_manager.js +1 -1
  55. package/.output/server/node_modules/mongodb/lib/client-side-encryption/state_machine.js +1 -0
  56. package/.output/server/node_modules/mongodb/lib/cmap/auth/aws4.js +161 -0
  57. package/.output/server/node_modules/mongodb/lib/cmap/auth/aws_temporary_credentials.js +11 -58
  58. package/.output/server/node_modules/mongodb/lib/cmap/auth/gssapi.js +4 -6
  59. package/.output/server/node_modules/mongodb/lib/cmap/auth/mongo_credentials.js +2 -16
  60. package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_aws.js +14 -23
  61. package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc/azure_machine_workflow.js +3 -3
  62. package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc/gcp_machine_workflow.js +3 -3
  63. package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc/k8s_machine_workflow.js +4 -3
  64. package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc/token_machine_workflow.js +4 -3
  65. package/.output/server/node_modules/mongodb/lib/cmap/auth/mongodb_oidc.js +4 -4
  66. package/.output/server/node_modules/mongodb/lib/cmap/auth/plain.js +1 -1
  67. package/.output/server/node_modules/mongodb/lib/cmap/auth/providers.js +0 -1
  68. package/.output/server/node_modules/mongodb/lib/cmap/auth/scram.js +53 -40
  69. package/.output/server/node_modules/mongodb/lib/cmap/commands.js +46 -39
  70. package/.output/server/node_modules/mongodb/lib/cmap/connect.js +35 -3
  71. package/.output/server/node_modules/mongodb/lib/cmap/connection.js +36 -32
  72. package/.output/server/node_modules/mongodb/lib/cmap/connection_pool.js +67 -67
  73. package/.output/server/node_modules/mongodb/lib/cmap/connection_pool_events.js +3 -3
  74. package/.output/server/node_modules/mongodb/lib/cmap/errors.js +1 -1
  75. package/.output/server/node_modules/mongodb/lib/cmap/handshake/client_metadata.js +15 -13
  76. package/.output/server/node_modules/mongodb/lib/cmap/metrics.js +3 -3
  77. package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/compression.js +26 -10
  78. package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/constants.js +3 -1
  79. package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/on_data.js +0 -1
  80. package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/on_demand/document.js +9 -9
  81. package/.output/server/node_modules/mongodb/lib/cmap/wire_protocol/responses.js +2 -2
  82. package/.output/server/node_modules/mongodb/lib/collection.js +1 -1
  83. package/.output/server/node_modules/mongodb/lib/connection_string.js +30 -15
  84. package/.output/server/node_modules/mongodb/lib/cursor/abstract_cursor.js +17 -34
  85. package/.output/server/node_modules/mongodb/lib/cursor/change_stream_cursor.js +2 -2
  86. package/.output/server/node_modules/mongodb/lib/cursor/find_cursor.js +37 -26
  87. package/.output/server/node_modules/mongodb/lib/cursor/run_command_cursor.js +1 -1
  88. package/.output/server/node_modules/mongodb/lib/db.js +6 -7
  89. package/.output/server/node_modules/mongodb/lib/deps.js +0 -13
  90. package/.output/server/node_modules/mongodb/lib/error.js +7 -10
  91. package/.output/server/node_modules/mongodb/lib/gridfs/download.js +7 -6
  92. package/.output/server/node_modules/mongodb/lib/gridfs/index.js +9 -9
  93. package/.output/server/node_modules/mongodb/lib/gridfs/upload.js +17 -23
  94. package/.output/server/node_modules/mongodb/lib/index.js +2 -4
  95. package/.output/server/node_modules/mongodb/lib/mongo_client.js +58 -67
  96. package/.output/server/node_modules/mongodb/lib/mongo_client_auth_providers.js +0 -6
  97. package/.output/server/node_modules/mongodb/lib/mongo_logger.js +11 -5
  98. package/.output/server/node_modules/mongodb/lib/mongo_types.js +1 -2
  99. package/.output/server/node_modules/mongodb/lib/operations/aggregate.js +0 -3
  100. package/.output/server/node_modules/mongodb/lib/operations/create_collection.js +0 -1
  101. package/.output/server/node_modules/mongodb/lib/operations/drop.js +8 -9
  102. package/.output/server/node_modules/mongodb/lib/operations/end_sessions.js +34 -0
  103. package/.output/server/node_modules/mongodb/lib/operations/execute_operation.js +121 -45
  104. package/.output/server/node_modules/mongodb/lib/operations/operation.js +1 -0
  105. package/.output/server/node_modules/mongodb/lib/read_preference.js +10 -14
  106. package/.output/server/node_modules/mongodb/lib/runtime_adapters.js +32 -0
  107. package/.output/server/node_modules/mongodb/lib/sdam/monitor.js +8 -8
  108. package/.output/server/node_modules/mongodb/lib/sdam/server.js +55 -43
  109. package/.output/server/node_modules/mongodb/lib/sdam/server_description.js +1 -1
  110. package/.output/server/node_modules/mongodb/lib/sdam/server_selection.js +135 -72
  111. package/.output/server/node_modules/mongodb/lib/sdam/srv_polling.js +3 -3
  112. package/.output/server/node_modules/mongodb/lib/sdam/topology.js +37 -77
  113. package/.output/server/node_modules/mongodb/lib/sdam/topology_description.js +1 -1
  114. package/.output/server/node_modules/mongodb/lib/sessions.js +150 -40
  115. package/.output/server/node_modules/mongodb/lib/transactions.js +2 -13
  116. package/.output/server/node_modules/mongodb/lib/utils.js +42 -90
  117. package/.output/server/node_modules/mongodb/package.json +49 -45
  118. package/.output/server/node_modules/mongodb-connection-string-url/lib/index.js +45 -19
  119. package/.output/server/node_modules/mongodb-connection-string-url/lib/redact.js +30 -19
  120. package/.output/server/node_modules/mongodb-connection-string-url/package.json +25 -16
  121. package/.output/server/node_modules/mongoose/lib/aggregate.js +108 -127
  122. package/.output/server/node_modules/mongoose/lib/cast/bigint.js +3 -3
  123. package/.output/server/node_modules/mongoose/lib/cast/boolean.js +3 -3
  124. package/.output/server/node_modules/mongoose/lib/cast/double.js +4 -4
  125. package/.output/server/node_modules/mongoose/lib/cast/int32.js +2 -2
  126. package/.output/server/node_modules/mongoose/lib/cast/number.js +6 -6
  127. package/.output/server/node_modules/mongoose/lib/cast/string.js +3 -3
  128. package/.output/server/node_modules/mongoose/lib/cast/uuid.js +5 -48
  129. package/.output/server/node_modules/mongoose/lib/cast.js +16 -24
  130. package/.output/server/node_modules/mongoose/lib/collection.js +6 -6
  131. package/.output/server/node_modules/mongoose/lib/connection.js +108 -105
  132. package/.output/server/node_modules/mongoose/lib/cursor/aggregationCursor.js +23 -33
  133. package/.output/server/node_modules/mongoose/lib/cursor/changeStream.js +60 -40
  134. package/.output/server/node_modules/mongoose/lib/cursor/queryCursor.js +21 -25
  135. package/.output/server/node_modules/mongoose/lib/document.js +712 -531
  136. package/.output/server/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js +85 -130
  137. package/.output/server/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js +32 -41
  138. package/.output/server/node_modules/mongoose/lib/error/cast.js +21 -12
  139. package/.output/server/node_modules/mongoose/lib/error/createCollectionsError.js +2 -2
  140. package/.output/server/node_modules/mongoose/lib/error/divergentArray.js +1 -1
  141. package/.output/server/node_modules/mongoose/lib/error/eachAsyncMultiError.js +1 -1
  142. package/.output/server/node_modules/mongoose/lib/error/index.js +3 -3
  143. package/.output/server/node_modules/mongoose/lib/error/invalidSchemaOption.js +1 -1
  144. package/.output/server/node_modules/mongoose/lib/error/messages.js +1 -0
  145. package/.output/server/node_modules/mongoose/lib/error/missingSchema.js +1 -1
  146. package/.output/server/node_modules/mongoose/lib/error/objectParameter.js +4 -5
  147. package/.output/server/node_modules/mongoose/lib/error/overwriteModel.js +1 -1
  148. package/.output/server/node_modules/mongoose/lib/error/setOptionError.js +3 -3
  149. package/.output/server/node_modules/mongoose/lib/error/strict.js +3 -3
  150. package/.output/server/node_modules/mongoose/lib/error/strictPopulate.js +2 -2
  151. package/.output/server/node_modules/mongoose/lib/error/syncIndexes.js +2 -2
  152. package/.output/server/node_modules/mongoose/lib/error/validation.js +2 -10
  153. package/.output/server/node_modules/mongoose/lib/error/validator.js +1 -1
  154. package/.output/server/node_modules/mongoose/lib/error/version.js +2 -2
  155. package/.output/server/node_modules/mongoose/lib/helpers/aggregate/prepareDiscriminatorPipeline.js +4 -4
  156. package/.output/server/node_modules/mongoose/lib/helpers/buildMiddlewareFilter.js +24 -0
  157. package/.output/server/node_modules/mongoose/lib/helpers/clone.js +35 -18
  158. package/.output/server/node_modules/mongoose/lib/helpers/common.js +5 -5
  159. package/.output/server/node_modules/mongoose/lib/helpers/cursor/eachAsync.js +4 -4
  160. package/.output/server/node_modules/mongoose/lib/helpers/discriminator/getConstructor.js +1 -1
  161. package/.output/server/node_modules/mongoose/lib/helpers/discriminator/getDiscriminatorByValue.js +1 -1
  162. package/.output/server/node_modules/mongoose/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js +1 -1
  163. package/.output/server/node_modules/mongoose/lib/helpers/discriminator/mergeDiscriminatorSchema.js +10 -5
  164. package/.output/server/node_modules/mongoose/lib/helpers/document/applyDefaults.js +1 -1
  165. package/.output/server/node_modules/mongoose/lib/helpers/document/applyTimestamps.js +11 -10
  166. package/.output/server/node_modules/mongoose/lib/helpers/document/applyVirtuals.js +10 -9
  167. package/.output/server/node_modules/mongoose/lib/helpers/document/cleanModifiedSubpaths.js +1 -1
  168. package/.output/server/node_modules/mongoose/lib/helpers/document/compile.js +17 -14
  169. package/.output/server/node_modules/mongoose/lib/helpers/document/getDeepestSubdocumentForPath.js +3 -3
  170. package/.output/server/node_modules/mongoose/lib/helpers/document/getEmbeddedDiscriminatorPath.js +2 -2
  171. package/.output/server/node_modules/mongoose/lib/helpers/document/isInPathsToSave.js +24 -0
  172. package/.output/server/node_modules/mongoose/lib/helpers/get.js +1 -1
  173. package/.output/server/node_modules/mongoose/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +1 -1
  174. package/.output/server/node_modules/mongoose/lib/helpers/indexes/getRelatedIndexes.js +3 -3
  175. package/.output/server/node_modules/mongoose/lib/helpers/indexes/isIndexEqual.js +3 -4
  176. package/.output/server/node_modules/mongoose/lib/helpers/indexes/isIndexSpecEqual.js +3 -3
  177. package/.output/server/node_modules/mongoose/lib/helpers/isBsonType.js +1 -1
  178. package/.output/server/node_modules/mongoose/lib/helpers/isMongooseObject.js +1 -1
  179. package/.output/server/node_modules/mongoose/lib/helpers/isObject.js +2 -2
  180. package/.output/server/node_modules/mongoose/lib/helpers/isSimpleValidator.js +2 -2
  181. package/.output/server/node_modules/mongoose/lib/helpers/minimize.js +2 -2
  182. package/.output/server/node_modules/mongoose/lib/helpers/model/applyDefaultsToPOJO.js +2 -2
  183. package/.output/server/node_modules/mongoose/lib/helpers/model/applyHooks.js +55 -54
  184. package/.output/server/node_modules/mongoose/lib/helpers/model/applyMethods.js +2 -2
  185. package/.output/server/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js +1 -48
  186. package/.output/server/node_modules/mongoose/lib/helpers/model/castBulkWrite.js +8 -12
  187. package/.output/server/node_modules/mongoose/lib/helpers/model/discriminator.js +1 -1
  188. package/.output/server/node_modules/mongoose/lib/helpers/parallelLimit.js +18 -36
  189. package/.output/server/node_modules/mongoose/lib/helpers/pluralize.js +4 -4
  190. package/.output/server/node_modules/mongoose/lib/helpers/populate/assignRawDocsToIdStructure.js +4 -11
  191. package/.output/server/node_modules/mongoose/lib/helpers/populate/assignVals.js +10 -10
  192. package/.output/server/node_modules/mongoose/lib/helpers/populate/createPopulateQueryFilter.js +3 -3
  193. package/.output/server/node_modules/mongoose/lib/helpers/populate/getModelsMapForPopulate.js +197 -69
  194. package/.output/server/node_modules/mongoose/lib/helpers/populate/getSchemaTypes.js +15 -15
  195. package/.output/server/node_modules/mongoose/lib/helpers/populate/markArraySubdocsPopulated.js +1 -1
  196. package/.output/server/node_modules/mongoose/lib/helpers/populate/modelNamesFromRefPath.js +10 -2
  197. package/.output/server/node_modules/mongoose/lib/helpers/populate/setPopulatedVirtualValue.js +5 -5
  198. package/.output/server/node_modules/mongoose/lib/helpers/printJestWarning.js +1 -1
  199. package/.output/server/node_modules/mongoose/lib/helpers/processConnectionOptions.js +1 -1
  200. package/.output/server/node_modules/mongoose/lib/helpers/projection/hasIncludedChildren.js +1 -1
  201. package/.output/server/node_modules/mongoose/lib/helpers/projection/isPathExcluded.js +3 -3
  202. package/.output/server/node_modules/mongoose/lib/helpers/projection/isSubpath.js +1 -1
  203. package/.output/server/node_modules/mongoose/lib/helpers/projection/parseProjection.js +9 -4
  204. package/.output/server/node_modules/mongoose/lib/helpers/query/cast$expr.js +8 -10
  205. package/.output/server/node_modules/mongoose/lib/helpers/query/castFilterPath.js +1 -1
  206. package/.output/server/node_modules/mongoose/lib/helpers/query/castUpdate.js +44 -38
  207. package/.output/server/node_modules/mongoose/lib/helpers/query/getEmbeddedDiscriminatorPath.js +8 -8
  208. package/.output/server/node_modules/mongoose/lib/helpers/query/handleImmutable.js +8 -8
  209. package/.output/server/node_modules/mongoose/lib/helpers/schema/applyPlugins.js +2 -2
  210. package/.output/server/node_modules/mongoose/lib/helpers/schema/applyReadConcern.js +1 -1
  211. package/.output/server/node_modules/mongoose/lib/helpers/schema/applyWriteConcern.js +4 -2
  212. package/.output/server/node_modules/mongoose/lib/helpers/schema/getIndexes.js +5 -11
  213. package/.output/server/node_modules/mongoose/lib/helpers/schema/getSubdocumentStrictValue.js +2 -2
  214. package/.output/server/node_modules/mongoose/lib/helpers/schema/handleIdOption.js +1 -1
  215. package/.output/server/node_modules/mongoose/lib/helpers/schema/idGetter.js +1 -1
  216. package/.output/server/node_modules/mongoose/lib/helpers/schematype/handleImmutable.js +1 -1
  217. package/.output/server/node_modules/mongoose/lib/helpers/setDefaultsOnInsert.js +26 -13
  218. package/.output/server/node_modules/mongoose/lib/helpers/timestamps/setDocumentTimestamps.js +2 -2
  219. package/.output/server/node_modules/mongoose/lib/helpers/timestamps/setupTimestamps.js +60 -38
  220. package/.output/server/node_modules/mongoose/lib/helpers/update/applyTimestampsToUpdate.js +13 -10
  221. package/.output/server/node_modules/mongoose/lib/helpers/update/castArrayFilters.js +4 -4
  222. package/.output/server/node_modules/mongoose/lib/helpers/update/decorateUpdateWithVersionKey.js +1 -1
  223. package/.output/server/node_modules/mongoose/lib/helpers/update/modifiedPaths.js +2 -2
  224. package/.output/server/node_modules/mongoose/lib/helpers/update/removeUnusedArrayFilters.js +7 -2
  225. package/.output/server/node_modules/mongoose/lib/helpers/updateValidators.js +58 -119
  226. package/.output/server/node_modules/mongoose/lib/model.js +940 -946
  227. package/.output/server/node_modules/mongoose/lib/mongoose.js +131 -79
  228. package/.output/server/node_modules/mongoose/lib/options/schemaArrayOptions.js +2 -2
  229. package/.output/server/node_modules/mongoose/lib/options/schemaBufferOptions.js +1 -1
  230. package/.output/server/node_modules/mongoose/lib/options/schemaDocumentArrayOptions.js +23 -0
  231. package/.output/server/node_modules/mongoose/lib/options/schemaNumberOptions.js +3 -3
  232. package/.output/server/node_modules/mongoose/lib/options/schemaObjectIdOptions.js +2 -2
  233. package/.output/server/node_modules/mongoose/lib/options/schemaStringOptions.js +6 -6
  234. package/.output/server/node_modules/mongoose/lib/options/schemaSubdocumentOptions.js +23 -0
  235. package/.output/server/node_modules/mongoose/lib/options/schemaTypeOptions.js +27 -13
  236. package/.output/server/node_modules/mongoose/lib/options/virtualOptions.js +12 -12
  237. package/.output/server/node_modules/mongoose/lib/plugins/index.js +0 -1
  238. package/.output/server/node_modules/mongoose/lib/plugins/saveSubdocs.js +84 -92
  239. package/.output/server/node_modules/mongoose/lib/plugins/sharding.js +33 -15
  240. package/.output/server/node_modules/mongoose/lib/plugins/trackTransaction.js +29 -25
  241. package/.output/server/node_modules/mongoose/lib/query.js +700 -548
  242. package/.output/server/node_modules/mongoose/lib/queryHelpers.js +34 -32
  243. package/.output/server/node_modules/mongoose/lib/schema/array.js +69 -113
  244. package/.output/server/node_modules/mongoose/lib/schema/bigint.js +18 -20
  245. package/.output/server/node_modules/mongoose/lib/schema/boolean.js +20 -22
  246. package/.output/server/node_modules/mongoose/lib/schema/buffer.js +23 -25
  247. package/.output/server/node_modules/mongoose/lib/schema/date.js +19 -21
  248. package/.output/server/node_modules/mongoose/lib/schema/decimal128.js +16 -18
  249. package/.output/server/node_modules/mongoose/lib/schema/documentArray.js +94 -131
  250. package/.output/server/node_modules/mongoose/lib/schema/documentArrayElement.js +50 -16
  251. package/.output/server/node_modules/mongoose/lib/schema/double.js +16 -18
  252. package/.output/server/node_modules/mongoose/lib/schema/index.js +1 -0
  253. package/.output/server/node_modules/mongoose/lib/schema/int32.js +17 -19
  254. package/.output/server/node_modules/mongoose/lib/schema/map.js +17 -24
  255. package/.output/server/node_modules/mongoose/lib/schema/mixed.js +14 -14
  256. package/.output/server/node_modules/mongoose/lib/schema/number.js +38 -28
  257. package/.output/server/node_modules/mongoose/lib/schema/objectId.js +18 -20
  258. package/.output/server/node_modules/mongoose/lib/schema/operators/exists.js +1 -1
  259. package/.output/server/node_modules/mongoose/lib/schema/operators/geospatial.js +1 -1
  260. package/.output/server/node_modules/mongoose/lib/schema/operators/text.js +4 -4
  261. package/.output/server/node_modules/mongoose/lib/schema/string.js +42 -27
  262. package/.output/server/node_modules/mongoose/lib/schema/subdocument.js +47 -58
  263. package/.output/server/node_modules/mongoose/lib/schema/union.js +54 -4
  264. package/.output/server/node_modules/mongoose/lib/schema/uuid.js +17 -40
  265. package/.output/server/node_modules/mongoose/lib/schema.js +235 -176
  266. package/.output/server/node_modules/mongoose/lib/schemaType.js +227 -158
  267. package/.output/server/node_modules/mongoose/lib/stateMachine.js +5 -8
  268. package/.output/server/node_modules/mongoose/lib/types/array/index.js +5 -5
  269. package/.output/server/node_modules/mongoose/lib/types/array/methods/index.js +27 -28
  270. package/.output/server/node_modules/mongoose/lib/types/arraySubdocument.js +11 -11
  271. package/.output/server/node_modules/mongoose/lib/types/buffer.js +15 -15
  272. package/.output/server/node_modules/mongoose/lib/types/decimal128.js +1 -1
  273. package/.output/server/node_modules/mongoose/lib/types/documentArray/index.js +4 -4
  274. package/.output/server/node_modules/mongoose/lib/types/documentArray/methods/index.js +15 -13
  275. package/.output/server/node_modules/mongoose/lib/types/double.js +1 -1
  276. package/.output/server/node_modules/mongoose/lib/types/map.js +20 -71
  277. package/.output/server/node_modules/mongoose/lib/types/objectid.js +1 -1
  278. package/.output/server/node_modules/mongoose/lib/types/subdocument.js +32 -81
  279. package/.output/server/node_modules/mongoose/lib/types/uuid.js +1 -1
  280. package/.output/server/node_modules/mongoose/lib/utils.js +91 -70
  281. package/.output/server/node_modules/mongoose/lib/validOptions.js +4 -3
  282. package/.output/server/node_modules/mongoose/lib/virtualType.js +18 -18
  283. package/.output/server/node_modules/mongoose/package.json +46 -63
  284. package/.output/server/node_modules/mquery/lib/collection/collection.js +3 -1
  285. package/.output/server/node_modules/mquery/lib/collection/node.js +17 -3
  286. package/.output/server/node_modules/mquery/lib/mquery.js +136 -93
  287. package/.output/server/node_modules/mquery/lib/permissions.js +21 -6
  288. package/.output/server/node_modules/mquery/package.json +4 -7
  289. package/.output/server/package.json +7 -9
  290. package/package.json +3 -3
  291. package/.output/public/_nuxt/builds/meta/0d6006db-fbb0-4297-85cf-bf92ceafcb79.json +0 -1
  292. package/.output/public/_nuxt/error-404.CTWLHxjC.css +0 -1
  293. package/.output/public/_nuxt/error-500.UBfk8-QP.css +0 -1
  294. package/.output/server/chunks/build/error-404-8tbBXju4.mjs.map +0 -1
  295. package/.output/server/chunks/build/error-404-styles.BeWfK6Py.mjs +0 -8
  296. package/.output/server/chunks/build/error-404-styles.BeWfK6Py.mjs.map +0 -1
  297. package/.output/server/chunks/build/error-500-DxFsom1i.mjs.map +0 -1
  298. package/.output/server/chunks/build/error-500-styles.CPUUvoY-.mjs +0 -8
  299. package/.output/server/chunks/build/error-500-styles.CPUUvoY-.mjs.map +0 -1
  300. package/.output/server/chunks/build/index-BB-Clavm.mjs.map +0 -1
  301. package/.output/server/node_modules/debug/package.json +0 -64
  302. package/.output/server/node_modules/debug/src/browser.js +0 -272
  303. package/.output/server/node_modules/debug/src/common.js +0 -292
  304. package/.output/server/node_modules/debug/src/index.js +0 -10
  305. package/.output/server/node_modules/debug/src/node.js +0 -263
  306. package/.output/server/node_modules/mongodb/lib/client-side-encryption/crypto_callbacks.js +0 -81
  307. package/.output/server/node_modules/mongodb/lib/resource_management.js +0 -58
  308. package/.output/server/node_modules/mongoose/lib/browserDocument.js +0 -101
  309. package/.output/server/node_modules/mongoose/lib/documentProvider.js +0 -30
  310. package/.output/server/node_modules/mongoose/lib/helpers/createJSONSchemaTypeDefinition.js +0 -24
  311. package/.output/server/node_modules/mongoose/lib/helpers/promiseOrCallback.js +0 -54
  312. package/.output/server/node_modules/mongoose/lib/plugins/validateBeforeSave.js +0 -51
  313. package/.output/server/node_modules/supports-color/index.js +0 -202
  314. 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 {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.
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, skipId, options) {
90
- if (typeof skipId === 'object' && skipId != null) {
91
- options = skipId;
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 = skipId;
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) && Object.keys(fields).length > 0) {
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 {Object} obj
551
- * @param {Object} [fields]
552
- * @param {Boolean} [skipId]
553
- * @param {Boolean} [exclude]
554
- * @param {Object} [hasIncludedChildren]
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 {Object} doc raw document returned by mongo
639
- * @param {Object} [opts]
640
- * @param {Boolean} [opts.hydratedPopulatedDocs=false] If true, hydrate and mark as populated any paths that are populated in the raw document
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 {Object} [opts]
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 == null || child.$__ == null) {
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 {Object} self document instance
731
- * @param {Object} obj raw mongodb doc
732
- * @param {Object} doc object we are initializing
733
- * @param {Object} [opts] Optional Options
734
- * @param {Boolean} [opts.setters] Call `applySetters` instead of `cast`
735
- * @param {String} [prefix] Prefix to add to each path
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 && opts.setters) {
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] && doc[i].$__ && doc[i].$__.wasPopulated) {
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 {Object} update
854
- * @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
855
- * @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).
856
- * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
857
- * @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.
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, callback) {
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(cb) {
868
- self.constructor._middleware.execPre('updateOne', self, [self, update, options], (err, res) => {
869
- this.updateOne({ _id: self._doc._id }, update, options);
870
- if (self.$session() != null) {
871
- if (!('session' in query.options)) {
872
- query.options.session = self.$session();
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
- return cb(err, res);
876
- });
895
+ }
896
+ return res;
877
897
  });
878
- query.post(function queryPostUpdateOne(cb) {
879
- self.constructor._middleware.execPost('updateOne', self, [self], {}, cb);
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 {Object} doc
898
- * @param {Object} [options]
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 != null && this.$__.session.hasEnded) {
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 != null && session.hasEnded) {
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 {Boolean} [value] overwrite the current session
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 {Object} obj the object to overwrite this document with
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 = Array.from(new Set(Object.keys(this._doc).concat(Object.keys(obj))));
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 (this.$__schema.options.versionKey && key === this.$__schema.options.versionKey) {
1048
+ if (schemaOptions.versionKey && key === schemaOptions.versionKey) {
1029
1049
  continue;
1030
1050
  }
1031
- if (this.$__schema.options.discriminatorKey && key === this.$__schema.options.discriminatorKey) {
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 {String|Object} path path or object of key/vals to set
1044
- * @param {Any} val the value to set
1045
- * @param {Schema|String|Number|Buffer|*} [type] optionally specify a type for "on-the-fly" attributes
1046
- * @param {Object} [options] optionally specify options that modify the behavior of the set
1047
- * @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);`
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 && options.merge;
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 && options._skipMinimizeTopLevel || false;
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
- const refPath = schema.options.refPath;
1431
+ let refPath = schema.options.refPath;
1412
1432
  if (refPath == null) {
1413
1433
  return false;
1414
1434
  }
1415
- const modelName = val.get(refPath);
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 = (schema && schema.$isSingleNested) ? schema.cast(val, this) : val._doc._id;
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 != null && options.overwriteImmutable) {
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 {String|Object} path path or object of key/vals to set
1600
- * @param {Any} val the value to set
1601
- * @param {Schema|String|Number|Buffer|*} [type] optionally specify a type for "on-the-fly" attributes
1602
- * @param {Object} [options] optionally specify options that modify the behavior of the set
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 {String|Symbol} path
1617
- * @param {Object} options
1618
- * @param {Any} constructing
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 {Any} val
1622
- * @param {Any} priorVal
1623
- * @return {Boolean}
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 && options._skipMarkModified) {
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 {String} pathToMark
1681
- * @param {String|Symbol} path
1682
- * @param {Object} options
1683
- * @param {Any} constructing
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 {Any} val
1687
- * @param {Any} priorVal
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.$__shouldModify(pathToMark, path, options, constructing, parts,
1698
- schema, val, priorVal);
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 && this.$__.primitiveAtomics[path]) {
1734
+ if (this.$__.primitiveAtomics?.[path]) {
1702
1735
  delete this.$__.primitiveAtomics[path];
1703
- if (Object.keys(this.$__.primitiveAtomics).length === 0) {
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 {String} path
1792
- * @return {Any} Returns the value from the given `path`.
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 {String|Array} path path or paths to update
1825
- * @param {Number} val increment `path` by this value
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 {String} path
1883
- * @param {Object} value
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 {String} path
1905
- * @param {Schema|String|Number|Buffer|*} [type] optionally specify a type for on-the-fly attributes
1906
- * @param {Object} [options]
1907
- * @param {Boolean} [options.virtuals=false] Apply virtuals before getting this path
1908
- * @param {Boolean} [options.getters=true] If false, skip applying getters and just get the raw value
1909
- * @return {Any}
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 != null && schema.instance === 'Mixed') {
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 && obj._doc) {
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 {String} path
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 {String} path the path to mark modified
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 {String} path the path to unmark modified
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 {String} path the path to ignore
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 {String[]}
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 {String} [path]
2177
+ * @param {string} [path]
2146
2178
  * @memberOf Document
2147
2179
  * @instance
2148
2180
  * @api public
2149
2181
  * @method $isEmpty
2150
- * @return {Boolean}
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 {Object} [options]
2201
- * @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`.
2202
- * @return {String[]}
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 {String} [path] optional
2282
- * @param {Object} [options]
2283
- * @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()`
2284
- * @return {Boolean}
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 && options.ignoreAtomics;
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 != null && value[arrayAtomicsSymbol] != null && value[arrayAtomicsSymbol].$set === undefined) {
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 {String} [path]
2356
- * @return {Boolean}
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 {Boolean} [val] optional, overrides whether mongoose thinks the doc is deleted
2392
- * @return {Boolean|Document} whether mongoose thinks this doc is deleted.
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 {String|String[]} [path]
2418
- * @return {Boolean}
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 != null && subdoc.$__ != null && subdoc.isDirectModified(pieces.slice(i + 1).join('.'))) {
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 {String} [path]
2457
- * @return {Boolean}
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 {String|String[]} path
2488
- * @return {Boolean}
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 {String} path
2570
- * @return {Boolean}
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|String} [pathsToValidate] list of paths to validate. If set, Mongoose will validate only the modified paths that are in the given list.
2632
- * @param {Object} [options] internal options
2633
- * @param {Boolean} [options.validateModifiedOnly=false] if `true` mongoose validates only modified paths.
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 && options._skipParallelValidateCheck;
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
- return new Promise((resolve, reject) => {
2666
- this.$__validate(pathsToValidate, options, (error) => {
2667
- this.$op = null;
2668
- this.$__.validating = null;
2669
- if (error != null) {
2670
- return reject(error);
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
- resolve();
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
- * ignore
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 (p != null && typeof p.originalRequiredValue === 'function') {
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 && arr.length) {
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
- for (const path of paths) {
2810
- const _pathType = doc.$__schema.path(path);
2811
- if (!_pathType) {
2812
- continue;
2813
- }
2814
-
2815
- if (_pathType.$isMongooseDocumentArray) {
2816
- for (const p of paths) {
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
- !(_pathType && _pathType.schemaOptions && _pathType.schemaOptions.required))) {
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.$embeddedSchemaType.$isMongooseArray && // and arrays of arrays
2922
- _pathType.$embeddedSchemaType.validators.length === 0) {
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.$__validate = function(pathsToValidate, options, callback) {
2949
- if (this.$__.saveOptions && this.$__.saveOptions.pathsToSave && !pathsToValidate) {
2950
- pathsToValidate = [...this.$__.saveOptions.pathsToSave];
2951
- } else if (typeof pathsToValidate === 'function') {
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
- function complete() {
3150
- const error = _complete();
3151
- if (error) {
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 {Object} [options] options for validation
3222
- * @param {Boolean} [options.validateModifiedOnly=false] If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
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 && options.pathsToSkip;
3310
+ let pathsToSkip = options?.pathsToSkip;
3248
3311
 
3249
- const validateAllPaths = options && options.validateAllPaths;
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 || !schemaType.$isMongooseArray) {
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 {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.
3372
- * @param {String|Error} err the error which states the reason `path` was invalid
3373
- * @param {Object|String|Number|any} val optional invalid value
3374
- * @param {String} [kind] optional `kind` property for the error
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 {String} path the field to mark as valid
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 || !this.$__.validationError.errors[path]) {
3479
+ if (!this.$__.validationError?.errors[path]) {
3417
3480
  return;
3418
3481
  }
3419
3482
 
3420
3483
  delete this.$__.validationError.errors[path];
3421
- if (Object.keys(this.$__.validationError.errors).length === 0) {
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 (Object.keys(doc.$__.validationError.errors).length === 0) {
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 {Object} [options] options optional options
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 {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](https://mongoosejs.com/docs/guide.html#safe). Use the `w` option instead.
3489
- * @param {Boolean} [options.validateBeforeSave] set to false to save without validating.
3490
- * @param {Boolean} [options.validateModifiedOnly=false] If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
3491
- * @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)
3492
- * @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)
3493
- * @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).
3494
- * @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)
3495
- * @param {Boolean} [options.timestamps=true] if `false` and [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this `save()`.
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 {String|String[]} [path] the field to check. If unset will always return "false"
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 || Object.keys(this.$__.validationError.errors).length === 0) {
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
- // Skip for subdocuments
3547
- const subdocs = !this.$isSubdocument ? this.$getAllSubdocs({ useCache: true }) : null;
3548
- if (subdocs && subdocs.length > 0) {
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
- // clear atomics
3555
- this.$__dirty().forEach(function(dirt) {
3556
- const type = dirt.value;
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 == null || this.$__.backup.activePaths == null) {
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 && type[arrayAtomicsSymbol] && type[arrayAtomicsBackupSymbol]) {
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 (top == null) {
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 {Object} [options] options. Currently for internal use.
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 != null && 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 != null && 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 && this.constructor.listeners('error').length) {
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 {Object}
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 != null && defaultOptions.minimize != null) {
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/4.9/classes/Binary.html) for proper storage.
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 {Object} [options]
4143
- * @param {Boolean} [options.getters=false] if true, apply all getters, including virtuals
4144
- * @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.
4145
- * @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`.
4146
- * @param {Boolean} [options.minimize=true] if true, omit any empty objects from the output
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 {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.
4149
- * @param {Boolean} [options.versionKey=true] if false, exclude the version key (`__v` by default) from the output
4150
- * @param {Boolean} [options.flattenMaps=false] if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`.
4151
- * @param {Boolean} [options.flattenObjectIds=false] if true, convert any ObjectIds in the result to 24 character hex strings.
4152
- * @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.
4153
- * @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.
4154
- * @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.
4155
- * @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.
4156
- * @see mongodb.Binary https://mongodb.github.io/node-mongodb-native/4.9/classes/Binary.html
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 (toObjectOptions && toObjectOptions.aliases) === 'boolean'
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 && options.virtuals.pathsToSkip) {
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 {Object} json
4255
- * @return {Object} `json`
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].$embeddedSchemaType) {
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].$embeddedSchemaType.applyGetters(
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 {Object} json
4327
- * @return {Object} `json`
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.$embeddedSchemaType?.options?.transform
4344
- ?? schematype.$embeddedSchemaType?.constructor?.defaultOptions?.transform;
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 || Object.keys(selected).length === 0) {
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 {Object} options
4423
- * @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.
4424
- * @param {Boolean} [options.flattenObjectIds=false] if true, convert any ObjectIds in the result to 24 character hex strings.
4425
- * @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.
4426
- * @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.
4427
- * @return {Object}
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 {String}
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 {String}
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 {Boolean}
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 {String|Object|Array} path either the path to populate or an object specifying all parameters, or either an array of those
4600
- * @param {Object|String} [select] Field selection for the population query
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 {Object} [match] Conditions for the population query
4603
- * @param {Object} [options] Options for the population query (sort, etc)
4604
- * @param {String} [options.path=null] The path to populate.
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 {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.
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 {Object} [options.options=null] Additional options like `limit` and `lean`.
4612
- * @param {Boolean} [options.forceRepopulate=true] Set to `false` to prevent Mongoose from repopulating paths that are already populated
4613
- * @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.
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 {String} path
4712
- * @param {Any} [val]
4713
- * @param {Object} [options]
4714
- * @return {Array|ObjectId|Number|Buffer|String|undefined}
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 != null && subdoc.$__ != null && this.$populated(subpath)) {
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 {String|String[]} path path or array of paths to check. `$assertPopulated` throws if any of the given paths is not populated.
4787
- * @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.
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 {String|String[]} [path] Specific Path to depopulate. If unset, will depopulate all paths on the Document. Or multiple space-delimited paths.
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.$__ && this.$__.populated || {};
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 {String} [path]
4914
- * @return {String}
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.getChanges(); // { }
5041
+ * user.$getChanges(); // { }
4946
5042
  *
4947
5043
  * user.country = undefined;
4948
5044
  * user.age = 26;
4949
5045
  *
4950
- * user.getChanges(); // { $set: { age: 26 }, { $unset: { country: 1 } } }
5046
+ * user.$getChanges(); // { $set: { age: 26 }, { $unset: { country: 1 } } }
4951
5047
  *
4952
5048
  * await user.save();
4953
5049
  *
4954
- * user.getChanges(); // { }
5050
+ * user.$getChanges(); // { }
4955
5051
  *
4956
- * Modifying the object that `getChanges()` returns does not affect the document's
4957
- * change tracking state. Even if you `delete user.getChanges().$set`, Mongoose
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 {Object}
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.getChanges = function() {
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 dirty = this.$__dirty();
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
- const optCon = new Set(optimisticConcurrency);
4988
- const modPaths = this.modifiedPaths();
4989
- if (modPaths.find(path => optCon.has(path))) {
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 ((where && where._id && where._id.$__ || null) != null) {
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 && this.$__.primitiveAtomics[data.path] != null) {
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
- return new DivergentArrayError(divergent);
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 (Object.keys(delta).length === 0) {
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 {String} path
5108
- * @param {Any} array
5109
- * @return {String|undefined}
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 && pop.options.options.skip || // 0 is permitted
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 (Object.keys(atomics).length === 0 || atomics.$set || atomics.$pop) {
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 {Object} where Unused
5158
- * @param {Object} delta
5159
- * @param {Object} data
5305
+ * @param {object} where Unused
5306
+ * @param {object} delta
5307
+ * @param {object} data
5160
5308
  * @param {Mixed} val
5161
- * @param {String} [op]
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 (self.$__schema.options.optimisticConcurrency) {
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 {Object} where
5226
- * @param {Object} delta
5227
- * @param {Object} data
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 && delta.$set[data.path]) {
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 {String} path
5307
- * @return {Boolean} true if versioning should be skipped for the given path
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(clonedCache.activePaths, clone({ ...this.$__.activePaths }));
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;