Skip to content

fix(lokerpc/codegen): pointerize optional scalar fields in go output - #39

Open
MrDwarf7 wants to merge 2 commits into
masterfrom
feat/go-codegen-optional-scalars
Open

MrDwarf7 wants to merge 2 commits into
masterfrom
feat/go-codegen-optional-scalars

Conversation

@MrDwarf7

@MrDwarf7 MrDwarf7 commented Sep 24, 2026 •

Copy link
Copy Markdown

Internal change only

Optional string, bool, float, enum, timestamp and object properties in generated Go clients now render as pointers, as optional integers already did. As value types an absent field and a legitimate zero decode the same way: an absent timestamp decodes to time.Time{}, and an absent object is only detectable by guessing from a field like id != "". Collections keep omitzero, since a nil slice or map already means absent.

This changes the shape of every generated Go client. Consumers of optional scalars and objects need a pass to dereference them.

Screenshots / Videos

Updated goldens under lokerpc/codegen/testdata/ (optional-collections, optional-refs) show optional scalars, enums and objects as pointers with omitempty, while collections keep omitzero.

I have:

  • Run and tested the code and provided clear evidence of this above
  • Self reviewed the code and removed extraneous comments, debug logging, checked code style
  • Listed any dependant PRs required for this change
  • Added tests where practical and possible
  • Documented a way to roll this change back if it is more than a code revert

all the above must be ticked

@MrDwarf7
MrDwarf7 force-pushed the feat/go-codegen-optional-scalars branch from 7e03fbd to 7b1aa83 Compare September 24, 2026 21:01
@MrDwarf7 MrDwarf7 self-assigned this Sep 25, 2026
@MrDwarf7
MrDwarf7 requested review from a team and zgatt-loke and removed request for a team September 25, 2026 04:23
@MrDwarf7
MrDwarf7 force-pushed the feat/go-codegen-optional-scalars branch from 7b1aa83 to e44b749 Compare September 28, 2026 00:54
@MrDwarf7
MrDwarf7 force-pushed the feat/go-codegen-discriminators branch from f4e0045 to 16b112c Compare September 28, 2026 00:54
@MrDwarf7
MrDwarf7 requested a review from J-tt September 28, 2026 00:54
@MrDwarf7
MrDwarf7 changed the base branch from feat/go-codegen-discriminators to master September 28, 2026 00:54
@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 0784f4a2-ad88-475f-b683-0f8be64d02ba
📥 Commits

Reviewing files that changed from the base of the PR and between e44b749 and 89c9ba4.

📒 Files selected for processing: 2
  • lokerpc/codegen/go.go
  • lokerpc/codegen/testdata/discriminator.json.go

Included review availability: This review used your included allowance. 4 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.

📝 Walkthrough

The Go code generator now renders optional scalar, enum, object, and discriminator fields as pointers with omitempty. The fixtures add an optional enum and an optional object reference, with matching Go and TypeScript generated declarations.

Suggested reviewers: thejacob1000

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to 89c9b

No actionable issue remains; this change is mergeable after normal checks.

Security architecture risk: 🔵 Low · up to e44b7

The change makes missing optional values distinguishable from legitimate zero values, but changes generated Go field types. No new security boundary or exposed entrypoint was identified; the impact on deployed consumers remains unknown.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — Generated consumers can inherit the changed representation of decoded optional fields, but the evidenced exported example types are golden fixtures. Their production reachability and maximum affected scope are unknown.

Hardening Proposals

  • proposed — Before regenerating deployed clients, identify consumers that make security-sensitive decisions from optional timestamps, flags, or objects, and verify their handling of both missing and present-zero values.
Pre-merge checks: Passed 5
Check name Status Explanation
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 6 files.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title clearly and concisely describes the main change: optional scalar fields in generated Go output now use pointers.
Description check Passed The description directly explains the pointer conversion, its rationale, collection behavior, generated goldens, and consumer impact.

Comment @coderabbitai help to get the list of available commands.

@zgatt-loke
zgatt-loke removed their request for review September 28, 2026 02:34
@THEjacob1000

Copy link
Copy Markdown
Contributor

timestamps don't need to be pointers, #36 went with time.Time + omitzero on purpose and IsZero() already reads absence correctly since year 1 is never a real value. same for enums, "" isn't a valid member. can we keep those as value types and only pointer the scalars/objects whose zero is legit data (string/bool/float/structs)? that fixes the taxRate: 0 / closed: false / coords cases without the extra deref churn on every timestamp

@THEjacob1000
THEjacob1000 removed the request for review from J-tt September 28, 2026 21:43
@smithamax

Copy link
Copy Markdown
Member

This has been discussed, I think the best way to address it will be to have meta hints on the JTD for the omit that the type wants

Optional properties holding an object rendered as a value type, so an absent
object and one whose fields all happen to be zero decoded identically.
Consumers had no way to tell them apart and resorted to guessing from a field
(if x.Order.ID != ""), which is wrong whenever the zero value is legitimate.

Optional properties and discriminator forms now render as pointers. Adds a
ref-to-struct case to the optional-refs fixture, which previously only covered
scalars and collections.

Optional string, bool, float64 and timestamp fields are ambiguous for the same
reason but are left alone: changing them affects every generated client, so it
wants its own decision.
Optional scalars rendered as value types, so absence and a legitimate zero
value decoded identically. Timestamps were the worst case: omitzero only
affects marshalling, so an absent timestamp still decoded to time.Time{} and
read downstream as a real instant in year 1 rather than as missing.

Optional string, bool, float and timestamp properties now render as pointers,
matching the treatment integers already had. Collections keep omitzero, since
a nil slice or map already distinguishes absence.

This changes the shape of every generated Go client, so it is split from the
object-field fix it stacks on: consumers of optional scalars need a pass to
dereference them.
@MrDwarf7
MrDwarf7 force-pushed the feat/go-codegen-optional-scalars branch from e44b749 to 89c9ba4 Compare October 16, 2026 00:44
@MrDwarf7
MrDwarf7 requested a review from J-tt October 16, 2026 01:43
NullableTags *[]string `json:"nullableTags,omitempty"`
Scores map[string]int32 `json:"scores,omitzero"`
SeenAt time.Time `json:"seenAt,omitzero"`
SeenAt *time.Time `json:"seenAt,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really think omitzero is just much more ergonomic here

It is worth keeping in mind that making something a pointer forces you to either check it everywhere or pull it out of the struct, so if we can avoid it and rely on validation it just becomes much simpler.

Anyway, I think @smithamax has a design in mind for this as I've mentioned, I'll defer to him

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants