Custom `String` implementations are not respected
zakcutner opened this issue · comments
Hello! I expect the following example to print int=23&foo=bar
, but instead it prints int=23
. It looks like this was previously working in #45, so there might have been a regression.
package main
import (
"fmt"
"github.com/google/go-querystring/query"
)
type Foo struct{}
func (f Foo) String() string {
return "bar"
}
type Options struct {
Int int `url:"int"`
Foo Foo `url:"foo"`
}
func main() {
opt := Options{23, Foo{}}
v, _ := query.Values(opt)
fmt.Println(v.Encode())
}
because type Foo
is a struct, the default behavior is for go-querystring to try and process the fields of that struct. In this case, it has no fields, so there's nothing to encode. If you want custom behavior, you would need to implement the query.Encoder
interface.
The reason a value was being returned in #45 (I think) is because the field in question was an int
, which defaults to its string representation.
This seems to do what you want: https://go.dev/play/p/K4rYQ7Oeq0k
Thanks for answering so quickly! I don't completely agree about #45 since they said
// got "level=info", want "level=1"
If it was using a default string representation, wouldn't level=1
be returned? In any case, the docs say that
All other values are encoded using their default string representation.
Sorry if I'm missing something but it seems to me that this behaviour conflicts with that.
ah, you're right about it not being the default string representation. But the difference in behavior is still due to using a struct versus non-struct field. The relevant code is here.
In your case, sv.Kind() of your Foo field does return a struct, so it is processed as a struct. In the case of #45, sv.Kind() is an int, so it gets processed by the valueString()
func. Which as you point out, uses the String() method of the type if present, hence the "level=info".
The existing docs do talk about struct fields a little bit, but if there's a way we can describe this behavior better to make it more obvious, I'd welcome that.
Maybe it could be as simple as changing this line in the docs:
Nested structs are encoded including parent fields in value names for scoping.
to something like:
Nested structs have their fields processed recursively and are encoded including parent fields in value names for scoping.
Would that be clearer?
(And here's a quick example I did to double check myself that sv.Kind() returns the underlying kind, even for custom types... https://go.dev/play/p/MJUTVO5RZWn)
Thanks so much, yes I think that would be clearer 😄