-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtriggers.py
334 lines (290 loc) · 9.97 KB
/
triggers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
import inspect
import models
from alembic_utils.pg_function import PGFunction
from alembic_utils.pg_trigger import PGTrigger
# All hame tables
hame_tables = [
klass.__tablename__
for _, klass in inspect.getmembers(models, inspect.isclass)
if inspect.getmodule(klass) == models # Ignore imported classes
]
# All tables that inherit PlanBase
tables_with_lifecycle_date = [
klass.__tablename__
for _, klass in inspect.getmembers(models, inspect.isclass)
if inspect.getmodule(klass) == models and issubclass(klass, models.PlanBase)
]
# Regulations and propositions link to plan via plan regulation group
# or via plan regulation group *and* plan object, so lifecycle state
# will have to be updated in a slightly more convoluted fashion.
plan_regulation_tables = ["plan_regulation", "plan_proposition"]
# All plan objects also have lifecycle status and link directly to plan
plan_object_tables = [
klass.__tablename__
for _, klass in inspect.getmembers(models, inspect.isclass)
if inspect.getmodule(klass) == models and issubclass(klass, models.PlanObjectBase)
]
def generate_modified_at_triggers():
trgfunc_signature = "trgfunc_modified_at()"
trgfunc_definition = """
RETURNS TRIGGER AS $$
BEGIN
NEW.modified_at = CURRENT_TIMESTAMP;
return NEW;
END;
$$ language 'plpgsql'
"""
trgfunc = PGFunction(
schema="hame",
signature=trgfunc_signature,
definition=trgfunc_definition,
)
trgs = []
for table in hame_tables:
trg_signature = f"trg_{table}_modified_at"
trg_definition = f"""
BEFORE INSERT OR UPDATE ON {table}
FOR EACH ROW
EXECUTE FUNCTION hame.{trgfunc_signature}
"""
trg = PGTrigger(
schema="hame",
signature=trg_signature,
on_entity=f"hame.{table}",
is_constraint=False,
definition=trg_definition,
)
trgs.append(trg)
return trgs, [trgfunc]
def generate_new_lifecycle_date_triggers():
trgs = []
trgfuncs = []
for table in tables_with_lifecycle_date:
trgfunc_signature = f"trgfunc_{table}_new_lifecycle_date()"
trgfunc_definition = f"""
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO hame.lifecycle_date
(lifecycle_status_id, {table}_id, starting_at)
VALUES
(NEW.lifecycle_status_id, NEW.id, CURRENT_TIMESTAMP);
UPDATE hame.lifecycle_date
SET ending_at=CURRENT_TIMESTAMP
WHERE {table}_id=NEW.id
AND ending_at IS NULL
AND lifecycle_status_id=OLD.lifecycle_status_id;
RETURN NEW;
END;
$$ language 'plpgsql'
"""
trg_signature = f"trg_{table}_new_lifecycle_date"
trg_definition = f"""
BEFORE UPDATE ON {table}
FOR EACH ROW
WHEN (NEW.lifecycle_status_id <> OLD.lifecycle_status_id)
EXECUTE FUNCTION hame.{trgfunc_signature}
"""
trgfunc = PGFunction(
schema="hame",
signature=trgfunc_signature,
definition=trgfunc_definition,
)
trgfuncs.append(trgfunc)
trg = PGTrigger(
schema="hame",
signature=trg_signature,
on_entity=f"hame.{table}",
is_constraint=False,
definition=trg_definition,
)
trgs.append(trg)
return trgs, trgfuncs
def generate_update_lifecycle_status_triggers():
trgs = []
trgfuncs = []
for object_table in plan_object_tables:
trgfunc_signature = f"trgfunc_{object_table}_update_lifecycle_status()"
trgfunc_definition = f"""
RETURNS TRIGGER AS $$
BEGIN
UPDATE hame.{object_table}
SET lifecycle_status_id = NEW.lifecycle_status_id
WHERE (plan_id = NEW.id
AND lifecycle_status_id = OLD.lifecycle_status_id);
RETURN NEW;
END;
$$ language 'plpgsql'
"""
trg_signature = f"trg_{object_table}_update_lifecycle_status"
trg_definition = f"""
BEFORE UPDATE ON plan
FOR EACH ROW
WHEN (NEW.lifecycle_status_id <> OLD.lifecycle_status_id)
EXECUTE FUNCTION hame.{trgfunc_signature}
"""
trgfunc = PGFunction(
schema="hame", signature=trgfunc_signature, definition=trgfunc_definition
)
trgfuncs.append(trgfunc)
trg = PGTrigger(
schema="hame",
signature=trg_signature,
on_entity="hame.plan",
is_constraint=False,
definition=trg_definition,
)
trgs.append(trg)
# Update lifecycle status of regulations after a lifecycle status change of a plan
for regulation_table in plan_regulation_tables:
trgfunc_signature = f"trgfunc_plan_{regulation_table}_update_lifecycle_status()"
trgfunc_definition = f"""
RETURNS TRIGGER AS $$
BEGIN
UPDATE hame.{regulation_table} rt
SET lifecycle_status_id = NEW.lifecycle_status_id
WHERE
EXISTS (
SELECT 1
FROM hame.plan_regulation_group prg
WHERE
prg.id = rt.plan_regulation_group_id
AND prg.plan_id = NEW.id
)
AND lifecycle_status_id = OLD.lifecycle_status_id
;
RETURN NEW;
END;
$$ language 'plpgsql'
"""
trg_signature = f"trg_plan_{regulation_table}_update_lifecycle_status"
trg_definition = f"""
BEFORE UPDATE ON hame.plan
FOR EACH ROW
WHEN (NEW.lifecycle_status_id <> OLD.lifecycle_status_id)
EXECUTE FUNCTION hame.{trgfunc_signature}
"""
trgfunc = PGFunction(
schema="hame",
signature=trgfunc_signature,
definition=trgfunc_definition,
)
trgfuncs.append(trgfunc)
trg = PGTrigger(
schema="hame",
signature=trg_signature,
on_entity="hame.plan",
is_constraint=False,
definition=trg_definition,
)
trgs.append(trg)
return trgs, trgfuncs
def generate_new_lifecycle_status_triggers():
trgs = []
trgfuncs = []
for object_table in plan_object_tables:
trgfunc_signature = f"trgfunc_{object_table}_new_lifecycle_status()"
trgfunc_definition = """
RETURNS TRIGGER AS $$
BEGIN
NEW.lifecycle_status_id = (
SELECT lifecycle_status_id FROM hame.plan WHERE plan.id = NEW.plan_id
);
RETURN NEW;
END;
$$ language 'plpgsql'
"""
trg_signature = f"trg_{object_table}_new_lifecycle_status"
trg_definition = f"""
BEFORE INSERT ON {object_table}
FOR EACH ROW
WHEN (NEW.plan_id IS NOT NULL)
EXECUTE FUNCTION hame.{trgfunc_signature}
"""
trgfunc = PGFunction(
schema="hame", signature=trgfunc_signature, definition=trgfunc_definition
)
trgfuncs.append(trgfunc)
trg = PGTrigger(
schema="hame",
signature=trg_signature,
on_entity=f"hame.{object_table}",
is_constraint=False,
definition=trg_definition,
)
trgs.append(trg)
# Set the life cycle status of the new regulation to the same as the plan
for regulation_table in plan_regulation_tables:
trgfunc_signature = f"trgfunc_{regulation_table}_plan_new_lifecycle_status()"
trgfunc_definition = """
RETURNS TRIGGER AS $$
BEGIN
NEW.lifecycle_status_id = (
SELECT p.lifecycle_status_id
FROM
hame.plan p
JOIN hame.plan_regulation_group prg
ON p.id = prg.plan_id
WHERE prg.id = NEW.plan_regulation_group_id
);
RETURN NEW;
END;
$$ language 'plpgsql'
"""
trg_signature = f"trg_{regulation_table}_plan_new_lifecycle_status"
trg_definition = f"""
BEFORE INSERT ON hame.{regulation_table}
FOR EACH ROW
EXECUTE FUNCTION hame.{trgfunc_signature}
"""
trgfunc = PGFunction(
schema="hame", signature=trgfunc_signature, definition=trgfunc_definition
)
trgfuncs.append(trgfunc)
trg = PGTrigger(
schema="hame",
signature=trg_signature,
on_entity=f"hame.{regulation_table}",
is_constraint=False,
definition=trg_definition,
)
trgs.append(trg)
return trgs, trgfuncs
def generate_add_plan_id_fkey_triggers():
trgfunc_signature = "trgfunc_add_plan_id_fkey()"
trgfunc_definition = """
RETURNS TRIGGER AS $$
BEGIN
-- Get the most recent plan whose geometry contains the plan object
IF NEW.plan_id IS NULL THEN
NEW.plan_id := (
SELECT id
FROM hame.plan
WHERE ST_Contains(geom, NEW.geom)
ORDER BY created_at DESC
LIMIT 1
);
END IF;
RETURN NEW;
END;
$$ language 'plpgsql'
"""
trgfunc = PGFunction(
schema="hame", signature=trgfunc_signature, definition=trgfunc_definition
)
trgs = []
for table in plan_object_tables:
trg_signature = f"trg_{table}_add_plan_id_fkey"
trg_definition = f"""
BEFORE INSERT ON {table}
FOR EACH ROW
EXECUTE FUNCTION hame.{trgfunc_signature}
"""
trg = PGTrigger(
schema="hame",
signature=trg_signature,
on_entity=f"hame.{table}",
is_constraint=False,
definition=trg_definition,
)
trgs.append(trg)
return trgs, [trgfunc]