jsonlogic
jsonlogic copied to clipboard
feat: Add three new operators for comparing arrays, commonly needed in workflow automation systems.
Summary
Add three new operators for comparing arrays, commonly needed in workflow automation systems.
New Operators
| Operator | Description | Example |
|---|---|---|
contains_all |
Returns true if all elements of the second array exist in the first | {"contains_all": [["a","b","c"], ["a","b"]]} → true |
contains_any |
Returns true if any element of the second array exists in the first | {"contains_any": [["a","b"], ["x","a"]]} → true |
contains_none |
Returns true if no elements of the second array exist in the first | {"contains_none": [["a","b"], ["x","y"]]} → true |
Use Case
I'm building a workflow automation system where users define conditions in the UI:
- "If selected options contain all of ['VIP', 'Premium'] → send to Slack"
- "If tags contain any of ['urgent', 'important'] → notify immediately"
- "If categories contain none of ['blocked', 'spam'] → proceed"
The current in operator only checks if a single value exists in an array. These new operators enable array-to-array comparison.
Usage
// Check if user has all required roles
logic := strings.NewReader(`{"contains_all": [{"var": "roles"}, ["admin", "editor"]]}`)
data := strings.NewReader(`{"roles": ["admin", "editor", "viewer"]}`)
var result bytes.Buffer
jsonlogic.Apply(logic, data, &result)
// result: true
// Check if any priority tag exists
logic := strings.NewReader(`{"contains_any": [{"var": "tags"}, ["urgent", "important"]]}`)
data := strings.NewReader(`{"tags": ["normal", "urgent"]}`)
// result: true
// Check if content has no blocked words
logic := strings.NewReader(`{"contains_none": [{"var": "words"}, ["spam", "blocked"]]}`)
data := strings.NewReader(`{"words": ["hello", "world"]}`)
// result: true
Changes
- arrays.go - New operators implementation
- arrays_test.go - Comprehensive test cases (24 tests)
Tests
All tests passing:
=== RUN TestContainsAll --- PASS: TestContainsAll (0.00s) === RUN TestContainsAny --- PASS: TestContainsAny (0.00s) === RUN TestContainsNone --- PASS: TestContainsNone (0.00s) PASS
Notes
- I can add README documentation if you'd like
- Open to renaming operators if you prefer different naming conventions
- Happy to split into separate PRs if preferred
#129