Skip to content

Commit f54ecc2

Browse files
committed
Shallow causal exceptions
1 parent 012b5cb commit f54ecc2

1 file changed

Lines changed: 175 additions & 0 deletions

File tree

src/Share/Web/UCM/SyncV2/Queries.hs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,181 @@ import Unison.SyncV2.Types (CBORBytes)
1818

1919
allSerializedDependenciesOfCausalCursor :: CausalId -> Set CausalHash -> CodebaseM e (PGCursor (CBORBytes TempEntity, Hash32))
2020
allSerializedDependenciesOfCausalCursor cid exceptCausalHashes = do
21+
ownerUserId <- asks codebaseOwner
22+
-- Create a temp table for storing the dependencies we know the calling client already has.
23+
execute_ [sql| CREATE TEMP TABLE except_causals (causal_id INTEGER PRIMARY KEY ) ON COMMIT DROP |]
24+
execute_
25+
[sql|
26+
WITH the_causal_hashes(hash) AS (
27+
SELECT * FROM ^{singleColumnTable (toList exceptCausalHashes)}
28+
), known_causal_ids(causal_id) AS (
29+
) INSERT INTO except_causals(causal_id)
30+
SELECT DISTINCT c.id
31+
FROM the_causal_hashes tch
32+
JOIN causals c ON tch.hash = c.hash
33+
ON CONFLICT DO NOTHING
34+
|]
35+
cursor <-
36+
PGCursor.newRowCursor @(CBORBytes TempEntity, Hash32, Maybe Int32)
37+
"serialized_entities"
38+
[sql|
39+
WITH RECURSIVE transitive_causals(causal_id, causal_hash, causal_namespace_hash_id) AS (
40+
SELECT causal.id, causal.hash, causal.namespace_hash_id
41+
FROM causals causal
42+
WHERE causal.id = #{cid}
43+
AND EXISTS (SELECT FROM causal_ownership co WHERE co.user_id = #{ownerUserId} AND co.causal_id = causal.id)
44+
AND NOT EXISTS (SELECT FROM except_causals ec WHERE ec.causal_id = causal.id)
45+
UNION
46+
-- This nested CTE is required because RECURSIVE CTEs can't refer
47+
-- to the recursive table more than once.
48+
( WITH rec AS (
49+
SELECT tc.causal_id, tc.causal_namespace_hash_id
50+
FROM transitive_causals tc
51+
)
52+
SELECT ancestor_causal.id, ancestor_causal.hash, ancestor_causal.namespace_hash_id
53+
FROM causal_ancestors ca
54+
JOIN rec tc ON ca.causal_id = tc.causal_id
55+
JOIN causals ancestor_causal ON ca.ancestor_id = ancestor_causal.id
56+
WHERE NOT EXISTS (SELECT FROM except_causals ec WHERE ec.causal_id = ancestor_causal.id)
57+
UNION
58+
SELECT child_causal.id, child_causal.hash, child_causal.namespace_hash_id
59+
FROM rec tc
60+
JOIN namespace_children nc ON tc.causal_namespace_hash_id = nc.parent_namespace_hash_id
61+
JOIN causals child_causal ON nc.child_causal_id = child_causal.id
62+
WHERE NOT EXISTS (SELECT FROM except_causals ec WHERE ec.causal_id = child_causal.id)
63+
)
64+
), all_namespaces(namespace_hash_id, namespace_hash) AS (
65+
SELECT DISTINCT tc.causal_namespace_hash_id AS namespace_hash_id, bh.base32 as namespace_hash
66+
FROM transitive_causals tc
67+
JOIN branch_hashes bh ON tc.causal_namespace_hash_id = bh.id
68+
), all_patches(patch_id, patch_hash) AS (
69+
SELECT DISTINCT patch.id, patch.hash
70+
FROM all_namespaces an
71+
JOIN namespace_patches np ON an.namespace_hash_id = np.namespace_hash_id
72+
JOIN patches patch ON np.patch_id = patch.id
73+
),
74+
-- term components to start transitively joining dependencies to
75+
base_term_components(component_hash_id) AS (
76+
SELECT DISTINCT term.component_hash_id
77+
FROM all_namespaces an
78+
JOIN namespace_terms nt ON an.namespace_hash_id = nt.namespace_hash_id
79+
JOIN terms term ON nt.term_id = term.id
80+
UNION
81+
SELECT DISTINCT term.component_hash_id
82+
FROM all_patches ap
83+
JOIN patch_term_mappings ptm ON ap.patch_id = ptm.patch_id
84+
JOIN terms term ON ptm.to_term_id = term.id
85+
UNION
86+
-- term metadata
87+
SELECT DISTINCT term.component_hash_id
88+
FROM all_namespaces an
89+
JOIN namespace_terms nt ON an.namespace_hash_id = nt.namespace_hash_id
90+
JOIN namespace_term_metadata meta ON nt.id = meta.named_term
91+
JOIN terms term ON meta.metadata_term_id = term.id
92+
UNION
93+
-- type metadata
94+
SELECT DISTINCT term.component_hash_id
95+
FROM all_namespaces an
96+
JOIN namespace_types nt ON an.namespace_hash_id = nt.namespace_hash_id
97+
JOIN namespace_type_metadata meta ON nt.id = meta.named_type
98+
JOIN terms term ON meta.metadata_term_id = term.id
99+
),
100+
-- type components to start transitively joining dependencies to
101+
base_type_components(component_hash_id) AS (
102+
SELECT DISTINCT typ.component_hash_id
103+
FROM all_namespaces an
104+
JOIN namespace_types nt ON an.namespace_hash_id = nt.namespace_hash_id
105+
JOIN types typ ON nt.type_id = typ.id
106+
UNION
107+
SELECT DISTINCT typ.component_hash_id
108+
FROM all_namespaces an
109+
JOIN namespace_terms nt ON an.namespace_hash_id = nt.namespace_hash_id
110+
JOIN constructors con ON nt.constructor_id = con.id
111+
JOIN types typ ON con.type_id = typ.id
112+
UNION
113+
SELECT DISTINCT typ.component_hash_id
114+
FROM all_patches ap
115+
JOIN patch_type_mappings ptm ON ap.patch_id = ptm.patch_id
116+
JOIN types typ ON ptm.to_type_id = typ.id
117+
UNION
118+
SELECT DISTINCT typ.component_hash_id
119+
FROM all_patches ap
120+
JOIN patch_constructor_mappings pcm ON ap.patch_id = pcm.patch_id
121+
JOIN constructors con ON pcm.to_constructor_id = con.id
122+
JOIN types typ ON con.type_id = typ.id
123+
),
124+
-- All the dependencies we join in transitively from the known term & type components we depend on.
125+
-- Unfortunately it's not possible to know which hashes are terms vs types :'(
126+
transitive_components(component_hash_id) AS (
127+
SELECT DISTINCT btc.component_hash_id
128+
FROM base_term_components btc
129+
UNION
130+
SELECT DISTINCT btc.component_hash_id
131+
FROM base_type_components btc
132+
UNION
133+
( WITH rec AS (
134+
SELECT component_hash_id
135+
FROM transitive_components tc
136+
)
137+
-- recursively union in term dependencies
138+
SELECT DISTINCT ref.component_hash_id
139+
FROM rec atc
140+
-- This joins in ALL the terms from the component, not just the one that caused the dependency on the
141+
-- component
142+
JOIN terms term ON atc.component_hash_id = term.component_hash_id
143+
JOIN term_local_component_references ref ON term.id = ref.term_id
144+
UNION
145+
-- recursively union in type dependencies
146+
SELECT DISTINCT ref.component_hash_id
147+
FROM rec atc
148+
-- This joins in ALL the types from the component, not just the one that caused the dependency on the
149+
-- component
150+
JOIN types typ ON atc.component_hash_id = typ.component_hash_id
151+
JOIN type_local_component_references ref ON typ.id = ref.type_id
152+
)
153+
)
154+
(SELECT bytes.bytes, ch.base32, cd.depth
155+
FROM transitive_components tc
156+
JOIN serialized_components sc ON sc.user_id = #{ownerUserId} AND tc.component_hash_id = sc.component_hash_id
157+
JOIN bytes ON sc.bytes_id = bytes.id
158+
JOIN component_hashes ch ON tc.component_hash_id = ch.id
159+
LEFT JOIN component_depth cd ON ch.id = cd.component_hash_id
160+
)
161+
UNION ALL
162+
(SELECT bytes.bytes, ap.patch_hash, pd.depth
163+
FROM all_patches ap
164+
JOIN serialized_patches sp ON ap.patch_id = sp.patch_id
165+
JOIN bytes ON sp.bytes_id = bytes.id
166+
LEFT JOIN patch_depth pd ON ap.patch_id = pd.patch_id
167+
)
168+
UNION ALL
169+
(SELECT bytes.bytes, an.namespace_hash, nd.depth
170+
FROM all_namespaces an
171+
JOIN serialized_namespaces sn ON an.namespace_hash_id = sn.namespace_hash_id
172+
JOIN bytes ON sn.bytes_id = bytes.id
173+
LEFT JOIN namespace_depth nd ON an.namespace_hash_id = nd.namespace_hash_id
174+
)
175+
UNION ALL
176+
(SELECT bytes.bytes, tc.causal_hash, cd.depth
177+
FROM transitive_causals tc
178+
JOIN serialized_causals sc ON tc.causal_id = sc.causal_id
179+
JOIN bytes ON sc.bytes_id = bytes.id
180+
LEFT JOIN causal_depth cd ON tc.causal_id = cd.causal_id
181+
)
182+
-- Put them in dependency order, nulls come first because we want to bail and
183+
-- report an error if we are somehow missing a depth.
184+
ORDER BY depth ASC NULLS FIRST
185+
|]
186+
pure
187+
( cursor <&> \(bytes, hash, depth) -> case depth of
188+
-- This should never happen, but is a sanity check in case we're missing a depth.
189+
-- Better than silently omitting a required result.
190+
Nothing -> error $ "allSerializedDependenciesOfCausalCursor: Missing depth for entity: " <> show hash
191+
Just _ -> (bytes, hash)
192+
)
193+
194+
_allSerializedDependenciesOfCausalCursorOld :: CausalId -> Set CausalHash -> CodebaseM e (PGCursor (CBORBytes TempEntity, Hash32))
195+
_allSerializedDependenciesOfCausalCursorOld cid exceptCausalHashes = do
21196
ownerUserId <- asks codebaseOwner
22197
-- Create a temp table for storing the dependencies we know the calling client already has.
23198
execute_ [sql| CREATE TEMP TABLE except_causals (causal_id INTEGER PRIMARY KEY ) ON COMMIT DROP |]

0 commit comments

Comments
 (0)