Repository navigation
Add opt-in freezed_nullable_presence for PATCH null semantics - #478
Open
Winget-Software wants to merge 2 commits into
Open
Winget-Software wants to merge 2 commits into
Winget-Software wants to merge 2 commits into
Conversation
…mantics Optional nullable fields generated as `T? field` with `@JsonKey(includeIfNull: false)` cannot express "send an explicit null", so a PATCH body cannot clear a field: omitted and null collapse into the same Dart value. With `freezed_nullable_presence: true` (default false, freezed only, requires freezed_json_serialization), each optional nullable field gets a `<name>Present` flag: - fromJson sets the flag from `json.containsKey(key)`, so round trips keep the difference between an omitted key and an explicit null. - toJson writes `"key": null` when the value is null and the flag is set, and omits the key when it is not. Freezed JSON generation is disabled for these classes (`@Freezed(fromJson: false, toJson: false)`) and a private `@JsonSerializable()` helper keeps json_serializable doing all value conversion. Unions and classes without optional nullable fields are unchanged, and output is byte-for-byte identical when the option is off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Carapacik
self-requested a review
October 31, 2026 01:24
This branch has not been deployed
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.
Closes #477.
This PR adds an opt-in
freezed_nullable_presenceoption (defaultfalse). For Freezed models with JSON serialization enabled, it generates a<name>Presentflag next to each optional nullable property. With the flag,toJsoncan tell an omitted key from an explicitnull. A PATCH body needs that difference to clear a field without sendingnullfor every other unset field. It is the Dart counterpart of OpenAPI Generator'sopenApiNullable/JsonNullable<T>. #477 has the background and links.With the option enabled:
@Default(false) bool <name>Presentfor each property that is not required and isnullable(or references a nullable schema).@Freezed(fromJson: false, toJson: false)together with a privateconst X._()constructor.fromJson/toJson: both are generated by hand. They delegate value conversion to a private@JsonSerializable()helper class (_XJson), so enum, date, nested-model and@JsonKeyhandling stay withjson_serializable.fromJsonsets each flag fromjson.containsKey(key). For a property that isnull,toJsonwritesnullwhen the flag is set and removes the key otherwise.protectJsonKey, the same as@JsonKey(name: ...).The option is ignored, and the current output is generated, when any of these is true:
freezed_json_serialization: falseChanges:
SWPConfig/GeneratorConfig/FillController/ProgrammingLanguage: readfreezed_nullable_presencefrom YAML (inheriting from the root config) and pass it to the Freezed template, the same wayfreezed_json_serialization(using freezed required json_serializable #473) is wired.dart_freezed_dto_template.dart: presence-aware factory parameters,fromJson/toJsonand helper class. The existing@JsonKeylogic moved unchanged into_jsonKeyParams, so the helper class can reuse it.README.md: documents the option.CHANGELOG.md: adds a1.46.0entry.pubspec.yamlis left for the release commit, as in Fix properties becoming required when a sibling uses allOf #475.swp_config_test.dart: default value and YAML parsing.data_classes_test.dart: expected output for a model with an optional nullableallOfreference, a nullable string and adefaultfield. It also checks that nothing changes when the option is off orfreezed_json_serializationisfalse.patch_optional_nullablee2e test with a PATCH endpoint.With the option off, generation is byte-identical to
main, and every existing e2e expectation passes unchanged. The parser is not touched.Known trade-offs, open to discussion:
nullable: truealso get a flag. The flag is harmless, because it defaults tofalseand the field is omitted as before.copyWith:copyWith(notes: null)does not setnotesPresent. To clear a field, set the flag as well:copyWith(notes: null, notesPresent: true).notesand a realnotesPresentproperty would collide. I kept the name short and readable, but I can add a collision check or a configurable suffix if you prefer.dart format,dart analyzeand the fulldart testsuite (437 passed, 2 skipped) pass. I also enabled the option in a Flutter app with about 500 presence-tracked fields:build_runnergenerates everything without errors, and the app's test suite passes.🤖 Generated with Claude Code