video enrichment: survive legacy UNIQUE on tmdb_id/tvdb_id (no scan crash)
Existing DBs created before the schema dropped UNIQUE still have shows.tvdb_id / movies.tmdb_id UNIQUE, so enrichment matching two items to the same id threw 'UNIQUE constraint failed' repeatedly. enrichment_apply now catches the IntegrityError and retries without the id columns — keeps the existing (authoritative) id and still records match_status + metadata. Non-destructive (no table rebuild). Test simulates the legacy unique index.
This commit is contained in:
parent
2901e4ec4d
commit
776afdd1fd
2 changed files with 45 additions and 10 deletions
|
|
@ -179,21 +179,39 @@ class VideoDatabase:
|
|||
if not spec:
|
||||
return
|
||||
tbl, idc, sc, ac = spec
|
||||
sets = [f"{sc}=?", f"{ac}=CURRENT_TIMESTAMP"]
|
||||
params = ["matched" if matched else "not_found"]
|
||||
if matched and external_id is not None:
|
||||
sets.append(f"{idc}=?")
|
||||
params.append(external_id)
|
||||
allowed = _ENRICH_META_COLS.get(tbl, set())
|
||||
for col, val in (metadata or {}).items():
|
||||
if val is not None and col in allowed:
|
||||
# On legacy DBs tmdb_id/tvdb_id may still carry a UNIQUE index; if a match
|
||||
# would collide with another row's id we drop the id columns and keep the
|
||||
# existing (authoritative) id, still recording status + metadata.
|
||||
id_cols = {"tmdb_id", "tvdb_id", "imdb_id"}
|
||||
|
||||
def build(include_ids):
|
||||
sets = [f"{sc}=?", f"{ac}=CURRENT_TIMESTAMP"]
|
||||
params = ["matched" if matched else "not_found"]
|
||||
if matched and external_id is not None and include_ids:
|
||||
sets.append(f"{idc}=?")
|
||||
params.append(external_id)
|
||||
for col, val in (metadata or {}).items():
|
||||
if val is None or col not in allowed:
|
||||
continue
|
||||
if not include_ids and col in id_cols:
|
||||
continue
|
||||
sets.append(f"{col}=?")
|
||||
params.append(val)
|
||||
params.append(item_id)
|
||||
params.append(item_id)
|
||||
return f"UPDATE {tbl} SET {', '.join(sets)} WHERE id=?", params
|
||||
|
||||
conn = self._get_connection()
|
||||
try:
|
||||
conn.execute(f"UPDATE {tbl} SET {', '.join(sets)} WHERE id=?", params)
|
||||
conn.commit()
|
||||
sql, params = build(True)
|
||||
try:
|
||||
conn.execute(sql, params)
|
||||
conn.commit()
|
||||
except sqlite3.IntegrityError:
|
||||
conn.rollback()
|
||||
sql, params = build(False) # keep existing id, just record status/metadata
|
||||
conn.execute(sql, params)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -365,6 +365,23 @@ def test_enrichment_apply_matched_sets_id_status_and_metadata(db):
|
|||
assert (row["overview"], row["backdrop_url"], row["imdb_id"]) == ("O", "/b.jpg", "tt1")
|
||||
|
||||
|
||||
def test_enrichment_apply_survives_legacy_unique(db):
|
||||
# Simulate a pre-existing DB where tvdb_id still carries a UNIQUE index.
|
||||
with db.connect() as c:
|
||||
c.execute("CREATE UNIQUE INDEX ux_legacy_shows_tvdb ON shows(tvdb_id)")
|
||||
c.commit()
|
||||
a = db.upsert_show_tree("plex", {"server_id": "s1", "title": "A", "seasons": []})
|
||||
b = db.upsert_show_tree("plex", {"server_id": "s2", "title": "B", "seasons": []})
|
||||
db.enrichment_apply("tvdb", "show", a, matched=True, external_id=555, metadata={"overview": "OA"})
|
||||
# b would collide on tvdb_id=555 — must NOT crash; keeps existing id, records the rest.
|
||||
db.enrichment_apply("tvdb", "show", b, matched=True, external_id=555, metadata={"overview": "OB"})
|
||||
with db.connect() as c:
|
||||
ra = c.execute("SELECT tvdb_id, tvdb_match_status FROM shows WHERE id=?", (a,)).fetchone()
|
||||
rb = c.execute("SELECT tvdb_id, tvdb_match_status, overview FROM shows WHERE id=?", (b,)).fetchone()
|
||||
assert (ra["tvdb_id"], ra["tvdb_match_status"]) == (555, "matched")
|
||||
assert rb["tvdb_id"] is None and rb["tvdb_match_status"] == "matched" and rb["overview"] == "OB"
|
||||
|
||||
|
||||
def test_enrichment_breakdown_unmatched_retry(db):
|
||||
a = db.upsert_movie("plex", {"server_id": "m1", "title": "A"})
|
||||
b = db.upsert_movie("plex", {"server_id": "m2", "title": "B"})
|
||||
|
|
|
|||
Loading…
Reference in a new issue