// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 // source: merge.sql package dbq import ( "context" "github.com/jackc/pgx/v5/pgtype" ) const listDuplicateGroupMergeMembers = `-- name: ListDuplicateGroupMergeMembers :many SELECT t.id, t.file_path, t.file_format, t.file_size, t.added_at, t.album_id, t.mbid, albums.mbid AS album_mbid FROM duplicate_group_members m JOIN tracks t ON t.id = m.track_id JOIN albums ON albums.id = t.album_id WHERE m.group_id = $1 ORDER BY t.id ` type ListDuplicateGroupMergeMembersRow struct { ID pgtype.UUID FilePath string FileFormat string FileSize int64 AddedAt pgtype.Timestamptz AlbumID pgtype.UUID Mbid *string AlbumMbid *string } func (q *Queries) ListDuplicateGroupMergeMembers(ctx context.Context, groupID pgtype.UUID) ([]ListDuplicateGroupMergeMembersRow, error) { rows, err := q.db.Query(ctx, listDuplicateGroupMergeMembers, groupID) if err != nil { return nil, err } defer rows.Close() var items []ListDuplicateGroupMergeMembersRow for rows.Next() { var i ListDuplicateGroupMergeMembersRow if err := rows.Scan( &i.ID, &i.FilePath, &i.FileFormat, &i.FileSize, &i.AddedAt, &i.AlbumID, &i.Mbid, &i.AlbumMbid, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const lockDuplicateGroupForMerge = `-- name: LockDuplicateGroupForMerge :one SELECT id, tier, status FROM duplicate_groups WHERE id = $1 FOR UPDATE ` type LockDuplicateGroupForMergeRow struct { ID pgtype.UUID Tier string Status string } // Duplicate merge (Scribe #3911). 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. // Locks the group for the rest of the transaction, so two merges of one group // cannot run at once. func (q *Queries) LockDuplicateGroupForMerge(ctx context.Context, id pgtype.UUID) (LockDuplicateGroupForMergeRow, error) { row := q.db.QueryRow(ctx, lockDuplicateGroupForMerge, id) var i LockDuplicateGroupForMergeRow err := row.Scan(&i.ID, &i.Tier, &i.Status) return i, err } const markDuplicateGroupMerged = `-- name: MarkDuplicateGroupMerged :execrows UPDATE duplicate_groups SET status = 'merged', resolved_at = now() WHERE id = $1 AND status = 'pending' ` func (q *Queries) MarkDuplicateGroupMerged(ctx context.Context, id pgtype.UUID) (int64, error) { result, err := q.db.Exec(ctx, markDuplicateGroupMerged, id) if err != nil { return 0, err } return result.RowsAffected(), nil } const mergeCopyGeneralLikes = `-- name: MergeCopyGeneralLikes :many INSERT INTO general_likes (user_id, track_id, liked_at) SELECT user_id, $1::uuid, liked_at FROM general_likes WHERE track_id = $2::uuid ON CONFLICT (user_id, track_id) DO UPDATE SET liked_at = LEAST(general_likes.liked_at, EXCLUDED.liked_at) RETURNING user_id ` type MergeCopyGeneralLikesParams struct { SurvivorID pgtype.UUID LoserID pgtype.UUID } // 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. // One like per user. A user who liked both copies keeps a single like, dated to // the earlier of the two. func (q *Queries) MergeCopyGeneralLikes(ctx context.Context, arg MergeCopyGeneralLikesParams) ([]pgtype.UUID, error) { rows, err := q.db.Query(ctx, mergeCopyGeneralLikes, arg.SurvivorID, arg.LoserID) if err != nil { return nil, err } defer rows.Close() var items []pgtype.UUID for rows.Next() { var user_id pgtype.UUID if err := rows.Scan(&user_id); err != nil { return nil, err } items = append(items, user_id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const mergeCopyTrackSimilarity = `-- name: MergeCopyTrackSimilarity :execrows INSERT INTO track_similarity (track_a_id, track_b_id, score, source, fetched_at) SELECT CASE WHEN track_a_id = $1::uuid THEN $2::uuid ELSE track_a_id END, CASE WHEN track_b_id = $1::uuid THEN $2::uuid ELSE track_b_id END, score, source, fetched_at FROM track_similarity WHERE (track_a_id = $1::uuid OR track_b_id = $1::uuid) AND (CASE WHEN track_a_id = $1::uuid THEN $2::uuid ELSE track_a_id END) <> (CASE WHEN track_b_id = $1::uuid THEN $2::uuid ELSE track_b_id END) ON CONFLICT (track_a_id, track_b_id, source) DO NOTHING ` type MergeCopyTrackSimilarityParams struct { LoserID pgtype.UUID SurvivorID pgtype.UUID } // 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. func (q *Queries) MergeCopyTrackSimilarity(ctx context.Context, arg MergeCopyTrackSimilarityParams) (int64, error) { result, err := q.db.Exec(ctx, mergeCopyTrackSimilarity, arg.LoserID, arg.SurvivorID) if err != nil { return 0, err } return result.RowsAffected(), nil } const mergeCopyTrackTags = `-- name: MergeCopyTrackTags :execrows INSERT INTO track_tags (track_id, tag, weight) SELECT $1::uuid, tag, weight FROM track_tags WHERE track_id = $2::uuid ON CONFLICT (track_id, tag) DO NOTHING ` type MergeCopyTrackTagsParams struct { SurvivorID pgtype.UUID LoserID pgtype.UUID } func (q *Queries) MergeCopyTrackTags(ctx context.Context, arg MergeCopyTrackTagsParams) (int64, error) { result, err := q.db.Exec(ctx, mergeCopyTrackTags, arg.SurvivorID, arg.LoserID) if err != nil { return 0, err } return result.RowsAffected(), nil } const mergeInheritTrackMbid = `-- name: MergeInheritTrackMbid :exec UPDATE tracks AS survivor SET mbid = loser.mbid FROM tracks AS loser WHERE survivor.id = $1::uuid AND loser.id = $2::uuid AND survivor.mbid IS NULL AND loser.mbid IS NOT NULL ` type MergeInheritTrackMbidParams struct { SurvivorID pgtype.UUID LoserID pgtype.UUID } // 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. func (q *Queries) MergeInheritTrackMbid(ctx context.Context, arg MergeInheritTrackMbidParams) error { _, err := q.db.Exec(ctx, mergeInheritTrackMbid, arg.SurvivorID, arg.LoserID) return err } const mergeRepointContextualLikes = `-- name: MergeRepointContextualLikes :execrows UPDATE contextual_likes SET track_id = $1::uuid WHERE track_id = $2::uuid ` type MergeRepointContextualLikesParams struct { SurvivorID pgtype.UUID LoserID pgtype.UUID } func (q *Queries) MergeRepointContextualLikes(ctx context.Context, arg MergeRepointContextualLikesParams) (int64, error) { result, err := q.db.Exec(ctx, mergeRepointContextualLikes, arg.SurvivorID, arg.LoserID) if err != nil { return 0, err } return result.RowsAffected(), nil } const mergeRepointLidarrRequests = `-- name: MergeRepointLidarrRequests :execrows UPDATE lidarr_requests SET matched_track_id = $1::uuid WHERE matched_track_id = $2::uuid ` type MergeRepointLidarrRequestsParams struct { SurvivorID pgtype.UUID LoserID pgtype.UUID } func (q *Queries) MergeRepointLidarrRequests(ctx context.Context, arg MergeRepointLidarrRequestsParams) (int64, error) { result, err := q.db.Exec(ctx, mergeRepointLidarrRequests, arg.SurvivorID, arg.LoserID) if err != nil { return 0, err } return result.RowsAffected(), nil } const mergeRepointPlayEvents = `-- name: MergeRepointPlayEvents :execrows UPDATE play_events SET track_id = $1::uuid WHERE track_id = $2::uuid ` type MergeRepointPlayEventsParams struct { SurvivorID pgtype.UUID LoserID pgtype.UUID } // Plain repoints: no unique key involves track_id, so moving rows cannot collide. func (q *Queries) MergeRepointPlayEvents(ctx context.Context, arg MergeRepointPlayEventsParams) (int64, error) { result, err := q.db.Exec(ctx, mergeRepointPlayEvents, arg.SurvivorID, arg.LoserID) if err != nil { return 0, err } return result.RowsAffected(), nil } const mergeRepointPlaybackErrors = `-- name: MergeRepointPlaybackErrors :execrows UPDATE playback_errors SET track_id = $1::uuid WHERE track_id = $2::uuid ` type MergeRepointPlaybackErrorsParams struct { SurvivorID pgtype.UUID LoserID pgtype.UUID } func (q *Queries) MergeRepointPlaybackErrors(ctx context.Context, arg MergeRepointPlaybackErrorsParams) (int64, error) { result, err := q.db.Exec(ctx, mergeRepointPlaybackErrors, arg.SurvivorID, arg.LoserID) if err != nil { return 0, err } return result.RowsAffected(), nil } const mergeRepointPlaylistTracks = `-- name: MergeRepointPlaylistTracks :many UPDATE playlist_tracks SET track_id = $1::uuid WHERE track_id = $2::uuid RETURNING playlist_id ` type MergeRepointPlaylistTracksParams struct { SurvivorID pgtype.UUID LoserID pgtype.UUID } // 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. func (q *Queries) MergeRepointPlaylistTracks(ctx context.Context, arg MergeRepointPlaylistTracksParams) ([]pgtype.UUID, error) { rows, err := q.db.Query(ctx, mergeRepointPlaylistTracks, arg.SurvivorID, arg.LoserID) if err != nil { return nil, err } defer rows.Close() var items []pgtype.UUID for rows.Next() { var playlist_id pgtype.UUID if err := rows.Scan(&playlist_id); err != nil { return nil, err } items = append(items, playlist_id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const mergeRepointSkipEvents = `-- name: MergeRepointSkipEvents :execrows UPDATE skip_events SET track_id = $1::uuid WHERE track_id = $2::uuid ` type MergeRepointSkipEventsParams struct { SurvivorID pgtype.UUID LoserID pgtype.UUID } func (q *Queries) MergeRepointSkipEvents(ctx context.Context, arg MergeRepointSkipEventsParams) (int64, error) { result, err := q.db.Exec(ctx, mergeRepointSkipEvents, arg.SurvivorID, arg.LoserID) if err != nil { return 0, err } return result.RowsAffected(), nil }