Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Support simultanous name and group tags #381

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions constructor.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,15 @@ func (n *constructorNode) Call(c containerStore) (err error) {
// would be made to a containerWriter and defers them until Commit is called.
type stagingContainerWriter struct {
values map[key]reflect.Value
groups map[key][]reflect.Value
groups map[key][]keyedGroupValue
}

var _ containerWriter = (*stagingContainerWriter)(nil)

func newStagingContainerWriter() *stagingContainerWriter {
return &stagingContainerWriter{
values: make(map[key]reflect.Value),
groups: make(map[key][]reflect.Value),
groups: make(map[key][]keyedGroupValue),
}
}

Expand All @@ -201,12 +201,12 @@ func (sr *stagingContainerWriter) setDecoratedValue(_ string, _ reflect.Type, _
digerror.BugPanicf("stagingContainerWriter.setDecoratedValue must never be called")
}

func (sr *stagingContainerWriter) submitGroupedValue(group string, t reflect.Type, v reflect.Value) {
func (sr *stagingContainerWriter) submitGroupedValue(group, mapKey string, t reflect.Type, v reflect.Value) {
k := key{t: t, group: group}
sr.groups[k] = append(sr.groups[k], v)
sr.groups[k] = append(sr.groups[k], keyedGroupValue{key: mapKey, value: v})
}

func (sr *stagingContainerWriter) submitDecoratedGroupedValue(_ string, _ reflect.Type, _ reflect.Value) {
func (sr *stagingContainerWriter) submitDecoratedGroupedValue(_, _ string, _ reflect.Type, _ reflect.Value) {
digerror.BugPanicf("stagingContainerWriter.submitDecoratedGroupedValue must never be called")
}

Expand All @@ -216,9 +216,9 @@ func (sr *stagingContainerWriter) Commit(cw containerWriter) {
cw.setValue(k.name, k.t, v)
}

for k, vs := range sr.groups {
for _, v := range vs {
cw.submitGroupedValue(k.group, k.t, v)
for k, kgvs := range sr.groups {
for _, kgv := range kgvs {
cw.submitGroupedValue(k.group, kgv.key, k.t, kgv.value)
}
}
}
14 changes: 7 additions & 7 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ type containerWriter interface {
setDecoratedValue(name string, t reflect.Type, v reflect.Value)

// submitGroupedValue submits a value to the value group with the provided
// name.
submitGroupedValue(name string, t reflect.Type, v reflect.Value)
// name and optional map key.
submitGroupedValue(name, mapKey string, t reflect.Type, v reflect.Value)

// submitDecoratedGroupedValue submits a decorated value to the value group
// with the provided name.
submitDecoratedGroupedValue(name string, t reflect.Type, v reflect.Value)
// with the provided name and optional map key.
submitDecoratedGroupedValue(name, mapKey string, t reflect.Type, v reflect.Value)
}

// containerStore provides access to the Container's underlying data store.
Expand All @@ -108,7 +108,7 @@ type containerStore interface {
// Retrieves all values for the provided group and type.
//
// The order in which the values are returned is undefined.
getValueGroup(name string, t reflect.Type) []reflect.Value
getValueGroup(name string, t reflect.Type) []keyedGroupValue

// Retrieves all decorated values for the provided group and type, if any.
getDecoratedValueGroup(name string, t reflect.Type) (reflect.Value, bool)
Expand Down Expand Up @@ -273,8 +273,8 @@ func (bs byTypeName) Swap(i int, j int) {
bs[i], bs[j] = bs[j], bs[i]
}

func shuffledCopy(rand *rand.Rand, items []reflect.Value) []reflect.Value {
newItems := make([]reflect.Value, len(items))
func shuffledCopy(rand *rand.Rand, items []keyedGroupValue) []keyedGroupValue {
newItems := make([]keyedGroupValue, len(items))
for i, j := range rand.Perm(len(items)) {
newItems[i] = items[j]
}
Expand Down
6 changes: 4 additions & 2 deletions decorate.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,15 @@ func findResultKeys(r resultList) ([]key, error) {
case resultSingle:
keys = append(keys, key{t: innerResult.Type, name: innerResult.Name})
case resultGrouped:
if innerResult.Type.Kind() != reflect.Slice {
isMap := innerResult.Type.Kind() == reflect.Map && innerResult.Type.Key().Kind() == reflect.String
isSlice := innerResult.Type.Kind() == reflect.Slice
if !isMap && !isSlice {
return nil, newErrInvalidInput("decorating a value group requires decorating the entire value group, not a single value", nil)
}
keys = append(keys, key{t: innerResult.Type.Elem(), group: innerResult.Group})
case resultObject:
for _, f := range innerResult.Fields {
q = append(q, f.Result)
q = append(q, f.Results...)
}
case resultList:
q = append(q, innerResult.Results...)
Expand Down
99 changes: 99 additions & 0 deletions decorate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,64 @@ func TestDecorateSuccess(t *testing.T) {
}))
})

t.Run("map is treated as an ordinary dependency without group tag, named or unnamed, and passes through multiple scopes", func(t *testing.T) {
type params struct {
dig.In

Strings1 map[string]string
Strings2 map[string]string `name:"strings2"`
}

type childResult struct {
dig.Out

Strings1 map[string]string
Strings2 map[string]string `name:"strings2"`
}

type A map[string]string
type B map[string]string

parent := digtest.New(t)
parent.RequireProvide(func() map[string]string { return map[string]string{"key1": "val1", "key2": "val2"} })
parent.RequireProvide(func() map[string]string { return map[string]string{"key1": "val21", "key2": "val22"} }, dig.Name("strings2"))

parent.RequireProvide(func(p params) A { return A(p.Strings1) })
parent.RequireProvide(func(p params) B { return B(p.Strings2) })

child := parent.Scope("child")

parent.RequireDecorate(func(p params) childResult {
res := childResult{Strings1: make(map[string]string, len(p.Strings1))}
for k, s := range p.Strings1 {
res.Strings1[k] = strings.ToUpper(s)
}
res.Strings2 = p.Strings2
return res
})

child.RequireDecorate(func(p params) childResult {
res := childResult{Strings2: make(map[string]string, len(p.Strings2))}
for k, s := range p.Strings2 {
res.Strings2[k] = strings.ToUpper(s)
}
res.Strings1 = p.Strings1
res.Strings1["key3"] = "newval"
return res
})

require.NoError(t, child.Invoke(func(p params) {
require.Len(t, p.Strings1, 3)
assert.Equal(t, "VAL1", p.Strings1["key1"])
assert.Equal(t, "VAL2", p.Strings1["key2"])
assert.Equal(t, "newval", p.Strings1["key3"])
require.Len(t, p.Strings2, 2)
assert.Equal(t, "VAL21", p.Strings2["key1"])
assert.Equal(t, "VAL22", p.Strings2["key2"])

}))

})
t.Run("decorate values in soft group", func(t *testing.T) {
type params struct {
dig.In
Expand Down Expand Up @@ -393,6 +451,46 @@ func TestDecorateSuccess(t *testing.T) {
assert.Equal(t, `[]string[group = "animals"]`, info.Inputs[0].String())
})

t.Run("decorate with map value groups", func(t *testing.T) {
type Params struct {
dig.In

Animals map[string]string `group:"animals"`
}

type Result struct {
dig.Out

Animals map[string]string `group:"animals"`
}

c := digtest.New(t)
c.RequireProvide(func() string { return "dog" }, dig.Name("animal1"), dig.Group("animals"))
c.RequireProvide(func() string { return "cat" }, dig.Name("animal2"), dig.Group("animals"))
c.RequireProvide(func() string { return "gopher" }, dig.Name("animal3"), dig.Group("animals"))

var info dig.DecorateInfo
c.RequireDecorate(func(p Params) Result {
animals := p.Animals
for k, v := range animals {
animals[k] = "good " + v
}
return Result{
Animals: animals,
}
}, dig.FillDecorateInfo(&info))

c.RequireInvoke(func(p Params) {
assert.Len(t, p.Animals, 3)
assert.Equal(t, "good dog", p.Animals["animal1"])
assert.Equal(t, "good cat", p.Animals["animal2"])
assert.Equal(t, "good gopher", p.Animals["animal3"])
})

require.Equal(t, 1, len(info.Inputs))
assert.Equal(t, `map[string]string[group = "animals"]`, info.Inputs[0].String())
})

t.Run("decorate with optional parameter", func(t *testing.T) {
c := digtest.New(t)

Expand Down Expand Up @@ -918,6 +1016,7 @@ func TestMultipleDecorates(t *testing.T) {
assert.ElementsMatch(t, []int{2, 3, 4}, a.Values)
})
})

}

func TestFillDecorateInfoString(t *testing.T) {
Expand Down
Loading