Skip to content

feat(codec): Dual marshal preserve RawJSON#2276

Open
Cobalt0s wants to merge 1 commit into
cobalt0s/subscribe-unit-test-templatefrom
cobalt0s/codec-preserve-raw-json
Open

feat(codec): Dual marshal preserve RawJSON#2276
Cobalt0s wants to merge 1 commit into
cobalt0s/subscribe-unit-test-templatefrom
cobalt0s/codec-preserve-raw-json

Conversation

@Cobalt0s
Copy link
Copy Markdown
Contributor

@Cobalt0s Cobalt0s commented Nov 7, 2025

Description

This PR introduces codec.RawJSON[T any].

Key changes

  • codec.RawJSON[T any]
    A generic wrapper for JSON marshalling/unmarshalling that preserves data in two forms:
    • the original, unmodified map[string]any
    • the parsed concrete type T
      This enables lossless handling of responses. It’s particularly useful when multiple representations are possible—for example, when parsing provider responses where T represents a success model, but failures require access to the raw payload (e.g. to construct common.NewHTTPError).
image
  • JSON comparison utilities
    Adds mockutils.JSONComparator, a lightweight helper for comparing Go values against JSON string representations (commonly used in tests).

    • Equals compares single values
    • ListsEqual compares slices

    This simplifies assertions where expected data is expressed as JSON literals.

Live Tests

image image

Copy link
Copy Markdown
Contributor Author

Cobalt0s commented Nov 7, 2025

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@Cobalt0s Cobalt0s self-assigned this Nov 7, 2025
@Cobalt0s Cobalt0s marked this pull request as ready for review November 7, 2025 21:32
@Cobalt0s Cobalt0s requested a review from anushat05 November 7, 2025 21:32
@Cobalt0s Cobalt0s changed the base branch from cobalt0s/batch-salesforce-consistency to graphite-base/2276 November 7, 2025 22:36
@Cobalt0s Cobalt0s force-pushed the cobalt0s/codec-preserve-raw-json branch from 9af3528 to 55cd1bf Compare November 7, 2025 22:37
@Cobalt0s Cobalt0s changed the base branch from graphite-base/2276 to cobalt0s/batch-salesforce-batch-unit-tests November 7, 2025 22:37
Copy link
Copy Markdown
Contributor

@anushat05 anushat05 left a comment

Choose a reason for hiding this comment

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

The build is failing for this should we address that first?

@Cobalt0s Cobalt0s changed the base branch from cobalt0s/batch-salesforce-batch-unit-tests to graphite-base/2276 November 11, 2025 20:50
@Cobalt0s Cobalt0s force-pushed the cobalt0s/codec-preserve-raw-json branch from 55cd1bf to 4331b71 Compare November 11, 2025 21:59
@Cobalt0s Cobalt0s changed the base branch from graphite-base/2276 to main November 11, 2025 21:59
Comment thread test/utils/mockutils/jsonComparator.go Outdated
Comment thread internal/codec/raw.go Outdated
@Cobalt0s Cobalt0s requested a review from anushat05 November 11, 2025 22:08
@Cobalt0s
Copy link
Copy Markdown
Contributor Author

@anushat05 The original reason to include the utility is gone with Salesforce using new create method. However, the utility could still come in handy. I think it should replace some of the jsonquery package in favour of concrete Golang data types and still have the raw map[string]any alongside. The concrete data type doesn't have to be exhaustive. All the "extra" fields not unmarshalled into concrete golang struct will still be in Raw.

@Cobalt0s
Copy link
Copy Markdown
Contributor Author

Cobalt0s commented May 1, 2026

@anushat05 the PR is still relevant and was useful in the Microsoft Susbcribe implementation.

@Cobalt0s Cobalt0s force-pushed the cobalt0s/tests-compare-result branch from df5292b to d8d8483 Compare May 1, 2026 15:33
@Cobalt0s Cobalt0s force-pushed the cobalt0s/codec-preserve-raw-json branch 2 times, most recently from 31145b7 to aacd169 Compare May 1, 2026 17:33
@Cobalt0s Cobalt0s force-pushed the cobalt0s/tests-compare-result branch from d8d8483 to 814b593 Compare May 1, 2026 17:33
@Cobalt0s Cobalt0s changed the base branch from cobalt0s/tests-compare-result to graphite-base/2276 May 4, 2026 22:12
@Cobalt0s Cobalt0s force-pushed the graphite-base/2276 branch from 814b593 to f29bab8 Compare May 13, 2026 21:33
@Cobalt0s Cobalt0s force-pushed the cobalt0s/codec-preserve-raw-json branch from aacd169 to 0d809f3 Compare May 13, 2026 21:33
@Cobalt0s Cobalt0s changed the base branch from graphite-base/2276 to main May 13, 2026 21:33
@Cobalt0s Cobalt0s requested a review from jlimatampersand May 16, 2026 15:52
@Cobalt0s
Copy link
Copy Markdown
Contributor Author

@jlimatampersand
The util is already used by Salesforce it enhances it a bit.

codec.RawJSON[YourType] allows to deal with Raw representation of data map[string]any alongside the concrete Struct Type.

  • Conrete Type allows easy access to fields.
  • The Raw map will always contain all data so nothing is "wasted". Useful when you want the original data before Marshalling happened into the struct.

@Cobalt0s Cobalt0s changed the base branch from main to graphite-base/2276 May 18, 2026 23:35
@Cobalt0s Cobalt0s force-pushed the cobalt0s/codec-preserve-raw-json branch from 0d809f3 to 006225f Compare May 18, 2026 23:35
Comment thread internal/codec/raw.go Outdated
// ID string `json:"id"`
// Name string `json:"name"`
// }
type RawJSON[T any] struct {
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 see what this util is trying to achieve, but is this a necessary util?

I guess the win is there when you edit records in such a way that you are strictly adding items and fields, but if this wrapper is used when removing or deleting for a purpose, this is going to be very buggy and will introduce friction.

You will understand this utility, but many others will easily use it incorrectly unless they actually read this logic fully themselves, which will not be the case. Most likeley 90% of the contributors won't read the description as carefully as the logic itself.

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.

Convince me or fix the logic so I can approve. I am open to suggestions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I understand that it can be misused. Probably it should be more dedicated, or some features stripped away towards more immutable design. I started small, then got some code generated and thought it fits the concept.

(1)
For Microsoft Batch I need Dual Unmarshal -- therefore, it will be part of that Microsoft impl and not a utility:
image
Usage:
image

(2)
I changed the code and added tests for DecoratedRecord which has only one responsibility and that won't be growing.

Summary:

  • The existing DecoratedRecord is used by Salesforce. The mock test validates that Salesforce write operation sends correct payload..
  • The "DecoratedRecord" is doing only one thing -- enhancing any map with "sidecar data" to produce JSON for payload:
    • map[string]any + your extension,decoration struct => JSON
      Example:
image

PS: There are many write payloads that are "decorated", so this idea of DecoratedRecord makes payload construction automatic without any map[string]any assertions, key checks, etc -- it just combines 2 JSON representations. Let me know if it is an overkill 😅 .

@Cobalt0s Cobalt0s force-pushed the cobalt0s/codec-preserve-raw-json branch from f0d71a9 to b5d9039 Compare May 19, 2026 23:48
@Cobalt0s Cobalt0s changed the base branch from graphite-base/2276 to cobalt0s/subscribe-unit-test-template May 19, 2026 23:48
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