fix(firestore)!: decode missing keys for Optional and server-stamped fields - #85
Merged
Merged
Conversation
…fields `Firestore.Optional` database variants now use `Schema.OptionFromOptionalNullOr`, so a document without the field decodes to `Option.none()` again instead of failing with `SchemaError: Missing key` under Effect v4. `Option.none()` is still written as `null`. BREAKING CHANGE: the encoded type of `Optional` fields moves from `NullishOr<S>` to `optional(NullOr<S>)`, making the key optional in `Model.Encoded`; annotations using `Schema.OptionFromNullishOr<...>` must switch to `Schema.OptionFromOptionalNullOr<...>`. Also: - `OptionalDeletable.update` decodes a missing key and encodes `Option.none()` as an omitted key rather than `undefined`. - `DateTimeInsert`/`DateTimeUpdate`/`ServerDateTime` insert/update variants accept an omitted key for the server timestamp, so `createdAt: undefined` is no longer required. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UTvaTdYRhJ8MdaKxQ19miS
Regression test for models built from a struct whose field carries a
decoding default, and a MIGRATION note for the Effect v4 replacement of
`Schema.optionalWith(s, { default })`.
Closes #29
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTvaTdYRhJ8MdaKxQ19miS
Greptile SummaryThis PR restores missing-key decoding for optional Firestore fields and allows server-stamped fields to be omitted from write inputs.
Confidence Score: 5/5The PR appears safe to merge, with no new actionable findings and the previous nested-update omission issue fixed. The nested leaf encoder now distinguishes an omitted property from a present value, and payload assembly skips omitted leaves. Regression coverage includes dotted updates, merge updates, and deletion. The documentation-only changes since the previous review introduce no established blocking failure.
|
| Filename | Overview |
|---|---|
| packages/effect-firebase/src/lib/firestore/model/optional.ts | Updates optional-field schemas and types to support missing database keys. |
| packages/effect-firebase/src/lib/firestore/model/datetime.ts | Encodes omitted server-stamped fields as server timestamp sentinels. |
| packages/effect-firebase/src/lib/firestore/model/repository.ts | Preserves encoded key presence and skips omitted nested update leaves, addressing the previous finding. |
| packages/effect-firebase/src/lib/firestore/model/repository.spec.ts | Adds regression coverage for nested omission, delete sentinels, and spread decoding defaults. |
| packages/effect-firebase/AGENTS.md | Clarifies optional-key declarations and decoding-default usage. |
| packages/effect-firebase/MIGRATION.md | Documents changed optional-field types, omission semantics, and plain optional-field guidance. |
Reviews (3): Last reviewed commit: "docs(firestore): recommend Schema.option..." | Re-trigger Greptile
The per-path leaf encoder read the encoded property back unconditionally, so a nested `OptionalDeletable` given `Option.none()` produced a key with an `undefined` value that the Firebase SDKs reject. The encoder now reports key presence and the update loop skips omitted leaves. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UTvaTdYRhJ8MdaKxQ19miS
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UTvaTdYRhJ8MdaKxQ19miS
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.
Fixes a regression from the Effect v4 port:
Firestore.Optionaldatabase variants rejected a missing document key withSchemaError: Missing key, sogetById/queries/triggers failed on real documents that omit optional fields.Changes
Optionalselect/insert/update useSchema.OptionFromOptionalNullOr(s, { onNoneEncoding: null }). Missing key,nullandundefineddecode toOption.none();Option.none()still encodes asnull.OptionalDeletable.updateusesOptionFromOptional(Union([s, DeleteInstance])): decodes a missing key, encodesOption.none()as an omitted key instead ofundefined. Its fieldEvolve overload type is corrected to match runtime.DateTimeInsert/DateTimeUpdate/ServerDateTimeinsert/update variants targetSchema.optional(DateTimeUtc)and encode viaSchemaGetter.transformOptional, so the key can be omitted for a server timestamp.createdAt: undefinedis no longer required.Schema.optionalKey(s).pipe(Schema.withDecodingDefault(...)), the v4 form ofoptionalWith(..., { default })).Breaking (type-only)
Encoded type of
Optionalfields moves fromNullishOr<S>tooptional(NullOr<S>); the key becomes optional inModel.Encoded. Annotations usingSchema.OptionFromNullishOr<...>must switch toSchema.OptionFromOptionalNullOr<...>. A mergeupdatewhose only field isOption.none()on anOptionalDeletablenow failsinvalid-argument(empty payload).Closes #29
🤖 Generated with Claude Code
https://claude.ai/code/session_01UTvaTdYRhJ8MdaKxQ19miS
Generated by Claude Code