-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy path003_rebuild_listed_status.sql
More file actions
368 lines (351 loc) · 14.3 KB
/
003_rebuild_listed_status.sql
File metadata and controls
368 lines (351 loc) · 14.3 KB
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
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
CREATE OR REPLACE FUNCTION rebuild_listing_status_for_designation_and_node(
designation designations, node_id integer
) RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
deletion_id int;
addition_id int;
exception_id int;
designation_name TEXT;
status_flag varchar;
status_original_flag varchar;
listing_original_flag varchar;
listing_flag varchar;
listing_updated_at_flag varchar;
not_listed_flag varchar;
show_flag varchar;
level_of_listing_flag varchar;
flags_to_reset text[];
sql TEXT;
tmp_current_listing_changes_mview TEXT;
BEGIN
SELECT id INTO deletion_id FROM change_types
WHERE designation_id = designation.id AND name = 'DELETION';
SELECT id INTO addition_id FROM change_types
WHERE designation_id = designation.id AND name = 'ADDITION';
SELECT id INTO exception_id FROM change_types
WHERE designation_id = designation.id AND name = 'EXCEPTION';
designation_name = LOWER(designation.name);
status_flag = designation_name || '_status';
status_original_flag = designation_name || '_status_original';
listing_original_flag := designation_name || '_listing_original';
listing_flag := designation_name || '_listing';
listing_updated_at_flag = designation_name || '_updated_at';
level_of_listing_flag := designation_name || '_level_of_listing';
not_listed_flag := designation_name || '_not_listed';
show_flag := designation_name || '_show';
flags_to_reset := ARRAY[
status_flag, status_original_flag, listing_flag, listing_original_flag,
not_listed_flag, listing_updated_at_flag, level_of_listing_flag,
show_flag
];
IF designation.name = 'CITES' THEN
flags_to_reset := flags_to_reset ||
ARRAY['cites_I','cites_II','cites_III'];
ELSIF designation.name = 'EU' THEN
flags_to_reset := flags_to_reset ||
ARRAY['eu_A','eu_B','eu_C','eu_D'];
ELSIF designation.name = 'CMS' THEN
flags_to_reset := flags_to_reset ||
ARRAY['cms_I','cms_II'];
END IF;
-- reset the listing status (so we start clear)
UPDATE taxon_concepts
SET listing = (COALESCE(listing, ''::HSTORE) - flags_to_reset)
WHERE taxonomy_id = designation.taxonomy_id AND
CASE WHEN node_id IS NOT NULL THEN id = node_id ELSE TRUE END;
-- set status property to 'LISTED' for all explicitly listed taxa
-- i.e. ones which have at least one current ADDITION
-- that is not an inclusion
-- also set status_original & level_of_listing flags to true
-- also set the listing_updated_at property
WITH listed_taxa AS (
SELECT taxon_concepts.id, MAX(effective_at) AS listing_updated_at
FROM taxon_concepts
INNER JOIN listing_changes
ON taxon_concepts.id = listing_changes.taxon_concept_id
AND is_current = 't'
AND change_type_id = addition_id
WHERE taxonomy_id = designation.taxonomy_id
AND inclusion_taxon_concept_id IS NULL
GROUP BY taxon_concepts.id
)
UPDATE taxon_concepts
SET listing = listing || hstore(status_flag, 'LISTED') ||
hstore(status_original_flag, 't') ||
hstore(level_of_listing_flag, 't') ||
hstore(listing_updated_at_flag, listing_updated_at::VARCHAR)
FROM listed_taxa
WHERE taxon_concepts.id = listed_taxa.id AND
CASE WHEN node_id IS NOT NULL THEN taxon_concepts.id = node_id ELSE TRUE END;
-- set status property to 'EXCLUDED' for all explicitly excluded taxa
-- omit ones already marked as listed
-- also set status_original flag to true
-- note: this was moved before setting the "deleted" status,
-- because some taxa were deleted but still need to show up
-- in the checklist, and so they get the "excluded" status
-- to differentiate them
WITH excluded_taxa AS (
WITH listing_exceptions AS (
SELECT listing_changes.parent_id, taxon_concept_id
FROM listing_changes
INNER JOIN taxon_concepts
ON listing_changes.taxon_concept_id = taxon_concepts.id
AND taxonomy_id = designation.taxonomy_id
AND (
listing -> status_flag <> 'LISTED'
OR (listing -> status_flag)::VARCHAR IS NULL
)
WHERE change_type_id = exception_id
)
SELECT DISTINCT listing_exceptions.taxon_concept_id AS id
FROM listing_exceptions
INNER JOIN listing_changes
ON listing_changes.id = listing_exceptions.parent_id
AND listing_changes.taxon_concept_id <> listing_exceptions.taxon_concept_id
AND listing_changes.change_type_id = addition_id
AND listing_changes.is_current = TRUE
)
UPDATE taxon_concepts
SET listing = listing || hstore(status_flag, 'EXCLUDED') ||
hstore(status_original_flag, 't')
FROM excluded_taxa
WHERE taxon_concepts.id = excluded_taxa.id AND
CASE WHEN node_id IS NOT NULL THEN taxon_concepts.id = node_id ELSE TRUE END;
-- set status property to 'DELETED' for all explicitly deleted taxa
-- omit ones already marked as listed (applies to appendix III deletions)
-- also set status_original flag to true
-- also set a flag if there are listed subspecies of a deleted species
WITH deleted_taxa AS (
SELECT taxon_concepts.id
FROM taxon_concepts
INNER JOIN listing_changes
ON taxon_concepts.id = listing_changes.taxon_concept_id
AND is_current = 't' AND change_type_id = deletion_id
WHERE taxonomy_id = designation.taxonomy_id AND (
listing -> status_flag <> 'LISTED'
AND listing -> status_flag <> 'EXCLUDED'
OR (listing -> status_flag)::VARCHAR IS NULL
)
), not_really_deleted_taxa AS (
-- crazy stuff to do with species that were deleted but have listed subspecies
-- so in fact this is really confusing but what can you do, flag it
SELECT DISTINCT parent_id AS id
FROM taxon_concepts
JOIN deleted_taxa
ON taxon_concepts.parent_id = deleted_taxa.id
JOIN ranks
ON taxon_concepts.rank_id = ranks.id AND ranks.name = 'SUBSPECIES'
WHERE taxon_concepts.listing->status_flag = 'LISTED'
)
UPDATE taxon_concepts
SET listing = listing || hstore(status_flag, 'DELETED') ||
hstore(status_original_flag, 't') ||
hstore(
'not_really_deleted',
CASE WHEN not_really_deleted_taxa.id IS NOT NULL THEN 't'
ELSE 'f' END
)
FROM deleted_taxa
LEFT JOIN not_really_deleted_taxa
ON not_really_deleted_taxa.id = deleted_taxa.id
WHERE taxon_concepts.id = deleted_taxa.id AND
CASE WHEN node_id IS NOT NULL THEN taxon_concepts.id = node_id ELSE TRUE END;
-- propagate cites_status to descendants
SELECT listing_changes_mview_name('tmp_current', designation.name, NULL)
INTO tmp_current_listing_changes_mview;
sql := 'WITH RECURSIVE q AS (
SELECT
h.id,
h.parent_id,
listing->''' || designation_name || '_status'' AS inherited_status,
listing->''' || designation_name || '_updated_at'' AS inherited_listing_updated_at,
listed_geo_entities_ids,
excluded_geo_entities_ids,
excluded_taxon_concept_ids,
HSTORE(''' || designation_name || '_status_original'', ''t'') ||
CASE
WHEN lc.change_type_name = ''DELETION''
THEN HSTORE(''' || designation_name || '_status'', ''DELETED'') ||
HSTORE(''' || designation_name || '_not_listed'', ''NC'')
ELSE HSTORE(''' || designation_name || '_status'', ''LISTED'') ||
HSTORE(''' || designation_name || '_not_listed'', NULL)
END AS status_hstore
FROM taxon_concepts h
JOIN ' || tmp_current_listing_changes_mview || ' lc
ON h.id = lc.taxon_concept_id
AND lc.change_type_name IN (''ADDITION'', ''DELETION'')
AND inclusion_taxon_concept_id IS NULL
GROUP BY
h.id,
listed_geo_entities_ids,
excluded_geo_entities_ids,
excluded_taxon_concept_ids,
lc.change_type_name
UNION
SELECT
hi.id,
hi.parent_id,
inherited_status,
inherited_listing_updated_at,
listed_geo_entities_ids,
excluded_geo_entities_ids,
excluded_taxon_concept_ids,
CASE
WHEN (hi.listing->''' || designation_name || '_status_original'')::BOOLEAN
THEN SLICE(hi.listing, ARRAY[
''' || designation_name || '_status_original'',
''' || designation_name || '_status'',
''' || designation_name || '_level_of_listing'',
''' || designation_name || '_updated_at'',
''' || designation_name || '_not_listed''
])
ELSE
HSTORE(''' || designation_name || '_status_original'', ''f'') ||
HSTORE(''' || designation_name || '_level_of_listing'', ''f'') ||
CASE
WHEN ARRAY_UPPER(excluded_taxon_concept_ids, 1) IS NOT NULL
AND excluded_taxon_concept_ids @> ARRAY[hi.id]
THEN HSTORE(''' || designation_name || '_status'', ''EXCLUDED'') ||
HSTORE(''' || designation_name || '_not_listed'', ''NC'')
WHEN ARRAY_UPPER(excluded_geo_entities_ids, 1) IS NOT NULL
AND EXISTS (
SELECT 1 FROM distributions
WHERE q.excluded_geo_entities_ids @> ARRAY[geo_entity_id]
AND taxon_concept_id = hi.id
)
THEN HSTORE(''' || designation_name || '_status'', ''EXCLUDED'') ||
HSTORE(''' || designation_name || '_not_listed'', ''NC'')
WHEN ARRAY_UPPER(listed_geo_entities_ids, 1) IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM distributions
WHERE q.listed_geo_entities_ids @> ARRAY[geo_entity_id]
AND taxon_concept_id = hi.id
)
THEN HSTORE(''' || designation_name || '_status'', NULL) ||
HSTORE(''' || designation_name || '_not_listed'', ''NC'')
ELSE HSTORE(
''' || designation_name || '_status'',
q.status_hstore->''' || designation_name || '_status''
) || HSTORE(
''' || designation_name || '_not_listed'',
q.status_hstore->''' || designation_name || '_not_listed''
)
END
END
FROM q
JOIN taxon_concepts hi
ON hi.parent_id = q.id
), grouped AS (
SELECT id,
HSTORE(
''' || designation_name || '_status'',
CASE
WHEN BOOL_OR(status_hstore->''' || designation_name || '_status'' = ''LISTED'')
THEN ''LISTED''
ELSE MAX(status_hstore->''' || designation_name || '_status'')
END
) ||
HSTORE(
''' || designation_name || '_status_original'',
BOOL_OR((status_hstore->''' || designation_name || '_status_original'')::BOOLEAN)::TEXT
) ||
HSTORE(
''' || designation_name || '_not_listed'',
CASE
WHEN BOOL_AND(status_hstore->''' || designation_name || '_not_listed'' = ''NC'')
THEN ''NC''
ELSE NULL
END
) ||
HSTORE(
''' || designation_name || '_updated_at'',
MAX(inherited_listing_updated_at)
) AS status_hstore
FROM q
GROUP BY q.id --this grouping is to accommodate for split listings
)
UPDATE taxon_concepts
SET listing = COALESCE(listing, ''''::HSTORE) || grouped.status_hstore
FROM grouped
WHERE taxon_concepts.id = grouped.id';
EXECUTE sql;
-- set cites_status property to 'LISTED' for ancestors of listed taxa
WITH qq AS (
WITH RECURSIVE q AS
(
SELECT h.id, h.parent_id,
listing->status_flag AS inherited_status,
(listing->listing_updated_at_flag)::TIMESTAMP AS inherited_listing_updated_at
FROM taxon_concepts h
WHERE
listing->status_flag = 'LISTED'
AND (listing->status_original_flag)::BOOLEAN = 't'
AND
CASE WHEN node_id IS NOT NULL THEN id = node_id ELSE TRUE END
UNION
SELECT hi.id, hi.parent_id,
CASE
WHEN (listing->status_original_flag)::BOOLEAN = 't'
THEN listing->status_flag
ELSE inherited_status
END,
CASE
WHEN (listing->listing_updated_at_flag)::TIMESTAMP IS NOT NULL
THEN (listing->listing_updated_at_flag)::TIMESTAMP
ELSE inherited_listing_updated_at
END
FROM q
JOIN taxon_concepts hi
ON hi.id = q.parent_id
WHERE (listing->status_original_flag)::BOOLEAN IS NULL
)
SELECT DISTINCT id, inherited_status,
inherited_listing_updated_at
FROM q
)
UPDATE taxon_concepts
SET listing = COALESCE(listing, ''::HSTORE) ||
hstore(status_flag, inherited_status) ||
hstore(status_original_flag, 'f') ||
hstore(level_of_listing_flag, 'f') ||
hstore(listing_updated_at_flag, inherited_listing_updated_at::VARCHAR)
FROM qq
WHERE taxon_concepts.id = qq.id
AND (
listing IS NULL
OR (listing->status_original_flag)::BOOLEAN IS NULL
OR (listing->status_original_flag)::BOOLEAN = 'f'
);
END;
$$;
CREATE OR REPLACE FUNCTION set_cites_eu_historically_listed_flag_for_node(designation text, node_id integer)
RETURNS VOID
LANGUAGE sql
AS $$
WITH historically_listed_taxa AS (
SELECT taxon_concept_id AS id
FROM listing_changes
JOIN change_types
ON change_types.id = change_type_id
JOIN designations
ON designations.id = designation_id AND designations.name = UPPER($1)
WHERE CASE WHEN $2 IS NULL THEN TRUE ELSE taxon_concept_id = $2 END
GROUP BY taxon_concept_id
), taxa_with_historically_listed_flag AS (
SELECT taxon_concepts.id,
CASE WHEN t.id IS NULL THEN FALSE ELSE TRUE END AS historically_listed
FROM taxon_concepts
JOIN taxonomies
ON taxonomies.id = taxon_concepts.taxonomy_id AND taxonomies.name = 'CITES_EU'
LEFT JOIN historically_listed_taxa t
ON t.id = taxon_concepts.id
WHERE CASE WHEN $2 IS NULL THEN TRUE ELSE taxon_concepts.id = $2 END
)
UPDATE taxon_concepts
SET listing = COALESCE(listing, ''::HSTORE) ||
HSTORE(LOWER($1) || '_historically_listed', t.historically_listed::VARCHAR)
FROM taxa_with_historically_listed_flag t
WHERE t.id = taxon_concepts.id;
$$;