Reading Time: 12 minutes

A while back, I had a use case where I received a field that could contain either an array or a null value. If an array was present, it could have strings (including empty strings) or null values. If any of the values inside the array were empty, I had to completely ignore this field. This means that I had to create a function to check if the field or any of the values inside the array were empty, and ignore the field if that was the case. This blog will explain the four different solutions that I found to resolve this problem.

Let me start by showing some of the examples that I would receive in the payload:

null // null value
[] // Empty array
[""] // Array with empty string
[null] // Array with null value
["abc", "", "def", ""] // Array with strings and empty strings
[null, "abc", "def", null] // Array with nulls and empty strings
["abc", null, ""] // Array with strings, nulls, and empty strings
["abc", "def"] // Array with strings

From all these examples, only number eight is correct. The other examples should be ignored because they contain (or are) empty values as is illustrated with [“ ”] and “null.”

Now that we understand the problem, let’s cover the four solutions.

Solution #1: Core functions only

We can create a function that only uses DataWeave core functions. Such as this one:

%dw 2.0
output application/json
fun containsEmptyValues(arr) = if (isEmpty(arr)) true
   else not isEmpty(arr filter isEmpty($))
---
{
   one: containsEmptyValues(null), //true
   two: containsEmptyValues([]), //true
   three: containsEmptyValues([""]), //true
   four: containsEmptyValues([null]), //true
   five: containsEmptyValues(["abc", "", "def", ""]), //true
   six: containsEmptyValues([null, "abc", "def", null]), //true
   seven: containsEmptyValues(["abc", null, ""]), //true
   eight: containsEmptyValues(["abc", "def"]) //false
}

First, we check if the given parameter “arr” is empty and returns “true” if that’s the case. This will catch the empty array and null cases (fields one and two). Then, we need to break down what’s in the “else” statement (where the rest of the fields go). 

We first filter the array by empty values (arr filter isEmpty($)) — which will return the values that are empty (nulls and empty strings). 

%dw 2.0
output application/json
fun containsEmptyValues(arr) = arr filter isEmpty($)
---
{
   three: containsEmptyValues([""]), //[""]
   four: containsEmptyValues([null]), //[null]
   five: containsEmptyValues(["abc", "", "def", ""]), //["",""]
   six: containsEmptyValues([null, "abc", "def", null]), //[null,null]
   seven: containsEmptyValues(["abc", null, ""]), //[null,""]
   eight: containsEmptyValues(["abc", "def"]) //[]
}

Now that we have arrays with the empty values, we can check if the filtered arrays are empty. If they are, it means that there are no empty values in “arr.”

%dw 2.0
output application/json
fun containsEmptyValues(arr) = isEmpty(arr filter isEmpty($))
---
{
   three: containsEmptyValues([""]), //false
   four: containsEmptyValues([null]), //false
   five: containsEmptyValues(["abc", "", "def", ""]), //false
   six: containsEmptyValues([null, "abc", "def", null]), //false
   seven: containsEmptyValues(["abc", null, ""]), //false
   eight: containsEmptyValues(["abc", "def"]) //true
}

As expected, only field eight returns “true” meaning it doesn’t contain any empty values. Our last step is reversing the result because we want to have a true value when the array contains empty values. This is why we add the “not” operator.

Solution #2: Arrays module

Similar to the first solution, we also have an if/else statement, but we change the logic for the “else” statement to the “some” function from the Arrays module.

%dw 2.0
output application/json
import some from dw::core::Arrays
fun containsEmptyValues(arr) = if (isEmpty(arr)) true
   else arr some isEmpty($)
---
{
  one: containsEmptyValues(null), //true
  two: containsEmptyValues([]), //true
  three: containsEmptyValues([""]), //true
  four: containsEmptyValues([null]), //true
  five: containsEmptyValues(["abc", "", "def", ""]), //true
  six: containsEmptyValues([null, "abc", "def", null]), //true
  seven: containsEmptyValues(["abc", null, ""]), //true
  eight: containsEmptyValues(["abc", "def"]) //false
}

This logic is easier to understand, right? 

Fields one and two work the same way as before, but the logic for fields three to eight change. This time we’re directly checking if at least one of the values from the array is empty and the result is returned.

Solution #3: Pattern matching (match/case statements)

With this solution, we’re checking what kind of value was received in the “arr” parameter and then we’re handling the logic accordingly.

The first case statement checks if “arr” is an empty array and returns a true value. If this is not the case, it goes to the second case statement, which checks if “arr” is a type Array and executes the logic we previously had (a some isEmpty($)).

Lastly, if none of those conditions were met, it goes to the “else” statement, which returns true if “arr” is empty or false otherwise.

%dw 2.0
output application/json
import some from dw::core::Arrays
fun containsEmptyValues(arr) = arr match {
   case [] -> true
   case a is Array -> a some isEmpty($)
   else -> isEmpty(arr)
}
---
{
  one: containsEmptyValues(null), //true
  two: containsEmptyValues([]), //true
  three: containsEmptyValues([""]), //true
  four: containsEmptyValues([null]), //true
  five: containsEmptyValues(["abc", "", "def", ""]), //true
  six: containsEmptyValues([null, "abc", "def", null]), //true
  seven: containsEmptyValues(["abc", null, ""]), //true
  eight: containsEmptyValues(["abc", "def"]) //false
}

Solution #4: Function overloading

With this script, field one is immediately sent to the first overloaded function because it contains a null value. 

Fields two to eight are evaluated under the second overloaded function. In this case, we create an if/else statement to return true if the parameter “arr” is an empty array. If it’s not empty, we continue with the same logic we had before (using the Arrays module). 

%dw 2.0
output application/json
import some from dw::core::Arrays
fun containsEmptyValues(value: Null) = true //first overloaded function
fun containsEmptyValues(arr: Array) = ( //second overloaded function
   if (arr == []) true
   else arr some isEmpty($)
)
---
{
  one: containsEmptyValues(null), //true
  two: containsEmptyValues([]), //true
  three: containsEmptyValues([""]), //true
  four: containsEmptyValues([null]), //true
  five: containsEmptyValues(["abc", "", "def", ""]), //true
  six: containsEmptyValues([null, "abc", "def", null]), //true
  seven: containsEmptyValues(["abc", null, ""]), //true
  eight: containsEmptyValues(["abc", "def"]) //false
}

Note that you can also use pattern matching in the second function instead of using if/else conditions. This code would look something like this:

fun containsEmptyValues(arr: Array) = arr match { //second overloaded function
  case [] -> true
  else -> arr some isEmpty($)
}

If you’re not familiar with function overloading, you can read all about it in the Mule Docs here.

Conclusion

My advice to anyone facing similar issues is to continue trying different approaches to the same problem and evaluate which approach is the best for your case. 

When I was first working on this code, I created two additional solutions that did not give me the output that I was expecting and made the code so difficult to read! I had to do some research and experimentation to get to these four solutions. You can read about all my other attempts here.
Can you think of the pros and cons of using any of these four approaches? Let us know in the MuleSoft Developer LinkedIn Community group! Alexandra Martinez is a MuleSoft Ambassadress and can be reached here if you have any questions.