Skip to content

Commit

Permalink
Add support for flattened value groups (#700)
Browse files Browse the repository at this point in the history
Fixes #693.

Co-authored-by: Abhinav Gupta <abg@uber.com>
  • Loading branch information
robbertvanginkel and abhinav committed Apr 1, 2020
1 parent 3f21605 commit ca81c3b
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 7 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Expand Up @@ -5,7 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
- Back to development.
### Added
- Value groups can use the `flatten` option to indicate values in a slice should
be provided individually rather than providing the slice itself. See package
documentation for details.

## [1.10.0] - 2019-11-20
### Added
Expand Down
4 changes: 4 additions & 0 deletions annotated.go
Expand Up @@ -64,6 +64,10 @@ type Annotated struct {
// by the constructor. For more information on value groups, see the package documentation.
//
// A group option may not be provided if a name option is provided.
//
// Similar to group tags, the group name may be followed by a `,flatten`
// option to indicate that each element in the slice returned by the
// constructor should be injected into the value group individually.
Group string

// Target is the constructor being annotated with fx.Annotated.
Expand Down
22 changes: 21 additions & 1 deletion app_test.go
Expand Up @@ -141,6 +141,26 @@ func TestNewApp(t *testing.T) {
require.NoError(t, app.Err())
})

t.Run("ProvidesWithAnnotateFlattened", func(t *testing.T) {
app := fxtest.New(t,
Provide(Annotated{
Target: func() []int { return []int{1} },
Group: "foo,flatten",
}),
Invoke(
func(b struct {
In
Foos []int `group:"foo"`
}) {
assert.Len(t, b.Foos, 1)
},
),
)

defer app.RequireStart().RequireStop()
require.NoError(t, app.Err())
})

t.Run("ProvidesWithEmptyAnnotate", func(t *testing.T) {
type A struct{}

Expand Down Expand Up @@ -250,7 +270,7 @@ func TestInvokes(t *testing.T) {
)
err := app.Err()
require.Error(t, err)
assert.Contains(t, err.Error(), "fx_test.A is not in the container")
assert.Contains(t, err.Error(), "missing type: fx_test.A")
})

t.Run("ErrorHooksAreCalled", func(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -4,7 +4,7 @@ go 1.13

require (
github.com/stretchr/testify v1.4.0
go.uber.org/dig v1.8.0
go.uber.org/dig v1.9.0
go.uber.org/goleak v0.10.0
go.uber.org/multierr v1.4.0
golang.org/x/lint v0.0.0-20190930215403-16217165b5de
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -20,8 +20,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/dig v1.8.0 h1:1rR6hnL/bu1EVcjnRDN5kx1vbIjEJDTGhSQ2B3ddpcI=
go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=
go.uber.org/dig v1.9.0 h1:pJTDXKEhRqBI8W7rU7kwT5EgyRZuSMVSFcZolOvKK9U=
go.uber.org/dig v1.9.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=
go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4=
go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
Expand Down
11 changes: 11 additions & 0 deletions inout.go
Expand Up @@ -251,4 +251,15 @@ type In struct{ dig.In }
// value groups require parameter and result structs to use fields with
// different types: if a group of constructors each returns type T, parameter
// structs consuming the group must use a field of type []T.
//
// To provide multiple values for a group from a result struct, produce a
// slice and use the `,flatten` option on the group tag. This indicates that
// each element in the slice should be injected into the group individually.
//
// type IntResult struct {
// fx.Out
//
// Handler []int `group:"server"` // Consume as [][]int
// Handler []int `group:"server,flatten"` // Consume as []int
// }
type Out struct{ dig.Out }
4 changes: 2 additions & 2 deletions populate_test.go
Expand Up @@ -208,7 +208,7 @@ func TestPopulateErrors(t *testing.T) {
{
msg: "container pointer without fx.In",
opt: Populate(&containerNoIn{}),
wantErr: "is not in the container",
wantErr: "missing type: fx_test.containerNoIn",
},
{
msg: "function",
Expand All @@ -218,7 +218,7 @@ func TestPopulateErrors(t *testing.T) {
{
msg: "function pointer",
opt: Populate(&fn),
wantErr: "is not in the container",
wantErr: "missing type: func()",
},
{
msg: "invalid last argument",
Expand Down

0 comments on commit ca81c3b

Please sign in to comment.