form
form copied to clipboard
Incorrectly decode to embedded field
If same field exists both in parent and embedded struct and url.Values has value only for parent then decoder incorrect set embedded field to same value.
type Embed struct {
A string
}
var data struct {
A string
Embed
}
form.NewDecoder().Decode(&data, url.Values{
"A": {"one"},
})
fmt.Println(data.A, data.Embed.A)
// Output: one one
If we will add "Embed.A":{"two"} or keep only this one and remove "A": {"one"} then it'll work as expected.
This was one that I struggled with a bit and was done on purpose see:
https://github.com/go-playground/form/issues/19 https://github.com/go-playground/form/releases/tag/v3.0.0
in hindsight perhaps I should have made it a configurable option...that can still be done though.
if a struct and embedded struct have the same field, this will decode the value into both fields as there is no way to tell which you want
Why is that? It's very easy to tell - just use same rules as Go itself. If there are two different fields in a struct you're decoding to and just one input value then why do you think anyone may like to put this value into both fields? Go doesn't do this, and we shouldn't too.
Of course, there is another one, perfectly legal, use case - when field is just one, but it has two (or more) different names because of embedding struct. In this case decoder should let us to use any of these names (because Go let us work in same way) - and this is already supported.
I agree, for the most part, The trouble ATM is this library does not do a lookahead to know if there is another field with the same name to know that there are two fields which can also be quite an undertaking when multiple embeds exist I will have to look into 2 options:
-
look at extending the cache logic, which is difficult as many values can be uninitialized and need to be initialized before traversing, not insurmountable, but also not fun.
-
add a setting to each map value indicating it's already been set, which seems like the easiest and least performance impacting solution.
I'll think about how I can integrate # 2 which also gives me some ideas for solving/implementing some other enhancements.
know if there is another field with the same name
What's for? Why you can't just decode each value as is and let Go handle embedded fields for you?
In any case, just FYI, I'm now working on implementing #28 as a wrapper for this package (this doesn't mean I give up on idea to turn it into PR to this package if you'll decide you want it), and while it's still WIP and not stabilized yet I've already implemented user's data structure introspection which may be useful for you if you really need to know embedded field name aliases for something. (This code will be on github with MIT license as soon as it'll be finished - in a few days, I hope.) For example, given this data structure:
type Embed struct {
B string
}
var data struct {
A string
Embed
}
it'll return something like this:
type constraint struct {
alias string // shortest of all aliases
// there are other fields here too, unrelated to current subject
}
// keys in result are all possible legal url.Values keys which can be decoded
result := map[string]constraint{
"A": {alias: "A"},
"B": {alias: "B"},
"Embed.B": {alias: "B"},
}