diff --git a/docs/src/content/docs/documentation/models_and_relations.mdx b/docs/src/content/docs/documentation/models_and_relations.mdx
index 50ac5f7d..c18a9c98 100644
--- a/docs/src/content/docs/documentation/models_and_relations.mdx
+++ b/docs/src/content/docs/documentation/models_and_relations.mdx
@@ -3,7 +3,7 @@ title: Models & Relations
---
import { Image } from "astro:assets";
-import { Aside } from "@astrojs/starlight/components";
+import { Aside, Code } from "@astrojs/starlight/components";
import foo from "./_relations.svg"
@@ -150,10 +150,11 @@ For example, a user deletion may trigger related data to be deleted
automatically.
Let's look at the following data schema for a blog example,
@@ -196,14 +197,18 @@ There's an elephant in the room: while this is all pretty standard fair, at
least in SQL land, connecting relations across TrailBase's record APIs without
joins can be a lot more work.
Naively, for N:M relations, one would have to expose 3 different APIs including
-the bridge table, manage their ACLs and then have the client manually stich the
+the bridge table, manage their ACLs and then have the client manually stitch the
edges.
-For simple, single hop client ⇨ parent traversals we can use TrailBase builtin
-expansion support, i.e. a referenced parent record will be joined and then
-nested into the client response.
-First, we need to set a foreign key columns as "expand" in the API
-configuration, which changes the read schema to:
+For simple, single hop child ⇨ parent traversals we can use TrailBase's builtin
+*expansions*, i.e. a referenced parent record will be joined and then nested
+into the child record.
+To do so, we simply add the foreign key column to the record API's
+[*expand*](https://github.com/trailbaseio/trailbase/blob/e094d82f74b48b1b58a4c482dec89044114719d9/trailbase-core/proto/config.proto#L242)
+configuration property.
+This, in turn, changes the child's data representation, and thus the API
+definition, to create an affordance to nest the parent record.
+Concretely, the API's JSON schema definition of read responses changes to:
```ts
type Schema = {
@@ -215,30 +220,42 @@ type Schema = {
}
```
+Any pre-existing bindings for the API will need to be re-generated or updated.
+
Subsequently, joins can be requested for any of the configured foreign key
columns during read and list operations, e.g.:
-```
-await api.read(1, { expand: ["post"] })
-► {
- id: 1,
+export const readExpand = `
+curl -H "Content-Type: application/json" \\
+ $\{SITE\}/api/records/v1/post_tag/1?expand=post,tag
+
+{
post: {
- id: 'AZUECN4ZfEKDOhVAip8S3g==',
+ id: 1,
data: {
- id: 'AZUECN4ZfEKDOhVAip8S3g==',
+ id: 1,
author: 'AZUECMTAfqOZJjHfEzAqkA==',
title: 'first post',
body: 'body'
}
},
- author: { id: 'AZUECN4ZfEKDOhU6uTkLVw==' },
- body: 'first comment'
+ tag: {
+ id: 5,
+ data: {
+ id: 5,
+ label: "whimsical"
+ }
+ }
}
-```
+`;
-For more complex relations and traversals, it is recommended to push more
-responsibility to the server. Concretely, we can expose a single API tailored
-for specific client use-cases implementing a server-side join using `VIEW`s:
+
+
+
+For more complex relations and traversals, rather than manually stitching on
+the client-side, we recommend to push more responsibility to the server.
+Concretely, we can expose a single API tailored for specific client use-cases
+implementing a server-side join using `VIEW`s:
```sql
CREATE VIEW post_tag_view AS SELECT * FROM post AS P