Skip to content

Commit

Permalink
Enhanced 'search' operator to allow complex criteria matching on payl…
Browse files Browse the repository at this point in the history
…oad items
  • Loading branch information
erceth committed Jan 17, 2022
1 parent 0e27ccc commit 89003aa
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 525 deletions.
123 changes: 18 additions & 105 deletions st2common/st2common/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,20 @@ class UnrecognizedConditionError(Exception):

def search(value, criteria_pattern, criteria_condition, check_function):
"""
Search a list of values that match all child criteria. If condition is 'any', return a
successful match if any items match all child criteria. If condition is 'all', return a
successful match if ALL items match all child criteria.
Search a list of values that match all child criteria.
Allow comparison of payload items to multiple criteria using different logicial conditions.
If condition is 'any', return a successful match if any items match all child criteria.
If condition is 'all', return a successful match if ALL items match all child criteria.
Other allowed conditions: all2all, all2any, any2any and any2all.
value: the payload list to search
condition: one of:
* any - return true if any items of the list match and false if none of them match
* all - return true if all items of the list match and false if any of them do not match
* all2all - true if all payload items match all criteria items
* all2any - true if all payload items match any criteria items
* any2any - true if any payload items match any criteria items
* any2all - true if any payload items match all criteria items
* any - same as any2all (useful to maintain backward compatibility)
* all - same as all2all (useful to maintain backward compatibility)
pattern: a dictionary of criteria to apply to each item of the list
This operator has O(n) algorithmic complexity in terms of number of child patterns.
Expand All @@ -86,14 +92,14 @@ def search(value, criteria_pattern, criteria_condition, check_function):
]
}
And an example usage in criteria:
Example #1
---
criteria:
trigger.fields:
type: search
# Controls whether this criteria has to match any or all items of the list
condition: any # or all
condition: all
pattern:
# Here our context is each item of the list
# All of these patterns have to match the item for the item to match
Expand All @@ -105,105 +111,14 @@ def search(value, criteria_pattern, criteria_condition, check_function):
item.to_value:
type: "equals"
pattern: "Approved"
"""
if criteria_condition == "any":
# Any item of the list can match all patterns
rtn = any(
[
# Any payload item can match
all(
[
# Match all patterns
check_function(
child_criterion_k,
child_criterion_v,
PayloadLookup(
child_payload, prefix=TRIGGER_ITEM_PAYLOAD_PREFIX
),
)
for child_criterion_k, child_criterion_v in six.iteritems(
criteria_pattern
)
]
)
for child_payload in value
]
)
elif criteria_condition == "all":
# Every item of the list must match all patterns
rtn = all(
[
# All payload items must match
all(
[
# Match all patterns
check_function(
child_criterion_k,
child_criterion_v,
PayloadLookup(
child_payload, prefix=TRIGGER_ITEM_PAYLOAD_PREFIX
),
)
for child_criterion_k, child_criterion_v in six.iteritems(
criteria_pattern
)
]
)
for child_payload in value
]
)
else:
raise UnrecognizedConditionError(
"The '%s' search condition is not recognized, only 'any' "
"and 'all' are allowed" % criteria_condition
)

return rtn


def multiple(value, criteria_pattern, criteria_condition, check_function):
"""
Allow comparison of payload items to multiple criteria using different logicial conditions.
Performs same function as the "search" operator and contains additional features.
value: the payload items
condition: one of:
* all2all - true if all payload items match all criteria items
* all2any - true if all payload items match any criteria items
* any2any - true if any payload items match any criteria items
* any2all - true if any payload items match all criteria items
* all - same as all2all (useful to maintain backward compatibility with search operator)
* any - same as any2all (useful to maintain backward compatibility with search operator)
pattern: a dictionary of criteria to apply to each item of the list
This operator has O(n) algorithmic complexity in terms of number of child patterns.
This operator has O(n) algorithmic complexity in terms of number of payload fields.
However, it has O(n_patterns * n_payloads) algorithmic complexity, where:
n_patterns = number of child patterns
n_payloads = number of fields in payload
It is therefore very easy to write a slow rule when using this operator.
This operator should ONLY be used when trying to match a small number of child patterns and/or
a small number of payload list elements.
Data from the trigger:
{
"fields": [
{
"field_name": "waterLevel",
"to_value": 45,
}
]
}
And an example usage in criteria:
---
Example #2
---
criteria:
trigger.fields:
type: multiple
type: search
# Controls whether this criteria has to match any or all items of the list
condition: all2all # all2any, any2all or any2any
pattern:
Expand All @@ -224,7 +139,7 @@ def multiple(value, criteria_pattern, criteria_condition, check_function):
(len(criteria_condition_list) == 2 and (criteria_condition_list[0] == 'any' or criteria_condition_list[0] == 'all') and
(criteria_condition_list[1] == 'any' or criteria_condition_list[1] == 'all')))):
raise UnrecognizedConditionError(
"The '%s' condition is not recognized for type multiple, 'any', 'all', 'any2any', 'any2all', 'all2any'"
"The '%s' condition is not recognized for type search, 'any', 'all', 'any2any', 'any2all', 'all2any'"
" and 'all2all are allowed" % criteria_condition
)
payloadItemMatch = any
Expand Down Expand Up @@ -509,7 +424,6 @@ def ensure_operators_are_strings(value, criteria_pattern):
NINSIDE_LONG = "ninside"
NINSIDE_SHORT = "nin"
SEARCH = "search"
MULTIPLE = "multiple"

# operator lookups
operators = {
Expand Down Expand Up @@ -546,5 +460,4 @@ def ensure_operators_are_strings(value, criteria_pattern):
NINSIDE_LONG: ninside,
NINSIDE_SHORT: ninside,
SEARCH: search,
MULTIPLE: multiple
}
Loading

0 comments on commit 89003aa

Please sign in to comment.