Search code examples
muledataweavemulesoftmule4

How to verify that all elements of a list comply with some conditions


I have this input payload to a Mule 4 application:

{
  "P_CUST_ACCOUNTS": [
    {
      "ACCOUNT_NUMBER": 62972,
      "ADDR_CHG_FLAG": "N"
    },
    {
      "ACCOUNT_NUMBER": 94561,
      "ADDR_CHG_FLAG": null
    }
  ]
}

I need to ensure the following conditions.

  • check that each object in the array contains ACCOUNT_NUMBER and ADDR_CHG_FLAG
  • check that each array object's ACCOUNT_NUMBER value is not null and is not an empty
  • check that each array object's ADDR_CHG_FLAG value is not null and is not an empty string

and would like to simply return a true or false based on if all the above conditions are met.

So in the above case, I would get a boolean value of true.

So far, I have been able to get the first condition working with ...

%dw 2.0
output application/json
import * from dw::core::Arrays
---
{
  acctnbr: payload.P_CUST_ACCOUNTS every ($.ACCOUNT_NUMBER?),
  addrchgflag: payload.P_CUST_ACCOUNTS every ($.ADDR_CHG_FLAG?)
}

but needed to separate each field (like above), as putting them together (like below) to get a single boolean value returned doesn't return the correct value

if ((payload.P_CUST_ACCOUNTS every ($.ACCOUNT_NUMBER?) == false)
     or (payload.P_CUST_ACCOUNTS every ($.ADDR_CHG_FLAG?) == false)
   ) false
else true

Wondering if there is a way using DataWeave to correctly get a single boolean value based on if all of the conditions above are met.


Solution

  • You got the main part right, using the every() function to check that all members of an array comply with a condition. Also using the key present ? selector for the first condition.

    What is missing is to put all the conditions together. You just need to decide how to express each condition in DataWeave and then since each element needs to comply with all of them just connect with the and operator.

    For clarity I put the full expression of the condition in a new function.

    %dw 2.0
    output application/json
    import * from dw::core::Arrays
    fun check(x)=
        x.ACCOUNT_NUMBER? 
        and x.ADDR_CHG_FLAG?
        and isInteger(x.ACCOUNT_NUMBER)
        and (x.ADDR_CHG_FLAG is String)
        and !isEmpty(x.ADDR_CHG_FLAG)
    ---
    payload.P_CUST_ACCOUNTS every ((item) -> check(item))
    

    I'm assuming that the right condition for ACCOUNT_NUMBER is to check if it is an integer number. If that assumption is not correct you can change it to be is String as for ADDR_CHG_FLAG.

    The output for your input payload is false because the last ADDR_CHG_FLAG is null, so it doesn't satisfy the is String condition.

    Note that in general you should not compare a boolean expression to true or false, because it already returns one of those values and make the expression more verbose without adding value. If needed use the not operator ! to negate the condition.

    Now just as an alternative if you are interested in a more flexible or dynamic implementation, we could put the conditions in a list of lambdas. Then we check that for every item every condition in the list is true:

    %dw 2.0
    import * from dw::core::Arrays
    output application/json  
    
    var checks = [
      (x) -> x.ACCOUNT_NUMBER?,
      (x) -> x.ADDR_CHG_FLAG?,
      (x) -> isInteger(x.ACCOUNT_NUMBER),
      (x) -> x.ADDR_CHG_FLAG is String,
      (x) -> !isEmpty(x.ADDR_CHG_FLAG)
    ]
    
    fun check(a: Array, checks: Array)=
        a every (
            (item) -> checks every (
                (check) -> check(item)
            )
        )
    ---
    check(payload.P_CUST_ACCOUNTS, checks)
    

    This solution could be expanded to activate/deactivate some checks.