Skip to content

Commit 93d913a

Browse files
authored
doc: field-level policy (#546)
1 parent 1d6b144 commit 93d913a

File tree

2 files changed

+56
-3
lines changed

2 files changed

+56
-3
lines changed

docs/orm/access-control/field-level.md

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,59 @@
22
sidebar_position: 4
33
---
44

5-
# Field-Level Policies 🚧
5+
import AvailableSince from '../../_components/AvailableSince';
6+
import PreviewFeature from '../../_components/PreviewFeature'
67

7-
Coming soon.
8+
# Field-Level Policies
9+
10+
<AvailableSince version="v3.2.0" />
11+
<PreviewFeature name="Field-level policy" />
12+
13+
Field-level policies allow you to define access control rules at the individual field level within a model. This provides fine-grained control over who can read or write specific fields in your data models. To define field-level policies, use the `@allow` and `@deny` attributes directly on model fields (note the single `@`).
14+
15+
```zmodel
16+
model User {
17+
id Int @id
18+
19+
// email can be updated only by the user themselves
20+
email String @allow('update', auth() == this)
21+
22+
// name cannot be read by anonymous users
23+
name String @deny('read', auth() == null)
24+
}
25+
```
26+
27+
Field-level policies are similar to model-level ones, with the following key restrictions:
28+
29+
- Only "read" and "update" operations are supported. You can use "all" to denote both.
30+
- They cannot be defined on relation fields or computed fields.
31+
32+
## Read Behavior
33+
34+
When reading a row, fields that violates "read" policies will be nullified in the result. Conceptually, the following form of SQL is generated to guard the fields:
35+
36+
```sql
37+
SELECT
38+
CASE WHEN <read_policy_for_field_1> THEN field_1 ELSE NULL END AS field_1,
39+
...
40+
FROM table
41+
WHERE <model_level_policies> and <other_conditions>;
42+
```
43+
44+
If read policies are defined on foreign key fields, they will also control the readability of the corresponding relations.
45+
46+
:::info
47+
48+
Setting unreadable fields null brings a caveat that you cannot tell whether a field is actually `NULL` in the database or just unreadable due to access control. So why don't we instead omit the fields from the result?
49+
50+
The concern is that a non-readable field should still have a valid SQL value, because it can be used to compute other data (computed columns, joins, etc.). With `null` values, the computation remain valid in SQL (e.g., `NULL + 1` results in `NULL`), so the fields remain usable everywhere even though their actual values cannot be seen.
51+
52+
:::
53+
54+
## Update Behavior
55+
56+
When updating data, if an update involves setting fields that violate "update" policies, the entire update operation will be rejected with an `ORMError` with `reason` set to `REJECTED_BY_POLICY`.
57+
58+
## Samples
59+
60+
Coming soon!

docs/roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ This is a list of major features that are planned for the future releases of Zen
1313
- [x] TanStack Query integration
1414
- [ ] Databases
1515
- [ ] MySQL
16-
- [ ] Field-level access control
16+
- [x] Field-level access control
1717
- [ ] Zod utility
1818
- [ ] Custom functions
1919
- [ ] Custom procedures

0 commit comments

Comments
 (0)