Skip to content

Commit 483ce73

Browse files
committed
feat(codec): JSON Record decorator
1 parent 8a46341 commit 483ce73

1 file changed

Lines changed: 64 additions & 0 deletions

File tree

internal/codec/record.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package codec
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
"github.com/amp-labs/connectors/common"
8+
"github.com/amp-labs/connectors/internal/datautils"
9+
)
10+
11+
// DecoratedRecord merges a dynamic record with a structured extension,
12+
// producing a single flattened JSON object when marshaled.
13+
//
14+
// It embeds a [common.Record] containing user-defined key–value pairs
15+
// and a typed struct [T] representing schema-bound fields that must
16+
// coexist with those user-supplied values in the API payload.
17+
//
18+
// When marshaled, fields from both Record and Extension are serialized
19+
// at the same level in the resulting JSON. This allows connectors to
20+
// enrich arbitrary record data with well-defined metadata or attributes.
21+
//
22+
// Example:
23+
//
24+
// type MyPayloadForRecord = codec.DecoratedRecord[RecordExtension]
25+
//
26+
// type RecordExtension struct {
27+
// ObjectName string `json:"objectName"`
28+
// }
29+
//
30+
// record := common.Record{"name": "Bob"}
31+
// extension := RecordExtension{ObjectName: "users"}
32+
// item := codec.DecoratedRecord[RecordExtension]{Record: record, Extension: extension}
33+
//
34+
// // Output:
35+
// // {"name": "Bob", "objectName": "users"}
36+
type DecoratedRecord[T any] struct {
37+
common.Record
38+
Extension T
39+
}
40+
41+
func (d *DecoratedRecord[T]) MarshalJSON() ([]byte, error) {
42+
// Create a copy of records.
43+
jsonProperties, err := datautils.FromMap(d.Record).DeepCopy()
44+
if err != nil {
45+
return nil, err
46+
}
47+
48+
// Marshal the extension struct.
49+
extBytes, err := json.Marshal(d.Extension)
50+
if err != nil {
51+
return nil, fmt.Errorf("marshal extension: %w", err)
52+
}
53+
54+
var additionalProperties map[string]any
55+
if err = json.Unmarshal(extBytes, &additionalProperties); err != nil {
56+
return nil, fmt.Errorf("unmarshal extension: %w", err)
57+
}
58+
59+
// Enhance final JSON map with properties from extension.
60+
datautils.FromMap(jsonProperties).AddMapValues(additionalProperties)
61+
62+
// Marshall combined map.
63+
return json.Marshal(jsonProperties)
64+
}

0 commit comments

Comments
 (0)