Skip to content

Commit f0183c7

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

1 file changed

Lines changed: 174 additions & 0 deletions

File tree

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

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

0 commit comments

Comments
 (0)