|
53 | 53 | FROM "workflow_folder" l |
54 | 54 | WHERE NOT EXISTS (SELECT 1 FROM "folder" f WHERE f.id = l.id) |
55 | 55 | ), |
56 | | - -- A parent is only usable if it will exist AND shares this row's workspace — the |
57 | | - -- `folder_parent_resource_type_match` trigger enforces the workspace match, and the legacy |
58 | | - -- self-FK never did, so a cross-workspace parent is representable in the source data. |
| 56 | + -- A parent is only usable if it will exist, shares this row's workspace, and leaves the row |
| 57 | + -- REACHABLE. The workspace match is enforced by the `folder_parent_resource_type_match` |
| 58 | + -- trigger and was never enforced by the legacy self-FK, so a cross-workspace parent is |
| 59 | + -- representable in the source data. Reachability is the subtler half: filing an ACTIVE |
| 60 | + -- folder under a soft-deleted parent hides it in Recently Deleted just as thoroughly as a |
| 61 | + -- dangling parent would, so it re-roots too — matching `resolveRestoredFolderId`, which |
| 62 | + -- re-roots a restored folder whose original parent is archived. |
| 63 | + -- |
| 64 | + -- A soft-deleted row is exempt: it MAY keep a soft-deleted parent, because that is the |
| 65 | + -- normal shape of an archived subtree and flattening it would destroy the hierarchy a |
| 66 | + -- later restore rebuilds. |
| 67 | + -- |
59 | 68 | -- Anything else re-roots to the workspace root: losing one level of nesting beats losing the |
60 | 69 | -- folder and stranding every workflow inside it. |
61 | 70 | resolved AS ( |
|
65 | 74 | WHEN EXISTS ( |
66 | 75 | SELECT 1 FROM "folder" f |
67 | 76 | WHERE f.id = s.parent_id AND f.resource_type = 'workflow' AND f.workspace_id = s.workspace_id |
| 77 | + AND (s.deleted_at IS NOT NULL OR f.deleted_at IS NULL) |
68 | 78 | ) THEN s.parent_id |
69 | 79 | WHEN EXISTS ( |
70 | | - SELECT 1 FROM stranded s2 WHERE s2.id = s.parent_id AND s2.workspace_id = s.workspace_id |
| 80 | + SELECT 1 FROM stranded s2 |
| 81 | + WHERE s2.id = s.parent_id AND s2.workspace_id = s.workspace_id |
| 82 | + AND (s.deleted_at IS NOT NULL OR s2.deleted_at IS NULL) |
71 | 83 | ) THEN s.parent_id |
72 | 84 | ELSE NULL |
73 | 85 | END AS resolved_parent |
@@ -152,16 +164,20 @@ BEGIN |
152 | 164 | FROM "workspace_file_folders" l |
153 | 165 | WHERE NOT EXISTS (SELECT 1 FROM "folder" f WHERE f.id = l.id) |
154 | 166 | ), |
| 167 | + -- Same reachability rule as the workflow tree above. |
155 | 168 | resolved AS ( |
156 | 169 | SELECT s.*, |
157 | 170 | CASE |
158 | 171 | WHEN s.parent_id IS NULL THEN NULL |
159 | 172 | WHEN EXISTS ( |
160 | 173 | SELECT 1 FROM "folder" f |
161 | 174 | WHERE f.id = s.parent_id AND f.resource_type = 'file' AND f.workspace_id = s.workspace_id |
| 175 | + AND (s.deleted_at IS NOT NULL OR f.deleted_at IS NULL) |
162 | 176 | ) THEN s.parent_id |
163 | 177 | WHEN EXISTS ( |
164 | | - SELECT 1 FROM stranded s2 WHERE s2.id = s.parent_id AND s2.workspace_id = s.workspace_id |
| 178 | + SELECT 1 FROM stranded s2 |
| 179 | + WHERE s2.id = s.parent_id AND s2.workspace_id = s.workspace_id |
| 180 | + AND (s.deleted_at IS NOT NULL OR s2.deleted_at IS NULL) |
165 | 181 | ) THEN s.parent_id |
166 | 182 | ELSE NULL |
167 | 183 | END AS resolved_parent |
|
0 commit comments