fix: enforce case-insensitive genre uniqueness

genres had only case-sensitive name UNIQUE while authors/tags use
UNIQUE (lower(name)); sync_genres could race two case variants into duplicate
rows (audit DB-3). Migration 0038 pre-dedups then adds
UNIQUE (lower(name)); sync_genres upserts ON CONFLICT (lower(name)). Tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-13 21:25:46 +02:00
parent 75f4481bbd
commit c31830468c
6 changed files with 69 additions and 4 deletions

View File

@@ -247,10 +247,13 @@ async fn sync_genres(
let genre_id = match existing {
Some((id,)) => id,
None => {
// Conflict on lower(name) (0038) not name, so a racing insert of
// a differently-cased variant resolves to the existing row
// instead of raising a unique violation.
let (id,): (Uuid,) = sqlx::query_as(
r#"
INSERT INTO genres (name) VALUES ($1)
ON CONFLICT (name) DO UPDATE SET name = genres.name
ON CONFLICT (lower(name)) DO UPDATE SET name = genres.name
RETURNING id
"#,
)