or function doesn't seem to be working as expected

I have this expression rule :

a!localVariables(
  /* Loop checks against passed in value of type to pull values
     from specific requirementActivity match */
  a!forEach(
    items: ri!requirement.requirementActivities, 
    expression: 
    if(contains(fv!item.type, ri!activityType),
      'type!{urn:com:appian:types:UW}UW-Requirement-Activity'(
        key: fv!item.key,
        type: fv!item.type,
        creatorId: fv!item.creatorId,
        creatorFullName: fv!item.creatorFullName,
        createdDate: fv!item.createdDate,
        commentText: fv!item.commentText
    ), 
    {}), 
  ),
),

And I'm using it in my interface :

a!localVariables(
      requirementsResponse: rule!UW_GetRequirementsByCase_RDS("SomeKey"),
      local!requirements: {
        a!forEach(
          items: local!requirementsResponse,
          expression: 
          a!map(
            type: fv!item.name,
            status:fv!item.status,
            orderDate: fv!item.createdTimestamp,
            orderRep: fv!item.requestedBy,
            receiveDate: rule!UW_GetRequirementActivityByType(fv!item, "RECEIVED").createdDate,
            receiveRep: rule!UW_GetRequirementActivityByType(fv!item, "RECEIVED").creatorFullName,
            resolveDate: rule!UW_GetRequirementActivityByType(fv!item, or("WITHDRAWN", "ACCEPTED")).createdDate,
            resolveRep: rule!UW_GetRequirementActivityByType(fv!item, or("WITHDRAWN", "ACCEPTED")).creatorFullName,
            resolutionStatus: rule!UW_GetRequirementActivityByType(fv!item, or("ACCEPTED", "WITHDRAWN")).type,
            resolutionNotes: rule!UW_GetRequirementActivityByType(fv!item, or("ACCEPTED", "WITHDRAWN")).commentText
            )
        )
      },

Which I'm using to help populate fields. Everything works great until I save close out and go back...

Then I end up with this error: "Could not display interface. Please check definition and inputs. Interface Definition: Expression evaluation error at function a!forEach [line 6]: Error in a!forEach() expression during iteration 11: Expression evaluation error at function a!map parameter 7 [line 16]: Invalid index: Cannot index property 'createdDate' of type Text into type List of Variant"

Which is pointing to : resolveDate: rule!UW_GetRequirementActivityByType(fv!item, or("WITHDRAWN", "ACCEPTED")).createdDate,

It's not a fan of how I am using the or function - if I remove it and just pass one of the options all is fine. However I only want these fields populated if one or the other value is found. Is there another way to do this? I feel like this should work and again it does but then it does not.

  Discussion posts and replies are publicly visible

  • I would strongly suggest steering clear of using dot notation when you want to get information from somewhere. My general rule of thumb is:

    • If getting information use index() or property()
    • If saving information use dot notation or square brackets and quoted fields (Don't know what to call this but it would be something like ["createdDate"])

    Dot notation doesn't have inbuilt handling of when the field doesn't exist. When you use the function rule!UW_GetRequirementActivityByType(fv!item, or("WITHDRAWN", "ACCEPTED")).createdDate, you are saying "give me the createdDate field please" and dot notation can't handle if the field doesn't exist.

    Using the index() or poperty() functions on the other hand, such as property(rule!UW_GetRequirementActivityByType(fv!item, or("WITHDRAWN", "ACCEPTED")), "createdDate", null) says "give the createdDate field please, and if it doesn't exist give me null".

    So I suspect it has nothing much to do with your or() (although it could, I'll be honest, I didn't go through your code!).

    If this doesn't solve your issue I'll take a deeper look.

    EDIT: I have some further feedback

    1. I definitely didn't answer your question. And or() outputs a boolean and must have a true or false argument inside it. What you're saying is you want the input to be either "WITHDRAWN" or "ACCEPTED" but you've made no comparison and even if you had either "TRUE" or "FALSE" would be passed. I've left everything else I've said though as it is relevant and see code below for how I would fix it. I'm going to assume that "inputTwo" in the UW_GetRequirementActivityByType rule can accept arrays.
    2. If you find yourself repeating something over and over again there is likely a better way of doing it. You use the UW_GetRequirementActivityByType function over an over again with either similar or the same inputs. If this is a database call, WebAPI call or really anything you're getting the same info over and over again and as a principle this isn't so great. I'd suggest refactoring to the code below. There may even be more efficient ways depending on exactly what you're doing and what's being called but this is at least a step in the right direction. I've also swapped your dot notations to index() or poperty(). Be especially careful calling something within a a!forEach() loop! Things can quickly get out of hand and performance suffers. Essentially if you're calling the same information more than once there is a better more performant way to do it. Some situations matter more than others but if you don't practice the principles on the basic things you aren't likely to get them right when it does matter.
    3. ALWAYS use key value pairs. Your rules will have rule inputs, use these when calling the rule. I can't fix this as I don't know what your input names are but as a demonstration I've named them "inputOne", "inputTwo" etc.

    a!localVariables(
      local!requirementsResponse: rule!UW_GetRequirementsByCase_RDS(
        inputOne: "SomeKey"
      ),
      local!requirements: {
        a!forEach(
          items: local!requirementsResponse,
          expression: a!localVariables(
            local!receivedRequirementActivity: rule!UW_GetRequirementActivityByType(
              inputOne: fv!item,
              inputTwo: "RECEIVED"
            ),
            local!withdrawnOrAcceptedRequirementActivity: rule!UW_GetRequirementActivityByType(
              inputOne: fv!item,
              inputTwo: {
                "WITHDRAWN",
                "ACCEPTED"
              }
            ),
            a!map(
              type: property(
                fv!item,
                "name",
                {}
              ),
              status: property(
                fv!item,
                "status",
                {}
              ),
              orderDate: property(
                fv!item,
                "createdTimestamp",
                {}
              ),
              orderRep: property(
                fv!item,
                "requestedBy",
                {}
              ),
              receiveDate: property(
                local!receivedRequirementActivity,
                "createdDate",
                {}
              ),
              receiveRep: property(
                local!receivedRequirementActivity,
                "creatorFullName",
                {}
              ),
              resolveDate: property(
                local!withdrawnOrAcceptedRequirementActivity,
                "createdDate",
                {}
              ),
              resolveRep: property(
                local!withdrawnOrAcceptedRequirementActivity,
                "creatorFullName",
                {}
              ),
              resolutionStatus: property(
                local!withdrawnOrAcceptedRequirementActivity,
                "type",
                {}
              ),
              resolutionNotes: property(
                local!withdrawnOrAcceptedRequirementActivity,
                "commentText",
                {}
              )
            )
          )
        )
      },

  • I really appreciate your response! Very educational and detailed thank you so much.

    I will say that implementing your suggested solution unfortunately is not working when passing in 2 activityTypes - I'm not getting any errors which is great but I'm not getting data either.

    local!withdrawnOrAcceptedRequirementActivity: rule!UW_GetRequirementActivityByType(
                  requirement: fv!item,
                  activityType: {
                    "WITHDRAWN",
                    "ACCEPTED"
                  }
                ),

    local!requirements: {
            a!forEach(
              items: local!requirementsResponse,
              expression: a!localVariables(
                local!receivedRequirementActivity: rule!UW_GetRequirementActivityByType(
                  requirement: fv!item,
                  activityType:  "RECEIVED"
                ),
                local!withdrawnOrAcceptedRequirementActivity: rule!UW_GetRequirementActivityByType(
                  requirement: fv!item,
                  activityType: {
                    "WITHDRAWN",
                    "ACCEPTED"
                  }
                ),
                a!map(
                  type: property(
                    fv!item,
                    "name",
                    {}
                  ),
                  status: property(
                    fv!item,
                    "status",
                    {}
                  ),
                  orderDate: property(
                    fv!item,
                    "createdTimestamp",
                    {}
                  ),
                  orderRep: property(
                    fv!item,
                    "requestedBy",
                    {}
                  ),
                  receiveDate: property(
                    local!receivedRequirementActivity,
                    "createdDate",
                    {}
                  ),
                  receiveRep: property(
                    local!receivedRequirementActivity,
                    "creatorFullName",
                    {}
                  ),
                  resolveDate: property(
                    local!withdrawnOrAcceptedRequirementActivity,
                    "createdDate",
                    {}
                  ),
                  resolveRep: property(
                    local!withdrawnOrAcceptedRequirementActivity,
                    "creatorFullName",
                    {}
                  ),
                  resolutionStatus: property(
                    local!withdrawnOrAcceptedRequirementActivity,
                    "type",
                    {}
                  ),
                  resolutionNotes: property(
                    local!withdrawnOrAcceptedRequirementActivity,
                    "commentText",
                    {}
                  )
                )
              )
            )
          },

  • 0
    Certified Lead Developer
    in reply to seenaomi

    Note that since you posted the same thing twice for some reason, you have some other responses waiting for you in the other posting.

    I'll also note that if you're still using similar logic in your expression rule as you posted originally, your contains() call is written backwards; the array of values should come first followed by the value you're checking whether that array contains.

  • I apologize if my posting in two spots is an issue. Happy to make note on the other. I am new to appian clearly and learning the ropes. I appreciate the response here. Thank you.

  • 0
    Certified Lead Developer
    in reply to seenaomi

    I would not recommend deleting the other one.  At best, create a comment (or edit the original if possible) with a link pointing to this one if you want this one to be the main one.  Deleting it would erase the contributions already made by other responders.

  • +1
    Certified Lead Developer
    in reply to seenaomi

    "fv!item" is by definition one of the array elements that a!forEach() was called upon, and thus fv!item.type would be a single element.  If you've taken Chris's advice and converted ri!activityType to an array of text in which you will pass in all allowable text types, then this is the array.  Per the documentation for contains(), the array is passed first and the value you're looking for is passed second:

    Edit: by the time I finished writing this, the comment I was replying to has disappeared.  Hopefully that means you figured out this issue already?

  • Ah! I just needed to update the rule input to array for activityType - got it - all is well Thank you  and especially thank you again  for your clear and thorough response. Very grateful for the help. Slight smile