diff --git a/scripts/merge_altkey_tags.py b/scripts/merge_altkey_tags.py index e8867a9..8401986 100644 --- a/scripts/merge_altkey_tags.py +++ b/scripts/merge_altkey_tags.py @@ -85,23 +85,29 @@ def main() -> None: s.rollback() return + # UWAGA: NIE robimy UPDATE tag_id (kolizja PK gdy scena ma DWA warianty tego + # samego klastra → oba UPDATE na keep = duplikat (scene_id, keep)). Zamiast tego + # DODAJEMY membership kanonicznego (DISTINCT + ON CONFLICT), a wiersze dropów + # sprzątnie CASCADE przy DELETE FROM tags. Kolizyjno-odporne. + # EXISTS-guard na keep: gdyby kanoniczny zniknął między budową _dup_map a INSERT + # (współbieżny ingest/cleanup), pomijamy zamiast walić FK violation (całość rollback). r1 = s.execute(text(""" - UPDATE scene_tags st SET tag_id = m.keep_id - FROM _dup_map m - WHERE st.tag_id = m.drop_id - AND NOT EXISTS (SELECT 1 FROM scene_tags k - WHERE k.scene_id = st.scene_id AND k.tag_id = m.keep_id) + INSERT INTO scene_tags (scene_id, tag_id) + SELECT DISTINCT st.scene_id, m.keep_id + FROM scene_tags st JOIN _dup_map m ON st.tag_id = m.drop_id + WHERE EXISTS (SELECT 1 FROM tags kt WHERE kt.id = m.keep_id) + ON CONFLICT (scene_id, tag_id) DO NOTHING """)) - log.info("scene_tags migrated: %d", r1.rowcount) + log.info("scene_tags keep-memberships inserted: %d", r1.rowcount) r2 = s.execute(text(""" - UPDATE movie_tags mt SET tag_id = m.keep_id - FROM _dup_map m - WHERE mt.tag_id = m.drop_id - AND NOT EXISTS (SELECT 1 FROM movie_tags k - WHERE k.movie_id = mt.movie_id AND k.tag_id = m.keep_id) + INSERT INTO movie_tags (movie_id, tag_id) + SELECT DISTINCT mt.movie_id, m.keep_id + FROM movie_tags mt JOIN _dup_map m ON mt.tag_id = m.drop_id + WHERE EXISTS (SELECT 1 FROM tags kt WHERE kt.id = m.keep_id) + ON CONFLICT (movie_id, tag_id) DO NOTHING """)) - log.info("movie_tags migrated: %d", r2.rowcount) + log.info("movie_tags keep-memberships inserted: %d", r2.rowcount) # blacklisted_tags PK = (device_id, tag_id) → przenieś ban z dropa na kanoniczny per device. r3 = s.execute(text("""