Hi all,
Wanted to ask the community to see if anyone has some best practice recommendations to handle the edge cases caused by Appian limitations in how it detects null/empty values and how it converts null singleton types into array rule inputs; and especially recommendations on setting up re-usable query entity rules.
We've discovered that Appian handles nulls in unintuitive ways depending on the data-type. If a rule input is an array, and you pass in a singleton of the same type that is null, Appian will automatically convert that input to {null} (a one element array where that element is null), rather than null or {} (empty). According to Appian support, this is the expected behavior of the product.
However, this causes two issues for us:
A work-around here is to instead use a common rule that includes a length(ri!input)=0 check, as in: or(a!isNullOrEmpty(ri!input), length(ri!input) = 0 ). The downside here is that it is very easy for developers to miss using this.
We frequently develop expression rules for re-usable queries and prefer to use array inputs so that we can optionally use an "IN" filter, even in cases where we usually only pass in a single value to that filter. However, this is causing failures when we pass a null value in. We've found a few possible work-arounds, but there are drawbacks to each:
In all these work-around options, there is a major downside that it is very easy for developers to miss this edge case, even if we make it a best practice to always use the work-around. Because it's a rare edge case and seldom causes errors to be thrown, defects can easily go undetected for a very long time, and become challenging to trouble-shoot. The only way to detect that these work-arounds weren't applied is with a manual code review.
I was wondering if others have encountered these use cases and implemented any design principles or best practices to avoid this pitfall. Even if we have to use some of the above work-arounds on existing tech-debt, we'd like to set a new best practice for designs going forward, especially for query rule development.
Thanks!
Discussion posts and replies are publicly visible
I recently wrote a post on my blog about the magic of null checking in Appian. Find it here: appian.rocks/.../
My universalized, reusable Query Entity expression rules almost always use the "applyWhen: a!isNotNullOrEmpty(ri!filterItem)"; i never rely on "ignore filters with empty values" and for the most part pretend that option doesn't exist, as it only begets trouble in my experience. One of my most-used QE rules accepts a single or array as its primary key identifier for querying and i have basically no issues using it anywhere using just these standard techniques - the only thing I need to watch out for is, any time using it in the wild where the passed value could ever be blank, i null-check it there and pass in "-1" to make sure my query results in no results (instead of all results, which is... problematic).
Thanks. We actually do something similar to ensure that if all filters are null, we return no results instead of all results. We use the following pattern for this inside our query entity rules, to ensure they will always have this failsafe in place:if( or( ri!selectAllWhenFiltersNull, not(all( rule!UTIL_isNullBlankEmpty, {your_filters} )) ), your_query_entity, todatasubset({}))
(Before we implemented this we'd run into scenarios where unexpected missing values would be treated as null and therefore ignore filters and return ALL data rather than none. As you can imagine, this can cause huge security or UI problems.)
Part of the problem we've found is that a!isNotNullOrEmpty is not sufficient for determining an empty filter, because if you pass a singleton value into an array input, it will become "{null} ", which is then run as a filter rather than ignored. One work-around is to always put our utility rule that checks that additional case in the applyWhen.
Thanks for sharing this! Your rule capturing edge cases looks very robust for capturing even more edge cases than ours does. Ultimately I'm still wondering about the best solution for query entities, but it appears to be using a rule like this in applyWhen rather than relying on simply ignoreFiltersWithEmptyValues.