Skip to content

Commit

Permalink
lang/funcs: lookup() can work with maps of lists, maps and objects (#…
Browse files Browse the repository at this point in the history
…22269)

* lang/funcs: lookup() can work with maps of lists, maps and objects

lookup() can already handle aribtrary objects of (whatever) and should
handle maps of (whatever) similarly.
  • Loading branch information
mildwonkey committed Aug 1, 2019
1 parent e0329c2 commit 2b14a6b
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 13 deletions.
20 changes: 7 additions & 13 deletions lang/funcs/collection.go
Expand Up @@ -660,6 +660,12 @@ var LookupFunc = function.New(&function.Spec{
}
return cty.DynamicPseudoType, function.NewArgErrorf(0, "the given object has no attribute %q", key)
case ty.IsMapType():
if len(args) == 3 {
_, err = convert.Convert(args[2], ty.ElementType())
if err != nil {
return cty.NilType, function.NewArgErrorf(2, "the default value must have the same type as the map elements")
}
}
return ty.ElementType(), nil
default:
return cty.NilType, function.NewArgErrorf(0, "lookup() requires a map as the first argument")
Expand All @@ -686,19 +692,7 @@ var LookupFunc = function.New(&function.Spec{
return mapVar.GetAttr(lookupKey), nil
}
} else if mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True {
v := mapVar.Index(cty.StringVal(lookupKey))
if ty := v.Type(); !ty.Equals(cty.NilType) {
switch {
case ty.Equals(cty.String):
return cty.StringVal(v.AsString()), nil
case ty.Equals(cty.Number):
return cty.NumberVal(v.AsBigFloat()), nil
case ty.Equals(cty.Bool):
return cty.BoolVal(v.True()), nil
default:
return cty.NilVal, errors.New("lookup() can only be used with maps of primitive types")
}
}
return mapVar.Index(cty.StringVal(lookupKey)), nil
}

if defaultValueSet {
Expand Down
66 changes: 66 additions & 0 deletions lang/funcs/collection_test.go
Expand Up @@ -1469,6 +1469,26 @@ func TestLookup(t *testing.T) {
cty.StringVal("baz"),
}),
})
mapOfMaps := cty.MapVal(map[string]cty.Value{
"foo": cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("bar"),
}),
"baz": cty.MapVal(map[string]cty.Value{
"b": cty.StringVal("bat"),
}),
})
mapOfTuples := cty.MapVal(map[string]cty.Value{
"foo": cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
"baz": cty.TupleVal([]cty.Value{cty.StringVal("bat")}),
})
objectOfMaps := cty.ObjectVal(map[string]cty.Value{
"foo": cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("bar"),
}),
"baz": cty.MapVal(map[string]cty.Value{
"b": cty.StringVal("bat"),
}),
})
mapWithUnknowns := cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
"baz": cty.UnknownVal(cty.String),
Expand Down Expand Up @@ -1507,6 +1527,34 @@ func TestLookup(t *testing.T) {
cty.NumberIntVal(42),
false,
},
{
[]cty.Value{
mapOfMaps,
cty.StringVal("foo"),
},
cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("bar"),
}),
false,
},
{
[]cty.Value{
objectOfMaps,
cty.StringVal("foo"),
},
cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("bar"),
}),
false,
},
{
[]cty.Value{
mapOfTuples,
cty.StringVal("foo"),
},
cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
false,
},
{ // Invalid key
[]cty.Value{
simpleMap,
Expand Down Expand Up @@ -1541,6 +1589,15 @@ func TestLookup(t *testing.T) {
cty.StringVal("bar"),
false,
},
{ // Supplied default with valid (int) key
[]cty.Value{
simpleMap,
cty.StringVal("foobar"),
cty.NumberIntVal(-1),
},
cty.StringVal("-1"),
false,
},
{ // Supplied default with valid key
[]cty.Value{
mapWithObjects,
Expand All @@ -1559,6 +1616,15 @@ func TestLookup(t *testing.T) {
cty.StringVal(""),
false,
},
{ // Supplied default with type mismatch: expects a map return
[]cty.Value{
mapOfMaps,
cty.StringVal("foo"),
cty.StringVal(""),
},
cty.NilVal,
true,
},
{ // Supplied non-empty default with invalid key
[]cty.Value{
simpleMap,
Expand Down

0 comments on commit 2b14a6b

Please sign in to comment.