Relationships
Everything that connects two tables follows a foreign key the database declares, or a reference the App declares in its place.
related('Opportunities', 'opportunity', 'account_id', { show: ['name', 'stage', 'amount'] }),metric('Open tasks', 'task', { whose: 'account_id', query: 'status = open' }),account_id here is a hop: the name of a foreign key, written as its column
(a+b for a composite key, the constraint’s name where two keys share
columns). tablewalk-schema.d.ts lists every table’s hops under References.
What follows a foreign key
Section titled “What follows a foreign key”| Where | Written |
|---|---|
| A reference cell or field, drawn as its record’s name and a link | a column that is a foreign key |
A label path in show, recordLabel, a card |
account_id.name, opportunity_id.account_id.city |
| A related list, a metric, breakdown or chart on a page | whose: the hop on the from rows that points at the record |
| A section about another record than the page’s | about: the hop from the page’s record to it |
| A timeline stream | stream(from, whose, at, show) |
A rollup (count, sum, min, max) and a related list’s create |
the same hops |
similar() and a related list’s same match by column value and need no
foreign key.
A key the database does not declare
Section titled “A key the database does not declare”A text column holding another table’s code (site_code → site.code) is
not a relationship until something says so: paths refuse it, naming it a
column but not a foreign key. Declare the key in the database
(ALTER TABLE work_order ADD FOREIGN KEY (site_code) REFERENCES site (code);
SQLite declares keys in CREATE TABLE), or in the App:
work_order: { references: { site_code: { to: 'site', column: 'code' } } },Either way the target must be unique (its primary key, the default, or a
unique constraint on that column alone) and of the same kind. A declared
reference is followed like a key everywhere above, is never authority for
a write, and adds no delete impact. Then run tablewalk check.
Across sources
Section titled “Across sources”A foreign key lives in one database. Two sources on one
connection (a schema each) are one database, so a key or a declared
reference between them joins like any other. A declared reference into a
source on another connection is read in two steps: the list’s rows, then
one read of the targets the page names, through that source’s own grants
and row policy. It labels the list, opens the target, and gives the target
a related list; filters, sorts, groupings, rollups, tags and notify
paths through it are refused, since each database filters what it holds.
A tenant App’s references stay within its one source.