Skip to content

Commit 38e21e1

Browse files
Merge pull request #2 from CASParser/release-please--branches--main--changes--next
release: 0.0.3
2 parents 0ee4519 + a379433 commit 38e21e1

File tree

8 files changed

+142
-25
lines changed

8 files changed

+142
-25
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "0.0.2"
2+
".": "0.0.3"
33
}

.stats.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 5
22
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser%2Fcas-parser-b7fdba3d3f97c7debc22c7ca30b828bce81bcd64648df8c94029b27a3321ebb9.yml
33
openapi_spec_hash: 03f1315f1d32ada42445ca920f047dff
4-
config_hash: 0e1291f316b20497ad29b59a231a8680
4+
config_hash: cb5d75abef6264b5d86448caf7295afa

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
# Changelog
22

3+
## 0.0.3 (2025-09-06)
4+
5+
Full Changelog: [v0.0.2...v0.0.3](https://github.com/CASParser/cas-parser-go/compare/v0.0.2...v0.0.3)
6+
7+
### Bug Fixes
8+
9+
* close body before retrying ([891bbc6](https://github.com/CASParser/cas-parser-go/commit/891bbc6d9b7b2840269c438f9242274fbab9fe97))
10+
* **internal:** unmarshal correctly when there are multiple discriminators ([08c4f8a](https://github.com/CASParser/cas-parser-go/commit/08c4f8ad7fa898837bef8f1a8898f3e8b56329d9))
11+
12+
13+
### Chores
14+
15+
* **internal:** codegen related update ([86015d2](https://github.com/CASParser/cas-parser-go/commit/86015d220838b6d6d72472ba134308e8c851100b))
16+
317
## 0.0.2 (2025-08-18)
418

519
Full Changelog: [v0.0.1...v0.0.2](https://github.com/CASParser/cas-parser-go/compare/v0.0.1...v0.0.2)

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# Cas Parser Go API Library
22

3+
<!-- x-release-please-start-version -->
4+
35
<a href="https://pkg.go.dev/github.com/CASParser/cas-parser-go"><img src="https://pkg.go.dev/badge/github.com/CASParser/cas-parser-go.svg" alt="Go Reference"></a>
46

7+
<!-- x-release-please-end -->
8+
59
The Cas Parser Go library provides convenient access to the [Cas Parser REST API](https://docs.casparser.in/reference)
610
from applications written in Go.
711

@@ -24,7 +28,7 @@ Or to pin the version:
2428
<!-- x-release-please-start-version -->
2529

2630
```sh
27-
go get -u 'github.com/CASParser/[email protected].2'
31+
go get -u 'github.com/CASParser/[email protected].3'
2832
```
2933

3034
<!-- x-release-please-end -->

internal/apijson/decodeparam_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,36 @@ func init() {
351351
})
352352
}
353353

354+
type FooVariant struct {
355+
Type string `json:"type,required"`
356+
Value string `json:"value,required"`
357+
}
358+
359+
type BarVariant struct {
360+
Type string `json:"type,required"`
361+
Enable bool `json:"enable,required"`
362+
}
363+
364+
type MultiDiscriminatorUnion struct {
365+
OfFoo *FooVariant `json:",inline"`
366+
OfBar *BarVariant `json:",inline"`
367+
368+
paramUnion
369+
}
370+
371+
func init() {
372+
apijson.RegisterDiscriminatedUnion[MultiDiscriminatorUnion]("type", map[string]reflect.Type{
373+
"foo": reflect.TypeOf(FooVariant{}),
374+
"foo_v2": reflect.TypeOf(FooVariant{}),
375+
"bar": reflect.TypeOf(BarVariant{}),
376+
"bar_legacy": reflect.TypeOf(BarVariant{}),
377+
})
378+
}
379+
380+
func (m *MultiDiscriminatorUnion) UnmarshalJSON(data []byte) error {
381+
return apijson.UnmarshalRoot(data, m)
382+
}
383+
354384
func (d *DiscriminatedUnion) UnmarshalJSON(data []byte) error {
355385
return apijson.UnmarshalRoot(data, d)
356386
}
@@ -408,3 +438,61 @@ func TestDiscriminatedUnion(t *testing.T) {
408438
})
409439
}
410440
}
441+
442+
func TestMultiDiscriminatorUnion(t *testing.T) {
443+
tests := map[string]struct {
444+
raw string
445+
target MultiDiscriminatorUnion
446+
shouldFail bool
447+
}{
448+
"foo_variant": {
449+
raw: `{"type":"foo","value":"test"}`,
450+
target: MultiDiscriminatorUnion{OfFoo: &FooVariant{
451+
Type: "foo",
452+
Value: "test",
453+
}},
454+
},
455+
"foo_v2_variant": {
456+
raw: `{"type":"foo_v2","value":"test_v2"}`,
457+
target: MultiDiscriminatorUnion{OfFoo: &FooVariant{
458+
Type: "foo_v2",
459+
Value: "test_v2",
460+
}},
461+
},
462+
"bar_variant": {
463+
raw: `{"type":"bar","enable":true}`,
464+
target: MultiDiscriminatorUnion{OfBar: &BarVariant{
465+
Type: "bar",
466+
Enable: true,
467+
}},
468+
},
469+
"bar_legacy_variant": {
470+
raw: `{"type":"bar_legacy","enable":false}`,
471+
target: MultiDiscriminatorUnion{OfBar: &BarVariant{
472+
Type: "bar_legacy",
473+
Enable: false,
474+
}},
475+
},
476+
"invalid_type": {
477+
raw: `{"type":"unknown","value":"test"}`,
478+
target: MultiDiscriminatorUnion{},
479+
shouldFail: true,
480+
},
481+
}
482+
483+
for name, test := range tests {
484+
t.Run(name, func(t *testing.T) {
485+
var dst MultiDiscriminatorUnion
486+
err := json.Unmarshal([]byte(test.raw), &dst)
487+
if err != nil && !test.shouldFail {
488+
t.Fatalf("failed unmarshal with err: %v", err)
489+
}
490+
if err == nil && test.shouldFail {
491+
t.Fatalf("expected unmarshal to fail but it succeeded")
492+
}
493+
if !reflect.DeepEqual(dst, test.target) {
494+
t.Fatalf("failed equality, got %#v but expected %#v", dst, test.target)
495+
}
496+
})
497+
}
498+
}

internal/apijson/union.go

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,10 @@ func RegisterDiscriminatedUnion[T any](key string, mappings map[string]reflect.T
3939

4040
func (d *decoderBuilder) newStructUnionDecoder(t reflect.Type) decoderFunc {
4141
type variantDecoder struct {
42-
decoder decoderFunc
43-
field reflect.StructField
44-
discriminatorValue any
42+
decoder decoderFunc
43+
field reflect.StructField
4544
}
46-
47-
variants := []variantDecoder{}
45+
decoders := []variantDecoder{}
4846
for i := 0; i < t.NumField(); i++ {
4947
field := t.Field(i)
5048

@@ -53,18 +51,26 @@ func (d *decoderBuilder) newStructUnionDecoder(t reflect.Type) decoderFunc {
5351
}
5452

5553
decoder := d.typeDecoder(field.Type)
56-
variants = append(variants, variantDecoder{
54+
decoders = append(decoders, variantDecoder{
5755
decoder: decoder,
5856
field: field,
5957
})
6058
}
6159

60+
type discriminatedDecoder struct {
61+
variantDecoder
62+
discriminator any
63+
}
64+
discriminatedDecoders := []discriminatedDecoder{}
6265
unionEntry, discriminated := unionRegistry[t]
63-
for _, unionVariant := range unionEntry.variants {
64-
for i := 0; i < len(variants); i++ {
65-
variant := &variants[i]
66-
if variant.field.Type.Elem() == unionVariant.Type {
67-
variant.discriminatorValue = unionVariant.DiscriminatorValue
66+
for _, variant := range unionEntry.variants {
67+
// For each union variant, find a matching decoder and save it
68+
for _, decoder := range decoders {
69+
if decoder.field.Type.Elem() == variant.Type {
70+
discriminatedDecoders = append(discriminatedDecoders, discriminatedDecoder{
71+
decoder,
72+
variant.DiscriminatorValue,
73+
})
6874
break
6975
}
7076
}
@@ -73,10 +79,10 @@ func (d *decoderBuilder) newStructUnionDecoder(t reflect.Type) decoderFunc {
7379
return func(n gjson.Result, v reflect.Value, state *decoderState) error {
7480
if discriminated && n.Type == gjson.JSON && len(unionEntry.discriminatorKey) != 0 {
7581
discriminator := n.Get(unionEntry.discriminatorKey).Value()
76-
for _, variant := range variants {
77-
if discriminator == variant.discriminatorValue {
78-
inner := v.FieldByIndex(variant.field.Index)
79-
return variant.decoder(n, inner, state)
82+
for _, decoder := range discriminatedDecoders {
83+
if discriminator == decoder.discriminator {
84+
inner := v.FieldByIndex(decoder.field.Index)
85+
return decoder.decoder(n, inner, state)
8086
}
8187
}
8288
return errors.New("apijson: was not able to find discriminated union variant")
@@ -85,15 +91,15 @@ func (d *decoderBuilder) newStructUnionDecoder(t reflect.Type) decoderFunc {
8591
// Set bestExactness to worse than loose
8692
bestExactness := loose - 1
8793
bestVariant := -1
88-
for i, variant := range variants {
94+
for i, decoder := range decoders {
8995
// Pointers are used to discern JSON object variants from value variants
90-
if n.Type != gjson.JSON && variant.field.Type.Kind() == reflect.Ptr {
96+
if n.Type != gjson.JSON && decoder.field.Type.Kind() == reflect.Ptr {
9197
continue
9298
}
9399

94100
sub := decoderState{strict: state.strict, exactness: exact}
95-
inner := v.FieldByIndex(variant.field.Index)
96-
err := variant.decoder(n, inner, &sub)
101+
inner := v.FieldByIndex(decoder.field.Index)
102+
err := decoder.decoder(n, inner, &sub)
97103
if err != nil {
98104
continue
99105
}
@@ -116,11 +122,11 @@ func (d *decoderBuilder) newStructUnionDecoder(t reflect.Type) decoderFunc {
116122
return errors.New("apijson: was not able to coerce type as union strictly")
117123
}
118124

119-
for i := 0; i < len(variants); i++ {
125+
for i := 0; i < len(decoders); i++ {
120126
if i == bestVariant {
121127
continue
122128
}
123-
v.FieldByIndex(variants[i].field.Index).SetZero()
129+
v.FieldByIndex(decoders[i].field.Index).SetZero()
124130
}
125131

126132
return nil

internal/requestconfig/requestconfig.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,11 @@ func (cfg *RequestConfig) Execute() (err error) {
461461
break
462462
}
463463

464+
// Close the response body before retrying to prevent connection leaks
465+
if res != nil && res.Body != nil {
466+
res.Body.Close()
467+
}
468+
464469
time.Sleep(retryDelay(res, retryCount))
465470
}
466471

internal/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
package internal
44

5-
const PackageVersion = "0.0.2" // x-release-please-version
5+
const PackageVersion = "0.0.3" // x-release-please-version

0 commit comments

Comments
 (0)