Skip to content

AccessQueryBuilder

Defined in: packages/core/src/access/constraintTypes.ts:361

The q a query-shaped rule receives.

Mirrors Convex’s own query surface, one layer up — each algebra gets its own callback with its own builder, and the two never meet in one expression:

// Convex
ctx.db.query("pages")
.withIndex("by_author", (q) => q.eq("authorId", u))
.filter((q) => q.neq(q.field("archived"), true));
// an access rule
q.withIndex("by_author", (ix) => ix.eq("authorId", u))
.filter((f) => f.neq("archived", true));

That confinement is load-bearing, not stylistic: ix exists only inside the range callback and f only inside the predicate callback, so an index expression cannot reach a boolean combinator even by accident.

Selecting the index through a METHOD is also what makes positional typing reachable — N is the method’s own type parameter, so the literal at the call site resolves that index’s real field tuple and Convex’s field ORDER becomes a compile error. A sibling property cannot be seen by its neighbour’s callback type, which is why earlier { withIndex, constraints } shapes could only offer the resource’s flat field-key union.

Rules on mutation actions receive a bare FilterConstraintBuilder instead — no query exists to narrow, so withIndex is absent rather than rejected.

TDoc

Document shape for the resource this rule governs.

TIndexFields extends Record<string, readonly string[]>

The resource’s declared indexes, name → field tuple in declaration order (IndexFieldsBySlug[slug], types/generated.ts).

filter(predicate): AccessConditionResult

Defined in: packages/core/src/access/constraintTypes.ts:321

Narrows by predicate.

(q) => ConstraintResult

Builds the expression from the flat filter algebra.

AccessConditionResult

The completed condition.

AccessPredicateBuilder.filter


withIndex<N>(name, range): IndexedAccessCondition<TDoc>

Defined in: packages/core/src/access/constraintTypes.ts:378

Narrows the query through a declared index.

The range callback is REQUIRED, unlike Convex’s, where it is optional. A range-less withIndex excludes no documents — every row has an index entry, so it only re-orders, and the docs are explicit that it scans the whole table. Convex allows it because a caller may legitimately want ordering; an access rule never does, and a range-less one would read as a restriction while being none.

N extends string

The index name, inferred from the literal passed.

N

A declared index on this resource.

(ix) => ConstraintResult

Builds the range. ix is positional: Convex’s index rules, field order included, apply inside it.

IndexedAccessCondition<TDoc>

A condition that may be returned as-is or continued with .filter(…).