gokubernetes-helmgo-templatessprig-template-functions

Combining two if conditions into one


The below works

{{- if hasKey (index $envAll.Values.policy) "type" }} 
{{- if has "two-wheeler" (index $envAll.Values.policy "type") }}
<code goes here>
{{- end }}
{{- end }}

while the below fails with "runtime error: invalid memory address or nil pointer dereference"

{{- if and (hasKey (index $envAll.Values.policy) "type") (has "two-wheeler" (index $envAll.Values.policy "type")) }}
<code goes here>
{{- end}}

There is no list by name "type" declared under $envAll.Values.policy.

In Go, if the right operand is evaluated conditionally, why does the last condition gets evaluated in the second code snippet? How do I solve it?

Edit (since it marked as duplicate): Unfortunately, I cannot use embedded {{ if }} like it is mentioned in the other post.

I simplified my problem above. I actually have to achieve this...

{{if or (and (condition A) (condition B)) (condition C)) }}
    <code goes here>
{{ end }}

Solution

  • Update: The following answer predates Go 1.18 where the argument evaluation for and and or template function changed to stop early if the results is know. The answer is only valid for prior Go versions.


    You get an error when using the and function because the and function in Go templates is not short-circuit evaluated (unlike the && operator in Go), all its arguments are evaluated always. Read more about it here: Golang template and testing for Valid fields

    So you have to use embedded {{if}} actions so the 2nd argument is only evaluated if the first is also true.

    You edited the question and stated that your actual problem is this:

    {{if or (and (condition A) (condition B)) (condition C)) }}
        <code goes here>
    {{ end }}
    

    This is how you can do it in templates only:

    {{ $result := false }}
    {{ if (conddition A )}}
        {{ if (condition B) }}
            {{ $result = true }}
        {{ end }}
    {{ end }}
    {{ if or $result (condition C) }}
        <code goes here>
    {{ end }}
    

    Another option is to pass the result of that logic to the template as a parameter.

    If you can't or don't know the result before calling the template, yet another option is to register a custom function, and call this custom function from the template, and you can do short-circuit evaluation in Go code. For an example, see How to calculate something in html/template.