Skip to content

Commit 8e44b94

Browse files
danicc097mromaszewiczclaude
authored
Support array of objects parameters (#40)
* test update * fix array of objects unmarshaling * update tests * update tests * update tests * chore: revert cosmetic changes to deepobject.go Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Marcin Romaszewicz <marcinr@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7c15f63 commit 8e44b94

File tree

2 files changed

+67
-20
lines changed

2 files changed

+67
-20
lines changed

bindparam_test.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,20 @@ func TestSplitParameter(t *testing.T) {
294294

295295
func TestBindQueryParameter(t *testing.T) {
296296
t.Run("deepObject", func(t *testing.T) {
297+
type Object struct {
298+
Count int `json:"count"`
299+
}
300+
type Nested struct {
301+
Object Object `json:"object"`
302+
Objects []Object `json:"objects"`
303+
}
297304
type ID struct {
298305
FirstName *string `json:"firstName"`
299306
LastName *string `json:"lastName"`
300307
Role string `json:"role"`
301308
Birthday *types.Date `json:"birthday"`
302309
Married *MockBinder `json:"married"`
310+
Nested Nested `json:"nested"`
303311
}
304312

305313
expectedName := "Alex"
@@ -308,16 +316,23 @@ func TestBindQueryParameter(t *testing.T) {
308316
Role: "admin",
309317
Birthday: &types.Date{Time: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)},
310318
Married: &MockBinder{time.Date(2020, 2, 2, 0, 0, 0, 0, time.UTC)},
319+
Nested: Nested{
320+
Object: Object{Count: 123},
321+
Objects: []Object{{Count: 1}, {Count: 2}},
322+
},
311323
}
312324

313325
actual := new(ID)
314326
paramName := "id"
315327
queryParams := url.Values{
316-
"id[firstName]": {"Alex"},
317-
"id[role]": {"admin"},
318-
"foo": {"bar"},
319-
"id[birthday]": {"2020-01-01"},
320-
"id[married]": {"2020-02-02"},
328+
"id[firstName]": {"Alex"},
329+
"id[role]": {"admin"},
330+
"foo": {"bar"},
331+
"id[birthday]": {"2020-01-01"},
332+
"id[married]": {"2020-02-02"},
333+
"id[nested][object][count]": {"123"},
334+
"id[nested][objects][0][count]": {"1"},
335+
"id[nested][objects][1][count]": {"2"},
321336
}
322337

323338
err := BindQueryParameter("deepObject", true, false, paramName, queryParams, &actual)

deepobject_test.go

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,45 @@ import (
1010
"github.com/stretchr/testify/require"
1111
)
1212

13+
type InnerArrayObject struct {
14+
Names []string `json:"names"`
15+
}
16+
1317
type InnerObject struct {
1418
Name string
1519
ID int
1620
}
1721

22+
type InnerObject2 struct {
23+
Foo string
24+
Is bool
25+
}
26+
27+
type InnerObject3 struct {
28+
Foo string
29+
Count *int `json:"count,omitempty"`
30+
}
31+
1832
// These are all possible field types, mandatory and optional.
1933
type AllFields struct {
20-
I int `json:"i"`
21-
Oi *int `json:"oi,omitempty"`
22-
F float32 `json:"f"`
23-
Of *float32 `json:"of,omitempty"`
24-
B bool `json:"b"`
25-
Ob *bool `json:"ob,omitempty"`
26-
As []string `json:"as"`
27-
Oas *[]string `json:"oas,omitempty"`
28-
O InnerObject `json:"o"`
29-
Oo *InnerObject `json:"oo,omitempty"`
30-
D MockBinder `json:"d"`
31-
Od *MockBinder `json:"od,omitempty"`
32-
M map[string]int `json:"m"`
33-
Om *map[string]int `json:"om,omitempty"`
34+
I int `json:"i"`
35+
Oi *int `json:"oi,omitempty"`
36+
Ab *[]bool `json:"ab,omitempty"`
37+
F float32 `json:"f"`
38+
Of *float32 `json:"of,omitempty"`
39+
B bool `json:"b"`
40+
Ob *bool `json:"ob,omitempty"`
41+
As []string `json:"as"`
42+
Oas *[]string `json:"oas,omitempty"`
43+
O InnerObject `json:"o"`
44+
Ao []InnerObject2 `json:"ao"`
45+
Aop *[]InnerObject3 `json:"aop"`
46+
Onas InnerArrayObject `json:"onas"`
47+
Oo *InnerObject `json:"oo,omitempty"`
48+
D MockBinder `json:"d"`
49+
Od *MockBinder `json:"od,omitempty"`
50+
M map[string]int `json:"m"`
51+
Om *map[string]int `json:"om,omitempty"`
3452
}
3553

3654
func TestDeepObject(t *testing.T) {
@@ -47,19 +65,33 @@ func TestDeepObject(t *testing.T) {
4765
}
4866
d := MockBinder{Time: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC)}
4967

68+
two := 2
69+
5070
srcObj := AllFields{
5171
I: 12,
5272
Oi: &oi,
5373
F: 4.2,
5474
Of: &of,
5575
B: true,
5676
Ob: &ob,
77+
Ab: &[]bool{true},
5778
As: []string{"hello", "world"},
5879
Oas: &oas,
5980
O: InnerObject{
6081
Name: "Joe Schmoe",
6182
ID: 456,
6283
},
84+
Ao: []InnerObject2{
85+
{Foo: "bar", Is: true},
86+
{Foo: "baz"},
87+
},
88+
Aop: &[]InnerObject3{
89+
{Foo: "a"},
90+
{Foo: "b", Count: &two},
91+
},
92+
Onas: InnerArrayObject{
93+
Names: []string{"Bill", "Frank"},
94+
},
6395
Oo: &oo,
6496
D: d,
6597
Od: &d,
@@ -69,7 +101,7 @@ func TestDeepObject(t *testing.T) {
69101

70102
marshaled, err := MarshalDeepObject(srcObj, "p")
71103
require.NoError(t, err)
72-
t.Log(marshaled)
104+
require.EqualValues(t, "p[ab][0]=true&p[ao][0][Foo]=bar&p[ao][0][Is]=true&p[ao][1][Foo]=baz&p[ao][1][Is]=false&p[aop][0][Foo]=a&p[aop][1][Foo]=b&p[aop][1][count]=2&p[as][0]=hello&p[as][1]=world&p[b]=true&p[d]=2020-02-01&p[f]=4.2&p[i]=12&p[m][additional]=1&p[o][ID]=456&p[o][Name]=Joe Schmoe&p[oas][0]=foo&p[oas][1]=bar&p[ob]=true&p[od]=2020-02-01&p[of]=3.7&p[oi]=5&p[om][additional]=1&p[onas][names][0]=Bill&p[onas][names][1]=Frank&p[oo][ID]=123&p[oo][Name]=Marcin Romaszewicz", marshaled)
73105

74106
params := make(url.Values)
75107
marshaledParts := strings.Split(marshaled, "&")

0 commit comments

Comments
 (0)