fix: preserve middleware through validation, hydration, and query options - #16512
Draft
AbdelrahmanHafez wants to merge 53 commits into
Draft
AbdelrahmanHafez wants to merge 53 commits into
AbdelrahmanHafez wants to merge 53 commits into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes middleware forwarding, validation, hydration, and query-option bugs.
Examples are independent.
Currentmeans before this PR;Expectedmeans after the fix.Validation hooks ignore suppression in document and bulk operations
Forward selection through parent and nested validation. Schema validators still run.
Also covers document arrays, Union subdocuments, validation error hooks, and edits to existing children.
Update queries and Model.validate() lose nested validation selection
Pass the owning operation's selection into internal validators.
Also fixes
findOneAndUpdate(),replaceOne(),findOneAndReplace(), and nested array$set,$push, and$addToSetvalidation.Invalid data still fails.
middlewarealone does not enablerunValidators.bulkSave() writes documents that fail asynchronous validation
Await one validation pass before save hooks and writes.
The later operation builder skips duplicate validation.
skipValidation: trueorvalidateBeforeSave: falsebypasses validation.Timestamps and sessions retain their behavior.
bulkSave() runs child save hooks under suppression
Forward the selection to child save hooks, including independent phases.
Repeated bulkSave() calls miss newly added children
Refresh the child cache for each call.
bulkSave() adds skipValidation to caller options
Give the operation builder its own options copy.
Hooks attached directly to queries ignore middleware selection
Filter query-instance callbacks while keeping internal callbacks active.
Phase selection works too. Internal document filters and sessions still apply.
Document write hooks ignore later setOptions() middleware selection
Read effective query options when document and subdocument hooks run.
The same fix covers
doc.deleteOne()and independent pre/post selection.Document writes overwrite later query options with original options
Apply call options once. Retain later query settings and changes made through document-hook arguments.
Also fixes
doc.deleteOne(). Hook argument identity, untouched options, sessions, shard filters, and the already-deleted guard remain intact.Hook changes and removals still apply.
strict,updatePipeline, and sort options keep their existing handling.find() drops middleware selection during result hydration
Pass selection to each returned document's initialization hooks.
Built-in initialization, defaults, sessions, and population remain active.
Cursors from one query change each other's middleware selection
Capture each cursor's selection before asynchronous pre-find hooks start.
The snapshot also controls construction and post-find hooks during overlapping cursor creation.
Pre hooks can still change ordinary driver options. Later cursors still inherit the query's current selection.
Suppressing init hooks drops populated virtuals
Keep the built-in virtual initialization hook active.
Array virtuals and their existing population metadata remain intact too.
Related virtual documents lose middleware selection during hydration
Forward selection when hydrating single and array virtual values.
Each path retains its existing hydration options and population behavior.
Default-created children run init hooks under suppression
Pass selection through default creation, casting, and child initialization.
Also covers nested defaults and default single-nested children. Default values and change tracking retain their existing behavior.
watch() sends middleware to MongoDB and omits it during hydration
Remove the driver option and retain it for Mongoose hydration.
The fix covers event listeners and callback or promise
next()calls.Disabled hydration, events without
fullDocument, and valid driver options retain their behavior.aggregate.explain() ignores options changed by pre hooks
Copy driver options after enabled pre-aggregate hooks finish.
The driver copy excludes
middleware; the aggregate retains its selection.Operation options do not reach createModel hooks
Forward selection into document construction, including replacements and discriminators.
Also covers
findOne(), cursors,hydrate(),insertOne(), replacements, and bulk inserts/replacements.{ pre: false }skips these synchronous hooks;{ post: false }keeps them enabled.Options cannot undo construction completed before the operation receives them.
Query.clone() shares Mongoose and population options
Copy mutable options while preserving model, connection, session, and callback identities.
Nested population settings also stay separate.
Public types reject supported validation, hydration, and construction options
Declare the missing options and synchronous hook overload without weakening result types.
Invalid middleware values still fail type checking. The default
thistype forcreateModelisunknownbecause input is uncast.Explicit custom method/static types reject supportsMiddlewareOption
Preserve the opt-in flag, function properties, parameter types, return types, and receivers.
The middleware guide awaits an empty aggregation pipeline
Use a stage that does not depend on pre hooks.
The adjacent cursor example uses the same pipeline for consistency. It did not fail the empty-pipeline execution guard.