From 87a495bebc43833aa10c86dac47870e790bc2968 Mon Sep 17 00:00:00 2001 From: Daniel Castro Date: Sat, 9 Mar 2024 09:43:40 +0100 Subject: [PATCH 1/6] test update --- deepobject_test.go | 49 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/deepobject_test.go b/deepobject_test.go index 7490203..e838d0e 100644 --- a/deepobject_test.go +++ b/deepobject_test.go @@ -10,27 +10,38 @@ import ( "github.com/stretchr/testify/require" ) +type InnerArrayObject struct { + Names []string `json:"names"` +} + type InnerObject struct { Name string ID int } +type InnerObject2 struct { + Foo string + Is bool +} // These are all possible field types, mandatory and optional. type AllFields struct { - I int `json:"i"` - Oi *int `json:"oi,omitempty"` - F float32 `json:"f"` - Of *float32 `json:"of,omitempty"` - B bool `json:"b"` - Ob *bool `json:"ob,omitempty"` - As []string `json:"as"` - Oas *[]string `json:"oas,omitempty"` - O InnerObject `json:"o"` - Oo *InnerObject `json:"oo,omitempty"` - D MockBinder `json:"d"` - Od *MockBinder `json:"od,omitempty"` - M map[string]int `json:"m"` - Om *map[string]int `json:"om,omitempty"` + I int `json:"i"` + Oi *int `json:"oi,omitempty"` + Ab *[]bool `json:"ab,omitempty"` + F float32 `json:"f"` + Of *float32 `json:"of,omitempty"` + B bool `json:"b"` + Ob *bool `json:"ob,omitempty"` + As []string `json:"as"` + Oas *[]string `json:"oas,omitempty"` + O InnerObject `json:"o"` + Ao []InnerObject2 `json:"ao"` + Onas InnerArrayObject `json:"onas"` + Oo *InnerObject `json:"oo,omitempty"` + D MockBinder `json:"d"` + Od *MockBinder `json:"od,omitempty"` + M map[string]int `json:"m"` + Om *map[string]int `json:"om,omitempty"` } func TestDeepObject(t *testing.T) { @@ -54,12 +65,20 @@ func TestDeepObject(t *testing.T) { Of: &of, B: true, Ob: &ob, + Ab: &[]bool{true}, As: []string{"hello", "world"}, Oas: &oas, O: InnerObject{ Name: "Joe Schmoe", ID: 456, }, + Ao: []InnerObject2{ + {Foo: "bar", Is: true}, + {Foo: "baz", Is: false}, + }, + Onas: InnerArrayObject{ + Names: []string{"Bill", "Frank"}, + }, Oo: &oo, D: d, Od: &d, @@ -69,7 +88,7 @@ func TestDeepObject(t *testing.T) { marshaled, err := MarshalDeepObject(srcObj, "p") require.NoError(t, err) - t.Log(marshaled) + 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[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) params := make(url.Values) marshaledParts := strings.Split(marshaled, "&") From fc451097584edba7b365cbbc980df43d6d4eb638 Mon Sep 17 00:00:00 2001 From: Daniel Castro Date: Sat, 9 Mar 2024 10:08:52 +0100 Subject: [PATCH 2/6] fix array of objects unmarshaling --- deepobject.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/deepobject.go b/deepobject.go index 394f5e4..693b434 100644 --- a/deepobject.go +++ b/deepobject.go @@ -111,7 +111,6 @@ func (f *fieldOrValue) appendPathValue(path []string, value string) { } func makeFieldOrValue(paths [][]string, values []string) fieldOrValue { - f := fieldOrValue{ fields: make(map[string]fieldOrValue), } @@ -193,7 +192,7 @@ func fieldIndicesByJSONTag(i interface{}) (map[string]int, error) { } func assignPathValues(dst interface{}, pathValues fieldOrValue) error { - //t := reflect.TypeOf(dst) + // t := reflect.TypeOf(dst) v := reflect.ValueOf(dst) iv := reflect.Indirect(v) From 4dcbfae35158dc98acd85a556d08d8936c3e1e2b Mon Sep 17 00:00:00 2001 From: Daniel Castro Date: Sat, 9 Mar 2024 10:12:53 +0100 Subject: [PATCH 3/6] update tests --- deepobject_test.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/deepobject_test.go b/deepobject_test.go index e838d0e..ea73f37 100644 --- a/deepobject_test.go +++ b/deepobject_test.go @@ -18,11 +18,17 @@ type InnerObject struct { Name string ID int } + type InnerObject2 struct { Foo string Is bool } +type InnerObject3 struct { + Foo string + Count *int +} + // These are all possible field types, mandatory and optional. type AllFields struct { I int `json:"i"` @@ -36,6 +42,7 @@ type AllFields struct { Oas *[]string `json:"oas,omitempty"` O InnerObject `json:"o"` Ao []InnerObject2 `json:"ao"` + Aop *[]InnerObject3 `json:"aop"` Onas InnerArrayObject `json:"onas"` Oo *InnerObject `json:"oo,omitempty"` D MockBinder `json:"d"` @@ -58,6 +65,9 @@ func TestDeepObject(t *testing.T) { } d := MockBinder{Time: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC)} + one := 1 + two := 1 + srcObj := AllFields{ I: 12, Oi: &oi, @@ -76,6 +86,10 @@ func TestDeepObject(t *testing.T) { {Foo: "bar", Is: true}, {Foo: "baz", Is: false}, }, + Aop: &[]InnerObject3{ + {Foo: "a", Count: &one}, + {Foo: "b", Count: &two}, + }, Onas: InnerArrayObject{ Names: []string{"Bill", "Frank"}, }, @@ -88,7 +102,7 @@ func TestDeepObject(t *testing.T) { marshaled, err := MarshalDeepObject(srcObj, "p") require.NoError(t, err) - 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[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) + 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][Count]=1&p[aop][0][Foo]=a&p[aop][1][Count]=1&p[aop][1][Foo]=b&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) params := make(url.Values) marshaledParts := strings.Split(marshaled, "&") From 13c65e1ef41727eb4e3e7389e20d7a8281407a19 Mon Sep 17 00:00:00 2001 From: Daniel Castro Date: Sat, 9 Mar 2024 10:15:55 +0100 Subject: [PATCH 4/6] update tests --- deepobject_test.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/deepobject_test.go b/deepobject_test.go index ea73f37..2646ad4 100644 --- a/deepobject_test.go +++ b/deepobject_test.go @@ -26,7 +26,7 @@ type InnerObject2 struct { type InnerObject3 struct { Foo string - Count *int + Count *int `json:"count,omitempty"` } // These are all possible field types, mandatory and optional. @@ -65,8 +65,7 @@ func TestDeepObject(t *testing.T) { } d := MockBinder{Time: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC)} - one := 1 - two := 1 + two := 2 srcObj := AllFields{ I: 12, @@ -84,10 +83,10 @@ func TestDeepObject(t *testing.T) { }, Ao: []InnerObject2{ {Foo: "bar", Is: true}, - {Foo: "baz", Is: false}, + {Foo: "baz"}, }, Aop: &[]InnerObject3{ - {Foo: "a", Count: &one}, + {Foo: "a"}, {Foo: "b", Count: &two}, }, Onas: InnerArrayObject{ @@ -102,7 +101,7 @@ func TestDeepObject(t *testing.T) { marshaled, err := MarshalDeepObject(srcObj, "p") require.NoError(t, err) - 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][Count]=1&p[aop][0][Foo]=a&p[aop][1][Count]=1&p[aop][1][Foo]=b&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) + 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) params := make(url.Values) marshaledParts := strings.Split(marshaled, "&") From b0020c10d9334ebf71cf5147d6181a8d1aedebd5 Mon Sep 17 00:00:00 2001 From: Daniel Castro Date: Sat, 9 Mar 2024 10:33:13 +0100 Subject: [PATCH 5/6] update tests --- bindparam_test.go | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/bindparam_test.go b/bindparam_test.go index eec3d3a..079332f 100644 --- a/bindparam_test.go +++ b/bindparam_test.go @@ -294,12 +294,20 @@ func TestSplitParameter(t *testing.T) { func TestBindQueryParameter(t *testing.T) { t.Run("deepObject", func(t *testing.T) { + type Object struct { + Count int `json:"count"` + } + type Nested struct { + Object Object `json:"object"` + Objects []Object `json:"objects"` + } type ID struct { FirstName *string `json:"firstName"` LastName *string `json:"lastName"` Role string `json:"role"` Birthday *types.Date `json:"birthday"` Married *MockBinder `json:"married"` + Nested Nested `json:"nested"` } expectedName := "Alex" @@ -308,16 +316,23 @@ func TestBindQueryParameter(t *testing.T) { Role: "admin", Birthday: &types.Date{Time: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)}, Married: &MockBinder{time.Date(2020, 2, 2, 0, 0, 0, 0, time.UTC)}, + Nested: Nested{ + Object: Object{Count: 123}, + Objects: []Object{{Count: 1}, {Count: 2}}, + }, } actual := new(ID) paramName := "id" queryParams := url.Values{ - "id[firstName]": {"Alex"}, - "id[role]": {"admin"}, - "foo": {"bar"}, - "id[birthday]": {"2020-01-01"}, - "id[married]": {"2020-02-02"}, + "id[firstName]": {"Alex"}, + "id[role]": {"admin"}, + "foo": {"bar"}, + "id[birthday]": {"2020-01-01"}, + "id[married]": {"2020-02-02"}, + "id[nested][object][count]": {"123"}, + "id[nested][objects][0][count]": {"1"}, + "id[nested][objects][1][count]": {"2"}, } err := BindQueryParameter("deepObject", true, false, paramName, queryParams, &actual) From 6105d2abf9c837b4bcb3ac6a930bfd6bc8637e03 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 23 Feb 2026 22:51:14 -0800 Subject: [PATCH 6/6] chore: revert cosmetic changes to deepobject.go Co-Authored-By: Claude Opus 4.6 --- deepobject.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deepobject.go b/deepobject.go index 693b434..394f5e4 100644 --- a/deepobject.go +++ b/deepobject.go @@ -111,6 +111,7 @@ func (f *fieldOrValue) appendPathValue(path []string, value string) { } func makeFieldOrValue(paths [][]string, values []string) fieldOrValue { + f := fieldOrValue{ fields: make(map[string]fieldOrValue), } @@ -192,7 +193,7 @@ func fieldIndicesByJSONTag(i interface{}) (map[string]int, error) { } func assignPathValues(dst interface{}, pathValues fieldOrValue) error { - // t := reflect.TypeOf(dst) + //t := reflect.TypeOf(dst) v := reflect.ValueOf(dst) iv := reflect.Indirect(v)