jsonlogic icon indicating copy to clipboard operation
jsonlogic copied to clipboard

feat: Add three new operators for comparing arrays, commonly needed in workflow automation systems.

Open iyk2h opened this issue 1 month ago • 0 comments

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

iyk2h avatar Nov 30 '25 11:11 iyk2h