Skip to content

Commit 72e1c75

Browse files
docs: update diagram spec for Diagram.cascade() classmethod API
- cascade() is now a classmethod: Diagram.cascade(table_expr) - Update all code examples (no intermediate dj.Diagram(schema) step) - restrict() constraint: "cannot be called on cascade Diagram" - prune() constraint: raises on cascade Diagrams (race condition safety) - counts() requires Diagram.cascade() or restrict() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 32ed917 commit 72e1c75

1 file changed

Lines changed: 12 additions & 19 deletions

File tree

src/reference/specs/diagram.md

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -120,17 +120,17 @@ dj.Diagram(Subject) + dj.Diagram(analysis).collapse()
120120
## Operational Methods
121121

122122
!!! version-added "New in 2.2"
123-
Operational methods (`cascade`, `restrict`, `counts`, `prune`) were added in DataJoint 2.2.
123+
Operational methods (`Diagram.cascade()`, `restrict`, `counts`, `prune`) were added in DataJoint 2.2.
124124

125125
Diagrams can propagate restrictions through the dependency graph and inspect affected data using the graph structure. These methods turn Diagram from a visualization tool into a graph computation and inspection component. All mutation operations (delete, drop) are executed by `Table.delete()` and `Table.drop()`, which use Diagram internally.
126126

127-
### `cascade()`
127+
### `Diagram.cascade()` (class method)
128128

129129
```python
130-
diag.cascade(table_expr, part_integrity="enforce")
130+
dj.Diagram.cascade(table_expr, part_integrity="enforce")
131131
```
132132

133-
Prepare a cascading delete. Starting from a restricted table expression, propagate the restriction downstream through all descendants using **OR** semantics — a descendant row is marked for deletion if *any* ancestor path reaches it. The returned Diagram is **trimmed** to the cascade subgraph: only the seed table and its descendants remain; all ancestors and unrelated tables are removed. The trimmed diagram is ready for `counts()` and `delete()`.
133+
Create a cascade diagram for delete. Builds a complete dependency graph from the table expression, includes all descendants across all loaded schemas, propagates the restriction downstream using **OR** semantics — a descendant row is marked for deletion if *any* ancestor path reaches it — and **trims** to the cascade subgraph.
134134

135135
| Parameter | Type | Default | Description |
136136
|-----------|------|---------|-------------|
@@ -139,12 +139,6 @@ Prepare a cascading delete. Starting from a restricted table expression, propaga
139139

140140
**Returns:** New `Diagram` containing only the seed table and its descendants, with cascade restrictions applied.
141141

142-
**Constraints:**
143-
144-
- **One-shot** — can only be called once on an unrestricted Diagram
145-
- Mutually exclusive with `restrict()`
146-
- `table_expr.full_table_name` must be a node in the diagram
147-
148142
**`part_integrity` values:**
149143

150144
| Value | Behavior |
@@ -156,9 +150,8 @@ Prepare a cascading delete. Starting from a restricted table expression, propaga
156150
With `"cascade"`, the restriction flows **upward** from a part table to its master: the restricted part rows identify which master rows are affected, those masters receive a restriction, and that restriction propagates back downstream through the normal cascade — deleting the entire compositional unit (master + all parts), not just the originally matched part rows.
157151

158152
```python
159-
# Build a cascade from a restricted table
160-
diag = dj.Diagram(schema)
161-
restricted = diag.cascade(Session & {'subject_id': 'M001'})
153+
# Preview cascade impact across all loaded schemas
154+
dj.Diagram.cascade(Session & {'subject_id': 'M001'}).counts()
162155
```
163156

164157
### `restrict()`
@@ -178,7 +171,7 @@ Select a subset of data for export or inspection. Starting from a restricted tab
178171
**Constraints:**
179172

180173
- **Chainable** — call multiple times to add conditions from different seed tables
181-
- Mutually exclusive with `cascade()`
174+
- Cannot be called on a Diagram produced by `Diagram.cascade()`
182175
- `table_expr.full_table_name` must be a node in the diagram
183176

184177
```python
@@ -199,12 +192,10 @@ Return affected row counts per table without modifying data. Works with both `ca
199192

200193
**Returns:** `dict[str, int]` — mapping of full table names to affected row counts.
201194

202-
**Requires:** `cascade()` or `restrict()` must be called first.
195+
**Requires:** `Diagram.cascade()` or `restrict()` must be called first.
203196

204197
```python
205-
diag = dj.Diagram(schema)
206-
restricted = diag.cascade(Session & {'subject_id': 'M001'})
207-
counts = restricted.counts()
198+
counts = dj.Diagram.cascade(Session & {'subject_id': 'M001'}).counts()
208199
# {'`lab`.`session`': 3, '`lab`.`trial`': 45, '`lab`.`processed_data`': 45}
209200
```
210201

@@ -214,10 +205,12 @@ counts = restricted.counts()
214205
diag.prune()
215206
```
216207

217-
Remove tables with zero matching rows from the diagram view. This only affects the diagram object — no tables or data are modified in the database. Without prior restrictions, removes physically empty tables from the diagram. With restrictions (`cascade()` or `restrict()`), removes tables where the restricted query yields zero rows.
208+
Remove tables with zero matching rows from the diagram view. This only affects the diagram object — no tables or data are modified in the database. Without prior restrictions, removes physically empty tables from the diagram. After `restrict()`, removes tables where the restricted query yields zero rows.
218209

219210
**Returns:** New `Diagram` with empty tables removed.
220211

212+
**Constraints:** Cannot be used on a Diagram produced by `Diagram.cascade()`. Cascade diagrams must retain all descendant tables because a table empty at cascade time could have rows by the time `delete()` executes.
213+
221214
**Note:** Queries the database to determine row counts. The underlying graph structure is preserved — subsequent `restrict()` calls can still seed at any table in the schema.
222215

223216
```python

0 commit comments

Comments
 (0)