Skip to content

Commit fb9fcce

Browse files
author
Cameron Custer
committed
Fix subscription usage union selection bug for grouped responses
Add CustomMatcher support to apijson union system to properly handle subscription usage responses where grouped and ungrouped variants both match gjson.JSON TypeFilter. The issue was that both SubscriptionUsageGroupedSubscriptionUsage and SubscriptionUsageUngroupedSubscriptionUsage used identical TypeFilter values, causing incorrect variant selection based on ordering rather than content. Solution: - Extended UnionVariant with CustomMatcher function field - Modified union decoder to check CustomMatcher before TypeFilter - Used CustomMatcher to detect presence of metric_group field in data - Ensures grouped responses select grouped variant, ungrouped select ungrouped Fixes: Analytics functionality that depends on GroupBy parameter Affects: All grouped usage requests in subscription usage API Versions: Confirmed broken in v1.4.1 through v1.18.0
1 parent 120f8d3 commit fb9fcce

File tree

3 files changed

+21
-3
lines changed

3 files changed

+21
-3
lines changed

internal/apijson/decoder.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,18 @@ func (d *decoderBuilder) newUnionDecoder(t reflect.Type) decoderFunc {
219219
// If there is a discriminator match, circumvent the exactness logic entirely
220220
for idx, variant := range unionEntry.variants {
221221
decoder := decoders[idx]
222+
223+
// Check custom matcher first
224+
if variant.CustomMatcher != nil {
225+
if variant.CustomMatcher([]byte(n.Raw)) {
226+
inner := reflect.New(variant.Type).Elem()
227+
err := decoder(n, inner, state)
228+
v.Set(inner)
229+
return err
230+
}
231+
continue
232+
}
233+
222234
if variant.TypeFilter != n.Type {
223235
continue
224236
}

internal/apijson/registry.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ type UnionVariant struct {
1010
TypeFilter gjson.Type
1111
DiscriminatorValue interface{}
1212
Type reflect.Type
13+
// CustomMatcher is an optional function that can be used for custom matching logic
14+
// If provided, it takes precedence over TypeFilter and DiscriminatorValue
15+
CustomMatcher func([]byte) bool
1316
}
1417

1518
var unionRegistry = map[reflect.Type]unionEntry{}

subscription.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5277,12 +5277,15 @@ func init() {
52775277
reflect.TypeOf((*SubscriptionUsageUnion)(nil)).Elem(),
52785278
"",
52795279
apijson.UnionVariant{
5280-
TypeFilter: gjson.JSON,
5281-
Type: reflect.TypeOf(SubscriptionUsageUngroupedSubscriptionUsage{}),
5280+
Type: reflect.TypeOf(SubscriptionUsageGroupedSubscriptionUsage{}),
5281+
CustomMatcher: func(data []byte) bool {
5282+
// Use grouped variant if metric_group field exists in any data element
5283+
return gjson.GetBytes(data, "data.0.metric_group").Exists()
5284+
},
52825285
},
52835286
apijson.UnionVariant{
52845287
TypeFilter: gjson.JSON,
5285-
Type: reflect.TypeOf(SubscriptionUsageGroupedSubscriptionUsage{}),
5288+
Type: reflect.TypeOf(SubscriptionUsageUngroupedSubscriptionUsage{}),
52865289
},
52875290
)
52885291
}

0 commit comments

Comments
 (0)