Ability to fx.Populate a named value
jkanywhere opened this issue · 6 comments
Is your feature request related to a problem? Please describe.
fx.Populate
makes it very easy to extract a value of a given type during testing.
It is less easy to use when the value is named.
Given a module that fx.Provide
s the following Result
package examplefx
type Result struct {
fx.Out
S string `name:"special"`
}
var Module := fx.Provide(
func(...) Result { ... },
)
If we want to test the module by seeing what value it provides, this does not work:
package examplefx_test
var s string
...
fx.Populate(&s)
Describe the solution you'd like
I'm open to suggestions. The cleanest solution probably involves fx.Annotate
.
Maybe something like
fx.Populate(
fx.Annotate(&s, fx.ParamTags(`name:"special"`)),
)
Using fx.Annotate
has the benefit it could also support extracting a value group, or an fx.From
.
Describe alternatives you've considered
Passing an fx.In
to fx.Populate
is currently supported in Fx and achieves the desired effect at the cost of more code, i.e. defining a new type that is then just thrown away.
type wrapper struct {
fx.In
S string `name:"special"`
}
var w wrapper
...
fx.Populate(&w),
...
w.S // Retrieve the desired value.
Another approach that is currently supported is to use fx.Invoke
instead of fx.Populate
. fx.Invoke
can be used with fx.Annotate
. This requires a wrapper function.
var s string
...
fx.Invoke(
fx.Annotate(
func(a string) { s = a }, // Requires a wrapper function.
fx.ParamTags(`name:"special"`),
),
),
...
s // Holds the desired value.
Is this a breaking change?
A backward compatible solution can be provided.
Additional context
n/a
fx.Populate can get a named value. The issue with the example you posted is that you're using an fx.Out
struct to populate that struct. Out
structs are strictly for populating result types that are returned by constructor.
Populate, on the other hand, is like extracting values from the DI container, so you should treat it like an input parameter struct. If you change that struct definition to be fx.In
, it should be able to populate the named field.
For example, the following code can populate S
func main() {
type Result struct {
fx.In
S string `name:"special"`
}
var r Result
app := fx.New(
fx.Provide(fx.Annotate(func() string {
return "hello"
}, fx.ResultTags(`name:"special"`))),
fx.Populate(&r),
)
fmt.Println(r.S)
app.Run()
}
On the other hand, fx.Annotate does not yet work with fx.Populate, and that's definitely something we can address.
fx.Annotate
does not yet work withfx.Populate
, and that's definitely something we can address.
Thanks!
The issue with the example you posted is that you're using an
fx.Out
struct to populate that struct.
Result
struct containing fx.Out
was meant to exemplify what a module under test would provide. I've clarified the issue.
On the other hand, fx.Annotate does not yet work with fx.Populate, and that's definitely something we can address.
That would be nice :)
cc @moisesvega in case you were interested in picking this up. (feel free to assign yourself if so)
Internal ref: GO-1951.
#1089 enables using fx.Annotate with fx.Populate.