@@ -18,6 +18,180 @@ import Unison.SyncV2.Types (CBORBytes)
1818
1919allSerializedDependenciesOfCausalCursor :: CausalId -> Set CausalHash -> CodebaseM e (PGCursor (CBORBytes TempEntity , Hash32 ))
2020allSerializedDependenciesOfCausalCursor 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