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

feat(dig): accepts string with dot or arrays as "path" parameters #352

Open
davinkevin opened this issue Nov 25, 2022 · 1 comment
Open

Comments

@davinkevin
Copy link

davinkevin commented Nov 25, 2022

Hello 👋 ,

I would like to use the really useful dig function within a range, but because the dig function only accepts "varargs" for path, I'm not able to use it.

With $someStruct equals to:

{
  "a": {
    "b": {
      "c": "value"
    }
  },
  "foo": {
    "bar": {
      "zoo": "value2"
    }
  }
}

First,

    {{- $keysToGet := list
      "foo.bar.zoo"
      "a.b.c"
    -}}
	{{ range $keysToGet }}
      {{ dig . "~" $someStruct }}
    {{ end }}

The result of this one is nil because dig looks for { "a.b.c": "value" } 🙂. So the result is twice ~ instead of value and value2.

Second, with array:

    {{- $keysToGet := list
      "foo.bar.zoo"
      "a.b.c.d.e"
    -}}
	{{ range $keysToGet }}
      {{ dig (splitList "." .) "~" $someStruct }}
    {{ end }}

Here, it's a type cast problem because the first parameter is not a string like expected by the function. I have the following error:

dig (splitList "." .) "~" $savedValues>: error calling dig: interface conversion: interface {} is []string, not string

It could be cool, especially in dynamic env like a range or with to have the ability to provide "path" coming from another variable dynamically

Thank you 😇

@traviswt
Copy link

I do the following, not perfect, but works when you can control the context:

func FuncMap() ttemplate.FuncMap {
	f := sprig.TxtFuncMap()
	f["getNested"] = getNested
	return f
}

func getNested(d map[string]interface{}, key string) interface{} {
	t := strings.Split(key, ".")
	for i := 0; i < len(t); i++ {
		if val, ok := d[t[i]]; ok {
			if i+1 == len(t) {
				return val
			} else {
				d = castAndGetMapStringInterface(val)
			}
		}
	}
	panic(fmt.Errorf("the map does not have a match for key %s", key))
}

func castAndGetMapStringInterface(i interface{}) map[string]interface{} {
	m, ok := i.(map[string]interface{})
	if ok {
		return m
	}
	return nil
}

then in your template you can do:

{{getNested .ImageMap "ingress-controller.registry"}}

for struct:

type InterpolateContext struct {
	ImageMap map[string]interface{}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants