Skip to main content

Condition Operators

A condition filters which instances of a subject a rule applies to. It's the fourth, optional slot of a rule tuple, and it's only evaluated when you check a subject instance (a wrapped object), not a bare subject name/type.

- [ allow, Update, Article, { owner_id: 1 } ]

Bare-value shorthand

A condition value that isn't itself an operator object is shorthand for $eq:

{ owner_id: 1 }
# is shorthand for
{ owner_id: { $eq: 1 } }

Comparison operators

OperatorMatches when
$eqsubject == value
$nesubject != value
$gtsubject > value
$gtesubject >= value
$ltsubject < value
$ltesubject <= value
$invalue[] contains subject
$hassubject[] contains value
{ status: { $in: [ "draft", "review" ] } }
{ tags: { $has: "featured" } }
Missing fields

A field condition on a field the subject doesn't have evaluates to false, whichever operator is nested inside it — except $ne. Since $ne is the exact negation of $eq (and a missing field makes $eq evaluate to false), $ne on a missing field evaluates to true instead: { status: { $ne: "archived" } } matches a subject with no status key at all. This exception applies only when $ne is the sole key of that condition object — in a multi-key object like { author: { $ne: null, $eq: "Alice" } }, a missing author field falls back to the ordinary blanket false.

$substr — pattern matching

{ $substr: pattern } matches when String(subject) contains a substring described by pattern — a small, deliberately non-regex pattern language, so every implementation matches identically regardless of the host language's regex engine.

TokenMeaning
^anchors the match to the start of the string (only valid as the first character)
$anchors the match to the end of the string (only valid as the last character)
*matches zero or more characters
\escapes the next character, making it literal
{ slug: { $substr: "^draft-*" } } # starts with "draft-"
{ slug: { $substr: "*-final$" } } # ends with "-final"
{ title: { $substr: "*Q3*Report*" } } # contains "Q3", then "Report", in order

A structurally invalid pattern (a stray ^ or $ not at a boundary) evaluates to false. A null/undefined subject is an ordinary non-match, not an error. See §5.4.6 of the v1.0 spec for the exact decomposition rules.

Logical operators

OperatorMatches when
$orat least one sub-condition in Condition[] matches
$andevery sub-condition in Condition[] matches
$notthe wrapped Condition does not match
- [ allow, Update, Article, {
$and: [
{ owner_id: 1 },
{ status: { $not: "archived" } }
]
} ]

Field access

By default, a key in a condition object that isn't an operator (doesn't start with $) is treated as a field name, and its value is evaluated as a condition against that field of the subject:

{ owner_id: 1 } # subject.owner_id == 1
{ author: { $ne: null } } # subject.author != null
{ tags: { $has: "featured" } } # subject.tags contains "featured"

v1 supports only top-level field access

A field condition may narrow into a subject's field exactly once — the Condition it narrows into must not itself be another field condition (bare-key or $field), whether directly or nested inside $or/$and/$not:

{ author: { name: "Alice" } } # invalid — { name: "Alice" } is itself
# a field condition, a second level of narrowing

This evaluates to false and produces the usual diagnostic, the same as any other malformed condition shape. Reaching into a nested object (subject.author.name) — or a dot-path/array-index shorthand for it — is out of scope for v1 and reserved for a future version. Comparison, collection, string, logical, and custom operators are unaffected, since they don't narrow the subject: { author: { $ne: null } } and { tags: { $has: "featured" } } above are both ordinary, valid top-level field conditions.

$field — explicit field access

If a field's name itself starts with $, use $field: [key, Condition] to disambiguate it from an operator. The same top-level-only restriction applies: Condition here must not itself be a field condition.

{ $field: [ "$special", { $eq: "value" } ] } # subject["$special"] == "value"

Custom operators

Implementations may support custom, application-defined operators ($op) in addition to the built-ins above — see each language guide's API reference for how to register one, and §5.5 of the v1.0 spec for the requirements a custom operator must satisfy.