Skip to content

Commit 00a62cb

Browse files
committed
Write entity depth update triggers.
1 parent a14b424 commit 00a62cb

File tree

1 file changed

+221
-0
lines changed

1 file changed

+221
-0
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
-- We can track the maximum dependency depth of any sub-dag rooted at each entity.
2+
-- The depth of any entity is simply the maximum depth of any of its children plus one.
3+
-- This allows us to trivially sort entities into a valid dependency order without needing a complex topological
4+
-- sort at query time.
5+
6+
-- These are all maintained by triggers on the relevant tables.
7+
8+
CREATE TABLE causal_depth (
9+
causal_id INTEGER PRIMARY KEY REFERENCES causals (id) ON DELETE CASCADE,
10+
depth INTEGER NOT NULL
11+
);
12+
13+
CREATE TABLE component_depth (
14+
component_hash_id INTEGER PRIMARY KEY REFERENCES component_hashes (id) ON DELETE CASCADE,
15+
depth INTEGER NOT NULL
16+
);
17+
18+
CREATE TABLE namespace_depth (
19+
namespace_hash_id INTEGER PRIMARY KEY REFERENCES branch_hashes (id) ON DELETE CASCADE,
20+
depth INTEGER NOT NULL
21+
);
22+
WHERE nc.namespace_hash_id = NEW.namespace_hash_id
23+
CREATE TABLE patch_depth (
24+
patch_id INTEGER PRIMARY KEY REFERENCES patches (id) ON DELETE CASCADE,
25+
depth INTEGER NOT NULL
26+
);
27+
28+
29+
-- Triggers
30+
31+
CREATE OR REPLACE FUNCTION update_causal_depth() RETURNS TRIGGER AS $$
32+
DECLARE
33+
max_namespace_depth INTEGER;
34+
max_child_causal_depth INTEGER;
35+
namespace_id INTEGER;
36+
BEGIN
37+
-- If there's already a depth entry for this causal, we're done.
38+
IF EXISTS (SELECT FROM causal_depth WHERE causal_id = NEW.id) THEN
39+
RETURN NEW;
40+
END IF;
41+
-- Find the max depth of the associated namespace
42+
-- Find the max depth of any child causal
43+
-- Set the depth of this causal to the max of those two plus one
44+
SELECT max(nd.depth) INTO max_namespace_depth
45+
FROM namespace_depth nd
46+
WHERE nd.namespace_hash_id = NEW.namespace_hash_id;
47+
SELECT max(cd.depth) INTO max_child_causal_depth
48+
FROM causal_depth cd
49+
JOIN causal_ancestors ca ON cd.causal_id = ca.ancestor_id
50+
WHERE ca.causal_id = NEW.id;
51+
INSERT INTO causal_depth (causal_id, depth)
52+
VALUES (NEW.id, GREATEST(max_namespace_depth, max_child_causal_depth) + 1)
53+
ON CONFLICT (causal_id) DO NOTHING;
54+
RETURN NEW;
55+
END;
56+
$$ LANGUAGE plpgsql;
57+
58+
CREATE TRIGGER causals_update_causal_depth_trig AFTER INSERT OR UPDATE ON causals
59+
FOR EACH ROW EXECUTE FUNCTION update_causal_depth();
60+
61+
62+
CREATE OR REPLACE FUNCTION update_component_depth() RETURNS TRIGGER AS $$
63+
DECLARE
64+
max_referenced_component_depth INTEGER;
65+
BEGIN
66+
-- If there's already a depth entry for this component, we're done.
67+
IF EXISTS (SELECT FROM component_depth WHERE component_hash_id = NEW.component_hash_id) THEN
68+
RETURN NEW;
69+
END IF;
70+
-- Find the max depth of any component referenced by this component
71+
-- Set the depth of this component to that plus one
72+
SELECT max(refs.depth) INTO max_referenced_component_depth
73+
FROM (
74+
( SELECT cd.depth AS depth
75+
FROM component_depth cd
76+
JOIN term_local_component_references cr
77+
ON cd.component_hash_id = cr.component_hash_id
78+
WHERE cr.component_hash_id = NEW.component_hash_id
79+
) UNION
80+
( SELECT cd.depth AS depth
81+
FROM component_depth cd
82+
JOIN type_local_component_references cr
83+
ON cd.component_hash_id = cr.component_hash_id
84+
WHERE cr.component_hash_id = NEW.component_hash_id
85+
)
86+
) AS refs;
87+
END;
88+
$$ LANGUAGE plpgsql;
89+
90+
CREATE TRIGGER component_hashes_update_component_depth_trig AFTER INSERT OR UPDATE ON component_hashes
91+
FOR EACH ROW EXECUTE FUNCTION update_component_depth();
92+
93+
CREATE OR REPLACE FUNCTION update_namespace_depth() RETURNS TRIGGER AS $$
94+
DECLARE
95+
max_child_causal_depth INTEGER;
96+
max_patch_depth INTEGER;
97+
max_referenced_component_depth INTEGER;
98+
BEGIN
99+
-- If there's already a depth entry for this namespace, we're done.
100+
IF EXISTS (SELECT FROM namespace_depth nd WHERE nd.namespace_hash_id = NEW.namespace_hash_id) THEN
101+
RETURN NEW;
102+
END IF;
103+
-- Find the max depth of any child causal
104+
-- Find the max depth of any patch
105+
-- Find the max depth of any component referenced by a term, type, or term metadata in this namespace
106+
-- Set the depth of this namespace to the max of those plus one
107+
SELECT max(cd.depth) INTO max_child_causal_depth
108+
FROM causal_depth cd
109+
JOIN namespace_children nc ON cd.causal_id = nc.child_causal_id
110+
WHERE nc.parent_namespace_hash_id = NEW.namespace_hash_id;
111+
SELECT max(pd.depth) INTO max_patch_depth
112+
FROM patch_depth pd
113+
JOIN namespace_patches np ON pd.patch_id = np.patch_id
114+
WHERE np.namespace_hash_id = NEW.namespace_hash_id;
115+
SELECT max(depth) INTO max_referenced_component_depth
116+
FROM (
117+
-- direct term references
118+
( SELECT cd.depth AS depth
119+
FROM component_depth cd
120+
JOIN term_local_component_references cr
121+
ON cd.component_hash_id = cr.component_hash_id
122+
JOIN terms t
123+
ON cr.term_id = t.id
124+
JOIN namespace_terms nt
125+
ON t.id = nt.term_id
126+
WHERE nt.namespace_hash_id = NEW.namespace_hash_id
127+
) UNION
128+
-- term metadata references
129+
( SELECT cd.depth AS depth
130+
FROM component_depth cd
131+
JOIN terms t
132+
ON cd.component_hash_id = t.component_hash_id
133+
JOIN namespace_term_metadata ntm
134+
ON ntm.metadata_term_id = t.id
135+
JOIN namespace_terms nt
136+
ON ntm.named_term = nt.id
137+
WHERE nt.namespace_hash_id = NEW.namespace_hash_id
138+
) UNION
139+
-- direct constructor references
140+
( SELECT cd.depth AS depth
141+
FROM component_depth cd
142+
JOIN constructors c
143+
ON cd.component_hash_id = c.constructor_type_component_hash_id
144+
JOIN namespace_terms nt
145+
ON c.id = nt.constructor_id
146+
WHERE nt.namespace_hash_id = NEW.namespace_hash_id
147+
) UNION
148+
-- direct type references
149+
( SELECT cd.depth AS depth
150+
FROM component_depth cd
151+
JOIN type_local_component_references cr
152+
ON cd.component_hash_id = cr.component_hash_id
153+
JOIN types t
154+
ON cr.type_id = t.id
155+
JOIN namespace_types nt
156+
ON t.id = nt.type_id
157+
WHERE nt.namespace_hash_id = NEW.namespace_hash_id
158+
) UNION
159+
-- type metadata references
160+
( SELECT cd.depth AS depth
161+
FROM component_depth cd
162+
JOIN terms t
163+
ON cd.component_hash_id = t.component_hash_id
164+
JOIN namespace_type_metadata ntm
165+
ON ntm.metadata_term_id = t.id
166+
JOIN namespace_types nt
167+
ON ntm.named_type = nt.id
168+
WHERE nt.namespace_hash_id = NEW.namespace_hash_id
169+
)
170+
) AS refs;
171+
INSERT INTO namespace_depth (namespace_hash_id, depth)
172+
VALUES (NEW.namespace_hash_id, GREATEST(max_child_causal_depth, max_patch_depth, max_referenced_component_depth) + 1)
173+
ON CONFLICT (namespace_hash_id) DO NOTHING;
174+
RETURN NEW;
175+
END;
176+
$$ LANGUAGE plpgsql;
177+
178+
CREATE TRIGGER namespaces_update_namespace_depth_trig AFTER INSERT OR UPDATE ON namespaces
179+
FOR EACH ROW EXECUTE FUNCTION update_namespace_depth();
180+
181+
182+
CREATE OR REPLACE FUNCTION update_patch_depth() RETURNS TRIGGER AS $$
183+
DECLARE
184+
max_referenced_component_depth INTEGER;
185+
BEGIN
186+
-- If there's already a depth entry for this patch, we're done.
187+
IF EXISTS (SELECT FROM patch_depth WHERE patch_id = NEW.id) THEN
188+
RETURN NEW;
189+
END IF;
190+
-- Find the max depth of any term component referenced by a patch
191+
-- Find the max depth of any type component referenced by a patch
192+
-- Set the depth of this patch to that plus one
193+
194+
SELECT max(cd.depth) INTO max_referenced_component_depth
195+
FROM (
196+
-- term references
197+
( SELECT from_term_component_hash_id AS component_hash_id
198+
FROM patch_term_mappings
199+
WHERE patch_id = NEW.id
200+
) UNION
201+
-- constructor mappings
202+
( SELECT from_constructor_component_hash_id AS component_hash_id
203+
FROM patch_constructor_mappings
204+
WHERE patch_id = NEW.id
205+
) UNION
206+
-- type references
207+
( SELECT from_type_component_hash_id AS component_hash_id
208+
FROM patch_type_mappings
209+
WHERE patch_id = NEW.id
210+
)
211+
) AS refs JOIN component_depth cd
212+
ON cd.component_hash_id = refs.component_hash_id;
213+
INSERT INTO patch_depth (patch_id, depth)
214+
VALUES (NEW.id, max_referenced_component_depth + 1)
215+
ON CONFLICT (patch_id) DO NOTHING;
216+
RETURN NEW;
217+
END;
218+
$$ LANGUAGE plpgsql;
219+
220+
CREATE TRIGGER patches_update_patch_depth_trig AFTER INSERT OR UPDATE ON patches
221+
FOR EACH ROW EXECUTE FUNCTION update_patch_depth();

0 commit comments

Comments
 (0)