Commit 86dfe93
committed
Upgrade to Zod 4
In truth, this is largely a ground-up reimplementation of our typed
model layer that takes advantage of a few years of experience working
with the original implementation. Upgrading to Zod 4 is *somewhat*
orthogonal.
My primary goal with this upgrade was to take advantage of Zod 4's
native support for JSON Schemas. There already exists a library
(zod-to-mongo-schema) which can utilize Zod's native JSON Schema support
to generate MongoDB-compatible JSON Schemas. Given that our needs here
are fairly undifferentiated, it doesn't feel like there's significant
benefit to maintaining this code ourselves. This allows us to clean up
the old code to generate JSON Schemas.
As part of this swap, we need to deal with some differences in how
zod-to-mongo-schemas represents schemas:
* Zod's `z.int()` can technically capture any (53-bit) integer value
representable in floating point, so zod-to-mongo-schema represents it
as a "long"; we previously used "int". The MongoDB Javascript driver
by default will serialize integer values to the BSON "int" type, so
this causes conflicts. Switch to `z.int32()` instead to get the
desired "int" type in the generated JSON Schema.
As always, the most complex element of our typed model layer is handling
fields which should be automatically populated. Our previous approach
(documented in #1394) was powerful and flexible, but abusing Zod's input
vs. output schemas and lying to the type system with transforms broke
down with Zod's native JSON Schemas, which refuses to serialize
transforms.
Instead of trying to modernize that approach, this commit uses two
systems to track automated fields. Within the type system, we use Zod's
branded types to mark fields which should be auto-populated (effectively
as a boolean marker), which we can then use to filter auto-populated
fields, making them optional at insertion-time. At runtime, we use
schema metadata, which captures when a field should be populated
(insert, update, or both) and what value should be used (which has been
limited to the specific types of values we actually use).
(In bringing in branded types, we do return to our old friend of
input/output schemas — auto-populated types are only branded on the
input side, which is only used for computing the insert type, since we
don't actually want nominal typing for our auto-populated fields.)
This has the effect of dropping support for arbitrary transformation
functions. In practice, we were only using that function to apply the
`answerify` transform to answer fields, but we had previously concluded
that answers were already uppercased at input time. In exchange for
dropping transforms, we no longer need to analyze the entire update
operation to make sure transformations are applied properly, and can
instead just rely on MongoDB to enforce that the result matches our
schema. This in turn lets us remove a significant amount of code around
updates (including the mechanisms around `relaxSchema` and
`parseMongoModifierAsync`).
In addition to dropping support for transform functions, I also dropped
support for the `bypassSchema` option for inserts, updates, and upserts.
This wasn't a great abstraction, since it attempted to otherwise
preserve the behavior of Meteor Collections' native methods, but had to
do some extra work to do that. Instead, users can just reach for
rawCollection. This only comes up in migration code anyway, which
generally requires a fair amount of abstraction bypass regardless.
And finally, I pulled the code into imports/lib/typedModel, rather than
leaving it strewn about with actual model declarations.1 parent 0691e58 commit 86dfe93
91 files changed
Lines changed: 1299 additions & 2903 deletions
File tree
- docs
- imports
- lib
- models
- mediasoup
- typedModel
- server
- jobs
- migrations
- models
- tests
- unit/imports/server
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
| 10 | + | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
4 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
4 | | - | |
5 | | - | |
6 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
21 | | - | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
2 | 6 | | |
3 | | - | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| |||
0 commit comments