From 1ce269b157fa297d25312b7ac10834b163a0548e Mon Sep 17 00:00:00 2001 From: Sam Morrison Date: Sat, 24 Jul 2021 12:14:41 -0600 Subject: [PATCH 1/7] Added tag option to JSON encode a field of type struct --- query/encode.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/query/encode.go b/query/encode.go index 91198f8..295345d 100644 --- a/query/encode.go +++ b/query/encode.go @@ -119,6 +119,14 @@ type Encoder interface { // // "user[name]=acme&user[addr][postcode]=1234&user[addr][city]=SFO" // +// Structs can be encoded as JSON by including the "json" option in that fields +// tag. The entire struct is then passed to encoding/json.Marshal where those +// tag signatures apply. +// +// // Encoding a struct as JSON +// Field A `url: "myName,json"` +// // Result: myName={"someField": "cat", "numField": 1} +// // All other values are encoded using their default string representation. // // Multiple fields that encode to the same URL parameter name will be included @@ -252,8 +260,17 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error { } if sv.Kind() == reflect.Struct { - if err := reflectValue(values, sv, name); err != nil { - return err + if opts.Contains("json") { + var b []byte + if b, err := json.Marshall(sv); err != nil { + return err + } + + values.Add(name, valueString(string(b), opts, sf)) + } else { + if err := reflectValue(values, sv, name); err != nil { + return err + } } continue } From 95f9246effb6f1d1748b76cc6c8859f3898fa6e6 Mon Sep 17 00:00:00 2001 From: Sam Morrison Date: Sat, 24 Jul 2021 12:19:54 -0600 Subject: [PATCH 2/7] remove 'l' from 'Marshall' --- query/encode.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/query/encode.go b/query/encode.go index 295345d..171493b 100644 --- a/query/encode.go +++ b/query/encode.go @@ -22,6 +22,7 @@ package query import ( "bytes" + "encoding/json" "fmt" "net/url" "reflect" @@ -262,7 +263,7 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error { if sv.Kind() == reflect.Struct { if opts.Contains("json") { var b []byte - if b, err := json.Marshall(sv); err != nil { + if b, err := json.Marshal(sv); err != nil { return err } From b1dafe0ac45be12b3d6aa7e915b83bc0260dd9ef Mon Sep 17 00:00:00 2001 From: Sam Morrison Date: Sun, 25 Jul 2021 11:33:11 -0600 Subject: [PATCH 3/7] add tests --- query/encode_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/query/encode_test.go b/query/encode_test.go index 8487858..c281200 100644 --- a/query/encode_test.go +++ b/query/encode_test.go @@ -404,6 +404,54 @@ func TestValues_EmbeddedStructs(t *testing.T) { } } + +func TestValues_StructsAsJSON(t *testing.T) { + type Inner struct { + A string `json:"a"` + B int `json:"b"` + T struct { + L bool `json:"l"` + M bool `json:"m"` + } `json:"t"` + } + + type Outer struct { + S Inner `url:"str,json"` + P *Inner `url:"ptr,json,omitempty"` + } + + tests := []struct { + input interface{} + want url.Values + }{ + { + Outer { + S: Inner { + A: "abc", + B: 5, + T: struct { + L bool `json:"l"` + M bool `json:"m"` + } `json:"t"`, + }, + P: nil, + }, + url.Values{ + "str": {"{\"a\": \"abc\", \"b\": 5, \"t\": {\"l\": false, \"m\": false}}"}, + "ptr": {""}, + }, + }, + { + nil, + url.Values{}, + }, + } + + for _, tt := range tests { + testValue(t, tt.input, tt.want) + } +} + func TestValues_InvalidInput(t *testing.T) { _, err := Values("") if err == nil { From f9f9cd1847b02ae86609c3380324a6a8ab21cab7 Mon Sep 17 00:00:00 2001 From: schmorrison Date: Sun, 25 Jul 2021 11:46:09 -0600 Subject: [PATCH 4/7] fix call to json.Marshal and reflect value of json --- query/encode.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/query/encode.go b/query/encode.go index 171493b..8086918 100644 --- a/query/encode.go +++ b/query/encode.go @@ -263,11 +263,12 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error { if sv.Kind() == reflect.Struct { if opts.Contains("json") { var b []byte - if b, err := json.Marshal(sv); err != nil { + b, err := json.Marshal(sv.Interface()) + if err != nil { return err } - values.Add(name, valueString(string(b), opts, sf)) + values.Add(name, valueString(reflect.ValueOf(string(b)), opts, sf)) } else { if err := reflectValue(values, sv, name); err != nil { return err From 63255daeb14a11025032f4c14f299a29e2e924fb Mon Sep 17 00:00:00 2001 From: schmorrison Date: Sun, 25 Jul 2021 11:46:56 -0600 Subject: [PATCH 5/7] fix test response, remove spaces and escapedquotes --- query/encode_test.go | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/query/encode_test.go b/query/encode_test.go index c281200..71255c4 100644 --- a/query/encode_test.go +++ b/query/encode_test.go @@ -404,19 +404,19 @@ func TestValues_EmbeddedStructs(t *testing.T) { } } - func TestValues_StructsAsJSON(t *testing.T) { + type Nested struct { + L bool `json:"l"` + M bool `json:"m"` + } type Inner struct { A string `json:"a"` - B int `json:"b"` - T struct { - L bool `json:"l"` - M bool `json:"m"` - } `json:"t"` + B int `json:"b"` + T Nested `json:"t"` } type Outer struct { - S Inner `url:"str,json"` + S Inner `url:"str,json"` P *Inner `url:"ptr,json,omitempty"` } @@ -425,20 +425,19 @@ func TestValues_StructsAsJSON(t *testing.T) { want url.Values }{ { - Outer { - S: Inner { + Outer{ + S: Inner{ A: "abc", B: 5, - T: struct { - L bool `json:"l"` - M bool `json:"m"` - } `json:"t"`, + T: Nested{ + L: true, + M: false, + }, }, P: nil, }, url.Values{ - "str": {"{\"a\": \"abc\", \"b\": 5, \"t\": {\"l\": false, \"m\": false}}"}, - "ptr": {""}, + "str": {`{"a":"abc","b":5,"t":{"l":true,"m":false}}`}, }, }, { From ff5bcf446f7898af7e04d1211704fdce29c05aad Mon Sep 17 00:00:00 2001 From: schmorrison Date: Sun, 25 Jul 2021 11:51:18 -0600 Subject: [PATCH 6/7] add tests --- query/encode_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/query/encode_test.go b/query/encode_test.go index 71255c4..2463927 100644 --- a/query/encode_test.go +++ b/query/encode_test.go @@ -440,6 +440,28 @@ func TestValues_StructsAsJSON(t *testing.T) { "str": {`{"a":"abc","b":5,"t":{"l":true,"m":false}}`}, }, }, + { + Outer{ + P: &Inner{ + A: "def", + B: 22, + T: Nested{ + L: true, + M: true, + }, + }, + }, + url.Values{ + "str": {`{"a":"","b":0,"t":{"l":false,"m":false}}`}, + "ptr": {`{"a":"def","b":22,"t":{"l":true,"m":true}}`}, + }, + }, + { + Outer{}, + url.Values{ + "str": {`{"a":"","b":0,"t":{"l":false,"m":false}}`}, + }, + }, { nil, url.Values{}, From 48243d2716303296b6a30ee73c63cd0ef21caedf Mon Sep 17 00:00:00 2001 From: Sam Morrison Date: Mon, 26 Jul 2021 08:44:17 -0600 Subject: [PATCH 7/7] Update go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 1053de0..92c04ec 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/google/go-querystring +module github.com/schmorrison/go-querystring go 1.10