Two modes
Check: forget, update, delete and create, Pawabase has the record (or the input) in hand and evaluates the whole rule: true or false.
Plan: for list, there are thousands of candidate rows. Pawabase first evaluates everything that doesn’t depend on a record (is the caller signed in, do they have the role, is the key a service key). Then:
- If that already decides it, the request is allowed or refused at once, before the database is touched.
- Otherwise, what remains is a rule about the record. If it is an equality between a column and a known value (
$record.owner_idequals$auth.user_id), it becomes a database filter:WHERE owner_id = '<caller>'. - Anything else stays as a per-row check applied to the rows the query returns.
Why it matters
What becomes a filter
-
The
ownershorthand and its string forms. -
eqbetween a record column and a value that is known when the request starts ($auth.user_id,$auth.org, a literal). -
Several such equalities combined with
all. -
All of these rules pass:
- Is signed in: yes
- Compare values:
$record.orgequals$auth.org
WHERE org = '<the caller's org>'.
What stays per-row
- Comparisons other than
eqbetween a column and a value (gt,in,starts_with…). anythat mixes record conditions (the database filter would need OR).notaround a record condition.- Anything comparing two columns of the same record.
Keep lists fast and exact
- Prefer plain equality on an indexed column:
owner_id,org,author_id. - Split by audience when you can. Instead of one “mine or published” rule on the table, expose “mine” through the table and “published” through a second table/view or route.
- Index the column the rule filters on (Indexes).
- Design your UI for
total: null: “Load more”, not “page 3 of N”.
Check mode is exact
get, update and delete see the real row, so they’re exact for any rule, including the per-row-only ones. A rule that is per-row for lists is still enforced precisely for single-record actions.
Create and update see $input
On create, the rule has no record yet, so it reads $input and $auth. On update it sees both the stored record and the new values, so you can say “owner can change a draft, and may only set status to draft or submitted”:
- All of these rules pass:
- Owns the record (field)
owner_id - Compare values:
$record.statusequalsdraft - Compare values:
$input.statusis one ofdraft, submitted
- Owns the record (field)
Related records and realtime
expandreads each related record under its own table’sget/listrule.- Realtime sends a change only to people the table’s read rule allows, checked against the row as it was and as it is now. See Live records.
Performance rules of thumb
Database access
Apply to tables.
Debugging
See what decided.