Skip to content

Commit a76511c

Browse files
tstirrat15samkim
andauthored
Add composable schema docs (#306)
* Add composable schema docs * Update pages/spicedb/modeling/composable-schemas.mdx Co-authored-by: Sam Kim <[email protected]> * Update pages/spicedb/modeling/composable-schemas.mdx Co-authored-by: Sam Kim <[email protected]> * Update pages/spicedb/modeling/composable-schemas.mdx Co-authored-by: Sam Kim <[email protected]> --------- Co-authored-by: Sam Kim <[email protected]>
1 parent 089f86a commit a76511c

File tree

4 files changed

+226
-1
lines changed

4 files changed

+226
-1
lines changed

pages/spicedb/modeling/_meta.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"developing-a-schema": "Developing a Schema",
3+
"composable-schemas": "Composable Schemas (Preview)",
34
"representing-users": "Representing Users",
45
"validation-testing-debugging": "Validation, Testing, Debugging",
56
"recursion-and-max-depth": "Recursion & Max Depth",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import { Callout, Tabs } from 'nextra/components'
2+
3+
# Composable Schemas (Preview)
4+
5+
<Callout type="info">
6+
This preview feature's functionality may change before general release.
7+
</Callout>
8+
9+
In zed version v0.27.0, we introduced a schema compilation command:
10+
11+
```
12+
zed preview schema compile some-schema.zed
13+
```
14+
15+
There are three new pieces of syntax: [import statements](#import-statements), [partial declarations](#partial-declarations), and [partial references](#partial-references).
16+
17+
This is a simple schema that demonstrates all three features:
18+
19+
<Tabs items={["root.zed", "subjects.zed"]}>
20+
<Tabs.Tab>
21+
22+
```zed
23+
import "./subjects.zed"
24+
25+
partial view_partial {
26+
relation user: user
27+
permission view = user
28+
}
29+
30+
definition resource {
31+
...view_partial
32+
33+
relation organization: organization
34+
permission manage = organization
35+
}
36+
```
37+
38+
</Tabs.Tab>
39+
<Tabs.Tab>
40+
41+
```zed
42+
definition user {}
43+
definition organization {}
44+
```
45+
46+
</Tabs.Tab>
47+
</Tabs>
48+
49+
Compiling the above with `zed preview schema compile root.zed` will produce an output schema that looks like:
50+
51+
```zed
52+
definition user {}
53+
54+
definition organization {}
55+
56+
definition resource {
57+
relation user: user
58+
permission view = user
59+
60+
relation organization: organization
61+
permission manage = organization
62+
}
63+
```
64+
65+
This compilation step provides new features that help you modularize your schema, making organization and collaboration easier.
66+
67+
## Import Statements
68+
69+
Import statements allow you to break down a schema along the lines of top-level declarations.
70+
71+
<Tabs items={["root.zed", "one.zed", "two.zed"]}>
72+
<Tabs.Tab>
73+
74+
```zed
75+
// An import keyword followed by a quoted relative filepath
76+
import "./one.zed"
77+
78+
// Note that a bare filename works as a relative path
79+
import "two.zed"
80+
81+
// The imports are included by the compilation process, which means that
82+
// they can be referenced by other definitions
83+
definition resource {
84+
relation user: user
85+
relation organization: organization
86+
87+
permission view = user + organization
88+
}
89+
```
90+
91+
</Tabs.Tab>
92+
<Tabs.Tab>
93+
94+
```zed
95+
definition user {}
96+
```
97+
98+
</Tabs.Tab>
99+
<Tabs.Tab>
100+
101+
```zed
102+
definition organization {}
103+
```
104+
105+
</Tabs.Tab>
106+
107+
</Tabs>
108+
109+
### Good to Know
110+
111+
* Import references must be within the folder where `zed` is invoked.
112+
* Import cycles are treated as errors.
113+
* All definitions in all imported files are pulled in.
114+
Any duplicate definitions will cause an error.
115+
116+
## Partials
117+
118+
Partial declarations and references provide a means of decomposing a schema along lines that cross definition boundaries.
119+
This can be useful for separating out a schema by team or domain concern, for example.
120+
121+
### Partial Declarations
122+
123+
A partial declaration is a top-level block that is declared using the `partial` keyword.
124+
It can contain relations, permissions, and partial references just like a `definition` block, but its contents
125+
must be referenced by a [partial reference](#partial-references) to show up in the compiled schema.
126+
127+
```zed
128+
partial view_partial {
129+
...some_other_partial
130+
131+
relation user: user
132+
permission view = user
133+
}
134+
```
135+
136+
#### Good to Know
137+
138+
* Any partial that isn't referenced is ignored by the compilation process.
139+
* Partial declarations can contain partial references, allowing for partials to be composed.
140+
141+
### Partial References
142+
143+
A partial reference takes a `partial` and includes the relations and permissions defined in that partial.
144+
It works similarly to [JS spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)
145+
or [python's dictionary unpacking](https://docs.python.org/3/reference/expressions.html#dictionary-displays).
146+
147+
This syntax:
148+
149+
```zed
150+
partial view_partial {
151+
relation user: user
152+
permission view = user
153+
}
154+
155+
definition resource {
156+
...view_partial
157+
}
158+
```
159+
160+
is equivalent to this declaration:
161+
162+
```zed
163+
definition resource {
164+
relation user: user
165+
permission view = user
166+
}
167+
```
168+
169+
#### Good to Know
170+
171+
* Duplicate relations and permissions introduced by a partial reference are treated as errors.
172+
* Circular references between partials are treated as errors.
173+
* You can only reference partial declarations.
174+
Attempting to reference other declaration types (e.g. a definition or a caveat) with a partial reference will result in a error.
175+
176+
## An Example Workflow
177+
178+
1. Make a change to your multi-file schema
179+
1. Run `zed validate` to ensure that the changes are valid
180+
1. Make a PR to your schema repository
181+
1. CI runs `zed validate` again
182+
183+
Then on merge:
184+
185+
1. CI runs `zed preview schema compile`
186+
1. CI calls SpiceDB with the compiled schema
187+
188+
## Notes
189+
190+
SpiceDB `WriteSchema` calls cannot interpret `import` or `partial` syntax.
191+
If using the new syntax, you must build the schema using `compile` before it can be submitted.
192+
This is because a schema write must happen in a single call to SpiceDB.

pages/spicedb/modeling/migrating-schema.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Callout, Tabs } from 'nextra/components';
1+
import { Callout } from 'nextra/components';
22

33
# Updating Migrating Schema in SpiceDB
44

public/authzed.tmLanguage.json

+32
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"foldingStopMarker": "^\\s*\\}",
77
"patterns": [
88
{ "include": "#comment" },
9+
{ "include": "#importStatement" },
910
{ "include": "#objectDefinition" },
1011
{ "include": "#objectRelation" },
1112
{ "include": "#objectPermission" },
@@ -144,6 +145,8 @@
144145
"patterns": [
145146
{ "include": "#definition" },
146147
{ "include": "#definitionMethodName" },
148+
{ "include": "#partial" },
149+
{ "include": "#partialMethodName" },
147150
{ "include": "#caveat" },
148151
{ "include": "#caveatMethodName" },
149152
{ "include": "#variable" },
@@ -160,6 +163,16 @@
160163
"match": "\\w+(?=\\s+\\{)",
161164
"name": "entity.name.type.class.authzed"
162165
},
166+
"partial": {
167+
"comment": "the word partial",
168+
"match": "^\\s*partial",
169+
"name": "keyword.control.class.authzed"
170+
},
171+
"partialMethodName": {
172+
"comment": "a word followed by an open bracket",
173+
"match": "\\w+(?=\\s+\\{)",
174+
"name": "entity.name.type.class.authzed"
175+
},
163176
"caveat": {
164177
"comment": "the word caveat",
165178
"match": "^\\s*caveat",
@@ -182,6 +195,25 @@
182195
}
183196
}
184197
},
198+
"importStatement": {
199+
"comment": "things that appear on lines that start with import",
200+
"patterns": [
201+
{ "include": "#import" },
202+
{ "include": "#importPath" }
203+
],
204+
"repository": {
205+
"import": {
206+
"comment": "the word import",
207+
"match": "^\\s*import",
208+
"name": "keyword.control.class.authzed"
209+
},
210+
"importPath": {
211+
"comment": "a quote-delimited string",
212+
"match": "[\"']\\w+[\"']",
213+
"name": "string.quoted"
214+
}
215+
}
216+
},
185217
"objectRelation": {
186218
"comment": "things that appear on lines that start with relation",
187219
"patterns": [

0 commit comments

Comments
 (0)