Skip to content

Commit 2f94b8c

Browse files
authored
Reimplement default values (#65)
1 parent 35832e6 commit 2f94b8c

File tree

9 files changed

+180
-74
lines changed

9 files changed

+180
-74
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: Setup go
2626
uses: actions/setup-go@v2
2727
with:
28-
go-version: '1.19'
28+
go-version: '1.20'
2929
- name: Setup
3030
run: |
3131
go install github.com/mattn/goveralls@latest

client.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99
"net/http/httptest"
1010
"net/url"
11+
"reflect"
1112
)
1213

1314
type HttpClient interface {
@@ -36,6 +37,14 @@ func NewMockClient(handler http.HandlerFunc) *Client {
3637
}
3738

3839
func (c Client) newRequest(ctx context.Context, method string, uri string, body interface{}) (*http.Request, error) {
40+
// Set default values for empty fields if `default` tag is present
41+
// And body is not nil
42+
if body != nil {
43+
if err := getDefaultValues(reflect.ValueOf(body)); err != nil {
44+
return nil, err
45+
}
46+
}
47+
3948
bodyJson, err := json.Marshal(body)
4049
if err != nil {
4150
return nil, err

core.go

Lines changed: 91 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"net/http"
66
"reflect"
7+
"strconv"
78
"testing"
89
"time"
910
)
@@ -32,51 +33,103 @@ func (r Response) CopyCommonResponse(rhs *CommonResponse) {
3233
rhs.Message = r.Message
3334
}
3435

35-
func getDefaultValues(v interface{}) (map[string]string, error) {
36-
isNil, err := isZero(v)
37-
if err != nil {
38-
return make(map[string]string), err
39-
}
40-
41-
if isNil {
42-
return make(map[string]string), nil
43-
}
44-
45-
out := make(map[string]string)
46-
47-
vType := reflect.TypeOf(v).Elem()
48-
vValue := reflect.ValueOf(v).Elem()
36+
func getDefaultValues(v reflect.Value) error {
37+
vValue := v.Elem()
38+
vType := vValue.Type()
4939

5040
for i := 0; i < vType.NumField(); i++ {
5141
field := vType.Field(i)
52-
tag := field.Tag.Get("json")
53-
defaultValue := field.Tag.Get("default")
54-
55-
if field.Type.Kind() == reflect.Slice {
56-
// Attach any slices as query params
57-
fieldVal := vValue.Field(i)
58-
for j := 0; j < fieldVal.Len(); j++ {
59-
out[tag] = fmt.Sprintf("%v", fieldVal.Index(j))
60-
}
61-
} else {
62-
// Add any scalar values as query params
63-
fieldVal := fmt.Sprintf("%v", vValue.Field(i))
64-
65-
// If no value was set by the user, use the default
66-
// value specified in the struct tag.
67-
if fieldVal == "" || fieldVal == "0" {
68-
if defaultValue == "" {
42+
43+
switch field.Type.Kind() {
44+
case reflect.Slice:
45+
for j := 0; j < vValue.Field(i).Len(); j++ {
46+
// skip if slice type is primitive
47+
if vValue.Field(i).Index(j).Kind() != reflect.Struct {
6948
continue
7049
}
7150

72-
fieldVal = defaultValue
51+
// Attach any slices as query params
52+
err := getDefaultValues(vValue.Field(i).Index(j).Addr())
53+
if err != nil {
54+
return err
55+
}
56+
}
57+
case reflect.String:
58+
isNil, err := isZero(vValue.Field(i).Addr())
59+
if err != nil {
60+
return err
61+
}
62+
if !isNil {
63+
continue
64+
}
65+
66+
defaultValue, ok := field.Tag.Lookup("default")
67+
if !ok {
68+
continue
69+
}
70+
71+
vValue.Field(i).SetString(defaultValue)
72+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
73+
isNil, err := isZero(vValue.Field(i).Addr())
74+
if err != nil {
75+
return err
76+
}
77+
if !isNil {
78+
continue
79+
}
80+
81+
defaultValue, ok := field.Tag.Lookup("default")
82+
if !ok {
83+
continue
84+
}
85+
defaultValueInt, err := strconv.Atoi(defaultValue)
86+
if err != nil {
87+
return err
88+
}
89+
90+
vValue.Field(i).SetInt(int64(defaultValueInt))
91+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
92+
isNil, err := isZero(vValue.Field(i).Addr())
93+
if err != nil {
94+
return err
95+
}
96+
if !isNil {
97+
continue
7398
}
7499

75-
out[tag] = fmt.Sprintf("%v", fieldVal)
100+
defaultValue, ok := field.Tag.Lookup("default")
101+
if !ok {
102+
continue
103+
}
104+
defaultValueUint, err := strconv.ParseUint(defaultValue, 10, 64)
105+
if err != nil {
106+
return err
107+
}
108+
109+
vValue.Field(i).SetUint(uint64(defaultValueUint))
110+
case reflect.Struct:
111+
err := getDefaultValues(vValue.Field(i).Addr())
112+
if err != nil {
113+
return err
114+
}
115+
case reflect.Ptr:
116+
isNil, err := isZero(vValue.Field(i).Addr())
117+
if err != nil {
118+
return err
119+
}
120+
if isNil {
121+
continue
122+
}
123+
124+
if err := getDefaultValues(vValue.Field(i)); err != nil {
125+
return err
126+
}
127+
default:
128+
continue
76129
}
77130
}
78131

79-
return out, nil
132+
return nil
80133
}
81134

82135
func buildRawQuery(req *http.Request, v interface{}) (string, error) {
@@ -86,23 +139,20 @@ func buildRawQuery(req *http.Request, v interface{}) (string, error) {
86139
return query.Encode(), nil
87140
}
88141

89-
values, err := getDefaultValues(v)
142+
err := getDefaultValues(reflect.ValueOf(v))
90143
if err != nil {
91144
return "", err
92145
}
93-
for k, v := range values {
94-
query.Add(k, v)
95-
}
96146

97147
return query.Encode(), nil
98148
}
99149

100-
func isZero(v interface{}) (bool, error) {
101-
t := reflect.TypeOf(v)
150+
func isZero(v reflect.Value) (bool, error) {
151+
t := v.Elem().Type()
102152
if !t.Comparable() {
103153
return false, fmt.Errorf("type is not comparable: %v", t)
104154
}
105-
return v == reflect.Zero(t).Interface(), nil
155+
return reflect.Zero(t).Equal(v.Elem()), nil
106156
}
107157

108158
func TimeFromString(t *testing.T, format, datetime string) time.Time {

core_test.go

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,56 @@
11
package core
22

33
import (
4-
"log"
4+
"reflect"
55
"testing"
6+
7+
"github.com/stretchr/testify/assert"
68
)
79

8-
type TestTagDefaultValueStruct struct {
9-
TestString string `json:"test_string" default:"something"`
10-
TestNumber int `json:"test_number" default:"12"`
10+
type DefaultStructure struct {
11+
EmptyField string `json:"empty_field" default:"empty_string"`
12+
Field string `json:"field" default:"string"`
1113
}
1214

13-
func TestTagDefaultValue(t *testing.T) {
14-
testStruct := &TestTagDefaultValueStruct{}
15-
16-
values, err := getDefaultValues(testStruct)
17-
if err != nil {
18-
log.Fatalf("error when getting default values from tags: %s", err)
19-
}
15+
type DefaultRequest struct {
16+
Field int `json:"field" default:"100"`
17+
EmptyField int `json:"empty_field" default:"14"`
18+
Structure DefaultStructure `json:"structure"`
19+
Slice []DefaultStructure `json:"slice"`
20+
OptionalStructure *DefaultStructure `json:"optional_structure"`
21+
EmptyOptionalStructure *DefaultStructure `json:"empty_optional_structure"`
22+
}
2023

21-
expected := map[string]string{
22-
"test_string": "something",
23-
"test_number": "12",
24+
func TestDefaultValues(t *testing.T) {
25+
req := &DefaultRequest{
26+
Field: 50,
27+
Structure: DefaultStructure{
28+
Field: "something",
29+
},
30+
Slice: []DefaultStructure{
31+
{
32+
Field: "something",
33+
},
34+
{
35+
Field: "something",
36+
},
37+
},
38+
OptionalStructure: &DefaultStructure{
39+
Field: "something",
40+
},
2441
}
42+
err := getDefaultValues(reflect.ValueOf(req))
43+
assert.Nil(t, err)
2544

26-
if len(values) != len(expected) {
27-
log.Fatalf("expected equal length of values and expected: expected: %d, got: %d", len(expected), len(values))
28-
}
29-
for expKey, expValue := range expected {
30-
if expValue != values[expKey] {
31-
log.Fatalf("not equal values for key %s", expKey)
32-
}
33-
}
45+
assert.Equal(t, 50, req.Field)
46+
assert.Equal(t, 14, req.EmptyField)
47+
assert.Equal(t, "something", req.Structure.Field)
48+
assert.Equal(t, "empty_string", req.Structure.EmptyField)
49+
assert.Equal(t, "something", req.Slice[0].Field)
50+
assert.Equal(t, "something", req.Slice[1].Field)
51+
assert.Equal(t, "empty_string", req.Slice[1].EmptyField)
52+
assert.Equal(t, "empty_string", req.Slice[1].EmptyField)
53+
assert.Equal(t, "something", req.OptionalStructure.Field)
54+
assert.Equal(t, "empty_string", req.OptionalStructure.EmptyField)
55+
assert.Equal(t, (*DefaultStructure)(nil), req.EmptyOptionalStructure)
3456
}

go.mod

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
module github.com/diphantxm/ozon-api-client
22

3-
go 1.19
3+
go 1.20
4+
5+
require (
6+
github.com/davecgh/go-spew v1.1.1 // indirect
7+
github.com/pmezard/go-difflib v1.0.0 // indirect
8+
github.com/stretchr/objx v0.5.0 // indirect
9+
github.com/stretchr/testify v1.8.4 // indirect
10+
gopkg.in/yaml.v3 v3.0.1 // indirect
11+
)

go.sum

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
6+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
7+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
8+
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
9+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
10+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
11+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
12+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
13+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
14+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
15+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
16+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
17+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

ozon/products.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1618,7 +1618,7 @@ func (c Products) GetProductRangeLimit(ctx context.Context) (*GetProductRangeLim
16181618

16191619
resp := &GetProductRangeLimitResponse{}
16201620

1621-
response, err := c.client.Request(ctx, http.MethodPost, url, &struct{}{}, resp, nil)
1621+
response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil)
16221622
if err != nil {
16231623
return nil, err
16241624
}

ozon/returns.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ func (c Returns) IsGiveoutEnabled(ctx context.Context) (*IsGiveoutEnabledRespons
667667

668668
resp := &IsGiveoutEnabledResponse{}
669669

670-
response, err := c.client.Request(ctx, http.MethodPost, url, struct{}{}, resp, nil)
670+
response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil)
671671
if err != nil {
672672
return nil, err
673673
}
@@ -697,7 +697,7 @@ func (c Returns) GetGiveoutPDF(ctx context.Context) (*GetGiveoutResponse, error)
697697

698698
resp := &GetGiveoutResponse{}
699699

700-
response, err := c.client.Request(ctx, http.MethodPost, url, struct{}{}, resp, nil)
700+
response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil)
701701
if err != nil {
702702
return nil, err
703703
}
@@ -714,7 +714,7 @@ func (c Returns) GetGiveoutPNG(ctx context.Context) (*GetGiveoutResponse, error)
714714

715715
resp := &GetGiveoutResponse{}
716716

717-
response, err := c.client.Request(ctx, http.MethodPost, url, struct{}{}, resp, nil)
717+
response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil)
718718
if err != nil {
719719
return nil, err
720720
}
@@ -739,7 +739,7 @@ func (c Returns) GetGiveoutBarcode(ctx context.Context) (*GetGiveoutBarcodeRespo
739739

740740
resp := &GetGiveoutBarcodeResponse{}
741741

742-
response, err := c.client.Request(ctx, http.MethodPost, url, struct{}{}, resp, nil)
742+
response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil)
743743
if err != nil {
744744
return nil, err
745745
}
@@ -758,7 +758,7 @@ func (c Returns) ResetGiveoutBarcode(ctx context.Context) (*GetGiveoutResponse,
758758

759759
resp := &GetGiveoutResponse{}
760760

761-
response, err := c.client.Request(ctx, http.MethodPost, url, struct{}{}, resp, nil)
761+
response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil)
762762
if err != nil {
763763
return nil, err
764764
}
@@ -814,7 +814,7 @@ func (c Returns) GetGiveoutList(ctx context.Context, params *GetGiveoutListParam
814814

815815
resp := &GetGiveoutListResponse{}
816816

817-
response, err := c.client.Request(ctx, http.MethodPost, url, struct{}{}, resp, nil)
817+
response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil)
818818
if err != nil {
819819
return nil, err
820820
}
@@ -867,7 +867,7 @@ func (c Returns) GetGiveoutInfo(ctx context.Context, params *GetGiveoutInfoParam
867867

868868
resp := &GetGiveoutInfoResponse{}
869869

870-
response, err := c.client.Request(ctx, http.MethodPost, url, struct{}{}, resp, nil)
870+
response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil)
871871
if err != nil {
872872
return nil, err
873873
}

ozon/warehouses.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ func (c Warehouses) GetListOfDeliveryMethods(ctx context.Context, params *GetLis
181181

182182
resp := &GetListOfDeliveryMethodsResponse{}
183183

184-
response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil)
184+
response, err := c.client.Request(ctx, http.MethodPost, url, params, resp, nil)
185185
if err != nil {
186186
return nil, err
187187
}

0 commit comments

Comments
 (0)