Skip to content

Commit 0b1ca6d

Browse files
authored
Merge pull request #1625 from jjkoh95/fix-discriminator
Fix build error
2 parents e0e0050 + 6062030 commit 0b1ca6d

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
{
2+
"openapi": "3.0.3",
3+
"info": {
4+
"title": "Discriminator with const-only fields",
5+
"version": "v0.1.0"
6+
},
7+
"paths": {
8+
"/check": {
9+
"post": {
10+
"operationId": "check",
11+
"responses": {
12+
"200": {
13+
"description": "OK",
14+
"content": {
15+
"application/json": {
16+
"schema": {
17+
"type": "object",
18+
"properties": {
19+
"status": { "type": "string" }
20+
}
21+
}
22+
}
23+
}
24+
},
25+
"412": {
26+
"description": "Business error",
27+
"content": {
28+
"application/json": {
29+
"schema": {
30+
"$ref": "#/components/schemas/CheckBusinessError"
31+
}
32+
}
33+
}
34+
},
35+
"default": {
36+
"description": "Error",
37+
"content": {
38+
"application/json": {
39+
"schema": {
40+
"type": "object",
41+
"properties": {
42+
"message": { "type": "string" }
43+
}
44+
}
45+
}
46+
}
47+
}
48+
}
49+
}
50+
}
51+
},
52+
"components": {
53+
"schemas": {
54+
"CheckBusinessError": {
55+
"oneOf": [
56+
{ "$ref": "#/components/schemas/AmlBlockedError" },
57+
{ "$ref": "#/components/schemas/SoftBlockedError" },
58+
{ "$ref": "#/components/schemas/MixedError" }
59+
],
60+
"discriminator": {
61+
"propertyName": "code",
62+
"mapping": {
63+
"AML_BLOCKED": "#/components/schemas/AmlBlockedError",
64+
"SOFT_BLOCKED": "#/components/schemas/SoftBlockedError",
65+
"MIXED": "#/components/schemas/MixedError"
66+
}
67+
}
68+
},
69+
"AmlBlockedError": {
70+
"type": "object",
71+
"required": ["code", "type"],
72+
"properties": {
73+
"code": { "type": "string", "const": "AML_BLOCKED" },
74+
"type": { "type": "string", "const": "general" }
75+
}
76+
},
77+
"SoftBlockedError": {
78+
"type": "object",
79+
"required": ["code", "type"],
80+
"properties": {
81+
"code": { "type": "string", "const": "SOFT_BLOCKED" },
82+
"type": { "type": "string", "const": "endpoint" }
83+
}
84+
},
85+
"MixedError": {
86+
"type": "object",
87+
"required": ["code", "type", "message"],
88+
"properties": {
89+
"code": { "type": "string", "const": "MIXED" },
90+
"type": { "type": "string", "const": "general" },
91+
"message": { "type": "string" }
92+
}
93+
}
94+
}
95+
}
96+
}

gen/_template/json/encoders_sum.tmpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ func (s {{ $.ReadOnlyReceiver }}) encodeFields(e *jx.Encoder) {
4848
{{- $j := $s.JSON.Except $.SumSpec.Discriminator }}
4949
{{- if $j.AnyFields }}
5050
{
51+
{{- if $j.NeedsReceiver }}
5152
s := s.{{ $s.Name }}
53+
{{- end }}
5254
{{- template "json/encode_struct_fields" $j }}
5355
}
5456
{{- end }}

gen/ir/json.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,30 @@ func (j JSON) AnyFields() bool {
3939
return false
4040
}
4141

42+
// NeedsReceiver reports whether encoding the fields would reference the
43+
// receiver variable "s". This is false when every non-excluded, non-inline
44+
// field carries a const value (encoded as a literal) and there are no
45+
// additional-properties, pattern-properties or inline-sum fields.
46+
func (j JSON) NeedsReceiver() bool {
47+
for _, f := range j.t.Fields {
48+
// Inline fields (additional / pattern / sum props) always reference s.
49+
if f.Inline != InlineNone {
50+
return true
51+
}
52+
53+
t := f.Tag.JSON
54+
if t == "" || slices.Contains(j.except, t) {
55+
continue
56+
}
57+
58+
// A non-const regular field will be encoded via field_elem → s.Name.
59+
if !f.Const().Set {
60+
return true
61+
}
62+
}
63+
return false
64+
}
65+
4266
// Except return JSON with filter by given properties.
4367
func (j JSON) Except(set ...string) JSON {
4468
return JSON{

gen/ir/json_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package ir
33
import (
44
"testing"
55

6+
"github.com/stretchr/testify/assert"
67
"github.com/stretchr/testify/require"
78

89
"github.com/ogen-go/ogen/jsonschema"
@@ -59,3 +60,71 @@ func TestJSONFields_RequiredMask(t *testing.T) {
5960
})
6061
}
6162
}
63+
64+
func TestJSON_NeedsReceiver(t *testing.T) {
65+
constField := &Field{
66+
Tag: Tag{JSON: "code"},
67+
Spec: &jsonschema.Property{
68+
Schema: &jsonschema.Schema{
69+
Const: "AML_BLOCKED",
70+
ConstSet: true,
71+
},
72+
},
73+
}
74+
regularField := &Field{
75+
Tag: Tag{JSON: "message"},
76+
Spec: &jsonschema.Property{
77+
Schema: &jsonschema.Schema{},
78+
},
79+
}
80+
inlineAdditional := &Field{
81+
Tag: Tag{JSON: "extra"},
82+
Inline: InlineAdditional,
83+
}
84+
85+
tests := []struct {
86+
name string
87+
fields []*Field
88+
except []string
89+
want bool
90+
}{
91+
{
92+
name: "AllConst",
93+
fields: []*Field{constField},
94+
want: false,
95+
},
96+
{
97+
name: "OneRegularField",
98+
fields: []*Field{regularField},
99+
want: true,
100+
},
101+
{
102+
name: "MixedConstAndRegular",
103+
fields: []*Field{constField, regularField},
104+
want: true,
105+
},
106+
{
107+
name: "InlineField",
108+
fields: []*Field{inlineAdditional},
109+
want: true,
110+
},
111+
{
112+
name: "ExcludedNonConst",
113+
fields: []*Field{regularField},
114+
except: []string{"message"},
115+
want: false,
116+
},
117+
{
118+
name: "NoFields",
119+
fields: nil,
120+
want: false,
121+
},
122+
}
123+
for _, tt := range tests {
124+
t.Run(tt.name, func(t *testing.T) {
125+
typ := &Type{Fields: tt.fields}
126+
j := JSON{t: typ, except: tt.except}
127+
assert.Equal(t, tt.want, j.NeedsReceiver())
128+
})
129+
}
130+
}

0 commit comments

Comments
 (0)