Add merge interpolation function
Add a `merge` interpolation function, which merges any number of maps. Duplicate keys are OK, with the last write winning.
This commit is contained in:
parent
8c4b4edd2f
commit
39bbbb8da6
|
@ -73,6 +73,7 @@ func Funcs() map[string]ast.Function {
|
|||
"lower": interpolationFuncLower(),
|
||||
"map": interpolationFuncMap(),
|
||||
"md5": interpolationFuncMd5(),
|
||||
"merge": interpolationFuncMerge(),
|
||||
"uuid": interpolationFuncUUID(),
|
||||
"replace": interpolationFuncReplace(),
|
||||
"sha1": interpolationFuncSha1(),
|
||||
|
@ -898,6 +899,26 @@ func interpolationFuncMd5() ast.Function {
|
|||
}
|
||||
}
|
||||
|
||||
func interpolationFuncMerge() ast.Function {
|
||||
return ast.Function{
|
||||
ArgTypes: []ast.Type{ast.TypeMap},
|
||||
ReturnType: ast.TypeMap,
|
||||
Variadic: true,
|
||||
VariadicType: ast.TypeMap,
|
||||
Callback: func(args []interface{}) (interface{}, error) {
|
||||
outputMap := make(map[string]ast.Variable)
|
||||
|
||||
for _, arg := range args {
|
||||
for k, v := range arg.(map[string]ast.Variable) {
|
||||
outputMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return outputMap, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// interpolationFuncUpper implements the "upper" function that does
|
||||
// string upper casing.
|
||||
func interpolationFuncUpper() ast.Function {
|
||||
|
|
|
@ -498,6 +498,103 @@ func TestInterpolateFuncConcat(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestInterpolateFuncMerge(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
// basic merge
|
||||
{
|
||||
`${merge(map("a", "b"), map("c", "d"))}`,
|
||||
map[string]interface{}{"a": "b", "c": "d"},
|
||||
false,
|
||||
},
|
||||
|
||||
// merge with conflicts is ok, last in wins.
|
||||
{
|
||||
`${merge(map("a", "b", "c", "X"), map("c", "d"))}`,
|
||||
map[string]interface{}{"a": "b", "c": "d"},
|
||||
false,
|
||||
},
|
||||
|
||||
// merge variadic
|
||||
{
|
||||
`${merge(map("a", "b"), map("c", "d"), map("e", "f"))}`,
|
||||
map[string]interface{}{"a": "b", "c": "d", "e": "f"},
|
||||
false,
|
||||
},
|
||||
|
||||
// merge with variables
|
||||
{
|
||||
`${merge(var.maps[0], map("c", "d"))}`,
|
||||
map[string]interface{}{"key1": "a", "key2": "b", "c": "d"},
|
||||
false,
|
||||
},
|
||||
|
||||
// only accept maps
|
||||
{
|
||||
`${merge(map("a", "b"), list("c", "d"))}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
// merge maps of maps
|
||||
{
|
||||
`${merge(map("a", var.maps[0]), map("b", var.maps[1]))}`,
|
||||
map[string]interface{}{
|
||||
"b": map[string]interface{}{"key3": "d", "key4": "c"},
|
||||
"a": map[string]interface{}{"key1": "a", "key2": "b"},
|
||||
},
|
||||
false,
|
||||
},
|
||||
// merge maps of lists
|
||||
{
|
||||
`${merge(map("a", list("b")), map("c", list("d", "e")))}`,
|
||||
map[string]interface{}{"a": []interface{}{"b"}, "c": []interface{}{"d", "e"}},
|
||||
false,
|
||||
},
|
||||
// merge map of various kinds
|
||||
{
|
||||
`${merge(map("a", var.maps[0]), map("b", list("c", "d")))}`,
|
||||
map[string]interface{}{"a": map[string]interface{}{"key1": "a", "key2": "b"}, "b": []interface{}{"c", "d"}},
|
||||
false,
|
||||
},
|
||||
},
|
||||
Vars: map[string]ast.Variable{
|
||||
"var.maps": {
|
||||
Type: ast.TypeList,
|
||||
Value: []ast.Variable{
|
||||
{
|
||||
Type: ast.TypeMap,
|
||||
Value: map[string]ast.Variable{
|
||||
"key1": {
|
||||
Type: ast.TypeString,
|
||||
Value: "a",
|
||||
},
|
||||
"key2": {
|
||||
Type: ast.TypeString,
|
||||
Value: "b",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ast.TypeMap,
|
||||
Value: map[string]ast.Variable{
|
||||
"key3": {
|
||||
Type: ast.TypeString,
|
||||
Value: "d",
|
||||
},
|
||||
"key4": {
|
||||
Type: ast.TypeString,
|
||||
Value: "c",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestInterpolateFuncDistinct(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
|
@ -1542,7 +1639,6 @@ type testFunctionCase struct {
|
|||
|
||||
func testFunction(t *testing.T, config testFunctionConfig) {
|
||||
for i, tc := range config.Cases {
|
||||
fmt.Println("running", i)
|
||||
ast, err := hil.Parse(tc.Input)
|
||||
if err != nil {
|
||||
t.Fatalf("Case #%d: input: %#v\nerr: %v", i, tc.Input, err)
|
||||
|
|
Loading…
Reference in New Issue