Skip to content

Add nullable and discriminated_union field encoding coercion - #1923

Open
jar-stripe wants to merge 4 commits into
masterfrom
jar/discriminated-union-coercion
Open

Add nullable and discriminated_union field encoding coercion#1923
jar-stripe wants to merge 4 commits into
masterfrom
jar/discriminated-union-coercion

Conversation

@jar-stripe

Copy link
Copy Markdown
Contributor

Why?

The sdk-codegen now emits V2RuntimeSchema field encoding descriptors with two new composite kinds — nullable and discriminated_union — that the Ruby runtime's RequestParams coercion layer didn't yet handle. Without these cases, fields wrapped in a nullable or behind a discriminated union would be passed through uncoerced, silently dropping int64_string / decimal_string conversions on nested fields.

What?

  • Adds :nullable handling to coerce_composite: defers nil to the existing early-return in coerce_value, then recurses with encoding[:inner] for non-nil values.
  • Adds :discriminated_union handling to coerce_composite: reads the discriminator field value from the hash (handles both symbol and string hash keys), looks up the matching variant schema by symbol key, and coerces the entire hash using that variant's schema. Returns the value unchanged if the discriminator field is absent or no variant matches.
  • Adds a private coerce_discriminated_union class method to keep the logic self-contained.
  • Adds 11 new unit tests covering: nil passthrough, inner-schema recursion, discriminator key lookup with both symbol and string hash keys, missing discriminator, unknown variant, array wrapping discriminated unions, and nullable wrapping discriminated unions.

See Also

Changelog

  • Adds support for nullable and discriminated_union field encoding kinds in RequestParams coercion, enabling correct int64_string/decimal_string serialization for fields nested inside nullable wrappers or discriminated unions.

jar-stripe and others added 2 commits August 6, 2026 11:57
Consolidates request-side (encode: native → wire) and response-side
(decode: wire → native) type coercion into a shared module that handles
all V2 encoding kinds: int64_string, decimal_string, object, array,
nullable, and discriminated_union.

Previously, request_params.rb had its own coercion implementation and
stripe_object.rb only handled decimal_string with a flat equality check.
This left int64_string fields uncoerced on the response side (returning
String instead of Integer) and didn't support nested schemas like
{kind: :nullable, inner: :decimal_string}.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
Extend RequestParams#coerce_composite to handle two new field encoding
kinds emitted by the V2RuntimeSchema codegen:

- :nullable — short-circuits on nil (already handled by coerce_value),
  then recurses with the inner schema for non-nil values
- :discriminated_union — reads the discriminator field from the hash,
  looks up the matching variant schema by symbol key, and coerces the
  whole value using that variant's schema; returns the value unchanged
  if the discriminator key is absent or no variant matches

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
@jar-stripe
jar-stripe force-pushed the jar/discriminated-union-coercion branch from fe994b7 to dfdef32 Compare August 6, 2026 19:03
@jar-stripe
jar-stripe marked this pull request as ready for review August 6, 2026 21:01
@jar-stripe
jar-stripe requested a review from a team as a code owner August 6, 2026 21:01
@jar-stripe
jar-stripe requested review from kidus-stripe and a lite review from Copilot and removed request for a team August 6, 2026 21:01
Tests discriminated union serialization for both request-side
(RequestParams with defaulted discriminator) and response-side
(StripeObject construction), covering standalone and inline variants.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude

Copilot AI left a comment

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (2)

test/stripe/discriminated_union_test.rb:71

  • This test claims to cover the case where the discriminator is not explicitly supplied, but it passes model: "rgb", so it isn't exercising the behavior described in the comment. Either omit model: and assert it’s not serialized, or change the test name/comment to reflect explicit passing.
      should "default discriminator to the variant name when not explicitly supplied" do
        # When the caller omits `model:`, the initialize default sets @model but
        # the explicit-key tracker does not include it.  Callers who rely on the
        # default must pass the discriminator explicitly for it to appear in the
        # serialized hash; this test documents that expectation.

test/stripe/discriminated_union_test.rb:14

  • The fixture comment says callers only need to supply variant-specific fields because the discriminator defaults, but RequestParams#to_h only includes keys that were explicitly set. With the current initialize using @model = model, omitting model: will not serialize the discriminator, so this comment is misleading.

This issue also appears on line 67 of the same file.

    # A standalone union where each variant is a distinct RequestParams class.
    # The discriminator field (model) defaults to the variant name so callers
    # only need to supply the variant-specific fields.

Inline module_function declarations, add super() calls in test fixture
initializers, and disable Naming/MethodParameterName for color component
params (r, g, b, h, s, v).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
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.

3 participants