1010This pre-migration moves legacy rows (with the referenced vocabulary's name)
1111into an aux table; the matching post-migration recreates them as
1212spp.gis.geofence.tag links and drops the aux table.
13+
14+ All SQL is literal and value-parameterized; identifiers are never composed.
1315"""
1416
1517import logging
1618
17- from psycopg2 import sql
18-
1919_logger = logging .getLogger ("odoo.addons.spp_gis.migrations.geofence_tags" )
2020
21- AUX_TABLE = "spp_gis_geofence_tag_legacy_migration"
21+ _CREATE_AUX = """
22+ CREATE TABLE IF NOT EXISTS spp_gis_geofence_tag_legacy_migration (
23+ geofence_id integer NOT NULL,
24+ vocab_name varchar NOT NULL
25+ )
26+ """
27+
28+ # name is a translated (jsonb) field: prefer en_US, else any value.
29+ _PARK_LEGACY = """
30+ INSERT INTO spp_gis_geofence_tag_legacy_migration (geofence_id, vocab_name)
31+ SELECT rel.geofence_id,
32+ COALESCE(v.name->>'en_US', (SELECT t.value FROM jsonb_each_text(v.name) t LIMIT 1))
33+ FROM spp_gis_geofence_tag_rel rel
34+ JOIN spp_vocabulary v ON v.id = rel.tag_id
35+ """
36+
37+ _DELETE_LEGACY = """
38+ DELETE FROM spp_gis_geofence_tag_rel rel
39+ USING spp_vocabulary v
40+ WHERE v.id = rel.tag_id
41+ """
42+
43+ # Variants used when the new tag table already exists (migration rerun or
44+ # tests): a row is a valid new-style link if its tag_id exists there; it is
45+ # legacy if it references a vocabulary instead. Checking the new table first
46+ # resolves numeric id collisions in favor of valid links.
47+ _PARK_LEGACY_SKIP_VALID = """
48+ INSERT INTO spp_gis_geofence_tag_legacy_migration (geofence_id, vocab_name)
49+ SELECT rel.geofence_id,
50+ COALESCE(v.name->>'en_US', (SELECT t.value FROM jsonb_each_text(v.name) t LIMIT 1))
51+ FROM spp_gis_geofence_tag_rel rel
52+ JOIN spp_vocabulary v ON v.id = rel.tag_id
53+ WHERE rel.tag_id NOT IN (SELECT id FROM spp_gis_geofence_tag)
54+ """
55+
56+ _DELETE_LEGACY_SKIP_VALID = """
57+ DELETE FROM spp_gis_geofence_tag_rel rel
58+ USING spp_vocabulary v
59+ WHERE v.id = rel.tag_id
60+ AND rel.tag_id NOT IN (SELECT id FROM spp_gis_geofence_tag)
61+ """
2262
2363
2464def _table_exists (cr , table ):
@@ -30,48 +70,17 @@ def migrate(cr, version):
3070 if not _table_exists (cr , "spp_gis_geofence_tag_rel" ):
3171 return
3272
33- # A row is a valid new-style link if its tag_id exists in the new tag
34- # table (only possible when this migration reruns or in tests); it is
35- # legacy if it references a vocabulary instead. Checking the new table
36- # first resolves numeric id collisions in favor of valid links.
3773 if _table_exists (cr , "spp_gis_geofence_tag" ):
38- valid_clause = sql .SQL ("AND rel.tag_id NOT IN (SELECT id FROM spp_gis_geofence_tag)" )
74+ park_query = _PARK_LEGACY_SKIP_VALID
75+ delete_query = _DELETE_LEGACY_SKIP_VALID
3976 else :
40- valid_clause = sql .SQL ("" )
41-
42- aux = sql .Identifier (AUX_TABLE )
43- cr .execute (
44- sql .SQL (
45- """
46- CREATE TABLE IF NOT EXISTS {aux} (
47- geofence_id integer NOT NULL,
48- vocab_name varchar NOT NULL
49- )
50- """
51- ).format (aux = aux )
52- )
53- cr .execute (
54- sql .SQL (
55- """
56- INSERT INTO {aux} (geofence_id, vocab_name)
57- SELECT rel.geofence_id,
58- COALESCE(v.name->>'en_US', (SELECT t.value FROM jsonb_each_text(v.name) t LIMIT 1))
59- FROM spp_gis_geofence_tag_rel rel
60- JOIN spp_vocabulary v ON v.id = rel.tag_id
61- WHERE true {valid_clause}
62- """
63- ).format (aux = aux , valid_clause = valid_clause )
64- )
77+ park_query = _PARK_LEGACY
78+ delete_query = _DELETE_LEGACY
79+
80+ cr .execute (_CREATE_AUX )
81+ cr .execute (park_query )
6582 parked = cr .rowcount
66- cr .execute (
67- sql .SQL (
68- """
69- DELETE FROM spp_gis_geofence_tag_rel rel
70- USING spp_vocabulary v
71- WHERE v.id = rel.tag_id {valid_clause}
72- """
73- ).format (valid_clause = valid_clause )
74- )
83+ cr .execute (delete_query )
7584 _logger .info (
7685 "spp_gis geofence tag migration: parked %s legacy vocabulary tag links (%s rows removed)" ,
7786 parked ,
0 commit comments