Skip to content

msggen: Add UnionField support to all generators for oneOf schemas#8965

Open
4xvgal wants to merge 3 commits intoElementsProject:masterfrom
4xvgal:feat/msggen-unionfield-support
Open

msggen: Add UnionField support to all generators for oneOf schemas#8965
4xvgal wants to merge 3 commits intoElementsProject:masterfrom
4xvgal:feat/msggen-unionfield-support

Conversation

@4xvgal
Copy link

@4xvgal 4xvgal commented Mar 22, 2026

Summary

msggen could not handle oneOf fields in JSON schemas. Every oneOf field was manually overridden to a single type, which dropped some variants. This PR adds UnionField support to all generators so that every variant in a oneOf schema is preserved without overrides.

For example, invoice.exposeprivatechannels accepts true, ["1x1x3"], or "1x1x3" in JSON-RPC, but cln-rpc only generated Option<Vec<ShortChannelId>>, making it impossible to pass true through the typed API.

Changes

model.py:

  • Fix UnionField.from_js() constructor bug (missing added/deprecated args)
  • Add top-level oneOf detection in CompositeField.from_js()
  • Remove 12 overrides that only existed because oneOf was not handled

Generators (6 files):

  • rust.py: Generate #[serde(untagged)] enums
  • proto.py: Generate protobuf oneof blocks with array wrapper messages
  • convert.py / unconvert.py: Generate bidirectional From impls
  • grpc2py.py: Generate WhichOneof()-based conversion
  • notification.py: Automatically supported via rust.py's gen_field

Traversal:

  • patch.py, checks.py: Add recursion into UnionField variants

Tests

  • cargo test -p cln-rpc — passed
  • cargo test -p cln-grpc --features server — passed (4/4)
  • msggen generate — runs without errors

Related

Resolves #8961, #8964

🤖 Generated with Claude Code

4xvgal and others added 2 commits March 23, 2026 00:12
The convert generator was capitalizing the union variant suffix
(e.g. ArrString) when constructing wrapper type names, while
the proto generator used the raw suffix (arr_string). This caused
prost-generated struct names to mismatch (DatastoreRequestarrStringWrapper
vs DatastoreRequestArrStringWrapper).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@4xvgal 4xvgal marked this pull request as ready for review March 22, 2026 15:29
@4xvgal 4xvgal requested a review from cdecker as a code owner March 22, 2026 15:29
optional uint64 generation = 2;
optional bytes hex = 3;
optional string string = 4;
repeated string key = 5;
Copy link
Member

Choose a reason for hiding this comment

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

This is a backwards incompatible change. Never change the field numbering in protobuf.

Copy link
Author

@4xvgal 4xvgal Mar 22, 2026

Choose a reason for hiding this comment

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

Fixed - the first variant of each oneof now reuses the original field number.
new numbers are only allocated for additional variants.

Reuse the original field number for the first variant of each oneOf,
instead of allocating new numbers for all variants. This maintains
backward compatibility with existing gRPC clients.

For example, Invoice.label was previously field 3 (string). Now the
oneof reuses 3 for label_string and only allocates a new number for
label_int.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@4xvgal 4xvgal requested a review from cdecker March 23, 2026 02:08
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.

msggen: Invoice.exposeprivatechannels override drops boolean variant from oneOf

2 participants