Rewrites the internal/db/queries comments to rule 32 and regenerates dbq, whose doc comments and embedded SQL carry them. The bugs behind the tiered mixes, the md5 order seed, the score bands and the round-robin arms are restated as the constraint each one enforces; counts from one library and stale cross-references are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
100 lines
4.5 KiB
SQL
100 lines
4.5 KiB
SQL
-- Duplicate merge. Every statement here runs inside the one
|
|
-- transaction library.MergeDuplicateGroup opens, after the removed copy's file
|
|
-- is already gone. The loser's own track row is deleted last with DeleteTrack;
|
|
-- what these do is move everything it carries onto the survivor first, so that
|
|
-- delete's CASCADE finds nothing left to destroy.
|
|
|
|
-- name: LockDuplicateGroupForMerge :one
|
|
-- Locks the group for the rest of the transaction, so two merges of one group
|
|
-- cannot run at once.
|
|
SELECT id, tier, status
|
|
FROM duplicate_groups
|
|
WHERE id = sqlc.arg(id)
|
|
FOR UPDATE;
|
|
|
|
-- name: ListDuplicateGroupMergeMembers :many
|
|
SELECT t.id, t.file_path, t.file_format, t.file_size, t.added_at, t.album_id
|
|
FROM duplicate_group_members m
|
|
JOIN tracks t ON t.id = m.track_id
|
|
WHERE m.group_id = sqlc.arg(group_id)
|
|
ORDER BY t.id;
|
|
|
|
-- Plain repoints: no unique key involves track_id, so moving rows cannot collide.
|
|
|
|
-- name: MergeRepointPlayEvents :execrows
|
|
UPDATE play_events SET track_id = sqlc.arg(survivor_id)::uuid WHERE track_id = sqlc.arg(loser_id)::uuid;
|
|
|
|
-- name: MergeRepointSkipEvents :execrows
|
|
UPDATE skip_events SET track_id = sqlc.arg(survivor_id)::uuid WHERE track_id = sqlc.arg(loser_id)::uuid;
|
|
|
|
-- name: MergeRepointContextualLikes :execrows
|
|
UPDATE contextual_likes SET track_id = sqlc.arg(survivor_id)::uuid WHERE track_id = sqlc.arg(loser_id)::uuid;
|
|
|
|
-- name: MergeRepointPlaybackErrors :execrows
|
|
UPDATE playback_errors SET track_id = sqlc.arg(survivor_id)::uuid WHERE track_id = sqlc.arg(loser_id)::uuid;
|
|
|
|
-- name: MergeRepointRequests :execrows
|
|
UPDATE requests SET matched_track_id = sqlc.arg(survivor_id)::uuid
|
|
WHERE matched_track_id = sqlc.arg(loser_id)::uuid;
|
|
|
|
-- name: MergeRepointPlaylistTracks :many
|
|
-- playlist_tracks is keyed by (playlist_id, position), so repointing keeps every
|
|
-- entry exactly where it was. A playlist that held both copies simply holds the
|
|
-- survivor twice — the user put two entries there, and both stay.
|
|
UPDATE playlist_tracks SET track_id = sqlc.arg(survivor_id)::uuid
|
|
WHERE track_id = sqlc.arg(loser_id)::uuid
|
|
RETURNING playlist_id;
|
|
|
|
-- Collision-safe merges: a unique key includes track_id, so the survivor may
|
|
-- already hold a matching row. Copy what it lacks; DeleteTrack's CASCADE then
|
|
-- removes the loser's originals.
|
|
|
|
-- name: MergeCopyGeneralLikes :many
|
|
-- One like per user. A user who liked both copies keeps a single like, dated to
|
|
-- the earlier of the two.
|
|
INSERT INTO general_likes (user_id, track_id, liked_at)
|
|
SELECT user_id, sqlc.arg(survivor_id)::uuid, liked_at
|
|
FROM general_likes
|
|
WHERE track_id = sqlc.arg(loser_id)::uuid
|
|
ON CONFLICT (user_id, track_id) DO UPDATE
|
|
SET liked_at = LEAST(general_likes.liked_at, EXCLUDED.liked_at)
|
|
RETURNING user_id;
|
|
|
|
-- name: MergeCopyTrackTags :execrows
|
|
INSERT INTO track_tags (track_id, tag, weight)
|
|
SELECT sqlc.arg(survivor_id)::uuid, tag, weight
|
|
FROM track_tags
|
|
WHERE track_id = sqlc.arg(loser_id)::uuid
|
|
ON CONFLICT (track_id, tag) DO NOTHING;
|
|
|
|
-- name: MergeCopyTrackSimilarity :execrows
|
|
-- Rewrites the loser to the survivor on either side of an edge. An edge between
|
|
-- the two copies would become a track similar to itself — the table forbids
|
|
-- that, and it means nothing — so it is dropped. An edge the survivor already
|
|
-- has from the same source is kept as it is.
|
|
INSERT INTO track_similarity (track_a_id, track_b_id, score, source, fetched_at)
|
|
SELECT CASE WHEN track_a_id = sqlc.arg(loser_id)::uuid THEN sqlc.arg(survivor_id)::uuid ELSE track_a_id END,
|
|
CASE WHEN track_b_id = sqlc.arg(loser_id)::uuid THEN sqlc.arg(survivor_id)::uuid ELSE track_b_id END,
|
|
score, source, fetched_at
|
|
FROM track_similarity
|
|
WHERE (track_a_id = sqlc.arg(loser_id)::uuid OR track_b_id = sqlc.arg(loser_id)::uuid)
|
|
AND (CASE WHEN track_a_id = sqlc.arg(loser_id)::uuid THEN sqlc.arg(survivor_id)::uuid ELSE track_a_id END)
|
|
<> (CASE WHEN track_b_id = sqlc.arg(loser_id)::uuid THEN sqlc.arg(survivor_id)::uuid ELSE track_b_id END)
|
|
ON CONFLICT (track_a_id, track_b_id, source) DO NOTHING;
|
|
|
|
-- name: MergeInheritTrackMbid :exec
|
|
-- A recording MBID is what the similarity pipeline keys on. If only the removed
|
|
-- copy carried one, the survivor takes it rather than going dark to similarity.
|
|
UPDATE tracks AS survivor
|
|
SET mbid = loser.mbid, mbid_source = loser.mbid_source
|
|
FROM tracks AS loser
|
|
WHERE survivor.id = sqlc.arg(survivor_id)::uuid
|
|
AND loser.id = sqlc.arg(loser_id)::uuid
|
|
AND survivor.mbid IS NULL
|
|
AND loser.mbid IS NOT NULL;
|
|
|
|
-- name: MarkDuplicateGroupMerged :execrows
|
|
UPDATE duplicate_groups
|
|
SET status = 'merged', resolved_at = now()
|
|
WHERE id = sqlc.arg(id) AND status = 'pending';
|