// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 // source: wanted.sql package dbq import ( "context" "github.com/jackc/pgx/v5/pgtype" ) const clearDefaultReleaseTypeProfile = `-- name: ClearDefaultReleaseTypeProfile :exec UPDATE release_type_profiles SET is_default = false, updated_at = now() WHERE is_default ` func (q *Queries) ClearDefaultReleaseTypeProfile(ctx context.Context) error { _, err := q.db.Exec(ctx, clearDefaultReleaseTypeProfile) return err } const countWants = `-- name: CountWants :one SELECT COUNT(*) FILTER (WHERE fulfilled_at IS NULL AND reason <> 'missing')::bigint AS wanted, COUNT(*) FILTER (WHERE fulfilled_at IS NULL AND reason = 'missing')::bigint AS missing, COUNT(*) FILTER (WHERE fulfilled_at IS NOT NULL)::bigint AS held, (SELECT COUNT(*) FROM follows)::bigint AS following, -- The Wanted view's other tabs (#5522): downloads running, those -- waiting on a person, and releases set aside. (SELECT COUNT(*) FROM grabs WHERE ended_at IS NULL)::bigint AS activity, (SELECT COUNT(*) FROM grabs WHERE ended_at IS NULL AND import_state IN ('review', 'failed'))::bigint AS attention, (SELECT COUNT(*) FROM release_blocks)::bigint AS blocked FROM wants ` type CountWantsRow struct { Wanted int64 Missing int64 Held int64 Following int64 Activity int64 Attention int64 Blocked int64 } func (q *Queries) CountWants(ctx context.Context) (CountWantsRow, error) { row := q.db.QueryRow(ctx, countWants) var i CountWantsRow err := row.Scan( &i.Wanted, &i.Missing, &i.Held, &i.Following, &i.Activity, &i.Attention, &i.Blocked, ) return i, err } const createReleaseTypeProfile = `-- name: CreateReleaseTypeProfile :one INSERT INTO release_type_profiles (name, primary_types, secondary_types) VALUES ($1, $2, $3) RETURNING id, name, primary_types, secondary_types, is_default, created_at, updated_at ` type CreateReleaseTypeProfileParams struct { Name string PrimaryTypes []string SecondaryTypes []string } func (q *Queries) CreateReleaseTypeProfile(ctx context.Context, arg CreateReleaseTypeProfileParams) (ReleaseTypeProfile, error) { row := q.db.QueryRow(ctx, createReleaseTypeProfile, arg.Name, arg.PrimaryTypes, arg.SecondaryTypes) var i ReleaseTypeProfile err := row.Scan( &i.ID, &i.Name, &i.PrimaryTypes, &i.SecondaryTypes, &i.IsDefault, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const deleteFollow = `-- name: DeleteFollow :execrows DELETE FROM follows WHERE artist_mbid = $1 ` func (q *Queries) DeleteFollow(ctx context.Context, artistMbid string) (int64, error) { result, err := q.db.Exec(ctx, deleteFollow, artistMbid) if err != nil { return 0, err } return result.RowsAffected(), nil } const deleteReleaseTypeProfile = `-- name: DeleteReleaseTypeProfile :execrows DELETE FROM release_type_profiles WHERE id = $1 AND NOT is_default ` // The default stays; one in use is refused by the follows foreign key. func (q *Queries) DeleteReleaseTypeProfile(ctx context.Context, id pgtype.UUID) (int64, error) { result, err := q.db.Exec(ctx, deleteReleaseTypeProfile, id) if err != nil { return 0, err } return result.RowsAffected(), nil } const deleteWant = `-- name: DeleteWant :execrows DELETE FROM wants WHERE id = $1 ` func (q *Queries) DeleteWant(ctx context.Context, id pgtype.UUID) (int64, error) { result, err := q.db.Exec(ctx, deleteWant, id) if err != nil { return 0, err } return result.RowsAffected(), nil } const fulfillWant = `-- name: FulfillWant :exec UPDATE wants SET fulfilled_at = now(), album_id = $1, updated_at = now() WHERE id = $2 AND fulfilled_at IS NULL ` type FulfillWantParams struct { AlbumID pgtype.UUID ID pgtype.UUID } func (q *Queries) FulfillWant(ctx context.Context, arg FulfillWantParams) error { _, err := q.db.Exec(ctx, fulfillWant, arg.AlbumID, arg.ID) return err } const getDefaultReleaseTypeProfile = `-- name: GetDefaultReleaseTypeProfile :one SELECT id, name, primary_types, secondary_types, is_default, created_at, updated_at FROM release_type_profiles WHERE is_default ` func (q *Queries) GetDefaultReleaseTypeProfile(ctx context.Context) (ReleaseTypeProfile, error) { row := q.db.QueryRow(ctx, getDefaultReleaseTypeProfile) var i ReleaseTypeProfile err := row.Scan( &i.ID, &i.Name, &i.PrimaryTypes, &i.SecondaryTypes, &i.IsDefault, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const getFollow = `-- name: GetFollow :one SELECT f.artist_mbid, f.artist_name, f.profile_id, f.followed_by, f.followed_at, f.baseline_at, f.want_existing, f.checked_at, f.updated_at, p.name AS profile_name FROM follows f JOIN release_type_profiles p ON p.id = f.profile_id WHERE f.artist_mbid = $1 ` type GetFollowRow struct { ArtistMbid string ArtistName string ProfileID pgtype.UUID FollowedBy pgtype.UUID FollowedAt pgtype.Timestamptz BaselineAt pgtype.Timestamptz WantExisting bool CheckedAt pgtype.Timestamptz UpdatedAt pgtype.Timestamptz ProfileName string } func (q *Queries) GetFollow(ctx context.Context, artistMbid string) (GetFollowRow, error) { row := q.db.QueryRow(ctx, getFollow, artistMbid) var i GetFollowRow err := row.Scan( &i.ArtistMbid, &i.ArtistName, &i.ProfileID, &i.FollowedBy, &i.FollowedAt, &i.BaselineAt, &i.WantExisting, &i.CheckedAt, &i.UpdatedAt, &i.ProfileName, ) return i, err } const getReleaseTypeProfile = `-- name: GetReleaseTypeProfile :one SELECT id, name, primary_types, secondary_types, is_default, created_at, updated_at FROM release_type_profiles WHERE id = $1 ` func (q *Queries) GetReleaseTypeProfile(ctx context.Context, id pgtype.UUID) (ReleaseTypeProfile, error) { row := q.db.QueryRow(ctx, getReleaseTypeProfile, id) var i ReleaseTypeProfile err := row.Scan( &i.ID, &i.Name, &i.PrimaryTypes, &i.SecondaryTypes, &i.IsDefault, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const getWantByReleaseGroup = `-- name: GetWantByReleaseGroup :one SELECT id, release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, album_id, created_by, wanted_at, fulfilled_at, created_at, updated_at, searched_at, search_outcome, search_considered, best_release, best_verdict, search_error FROM wants WHERE release_group_mbid = $1 ` func (q *Queries) GetWantByReleaseGroup(ctx context.Context, releaseGroupMbid string) (Want, error) { row := q.db.QueryRow(ctx, getWantByReleaseGroup, releaseGroupMbid) var i Want err := row.Scan( &i.ID, &i.ReleaseGroupMbid, &i.ArtistMbid, &i.ArtistName, &i.Title, &i.PrimaryType, &i.FirstReleaseDate, &i.Reason, &i.AlbumID, &i.CreatedBy, &i.WantedAt, &i.FulfilledAt, &i.CreatedAt, &i.UpdatedAt, &i.SearchedAt, &i.SearchOutcome, &i.SearchConsidered, &i.BestRelease, &i.BestVerdict, &i.SearchError, ) return i, err } const libraryHoldsReleaseGroup = `-- name: LibraryHoldsReleaseGroup :one SELECT EXISTS ( SELECT 1 FROM albums a WHERE (a.release_group_mbid = $1::text OR a.mbid = $1 OR a.mbid IN (SELECT r.mbid FROM mb_releases r WHERE r.release_group_mbid = $1) OR (lower(a.title) = lower($2::text) AND a.artist_id IN (SELECT ar.id FROM artists ar WHERE ar.mbid = $3::text))) AND EXISTS (SELECT 1 FROM tracks t WHERE t.album_id = a.id AND t.missing_since IS NULL) ) ` type LibraryHoldsReleaseGroupParams struct { GroupMbid string Title string ArtistMbid string } // Whether the library already has the group: an album tagged with it or // with one of its releases, or failing that an album of the artist's with // the same title. Only albums with a track on disk count. func (q *Queries) LibraryHoldsReleaseGroup(ctx context.Context, arg LibraryHoldsReleaseGroupParams) (bool, error) { row := q.db.QueryRow(ctx, libraryHoldsReleaseGroup, arg.GroupMbid, arg.Title, arg.ArtistMbid) var exists bool err := row.Scan(&exists) return exists, err } const listFollowGroups = `-- name: ListFollowGroups :many SELECT g.mbid, g.title, g.primary_type, g.secondary_types, g.first_release_date, EXISTS (SELECT 1 FROM follow_seen_groups s WHERE s.artist_mbid = $1 AND s.release_group_mbid = g.mbid) AS seen FROM mb_artist_release_groups ag JOIN mb_release_groups g ON g.mbid = ag.release_group_mbid WHERE ag.artist_mbid = $1 ORDER BY g.first_release_date, g.title ` type ListFollowGroupsRow struct { Mbid string Title string PrimaryType string SecondaryTypes []string FirstReleaseDate string Seen bool } // An artist's release groups from the catalogue, each with whether the // follow has judged it before. func (q *Queries) ListFollowGroups(ctx context.Context, artistMbid string) ([]ListFollowGroupsRow, error) { rows, err := q.db.Query(ctx, listFollowGroups, artistMbid) if err != nil { return nil, err } defer rows.Close() var items []ListFollowGroupsRow for rows.Next() { var i ListFollowGroupsRow if err := rows.Scan( &i.Mbid, &i.Title, &i.PrimaryType, &i.SecondaryTypes, &i.FirstReleaseDate, &i.Seen, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listFollows = `-- name: ListFollows :many SELECT f.artist_mbid, f.artist_name, f.profile_id, f.followed_at, f.baseline_at, f.checked_at, p.name AS profile_name, (SELECT a.id FROM artists a WHERE a.mbid = f.artist_mbid) AS artist_id, (SELECT COUNT(*) FROM wants w WHERE w.artist_mbid = f.artist_mbid AND w.fulfilled_at IS NULL)::bigint AS open_wants FROM follows f JOIN release_type_profiles p ON p.id = f.profile_id ORDER BY lower(f.artist_name), f.artist_mbid ` type ListFollowsRow struct { ArtistMbid string ArtistName string ProfileID pgtype.UUID FollowedAt pgtype.Timestamptz BaselineAt pgtype.Timestamptz CheckedAt pgtype.Timestamptz ProfileName string ArtistID pgtype.UUID OpenWants int64 } func (q *Queries) ListFollows(ctx context.Context) ([]ListFollowsRow, error) { rows, err := q.db.Query(ctx, listFollows) if err != nil { return nil, err } defer rows.Close() var items []ListFollowsRow for rows.Next() { var i ListFollowsRow if err := rows.Scan( &i.ArtistMbid, &i.ArtistName, &i.ProfileID, &i.FollowedAt, &i.BaselineAt, &i.CheckedAt, &i.ProfileName, &i.ArtistID, &i.OpenWants, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listFollowsDue = `-- name: ListFollowsDue :many SELECT f.artist_mbid, f.artist_name, f.profile_id, f.followed_by, f.followed_at, f.baseline_at, f.want_existing, f.checked_at, f.updated_at FROM follows f WHERE f.baseline_at IS NULL OR f.checked_at IS NULL OR f.checked_at < $1 ORDER BY f.baseline_at NULLS FIRST, f.checked_at NULLS FIRST, f.artist_mbid LIMIT $2 ` type ListFollowsDueParams struct { Before pgtype.Timestamptz MaxRows int32 } // Follows whose discography has not been applied since @before, never-read // first, so a new follow's baseline is not stuck behind daily re-checks. func (q *Queries) ListFollowsDue(ctx context.Context, arg ListFollowsDueParams) ([]Follow, error) { rows, err := q.db.Query(ctx, listFollowsDue, arg.Before, arg.MaxRows) if err != nil { return nil, err } defer rows.Close() var items []Follow for rows.Next() { var i Follow if err := rows.Scan( &i.ArtistMbid, &i.ArtistName, &i.ProfileID, &i.FollowedBy, &i.FollowedAt, &i.BaselineAt, &i.WantExisting, &i.CheckedAt, &i.UpdatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listOpenWants = `-- name: ListOpenWants :many SELECT id, release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, album_id, created_by, wanted_at, fulfilled_at, created_at, updated_at, searched_at, search_outcome, search_considered, best_release, best_verdict, search_error FROM wants WHERE fulfilled_at IS NULL ORDER BY wanted_at, id LIMIT $1 ` func (q *Queries) ListOpenWants(ctx context.Context, limit int32) ([]Want, error) { rows, err := q.db.Query(ctx, listOpenWants, limit) if err != nil { return nil, err } defer rows.Close() var items []Want for rows.Next() { var i Want if err := rows.Scan( &i.ID, &i.ReleaseGroupMbid, &i.ArtistMbid, &i.ArtistName, &i.Title, &i.PrimaryType, &i.FirstReleaseDate, &i.Reason, &i.AlbumID, &i.CreatedBy, &i.WantedAt, &i.FulfilledAt, &i.CreatedAt, &i.UpdatedAt, &i.SearchedAt, &i.SearchOutcome, &i.SearchConsidered, &i.BestRelease, &i.BestVerdict, &i.SearchError, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listReleaseTypeProfiles = `-- name: ListReleaseTypeProfiles :many SELECT p.id, p.name, p.primary_types, p.secondary_types, p.is_default, p.created_at, p.updated_at, (SELECT COUNT(*) FROM follows f WHERE f.profile_id = p.id)::bigint AS follow_count FROM release_type_profiles p ORDER BY p.is_default DESC, p.name ` type ListReleaseTypeProfilesRow struct { ID pgtype.UUID Name string PrimaryTypes []string SecondaryTypes []string IsDefault bool CreatedAt pgtype.Timestamptz UpdatedAt pgtype.Timestamptz FollowCount int64 } // The wanted list (M502 #5520): release-type profiles, follows and wants. func (q *Queries) ListReleaseTypeProfiles(ctx context.Context) ([]ListReleaseTypeProfilesRow, error) { rows, err := q.db.Query(ctx, listReleaseTypeProfiles) if err != nil { return nil, err } defer rows.Close() var items []ListReleaseTypeProfilesRow for rows.Next() { var i ListReleaseTypeProfilesRow if err := rows.Scan( &i.ID, &i.Name, &i.PrimaryTypes, &i.SecondaryTypes, &i.IsDefault, &i.CreatedAt, &i.UpdatedAt, &i.FollowCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listWants = `-- name: ListWants :many SELECT w.id, w.release_group_mbid, w.artist_mbid, w.artist_name, w.title, w.reason, w.album_id, w.wanted_at, w.fulfilled_at, -- A request names an album before the catalogue has read it: the -- catalogue's type and date fill in once it has. COALESCE(NULLIF(w.primary_type, ''), g.primary_type, '')::text AS primary_type, COALESCE(g.secondary_types, '{}')::text[] AS secondary_types, COALESCE(NULLIF(w.first_release_date, ''), g.first_release_date, '')::text AS first_release_date, u.username AS requested_by, (SELECT ar.id FROM artists ar WHERE ar.mbid = w.artist_mbid) AS library_artist_id, -- The search schedule's last look (#5521), and the download running. w.searched_at, w.search_outcome, w.search_considered, w.best_release, w.best_verdict, w.search_error, -- Its latest download, running or ended, and what the import made of -- it (#5522). gr.id AS grab_id, gr.name AS grab_name, gr.grabbed_at, gr.origin AS grab_origin, gr.quality AS grab_quality, gr.ended_at AS grab_ended_at, gr.end_reason AS grab_end_reason, gr.progress AS grab_progress, gr.import_state AS grab_import_state, gr.import_reason AS grab_import_reason, gr.imported_at AS grab_imported_at, gr.imported_files AS grab_imported_files FROM wants w LEFT JOIN users u ON u.id = w.created_by LEFT JOIN mb_release_groups g ON g.mbid = w.release_group_mbid LEFT JOIN grabs gr ON gr.id = (SELECT x.id FROM grabs x WHERE x.want_id = w.id ORDER BY x.ended_at IS NULL DESC, x.grabbed_at DESC LIMIT 1) WHERE CASE $1::text WHEN 'held' THEN w.fulfilled_at IS NOT NULL WHEN 'missing' THEN w.fulfilled_at IS NULL AND w.reason = 'missing' ELSE w.fulfilled_at IS NULL AND w.reason <> 'missing' END ORDER BY COALESCE(w.fulfilled_at, w.wanted_at) DESC, w.id LIMIT $3 OFFSET $2 ` type ListWantsParams struct { State string Skip int32 MaxRows int32 } type ListWantsRow struct { ID pgtype.UUID ReleaseGroupMbid string ArtistMbid string ArtistName string Title string Reason string AlbumID pgtype.UUID WantedAt pgtype.Timestamptz FulfilledAt pgtype.Timestamptz PrimaryType string SecondaryTypes []string FirstReleaseDate string RequestedBy *string LibraryArtistID pgtype.UUID SearchedAt pgtype.Timestamptz SearchOutcome string SearchConsidered int32 BestRelease string BestVerdict string SearchError string GrabID pgtype.UUID GrabName *string GrabbedAt pgtype.Timestamptz GrabOrigin *string GrabQuality *string GrabEndedAt pgtype.Timestamptz GrabEndReason *string GrabProgress *float32 GrabImportState *string GrabImportReason *string GrabImportedAt pgtype.Timestamptz GrabImportedFiles *int32 } // The Wanted page: open wants (all but missing ones, or only missing ones), // or what was held most recently. func (q *Queries) ListWants(ctx context.Context, arg ListWantsParams) ([]ListWantsRow, error) { rows, err := q.db.Query(ctx, listWants, arg.State, arg.Skip, arg.MaxRows) if err != nil { return nil, err } defer rows.Close() var items []ListWantsRow for rows.Next() { var i ListWantsRow if err := rows.Scan( &i.ID, &i.ReleaseGroupMbid, &i.ArtistMbid, &i.ArtistName, &i.Title, &i.Reason, &i.AlbumID, &i.WantedAt, &i.FulfilledAt, &i.PrimaryType, &i.SecondaryTypes, &i.FirstReleaseDate, &i.RequestedBy, &i.LibraryArtistID, &i.SearchedAt, &i.SearchOutcome, &i.SearchConsidered, &i.BestRelease, &i.BestVerdict, &i.SearchError, &i.GrabID, &i.GrabName, &i.GrabbedAt, &i.GrabOrigin, &i.GrabQuality, &i.GrabEndedAt, &i.GrabEndReason, &i.GrabProgress, &i.GrabImportState, &i.GrabImportReason, &i.GrabImportedAt, &i.GrabImportedFiles, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const markFollowChecked = `-- name: MarkFollowChecked :exec UPDATE follows SET checked_at = now(), baseline_at = COALESCE(baseline_at, now()), want_existing = false, updated_at = now() WHERE artist_mbid = $1 ` func (q *Queries) MarkFollowChecked(ctx context.Context, artistMbid string) error { _, err := q.db.Exec(ctx, markFollowChecked, artistMbid) return err } const markGroupSeen = `-- name: MarkGroupSeen :exec INSERT INTO follow_seen_groups (artist_mbid, release_group_mbid) VALUES ($1, $2) ON CONFLICT DO NOTHING ` type MarkGroupSeenParams struct { ArtistMbid string ReleaseGroupMbid string } func (q *Queries) MarkGroupSeen(ctx context.Context, arg MarkGroupSeenParams) error { _, err := q.db.Exec(ctx, markGroupSeen, arg.ArtistMbid, arg.ReleaseGroupMbid) return err } const repointWant = `-- name: RepointWant :exec UPDATE wants SET release_group_mbid = $2, updated_at = now() WHERE id = $1 ` type RepointWantParams struct { ID pgtype.UUID ReleaseGroupMbid string } // A want recorded under a release id before #5241 is moved to its group. func (q *Queries) RepointWant(ctx context.Context, arg RepointWantParams) error { _, err := q.db.Exec(ctx, repointWant, arg.ID, arg.ReleaseGroupMbid) return err } const setDefaultReleaseTypeProfile = `-- name: SetDefaultReleaseTypeProfile :execrows UPDATE release_type_profiles SET is_default = true, updated_at = now() WHERE id = $1 ` func (q *Queries) SetDefaultReleaseTypeProfile(ctx context.Context, id pgtype.UUID) (int64, error) { result, err := q.db.Exec(ctx, setDefaultReleaseTypeProfile, id) if err != nil { return 0, err } return result.RowsAffected(), nil } const updateReleaseTypeProfile = `-- name: UpdateReleaseTypeProfile :one UPDATE release_type_profiles SET name = $2, primary_types = $3, secondary_types = $4, updated_at = now() WHERE id = $1 RETURNING id, name, primary_types, secondary_types, is_default, created_at, updated_at ` type UpdateReleaseTypeProfileParams struct { ID pgtype.UUID Name string PrimaryTypes []string SecondaryTypes []string } func (q *Queries) UpdateReleaseTypeProfile(ctx context.Context, arg UpdateReleaseTypeProfileParams) (ReleaseTypeProfile, error) { row := q.db.QueryRow(ctx, updateReleaseTypeProfile, arg.ID, arg.Name, arg.PrimaryTypes, arg.SecondaryTypes, ) var i ReleaseTypeProfile err := row.Scan( &i.ID, &i.Name, &i.PrimaryTypes, &i.SecondaryTypes, &i.IsDefault, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const upsertFollow = `-- name: UpsertFollow :one INSERT INTO follows (artist_mbid, artist_name, profile_id, followed_by, want_existing) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (artist_mbid) DO UPDATE SET artist_name = EXCLUDED.artist_name, profile_id = EXCLUDED.profile_id, want_existing = follows.want_existing OR EXCLUDED.want_existing, baseline_at = CASE WHEN EXCLUDED.want_existing THEN NULL ELSE follows.baseline_at END, updated_at = now() RETURNING artist_mbid, artist_name, profile_id, followed_by, followed_at, baseline_at, want_existing, checked_at, updated_at ` type UpsertFollowParams struct { ArtistMbid string ArtistName string ProfileID pgtype.UUID FollowedBy pgtype.UUID WantExisting bool } // Following an artist already followed changes its profile. want_existing // only ever turns on here; the worker turns it off once applied, and turning // it on again re-reads the baseline so the existing releases are judged. func (q *Queries) UpsertFollow(ctx context.Context, arg UpsertFollowParams) (Follow, error) { row := q.db.QueryRow(ctx, upsertFollow, arg.ArtistMbid, arg.ArtistName, arg.ProfileID, arg.FollowedBy, arg.WantExisting, ) var i Follow err := row.Scan( &i.ArtistMbid, &i.ArtistName, &i.ProfileID, &i.FollowedBy, &i.FollowedAt, &i.BaselineAt, &i.WantExisting, &i.CheckedAt, &i.UpdatedAt, ) return i, err } const wantHoldings = `-- name: WantHoldings :many SELECT a.id AS album_id, COUNT(*) FILTER (WHERE t.missing_since IS NULL)::int AS present, COALESCE(bool_or(t.missing_since IS NULL AND t.added_at > $1::timestamptz), false)::bool AS arrived_since, COALESCE(bool_or(t.missing_since IS NOT NULL AND t.missing_since < $1::timestamptz), false)::bool AS missing_before, -- Missing tracks no track on disk stands in for, by position or -- title. A missing row whose song is back at a new path (#5245) is -- covered; a lost bonus track is not. COUNT(*) FILTER (WHERE t.missing_since IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tracks p WHERE p.album_id = a.id AND p.missing_since IS NULL AND ((p.track_number = t.track_number AND p.disc_number IS NOT DISTINCT FROM t.disc_number) OR lower(p.title) = lower(t.title))))::int AS uncovered_missing FROM albums a JOIN tracks t ON t.album_id = a.id WHERE a.release_group_mbid = $2::text OR a.mbid = $2 OR a.id = $3 OR a.mbid IN (SELECT r.mbid FROM mb_releases r WHERE r.release_group_mbid = $2) GROUP BY a.id ORDER BY present DESC, a.id ` type WantHoldingsParams struct { Since pgtype.Timestamptz GroupMbid string AlbumID pgtype.UUID } type WantHoldingsRow struct { AlbumID pgtype.UUID Present int32 ArrivedSince bool MissingBefore bool UncoveredMissing int32 } // Each library album that may answer a want, with what it has on disk: // tracks present, whether one arrived since the want, and whether a track // missing before the want is still missing. func (q *Queries) WantHoldings(ctx context.Context, arg WantHoldingsParams) ([]WantHoldingsRow, error) { rows, err := q.db.Query(ctx, wantHoldings, arg.Since, arg.GroupMbid, arg.AlbumID) if err != nil { return nil, err } defer rows.Close() var items []WantHoldingsRow for rows.Next() { var i WantHoldingsRow if err := rows.Scan( &i.AlbumID, &i.Present, &i.ArrivedSince, &i.MissingBefore, &i.UncoveredMissing, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const wantReleaseGroup = `-- name: WantReleaseGroup :one INSERT INTO wants (release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, created_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (release_group_mbid) DO UPDATE SET updated_at = wants.updated_at RETURNING id, release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, album_id, created_by, wanted_at, fulfilled_at, created_at, updated_at, searched_at, search_outcome, search_considered, best_release, best_verdict, search_error ` type WantReleaseGroupParams struct { ReleaseGroupMbid string ArtistMbid string ArtistName string Title string PrimaryType string FirstReleaseDate string Reason string CreatedBy pgtype.UUID } // Wants a release group, or returns the want already recorded for it. A // held want is not reopened here: the library has it. func (q *Queries) WantReleaseGroup(ctx context.Context, arg WantReleaseGroupParams) (Want, error) { row := q.db.QueryRow(ctx, wantReleaseGroup, arg.ReleaseGroupMbid, arg.ArtistMbid, arg.ArtistName, arg.Title, arg.PrimaryType, arg.FirstReleaseDate, arg.Reason, arg.CreatedBy, ) var i Want err := row.Scan( &i.ID, &i.ReleaseGroupMbid, &i.ArtistMbid, &i.ArtistName, &i.Title, &i.PrimaryType, &i.FirstReleaseDate, &i.Reason, &i.AlbumID, &i.CreatedBy, &i.WantedAt, &i.FulfilledAt, &i.CreatedAt, &i.UpdatedAt, &i.SearchedAt, &i.SearchOutcome, &i.SearchConsidered, &i.BestRelease, &i.BestVerdict, &i.SearchError, ) return i, err }