You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This proposes three array containment operators — as a community array extension (not JSON Logic Core), per @TotalTechGeek's recommendation in json-logic-engine#58:
All three take [haystack, probe] and return a boolean.
Background and use cases
Workflow/rule builders where non-technical users compose conditions in a 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"
Multi-select / checkbox answers are arrays, and the condition value picked in the UI is also an array, so array-to-array containment comes up constantly. in only covers scalar-in-array.
These are expressible today via scoped iterators, e.g. {"all": [["a","b"], {"in": [{"var": ""}, {"var": "../../selected"}]}]} — but rules built by a visual condition builder map naturally to {operator: [haystack, probe]}. Emitting a scoped iterator with a relative var/val path just to express "A contains all of B" makes generated rules significantly harder to produce, validate, and read back into the UI.
Empty haystack: contains_all([], B) → false (for non-empty B); contains_any([], B) → false; contains_none([], B) → true
Non-array operands are treated as empty arrays, consistent with how in treats a null haystack
Element equality follows the same equality the implementation uses for in membership (SameValueZero in JS engines); a Set/hash-set gives O(n+m)
Potential roadblocks
"Just use some + in." True — these are sugar. The claim is that the sugar carries its weight for UI-generated rules (flat {op: [haystack, probe]} shape round-trips cleanly through a condition builder) and that the pattern is common enough to standardize. If the TC feels iterator composition is the intended answer, this proposal should be rejected rather than fragmenting.
Cross-language equality. JS includes is SameValueZero; other runtimes have different native equality (e.g. deep equality for objects in some Go implementations). The proposal deliberately pins element equality to "whatever the implementation's in uses" to stay consistent within each runtime — but if the extension should mandate a single cross-runtime equality (e.g. scalars only, or RFC 8259 value equality), that needs deciding here. The attached test suite only exercises strings and numbers, where all implementations agree.
Naming.contains_all / contains_any / contains_none follow the snake_case precedent of missing_some, and match the names already shipped in the Go ecosystem (see below). Alternatives like supersetOf / intersects / disjoint are more set-theoretic but less approachable for the rule-builder audience.
Non-array coercion vs. hard error. Treating non-array operands as empty arrays matches in's lenient style, but an implementation with strict error semantics might prefer {"type": "Invalid Arguments"}. Open to tightening this.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Summary
This proposes three array containment operators — as a community array extension (not JSON Logic Core), per @TotalTechGeek's recommendation in json-logic-engine#58:
contains_all{"contains_all": [["a","b","c"], ["a","b"]]}→truecontains_any{"contains_any": [["a","b"], ["b","c"]]}→truecontains_none{"contains_none": [["a","b"], ["c","d"]]}→trueAll three take
[haystack, probe]and return a boolean.Background and use cases
Workflow/rule builders where non-technical users compose conditions in a UI:
['VIP', 'Premium']→ send to Slack"['urgent', 'important']→ notify immediately"['blocked', 'spam']→ proceed"Multi-select / checkbox answers are arrays, and the condition value picked in the UI is also an array, so array-to-array containment comes up constantly.
inonly covers scalar-in-array.These are expressible today via scoped iterators, e.g.
{"all": [["a","b"], {"in": [{"var": ""}, {"var": "../../selected"}]}]}— but rules built by a visual condition builder map naturally to{operator: [haystack, probe]}. Emitting a scoped iterator with a relativevar/valpath just to express "A contains all of B" makes generated rules significantly harder to produce, validate, and read back into the UI.Proposed semantics
contains_all(A, [])→true(vacuous truth);contains_any(A, [])→false;contains_none(A, [])→truecontains_all([], B)→false(for non-empty B);contains_any([], B)→false;contains_none([], B)→trueintreats anullhaystackinmembership (SameValueZero in JS engines); aSet/hash-set gives O(n+m)Potential roadblocks
some+in." True — these are sugar. The claim is that the sugar carries its weight for UI-generated rules (flat{op: [haystack, probe]}shape round-trips cleanly through a condition builder) and that the pattern is common enough to standardize. If the TC feels iterator composition is the intended answer, this proposal should be rejected rather than fragmenting.includesis SameValueZero; other runtimes have different native equality (e.g. deep equality for objects in some Go implementations). The proposal deliberately pins element equality to "whatever the implementation'sinuses" to stay consistent within each runtime — but if the extension should mandate a single cross-runtime equality (e.g. scalars only, or RFC 8259 value equality), that needs deciding here. The attached test suite only exercises strings and numbers, where all implementations agree.contains_all/contains_any/contains_nonefollow the snake_case precedent ofmissing_some, and match the names already shipped in the Go ecosystem (see below). Alternatives likesupersetOf/intersects/disjointare more set-theoretic but less approachable for the rule-builder audience.in's lenient style, but an implementation with strict error semantics might prefer{"type": "Invalid Arguments"}. Open to tightening this.Existing implementations
json-logic-enginein json-logic-engine#59 (kept as draft pending this proposal)Test suite
Formatted per TEST_FORMAT.md; these match the merged Go implementation's test matrix.
Happy to adjust naming, semantics, or scope to whatever the TC prefers.
All reactions