@@ -18,6 +18,181 @@ 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+ ), 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