Skip to content

Commit e2b8b59

Browse files
author
Jamie Tanna
committed
sq
1 parent ac39953 commit e2b8b59

7 files changed

Lines changed: 188 additions & 0 deletions

File tree

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
openapi: "3.0.0"
2+
info:
3+
version: 1.0.0
4+
title: prefer-skip-optional-pointer-with-omitzero
5+
components:
6+
schemas:
7+
Client:
8+
type: object
9+
required:
10+
- name
11+
properties:
12+
name:
13+
description: This field is required, so will never have an optional pointer, nor `omitzero`.
14+
type: string
15+
id:
16+
description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. However, it will receive `omitzero`.
17+
type: number
18+
ClientWithExtension:
19+
type: object
20+
required:
21+
- name
22+
properties:
23+
name:
24+
description: This field is required, so will never have an optional pointer, nor `omitzero`.
25+
type: string
26+
id:
27+
description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. However, it will receive `omitzero`.
28+
type: number
29+
pointer_id:
30+
type: number
31+
description: This field should have an optional pointer, as the field-level definition of `x-go-type-skip-optional-pointer` overrides the `prefer-skip-optional-pointer` Output Option. This will also not receive an `omitzero`.
32+
# NOTE that this overrides the global preference
33+
x-go-type-skip-optional-pointer: false
34+
NestedType:
35+
type: object
36+
properties:
37+
client:
38+
description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer.
39+
$ref: '#/components/schemas/Client'
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# yaml-language-server: $schema=../../../configuration-schema.json
2+
package: preferskipoptionalpointerwithomitzero
3+
output: gen.go
4+
generate:
5+
models: true
6+
output-options:
7+
# to make sure that all types are generated, even if they're unreferenced
8+
skip-prune: true
9+
prefer-skip-optional-pointer: true
10+
prefer-skip-optional-pointer-with-omitzero: true

examples/output-options/preferskipoptionalpointerwithomitzero/gen.go

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package preferskipoptionalpointerwithomitzero
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestClient(t *testing.T) {
12+
t.Run("zero value (empty string) on Name is not omitted", func(t *testing.T) {
13+
client := Client{
14+
Name: "",
15+
}
16+
17+
b, err := json.Marshal(client)
18+
require.NoError(t, err)
19+
20+
assert.True(t, jsonContainsKey(b, "name"))
21+
})
22+
23+
t.Run("value on Name is not omitted", func(t *testing.T) {
24+
client := Client{
25+
Name: "some value",
26+
}
27+
28+
b, err := json.Marshal(client)
29+
require.NoError(t, err)
30+
31+
assert.True(t, jsonContainsKey(b, "name"))
32+
})
33+
34+
t.Run("zero value (0.0) on Id is omitted (as `omitempty` and/or `omitzero` flags it as empty)", func(t *testing.T) {
35+
client := Client{
36+
Id: 0.0,
37+
}
38+
39+
b, err := json.Marshal(client)
40+
require.NoError(t, err)
41+
42+
assert.False(t, jsonContainsKey(b, "id"))
43+
})
44+
45+
t.Run("value on Id is not omitted", func(t *testing.T) {
46+
client := Client{
47+
Id: 3.142,
48+
}
49+
50+
b, err := json.Marshal(client)
51+
require.NoError(t, err)
52+
53+
assert.True(t, jsonContainsKey(b, "id"))
54+
})
55+
}
56+
57+
func TestNestedType(t *testing.T) {
58+
t.Run("zero value (empty struct) on Client is omitted", func(t *testing.T) {
59+
nestedType := NestedType{
60+
Client: Client{},
61+
}
62+
63+
b, err := json.Marshal(nestedType)
64+
require.NoError(t, err)
65+
66+
assert.False(t, jsonContainsKey(b, "client"))
67+
})
68+
69+
t.Run("value on Client is not omitted", func(t *testing.T) {
70+
nestedType := NestedType{
71+
Client: Client{
72+
Name: "foo",
73+
},
74+
}
75+
76+
b, err := json.Marshal(nestedType)
77+
require.NoError(t, err)
78+
79+
assert.True(t, jsonContainsKey(b, "client"))
80+
})
81+
}
82+
83+
// jsonContainsKey checks if the given JSON object contains the specified key at the top level.
84+
func jsonContainsKey(b []byte, key string) bool {
85+
var m map[string]any
86+
if err := json.Unmarshal(b, &m); err != nil {
87+
return false
88+
}
89+
_, ok := m[key]
90+
return ok
91+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package preferskipoptionalpointerwithomitzero
2+
3+
//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml

pkg/codegen/configuration.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,16 @@ type OutputOptions struct {
292292
// This is the same as adding `x-go-type-skip-optional-pointer` to each field (manually, or using an OpenAPI Overlay)
293293
PreferSkipOptionalPointer bool `yaml:"prefer-skip-optional-pointer,omitempty"`
294294

295+
// TODO
296+
// TODO
297+
// TODO
298+
// PreferSkipOptionalPointer allows defining at a global level whether to omit the pointer for a type to indicate that the field/type is optional.
299+
// This is the same as adding `x-go-type-skip-optional-pointer` to each field (manually, or using an OpenAPI Overlay)
300+
// TODO
301+
// TODO
302+
// TODO
303+
PreferSkipOptionalPointerWithOmitzero bool `yaml:"prefer-skip-optional-pointer-with-omitzero,omitempty"`
304+
295305
// PreferSkipOptionalPointerOnContainerTypes allows disabling the generation of an "optional pointer" for an optional field that is a container type (such as a slice or a map), which ends up requiring an additional, unnecessary, `... != nil` check
296306
PreferSkipOptionalPointerOnContainerTypes bool `yaml:"prefer-skip-optional-pointer-on-container-types,omitempty"`
297307
}

pkg/codegen/schema.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,11 @@ func GenFieldsFromProperties(props []Property) []string {
734734

735735
omitZero := false
736736

737+
// default, but allow turning of
738+
if shouldOmitEmpty && p.Schema.SkipOptionalPointer && globalState.options.OutputOptions.PreferSkipOptionalPointerWithOmitzero {
739+
omitZero = true
740+
}
741+
737742
// Support x-omitempty and x-omitzero
738743
if extOmitEmptyValue, ok := p.Extensions[extPropOmitEmpty]; ok {
739744
if xValue, err := extParseOmitEmpty(extOmitEmptyValue); err == nil {

0 commit comments

Comments
 (0)