Skip to content

Commit 2b84b63

Browse files
docs: update design doc to reflect cascade subgraph trimming
- cascade() now documents graph trimming step (step 4) - delete() walks all non-alias nodes (graph already trimmed) - _restrict_freetable() renamed to _restricted_table() (instance method) - Sharpen distinction between cascade (delete) and restrict (subset) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d235617 commit 2b84b63

File tree

1 file changed

+8
-7
lines changed

1 file changed

+8
-7
lines changed

docs/design/restricted-diagram.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,16 @@ If a child table lives in a schema not loaded into the dependency graph, the gra
110110

111111
### `cascade(self, table_expr, part_integrity="enforce") -> Diagram`
112112

113-
Apply cascade restriction and propagate downstream. Returns a new `Diagram`. One-shot — cannot be called twice or mixed with `restrict()`.
113+
Prepare a cascading delete. Propagate a restriction downstream, then trim the diagram to the cascade subgraph. Returns a new `Diagram` containing only the seed table and its descendants. One-shot — cannot be called twice or mixed with `restrict()`.
114114

115115
1. Verify no existing cascade or restrict restrictions
116116
2. Copy diagram, seed `_cascade_restrictions[root]` with `list(table_expr.restriction)`
117117
3. Propagate via `_propagate_restrictions(root, mode="cascade", part_integrity=part_integrity)`
118+
4. Trim graph: keep only nodes in `_cascade_restrictions` plus alias nodes connecting them; remove all ancestors and unrelated tables
118119

119120
### `restrict(self, table_expr) -> Diagram`
120121

121-
Apply restrict condition and propagate downstream. Returns a new `Diagram`. Chainable — can be called multiple times. Cannot be mixed with `cascade()`.
122+
Select a data subset for export or inspection. Propagate a restriction downstream but preserve the full diagram (ancestors and unrelated tables remain). Returns a new `Diagram`. Chainable — can be called multiple times from different seed tables. Cannot be mixed with `cascade()`.
122123

123124
1. Verify no existing cascade restrictions
124125
2. Copy diagram, seed/extend `_restrict_conditions[root]` with `table_expr.restriction`
@@ -129,10 +130,10 @@ Apply restrict condition and propagate downstream. Returns a new `Diagram`. Chai
129130
Execute cascading delete. Requires `cascade()` first.
130131

131132
1. If `dry_run`: return `preview()` without modifying data
132-
2. Get non-alias nodes with restrictions in topological order
133+
2. Get all non-alias nodes in topological order (graph is already trimmed by `cascade()`)
133134
3. If `prompt`: show preview (table name + row count for each)
134135
4. Start transaction
135-
5. Delete in **reverse** topological order (leaves first) via `_restrict_freetable()` + `delete_quick()`
136+
5. Delete in **reverse** topological order (leaves first) via `_restricted_table()` + `delete_quick()`
136137
6. On `IntegrityError`: cancel transaction, parse FK error for actionable message about unloaded schemas
137138
7. Post-check `part_integrity="enforce"`: if any part table had rows deleted but its master did not, cancel transaction and raise
138139
8. Confirm/commit, return count from the root table
@@ -143,15 +144,15 @@ Drop all tables in `nodes_to_show` in reverse topological order. Pre-checks `par
143144

144145
### `preview(self) -> dict[str, int]`
145146

146-
Return `{full_table_name: row_count}` for each node with a restriction. Requires `cascade()` or `restrict()` first. Uses `_restrict_freetable()` to apply restrictions with correct OR/AND semantics.
147+
Return `{full_table_name: row_count}` for each node with a restriction. Requires `cascade()` or `restrict()` first. Uses `_restricted_table()` to apply restrictions with correct OR/AND semantics.
147148

148149
### `prune(self) -> Diagram`
149150

150151
Remove tables with zero matching rows. With restrictions, removes nodes where the restricted query yields zero rows. Without restrictions, removes physically empty tables. Idempotent and chainable.
151152

152-
### `_restrict_freetable(ft, restrictions, mode="cascade") -> FreeTable`
153+
### `_restricted_table(self, node) -> FreeTable`
153154

154-
Static helper. Applies restrictions to a `FreeTable` using `restrict()` for proper SQL generation.
155+
Instance method. Creates a `FreeTable` for the given node and applies its accumulated restrictions using `restrict()` for proper SQL generation.
155156

156157
- **cascade mode:** Passes the entire restriction list to `restrict()`, creating an OrList (OR semantics).
157158
- **restrict mode:** Iterates restrictions, calling `restrict()` for each (AND semantics).

0 commit comments

Comments
 (0)