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

Nested conditional statements in map() lambda function fail #8782

Closed
Adunaphel opened this issue Oct 25, 2022 · 7 comments
Closed

Nested conditional statements in map() lambda function fail #8782

Adunaphel opened this issue Oct 25, 2022 · 7 comments
Assignees
Labels
intermediate language Related to the intermediate language revisit
Milestone

Comments

@Adunaphel
Copy link

Bicep version
Bicep CLI version 0.11.1 (030248d)

Describe the bug
A nested conditional statement inside a map() lambda function fails.

When deploying the following template:

var testArray = [
  {
    property1: 'test'
    property2: 1
  }
  {
    property1: 'dev'
    property2: 2
  }
  {
    property1: 'test'
    property2: 0
  }
  {
    property1: 'prod'
    property2: 1
  }
  {
    property1: 'prod'
    property2: 0
  }
  {
    property1: 'dev'
    property2: 0
  }
  {
    property1: 'test'
    property2: 0
  }
]

output testMap array = map(testArray, record => {
  result: record.property2 > 0 ? record.property1 : record.property1 =~ 'test' ? 'test!' : 'notTest!'
})

output testFor array = [for record in testArray: {
  result: record.property2 > 0 ? record.property1 : record.property1 =~ 'test' ? 'test!' : 'notTest!'
}]

The two outputs are expected to be the same, but the outputs are as follows:

Name             Type                       Value     
===============  =========================  ==========
testMap          Array                      [{"result":"test"},{"result":"dev"},{"result":""},{"result":""},{"result":""},{"result":""},{"result":""}]
testFor          Array                      [{"result":"test"},{"result":"dev"},{"result":"test!"},{"result":"prod"},{"result":"notTest!"},{"result":"notTest!"},{"result":"test!"}]

Clearly the nested conditional statement fails as soon as the false-value is processed.

To Reproduce
Steps to reproduce the behavior: deploy the above template.

@ghost ghost added the Needs: Triage 🔍 label Oct 25, 2022
@slavizh
Copy link
Contributor

slavizh commented Oct 25, 2022

+1

@anthony-c-martin
Copy link
Member

I believe this is the same issue as #8798 & #8843.

I dug into this, and found that the DeploymentEngine has an optimization to cache partial function values when using any of the or(), and() and if() ARM JSON functions (equivalent to &&, || and ternary (? :) in Bicep.

Unfortunately this is going to require a runtime fix. I have submitted this fix, which will be rolled out in the next ARM release (starting this week).

For now, the only thing I can recommend is avoiding using any of &&, || or : ? inside a lambda. Sorry that I can't offer anything more helpful at this time.

@jurjenoskam
Copy link

I am able to use if() ARM JSON in a lambda, but only when the conditional does not contain a lambda variable. Is that the same problem this issue is tracking?

In other words, this works as expected:

output output1 array = map(
  items(testObject),
  subObject => 1 == 2 ? [ 'yes' ] : [ 'no' ]
)
"output1": {
    "type": "Array",
    "value": [
      [
        "no"
      ],
      [
        "no"
      ]
    ]
  }

... but this doesn't (when the condition is false the ? : operator returns "" instead of the expected [ 'no ']):

output output2 array = map(
  items(testObject),
  subObject => subObject.key == 'a' ? [ 'yes' ] : [ 'no' ]
)
  "output2": {
    "type": "Array",
    "value": [
      [
        "yes"
      ],
      ""
    ]
  }

anthony-c-martin added a commit that referenced this issue Nov 22, 2022
@anthony-c-martin
Copy link
Member

@jurjenoskam - just confirmed it's the same issue. I've added a test case to verify this with #9102

@miqm
Copy link
Collaborator

miqm commented Nov 30, 2022

@anthony-c-martin - any ETA on the release? just hit it with map + contains + ternary.

@jikuja
Copy link

jikuja commented Dec 18, 2022

@anthony-c-martin - any ETA on the release? just hit it with map + contains + ternary.

Example for this:
main.bicep:

targetScope = 'subscription'

module test 'inner.bicep' = {
  name: 'test'
}

// fails
/*
{
  "code": "DeploymentOutputEvaluationFailed",
  "message": "Unable to evaluate template outputs: 'mapped1,mapped2'. Please see error details and deployment operations. Please see https://aka.ms/arm-debug for usage details.",
  "details": [
    {
      "code": "DeploymentOutputEvaluationFailed",
      "target": "mapped1",
      "message": "The template output 'mapped1' is not valid: The language expression property 'one' doesn't exist, available properties are 'two'.."
    },
    {
      "code": "DeploymentOutputEvaluationFailed",
      "target": "mapped2",
      "message": "The template output 'mapped2' is not valid: The language expression property 'two' doesn't exist, available properties are 'one'.."
    }
  ]
}
*/
//var mapped1 = map(test.outputs.foo, arg => arg.one)
//var mapped2 = map(test.outputs.foo, arg => arg.two)


var mapped1 = map(test.outputs.foo, arg => contains(arg, 'one') ? arg.one : 'placeholder1' )

var mapped2 = map(test.outputs.foo, arg => contains(arg, 'two') ? arg.two : 'placeholder2' )
var mapped2a = map(test.outputs.foo, arg => {
  xx: contains(arg, 'two') ? arg.two : 'placeholder2' 
})


output mapped1 array = mapped1
output mapped2 array = mapped2
output mapped2a array = mapped2a

inner.bicep:

targetScope = 'subscription'

output foo array = [
  {
    one: 'one'
  }
  {
    two: 'two'
  }
  {
    three: 'three'
  }
  {
    four: 'four'
  }
]

Results:

"outputs": {
      "mapped1": {
        "type": "Array",
        "value": [
          "one",
          "",
          "",
          ""
        ]
      },
      "mapped2": {
        "type": "Array",
        "value": [
          "placeholder2",
          "",
          "",
          ""
        ]
      },
      "mapped2a": {
        "type": "Array",
        "value": [
          {
            "xx": "placeholder2"
          },
          {
            "xx": ""
          },
          {
            "xx": ""
          },
          {
            "xx": ""
          }
        ]
      }

@anthony-c-martin
Copy link
Member

This has now been fixed and rolled out globally. Please open a new issue if you are still seeing this (or similar) behavior.

@ghost ghost locked as resolved and limited conversation to collaborators May 24, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
intermediate language Related to the intermediate language revisit
Projects
Archived in project
Development

No branches or pull requests

8 participants