-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
types: avoid FlattenMaps by default on toObject(), toJSON(), lean() #15518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: vkarpov15/schema-create
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR changes the default behavior so that Maps are no longer flattened by default in toObject()
, toJSON()
, and .lean()
calls, updating types and tests accordingly.
- Convert default Map outputs to
Record<string, …>
in generated types - Introduce explicit
flattenMaps: true
intoJSON()
tests - Add/adjust tests for
.lean()
map output and model instance methods
Reviewed Changes
Copilot reviewed 4 out of 10 changed files in this pull request and generated no comments.
File | Description |
---|---|
test/types/schema.create.test.ts | Updated schema typing from Map to Record<string, …> and added RawDocType3 for object vs. hydrated doc tests |
test/types/models.test.ts | Imported ObtainSchemaGeneric , changed expectType → expectAssignable , and instantiated ProjectModel to test instance methods |
test/types/maps.test.ts | Modified toJSON() call to include { flattenMaps: true } in map tests |
test/types/lean.test.ts | Added a new .lean() case verifying that Maps default to Record<string, …> |
Comments suppressed due to low confidence (2)
test/types/maps.test.ts:73
- Consider adding a test for the default
toJSON()
behavior (withoutflattenMaps
) to ensuremap1
remains aMap
whenflattenMaps
is not specified.
doc.toJSON({ flattenMaps: true }).map1.foo;
test/types/models.test.ts:580
- Await the Promise returned by
doSomething()
to prevent unhandled promise rejections, e.g.,await doc.doSomething();
.
doc.doSomething();
…anResultType can be computed by the same helper re: #13523
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Requires minimal changes to typegoose's tests, once something that was written wrongly by typegoose and once because it explicitly tested against having FlattenMaps
in a toJSON()
.
Is it intentional to target branch vkarpov15/schema-create
instead of 9.0
?
Potential consolidation we could do: make toObject() and toJSON() convert Buffers to mongodb.Binary, in both JS runtime and TypeScript types. This would be a breaking change, and most likely cause some headache for application developers because Binary and Buffer end up with different representations in JSON. But this would reduce the number of types we need to support in TypeScript. WDYT?
I dont have particular feelings about that, but it seems like it Binary
is base64 encoded and so requires less storage in json, but at the same time seemingly does not have a identifier marking it as a Buffer
or Binary
like Buffer
has.
Maybe make it toggle-able via similar options to flattenObjectIds
/ flattenMaps
?
@@ -256,23 +256,34 @@ declare module 'mongoose' { | |||
set(value: string | Record<string, any>): this; | |||
|
|||
/** The return value of this method is used in calls to JSON.stringify(doc). */ | |||
toJSON(options: ToObjectOptions & { flattenMaps: true, flattenObjectIds: true, virtuals: true }): FlattenMaps<ObjectIdToString<Default__v<Require_id<DocType & TVirtuals>>>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should those options be listed in ToObjectOptions
with documentation?
To avoid potential future conflict with Automattic/mongoose#15518 .
Yes, intentional to branch off of For now, I'll hold off on making |
Re: #13523
Summary
FlattenMaps
,BufferToBinary
, and similar recursive type transformations can be problematic with user-specified types because they end up transforming custom objects into records with no good workaround.The example from #13523 still fails. Another example is the following:
In general, I want us to minimize type transformations like this in favor of inferring from the schema definition, which is what
Schema.create()
does.With this PR,
toObject()
,toJSON()
, andlean()
no longerFlattenMaps
orBufferToBinary
by default. To support the unfortunate inconsistency thatlean()
returns Buffers asmongodb.Binary
buttoObject()
,toJSON()
etc. use Buffers, I added aTLeanResultType
to schemas.For backwards compatibility, I moved
BufferToBinary<>
into the schema class-level generics for definingTLeanResultType<>
. However, with this PR we won't FlattenMaps by default, so users who put maps in their raw doc type likenew Schema<{ myMap: Map<string, string> }>
will need to either change from using maps in raw doc type, or setflattenMaps
explicitly intoObject()
and uselean<FlattenMaps<RawDocType>>
for lean queries.Potential consolidation we could do: make
toObject()
andtoJSON()
convert Buffers to mongodb.Binary, in both JS runtime and TypeScript types. This would be a breaking change, and most likely cause some headache for application developers because Binary and Buffer end up with different representations in JSON. But this would reduce the number of types we need to support in TypeScript. WDYT?Examples