Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions internal/test/issues/issue-2031/prefer/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package: issue2031
generate:
models: true
client: true
output-options:
prefer-skip-optional-pointer: true
output: issue2031.gen.go
3 changes: 3 additions & 0 deletions internal/test/issues/issue-2031/prefer/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package issue2031

//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
251 changes: 251 additions & 0 deletions internal/test/issues/issue-2031/prefer/issue2031.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 63 additions & 0 deletions internal/test/issues/issue-2031/prefer/issue2031_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package issue2031

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestNewGetTestRequest(t *testing.T) {
t.Run("does not add the user_ids[] parameter if zero value", func(t *testing.T) {
params := GetTestParams{}

req, err := NewGetTestRequest("https://localhost", &params)
require.NoError(t, err)

assert.Equal(t, "https://localhost/test", req.URL.String())
})

t.Run("does not add the user_ids[] parameter if nil", func(t *testing.T) {
params := GetTestParams{
UserIds: nil,
}

req, err := NewGetTestRequest("https://localhost", &params)
require.NoError(t, err)

assert.Equal(t, "https://localhost/test", req.URL.String())
})

t.Run("adds the user_ids[] parameter if an explicitly initialised empty array", func(t *testing.T) {
params := GetTestParams{
UserIds: []int{},
}

req, err := NewGetTestRequest("https://localhost", &params)
require.NoError(t, err)

assert.Equal(t, "https://localhost/test?user_ids%5B%5D=", req.URL.String())
})

t.Run("adds the user_ids[] parameter if array contains a value", func(t *testing.T) {
params := GetTestParams{
UserIds: []int{1},
}

req, err := NewGetTestRequest("https://localhost", &params)
require.NoError(t, err)

assert.Equal(t, "https://localhost/test?user_ids%5B%5D=1", req.URL.String())
})

t.Run("handles multiple user_ids[] parameters", func(t *testing.T) {
params := GetTestParams{
UserIds: []int{1, 100},
}

req, err := NewGetTestRequest("https://localhost", &params)
require.NoError(t, err)

assert.Equal(t, "https://localhost/test?user_ids%5B%5D=1&user_ids%5B%5D=100", req.URL.String())
})
}
17 changes: 17 additions & 0 deletions internal/test/issues/issue-2031/prefer/openapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
openapi: "3.0.0"
info:
version: 1.0.0
title: Issue 2031
paths:
/test:
get:
parameters:
- name: "user_ids[]"
in: query
schema:
type: array
items:
type: integer
style: form
explode: true
required: false
17 changes: 17 additions & 0 deletions pkg/codegen/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,23 @@ func (pd ParameterDefinition) TypeDef() string {
return typeDecl
}

// RequiresNilCheck indicates whether the generated property should have a nil check performed on it before other checks.
// This should be used in templates when performing `nil` checks, but NOT when i.e. determining if there should be an optional pointer given to the type - in that case, use `HasOptionalPointer`
func (pd ParameterDefinition) RequiresNilCheck() bool {
return pd.ZeroValueIsNil() || pd.HasOptionalPointer()
}

// ZeroValueIsNil is a helper function to determine if the given Go type used for this property
// Will return true if the OpenAPI `type` is:
// - `array`
func (pd ParameterDefinition) ZeroValueIsNil() bool {
if pd.Schema.OAPISchema == nil {
return false
}

return pd.Schema.OAPISchema.Type.Is("array")
}

// JsonTag generates the JSON annotation to map GoType to json type name. If Parameter
// Foo is marshaled to json as "foo", this will create the annotation
// 'json:"foo"'
Expand Down
6 changes: 3 additions & 3 deletions pkg/codegen/templates/client.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
if params != nil {
queryValues := queryURL.Query()
{{range $paramIdx, $param := .QueryParams}}
{{if .HasOptionalPointer}} if params.{{.GoName}} != nil { {{end}}
{{if .RequiresNilCheck}} if params.{{.GoName}} != nil { {{end}}
{{if .IsPassThrough}}
queryValues.Add("{{.ParamName}}", {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}})
{{end}}
Expand All @@ -210,7 +210,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr

{{end}}
{{if .IsStyled}}
if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}); err != nil {
if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if and .RequiresNilCheck .HasOptionalPointer}}*{{end}}params.{{.GoName}}); err != nil {
return nil, err
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
return nil, err
Expand All @@ -222,7 +222,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
}
}
{{end}}
{{if .HasOptionalPointer}}}{{end}}
{{if .RequiresNilCheck}}}{{end}}
{{end}}
queryURL.RawQuery = queryValues.Encode()
}
Expand Down