Repository navigation
feat(codecs): add empty_or_null codec for nullable typed codes across Rust and Go - #382
Merged
Merged
Conversation
This adds a new field codec that decodes a required wire key holding a typed code whose absent value the provider sends as `""` or JSON null, per ADR 0033 (#368). Both spellings decode to `None`, while any other value is parsed with the type's `FromStr`, so whitespace-only or control-bearing input remains a decode error that never echoes the value. The key stays required, matching `required_option`, and `None` re-encodes as null through serde's default serialization. **New codec:** * Added the `empty_or_null` module in `crates/libfmp/src/codecs.rs`, applied via `deserialize_with = "crate::codecs::empty_or_null::deserialize"` (the exact path gen_go matches). * Added a test covering empty/null-to-`None` mapping, round-trip serialization, missing-field errors, and that decode errors never contain the offending value. **Documentation:** * Added ADR 0033 describing nullable response members. * Extended ADR 0001 to cover observed wire evidence where a typed code or date seen as `""` or null decodes to `None`. * Updated ADR 0030 to document the fifth Go field codec introduced by ADR 0033.
This pull request adds support for the `empty_or_null` typed-code codec in the Go model generator, so Rust fields using `crate::codecs::empty_or_null::deserialize` on an `Option` of a string-backed type map to a nil-able Go pointer. **Codec support:** * Added the `EmptyOrNullString` variant and its `EMPTY_OR_NULL_CODEC` path, mapping an `Option` of a string-backed scalar to a `*string` public type backed by a `jsontext.Value` shadow, and rejecting any other shape with an explanatory error. * Treated the key as required and decoded both `""` and null to nil through the raw shadow, per ADR 0033. **Testing:** * Added a test that decodes empty and null values to nil through the raw shadow, checks the rendered public and shadow tags, the required-key handling, and the generated unmarshal body, and asserts that non-string and bare shapes fail with an `empty_or_null` error.
Link ADR 0033 in the design index, covering nullable response members and how `""` or null on typed codes and dates decode to `None` / `nil` based on observed wire evidence.
benbenbang
enabled auto-merge (rebase)
September 30, 2026 12:14
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.
Providers sometimes send nullable typed codes as an empty string or JSON null on a key that is otherwise required. To handle these consistently and safely, this change introduces a dedicated codec that maps both spellings to an absent value while keeping decode errors from leaking the offending input, as specified by ADR 0033.
What changed:
empty_or_nullfield codec in libfmp, decoding""and null toNone, parsing other values viaFromStr, keeping the key required, and re-encodingNoneas null.EmptyOrNullStringvariant that maps an optional string-backed scalar to a nil-able*stringbacked by ajsontext.Valueshadow, rejecting unsupported shapes with a clear error.