Skip to content

Commit

Permalink
allow custom encoders to handle nil pointers
Browse files Browse the repository at this point in the history
If a custom encoder is defined on a pointer of a type, allow that
encoder to handle nil values.  Encoders defined on non-pointer types
will continue to be given the zero value of the type to encode (the
existing behavior).

Fixes #46
  • Loading branch information
willnorris committed Feb 24, 2021
1 parent 597fdbe commit 05266dc
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 14 deletions.
19 changes: 11 additions & 8 deletions query/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,10 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error {
continue
}

for sv.Kind() == reflect.Ptr {
if sv.IsNil() {
break
}
sv = sv.Elem()
}

if sv.Type().Implements(encoderType) {
if !reflect.Indirect(sv).IsValid() {
// if sv is a nil pointer and the custom encoder is defined on a non-pointer
// method receiver, set sv to the zero value of the underlying type
if !reflect.Indirect(sv).IsValid() && sv.Type().Elem().Implements(encoderType) {
sv = reflect.New(sv.Type().Elem())
}

Expand All @@ -197,6 +192,14 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error {
continue
}

// recursively dereference pointers. break on nil pointers
for sv.Kind() == reflect.Ptr {
if sv.IsNil() {
break
}
sv = sv.Elem()
}

if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array {
var del string
if opts.Contains("comma") {
Expand Down
13 changes: 7 additions & 6 deletions query/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,9 +553,10 @@ type customEncodedIntPtr int
// values cause an error.
func (m *customEncodedIntPtr) EncodeValues(key string, v *url.Values) error {
if m == nil {
return nil
v.Set(key, "undefined")
} else {
v.Set(key, fmt.Sprintf("_%d", *m))
}
v.Set(key, fmt.Sprintf("_%d", *m))
return nil
}

Expand Down Expand Up @@ -594,7 +595,7 @@ func TestValues_CustomEncodingPointer(t *testing.T) {
struct {
V *customEncodedIntPtr `url:"v"`
}{},
url.Values{"v": {"_0"}},
url.Values{"v": {"undefined"}},
},
{
struct {
Expand All @@ -606,19 +607,19 @@ func TestValues_CustomEncodingPointer(t *testing.T) {
struct {
V *customEncodedIntPtr `url:"v"`
}{&zero},
url.Values{"v": {"0"}},
url.Values{"v": {"_0"}},
},
{
struct {
V *customEncodedIntPtr `url:"v,omitempty"`
}{&zero},
url.Values{"v": {"0"}},
url.Values{"v": {"_0"}},
},
{
struct {
V *customEncodedIntPtr `url:"v"`
}{&one},
url.Values{"v": {"1"}},
url.Values{"v": {"_1"}},
},
}

Expand Down

0 comments on commit 05266dc

Please # to comment.