Add amazon_id column to artists table for full source parity

Schema: ALTER TABLE artists ADD COLUMN amazon_id TEXT with index, added via
_add_amazon_columns migration called after Discogs in _run_migrations.

SOURCE_ID_FIELD: add "amazon" -> "amazon_id" entry. find_library_artist_for_
source now looks up Amazon artists by slug before falling back to name match,
same as every other source. artist_source_detail already stamps artist_info
[source_id_field] = artist_id so the amazon_id is set on source-only payloads.

Tests: add "amazon": "amazon_id" to EXPECTED_SOURCE_ID_FIELD; revert test
assertion back to strict equality (SOURCE_ONLY_ARTIST_SOURCES == SOURCE_ID_
FIELD.keys() holds again now that amazon has a column).
This commit is contained in:
Broque Thomas 2026-05-16 17:06:54 -07:00
parent 265fe5233e
commit 121651da2c
3 changed files with 31 additions and 13 deletions

View file

@ -36,6 +36,7 @@ SOURCE_ID_FIELD = {
"discogs": "discogs_id",
"hydrabase": "soul_id",
"musicbrainz": "musicbrainz_id",
"amazon": "amazon_id",
}
@ -58,18 +59,19 @@ def find_library_artist_for_source(
Returns ``None`` on miss or on any database error.
"""
column = SOURCE_ID_FIELD.get(source)
if not column:
return None
try:
with database._get_connection() as conn:
cursor = conn.cursor()
if column:
cursor.execute(
f"SELECT id, name FROM artists WHERE {column} = ? LIMIT 1",
(str(source_artist_id),),
)
row = cursor.fetchone()
if row:
return row[0]
cursor.execute(
f"SELECT id, name FROM artists WHERE {column} = ? LIMIT 1",
(str(source_artist_id),),
)
row = cursor.fetchone()
if row:
return row[0]
if artist_name and active_server:
cursor.execute(

View file

@ -407,6 +407,9 @@ class MusicDatabase:
# Add Discogs enrichment columns (migration)
self._add_discogs_columns(cursor)
# Add Amazon artist ID column (migration)
self._add_amazon_columns(cursor)
# Backfill match_status for rows that already have an external ID but
# NULL status. Prevents enrichment workers from re-processing these
# rows forever. Must run AFTER all *_match_status columns have been
@ -2035,6 +2038,18 @@ class MusicDatabase:
except Exception as e:
logger.error(f"Error adding Discogs columns: {e}")
def _add_amazon_columns(self, cursor):
"""Add Amazon artist ID column to artists table."""
try:
cursor.execute("PRAGMA table_info(artists)")
artists_columns = [column[1] for column in cursor.fetchall()]
if 'amazon_id' not in artists_columns:
cursor.execute("ALTER TABLE artists ADD COLUMN amazon_id TEXT")
cursor.execute("CREATE INDEX IF NOT EXISTS idx_artists_amazon_id ON artists (amazon_id)")
logger.info("Amazon columns added/verified successfully")
except Exception as e:
logger.error(f"Error adding Amazon columns: {e}")
def _backfill_match_status_for_existing_ids(self, cursor):
"""Set `<provider>_match_status = 'matched'` for rows that already have a
populated external ID but NULL match_status.

View file

@ -31,6 +31,7 @@ EXPECTED_SOURCE_ID_FIELD = {
"discogs": "discogs_id",
"hydrabase": "soul_id",
"musicbrainz": "musicbrainz_id",
"amazon": "amazon_id",
}
@ -68,11 +69,11 @@ class TestSourceIdFieldMapping:
"(and the test body) to match."
)
def test_source_only_set_contains_all_mapped_sources(self):
"""Every source with a SOURCE_ID_FIELD column must also be in
SOURCE_ONLY_ARTIST_SOURCES. The reverse is not required sources
without a DB column (e.g. amazon) use name-based lookup only."""
assert frozenset(SOURCE_ID_FIELD.keys()).issubset(SOURCE_ONLY_ARTIST_SOURCES)
def test_source_only_set_matches_mapping_keys(self):
"""Sources eligible for the source-only fallback must all have a
column to look them up by otherwise the upgrade path silently
returns None."""
assert SOURCE_ONLY_ARTIST_SOURCES == frozenset(SOURCE_ID_FIELD.keys())
def test_every_mapped_column_exists_on_artists_table(self, db):
"""Regression for the 2026-04 ``deezer_artist_id`` typo: every column