Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix/enum queryparameters serialization #120

Merged
merged 4 commits into from
Nov 21, 2023
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

## [1.5.1] - 2023-11-15

### Added

- Added support for query an path parameters of enum type. [microsoft/kiota#3693](https://github.com/microsoft/kiota/issues/3693)

## [1.5.0] - 2023-11-08

### Added
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.18
require (
github.com/cjlapao/common-go v0.0.39
github.com/google/uuid v1.4.0
github.com/std-uritemplate/std-uritemplate/go v0.0.46
github.com/std-uritemplate/std-uritemplate/go v0.0.47
github.com/stretchr/testify v1.8.4
go.opentelemetry.io/otel v1.21.0
go.opentelemetry.io/otel/trace v1.21.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/std-uritemplate/std-uritemplate/go v0.0.46 h1:rWcEym/hz9YhPTXJELTXfrq48lTx69jNVhv+dOMmyZY=
github.com/std-uritemplate/std-uritemplate/go v0.0.46/go.mod h1:Qov4Ay4U83j37XjgxMYevGJFLbnZ2o9cEOhGufBKgKY=
github.com/std-uritemplate/std-uritemplate/go v0.0.47 h1:erzz/DR4sOzWr0ca2MgSTkMckpLEsDySaTZwVFQq9zw=
github.com/std-uritemplate/std-uritemplate/go v0.0.47/go.mod h1:Qov4Ay4U83j37XjgxMYevGJFLbnZ2o9cEOhGufBKgKY=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
Expand Down
9 changes: 6 additions & 3 deletions internal/person_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type PersonStatus int

const (
ACTIVE PersonStatus = iota
SUSPEND
SUSPENDED
)

func (i PersonStatus) String() string {
Expand All @@ -18,16 +18,19 @@ func ParsePersonStatus(v string) (interface{}, error) {
case "active":
result = ACTIVE
case "suspended":
result = SUSPEND
result = SUSPENDED
default:
return 0, errors.New("Unknown PersonStatus value: " + v)
}
return &result, nil
}
func SerializeTeamVisibilityType(values []PersonStatus) []string {
func SerializePersonStatus(values []PersonStatus) []string {
result := make([]string, len(values))
for i, v := range values {
result[i] = v.String()
}
return result
}
func (i PersonStatus) isMultiValue() bool {
return false
}
46 changes: 42 additions & 4 deletions request_information.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ type RequestInformation struct {
Headers *RequestHeaders
// The Query Parameters of the request.
// Deprecated: use QueryParametersAny instead
QueryParameters map[string]string
QueryParameters map[string]string
// The Query Parameters of the request.
QueryParametersAny map[string]any
// The Request Body.
Content []byte
// The path parameters to use for the URL template when generating the URI.
// Deprecated: use PathParametersAny instead
PathParameters map[string]string
// The path parameters to use for the URL template when generating the URI.
PathParametersAny map[string]any
// The Url template for the current request.
UrlTemplate string
options map[string]RequestOption
Expand All @@ -49,6 +53,7 @@ func NewRequestInformation() *RequestInformation {
QueryParametersAny: make(map[string]any),
options: make(map[string]RequestOption),
PathParameters: make(map[string]string),
PathParametersAny: make(map[string]any),
}
}

Expand Down Expand Up @@ -103,6 +108,9 @@ func (request *RequestInformation) GetUri() (*u.URL, error) {
for key, value := range request.PathParameters {
substitutions[key] = value
}
for key, value := range request.PathParametersAny {
substitutions[key] = request.normalizeEnumParameters(reflect.ValueOf(value), value, false)
}
for key, value := range request.QueryParameters {
substitutions[key] = value
}
Expand Down Expand Up @@ -483,7 +491,8 @@ func (request *RequestInformation) AddQueryParameters(source any) {
fieldName = tagValue
}
value := fieldValue.Interface()
if value == nil {
valueOfValue := reflect.ValueOf(value)
if valueOfValue.IsNil() {
continue
}
str, ok := value.(*string)
Expand All @@ -509,9 +518,38 @@ func (request *RequestInformation) AddQueryParameters(source any) {
}
request.QueryParametersAny[fieldName] = tmp
}
arr, ok := value.([]any)
if ok && len(arr) > 0 {
if arr, ok := value.([]any); ok && len(arr) > 0 {
request.QueryParametersAny[fieldName] = arr
}
normalizedEnumValue := request.normalizeEnumParameters(valueOfValue, value, true)
if normalizedEnumValue != nil {
request.QueryParametersAny[fieldName] = normalizedEnumValue
}
}
}
func (request *RequestInformation) normalizeEnumParameters(valueOfValue reflect.Value, value any, returnNilIfNotEnum bool) any {
if valueOfValue.Kind() == reflect.Slice && valueOfValue.Len() > 0 {
//type assertions to "enums" don't work if you don't know the enum type in advance, we need to use reflection
enumArr := valueOfValue.Slice(0, valueOfValue.Len())
strRepresentations := make([]string, valueOfValue.Len())
if _, ok := enumArr.Index(0).Interface().(kiotaEnum); ok {
// testing the first value is an enum to avoid iterating over the whole array if it's not
for i := range strRepresentations {
strRepresentations[i] = enumArr.Index(i).Interface().(kiotaEnum).String()
}
return strRepresentations
}
} else if enum, ok := value.(kiotaEnum); ok {
return enum.String()
}

if returnNilIfNotEnum {
return nil
} else {
return value
}
}

type kiotaEnum interface {
String() string
}
62 changes: 62 additions & 0 deletions request_information_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type QueryParameters struct {
Select_escaped []string
Skip *int32
Top *int32
Status *internal.PersonStatus `uriparametername:"status"`
Statuses []internal.PersonStatus `uriparametername:"statuses"`
}

func TestItAddsStringQueryParameters(t *testing.T) {
Expand Down Expand Up @@ -174,6 +176,66 @@ func TestItBuildsUrlOnProvidedBaseUrl(t *testing.T) {
assert.Equal(t, "http://localhost/users", resultUri.String())
}

func TestItSetsEnumValueInQueryParameters(t *testing.T) {
requestInformation := NewRequestInformation()
requestInformation.UrlTemplate = "{+baseurl}/users{?status}"

requestInformation.PathParameters["baseurl"] = "http://localhost"

status := internal.ACTIVE
requestInformation.AddQueryParameters(QueryParameters{
Status: &status,
})
resultUri, err := requestInformation.GetUri()
assert.Nil(t, err)
assert.Equal(t, "http://localhost/users?status=active", resultUri.String())
}

func TestItSetsEnumValuesInQueryParameters(t *testing.T) {
requestInformation := NewRequestInformation()
requestInformation.UrlTemplate = "{+baseurl}/users{?statuses}"

requestInformation.PathParameters["baseurl"] = "http://localhost"

statuses := make([]internal.PersonStatus, 2)
statuses[0] = internal.ACTIVE
statuses[1] = internal.SUSPENDED
requestInformation.AddQueryParameters(QueryParameters{
Statuses: statuses,
})
resultUri, err := requestInformation.GetUri()
assert.Nil(t, err)
assert.Equal(t, "http://localhost/users?statuses=active,suspended", resultUri.String())
}

func TestItSetsEnumValueInPathParameters(t *testing.T) {
requestInformation := NewRequestInformation()
requestInformation.UrlTemplate = "{+baseurl}/{status}"

status := internal.ACTIVE
requestInformation.PathParameters["baseurl"] = "http://localhost"
requestInformation.PathParametersAny["status"] = &status

resultUri, err := requestInformation.GetUri()
assert.Nil(t, err)
assert.Equal(t, "http://localhost/active", resultUri.String())
}

func TestItSetsEnumValuesInPathParameters(t *testing.T) {
requestInformation := NewRequestInformation()
requestInformation.UrlTemplate = "{+baseurl}/{statuses}"

statuses := make([]internal.PersonStatus, 2)
statuses[0] = internal.ACTIVE
statuses[1] = internal.SUSPENDED
requestInformation.PathParameters["baseurl"] = "http://localhost"
requestInformation.PathParametersAny["statuses"] = statuses

resultUri, err := requestInformation.GetUri()
assert.Nil(t, err)
assert.Equal(t, "http://localhost/active,suspended", resultUri.String())
}

func TestItSetsExplodedQueryParameters(t *testing.T) {
value := true
requestInformation := NewRequestInformation()
Expand Down
9 changes: 5 additions & 4 deletions utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package abstractions

import (
"errors"
"strconv"
"testing"

"github.com/microsoft/kiota-abstractions-go/internal"
"github.com/microsoft/kiota-abstractions-go/serialization"
"github.com/stretchr/testify/assert"
"strconv"
"testing"
)

func TestSetValueWithoutError(t *testing.T) {
Expand Down Expand Up @@ -133,15 +134,15 @@ func TestSetReferencedEnumValueValueValueWithError(t *testing.T) {
func TestSetCollectionOfReferencedEnumValueWithoutError(t *testing.T) {
person := internal.NewPerson()

slice := []interface{}{p(internal.ACTIVE), p(internal.SUSPEND)}
slice := []interface{}{p(internal.ACTIVE), p(internal.SUSPENDED)}
enumSource := func(parser serialization.EnumFactory) ([]interface{}, error) {
return slice, nil
}

err := SetCollectionOfReferencedEnumValue(enumSource, internal.ParsePersonStatus, person.SetPreviousStatus)
assert.Nil(t, err)
assert.Equal(t, person.GetPreviousStatus()[0].String(), internal.ACTIVE.String())
assert.Equal(t, person.GetPreviousStatus()[1].String(), internal.SUSPEND.String())
assert.Equal(t, person.GetPreviousStatus()[1].String(), internal.SUSPENDED.String())
}

func TestSetCollectionOfReferencedEnumValueWithError(t *testing.T) {
Expand Down