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>
142 lines
6.9 KiB
SQL
142 lines
6.9 KiB
SQL
-- Searching for wants and grabbing releases.
|
|
|
|
-- name: GetAcquisitionSettings :one
|
|
SELECT * FROM acquisition_settings WHERE id = true;
|
|
|
|
-- name: UpdateAcquisitionSettings :one
|
|
UPDATE acquisition_settings
|
|
SET auto_grab = sqlc.arg(auto_grab),
|
|
search_interval_hours = sqlc.arg(search_interval_hours),
|
|
allowed_qualities = sqlc.arg(allowed_qualities),
|
|
import_root = sqlc.arg(import_root),
|
|
seed_ratio = sqlc.arg(seed_ratio),
|
|
seed_days = sqlc.arg(seed_days),
|
|
stall_hours = sqlc.arg(stall_hours),
|
|
upgrade_until = sqlc.arg(upgrade_until),
|
|
updated_at = now()
|
|
WHERE id = true
|
|
RETURNING *;
|
|
|
|
-- name: RecordSearchPass :exec
|
|
UPDATE acquisition_settings SET last_pass_at = now(), last_pass = sqlc.arg(report) WHERE id = true;
|
|
|
|
-- name: ListWantsDueForSearch :many
|
|
-- Wants with no download running that were never searched or not since
|
|
-- @hours ago: open wants first (never-searched, then requests, then missing
|
|
-- files, then followed artists' releases), then held albums wanted for an
|
|
-- upgrade, which are searched at most weekly.
|
|
SELECT w.id, w.release_group_mbid, w.artist_name, w.title, w.reason, w.upgrade, w.held_tier, w.held_quality,
|
|
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
|
|
FROM wants w
|
|
LEFT JOIN mb_release_groups g ON g.mbid = w.release_group_mbid
|
|
WHERE (w.fulfilled_at IS NULL OR w.upgrade <> '')
|
|
AND NOT EXISTS (SELECT 1 FROM grabs gr WHERE gr.want_id = w.id AND gr.ended_at IS NULL)
|
|
AND (w.searched_at IS NULL
|
|
OR w.searched_at < now() - make_interval(hours => CASE WHEN w.fulfilled_at IS NULL
|
|
THEN sqlc.arg(hours)::int
|
|
ELSE GREATEST(sqlc.arg(hours)::int, 168) END))
|
|
ORDER BY w.fulfilled_at IS NOT NULL,
|
|
w.searched_at IS NOT NULL,
|
|
CASE w.reason WHEN 'request' THEN 0 WHEN 'missing' THEN 1 ELSE 2 END,
|
|
w.searched_at NULLS FIRST, w.wanted_at, w.id
|
|
LIMIT sqlc.arg(max_rows);
|
|
|
|
-- name: GetWantForSearch :one
|
|
SELECT w.id, w.release_group_mbid, w.artist_mbid, w.artist_name, w.title, w.reason, w.fulfilled_at,
|
|
w.upgrade, w.held_tier, w.held_quality, w.album_id,
|
|
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
|
|
FROM wants w
|
|
LEFT JOIN mb_release_groups g ON g.mbid = w.release_group_mbid
|
|
WHERE w.id = $1;
|
|
|
|
-- name: EditionTrackSpan :one
|
|
-- The fewest tracks an official edition of the group has (any edition when
|
|
-- none is official), and the most any has. Zero when none is catalogued.
|
|
SELECT COALESCE(MIN(track_count) FILTER (WHERE status = 'Official'), MIN(track_count), 0)::int AS min_tracks,
|
|
COALESCE(MAX(track_count), 0)::int AS max_tracks
|
|
FROM mb_releases
|
|
WHERE release_group_mbid = $1 AND track_count > 0;
|
|
|
|
-- name: RecordWantSearch :exec
|
|
UPDATE wants
|
|
SET searched_at = now(),
|
|
search_outcome = sqlc.arg(outcome),
|
|
search_considered = sqlc.arg(considered),
|
|
best_release = sqlc.arg(best_release),
|
|
best_verdict = sqlc.arg(best_verdict),
|
|
search_error = sqlc.arg(search_error),
|
|
updated_at = now()
|
|
WHERE id = sqlc.arg(id);
|
|
|
|
-- name: DeleteWantCandidates :exec
|
|
DELETE FROM want_candidates WHERE want_id = $1;
|
|
|
|
-- name: InsertWantCandidate :exec
|
|
INSERT INTO want_candidates (want_id, key, name, info_hash, indexer, source, size_bytes, seeders,
|
|
files_count, format, quality, year, verdict, reason, reasons, folded_from, rank)
|
|
VALUES (sqlc.arg(want_id), sqlc.arg(key), sqlc.arg(name), sqlc.arg(info_hash), sqlc.arg(indexer),
|
|
sqlc.arg(source), sqlc.arg(size_bytes), sqlc.arg(seeders), sqlc.arg(files_count), sqlc.arg(format),
|
|
sqlc.arg(quality), sqlc.arg(year), sqlc.arg(verdict), sqlc.arg(reason), sqlc.arg(reasons),
|
|
sqlc.arg(folded_from), sqlc.arg(rank))
|
|
ON CONFLICT (want_id, key) DO NOTHING;
|
|
|
|
-- name: ListWantCandidates :many
|
|
SELECT * FROM want_candidates WHERE want_id = $1 ORDER BY rank, key;
|
|
|
|
-- name: GetWantCandidate :one
|
|
SELECT * FROM want_candidates WHERE want_id = $1 AND key = $2;
|
|
|
|
-- name: MarkCandidatesBlocked :exec
|
|
UPDATE want_candidates
|
|
SET verdict = 'blocked', reason = sqlc.arg(reason),
|
|
reasons = jsonb_build_array(jsonb_build_object('kind', 'hard', 'code', 'blocked', 'text', sqlc.arg(reason)::text))
|
|
WHERE info_hash = sqlc.arg(info_hash);
|
|
|
|
-- name: MarkCandidatesUnblocked :exec
|
|
UPDATE want_candidates
|
|
SET verdict = 'review', reason = sqlc.arg(reason),
|
|
reasons = jsonb_build_array(jsonb_build_object('kind', 'soft', 'code', 'unblocked', 'text', sqlc.arg(reason)::text))
|
|
WHERE info_hash = sqlc.arg(info_hash) AND verdict = 'blocked';
|
|
|
|
-- name: GetLiveGrab :one
|
|
SELECT * FROM grabs WHERE want_id = $1 AND ended_at IS NULL;
|
|
|
|
-- name: InsertGrab :one
|
|
INSERT INTO grabs (want_id, info_hash, name, key, indexer, source, client, save_path, quality,
|
|
origin, forced, grabbed_by)
|
|
VALUES (sqlc.narg(want_id), sqlc.arg(info_hash), sqlc.arg(name), sqlc.arg(key), sqlc.arg(indexer),
|
|
sqlc.arg(source), sqlc.arg(client), sqlc.arg(save_path), sqlc.arg(quality),
|
|
sqlc.arg(origin), sqlc.arg(forced), sqlc.narg(grabbed_by))
|
|
RETURNING *;
|
|
|
|
-- name: EndGrab :exec
|
|
UPDATE grabs
|
|
SET ended_at = now(), end_reason = sqlc.arg(end_reason), end_detail = sqlc.arg(end_detail)
|
|
WHERE id = sqlc.arg(id) AND ended_at IS NULL;
|
|
|
|
-- name: ListReleaseBlocks :many
|
|
-- Every release set aside and still held back: a stalled one lifts by itself
|
|
-- at expires_at.
|
|
SELECT * FROM release_blocks
|
|
WHERE expires_at IS NULL OR expires_at > now()
|
|
ORDER BY blocked_at DESC;
|
|
|
|
-- name: BlockRelease :exec
|
|
-- A release set aside. expires_at NULL is for good. A block for good is never
|
|
-- shortened by a timed one: only a timed block, or another for good, is
|
|
-- replaced.
|
|
INSERT INTO release_blocks (info_hash, name, reason, detail, want_id, blocked_by, expires_at)
|
|
VALUES (sqlc.arg(info_hash), sqlc.arg(name), sqlc.arg(reason), sqlc.arg(detail),
|
|
sqlc.narg(want_id), sqlc.narg(blocked_by), sqlc.narg(expires_at))
|
|
ON CONFLICT (info_hash) DO UPDATE
|
|
SET reason = EXCLUDED.reason, detail = EXCLUDED.detail, blocked_at = now(),
|
|
expires_at = EXCLUDED.expires_at, blocked_by = EXCLUDED.blocked_by
|
|
WHERE release_blocks.expires_at IS NOT NULL OR EXCLUDED.expires_at IS NULL;
|
|
|
|
-- name: UnblockRelease :execrows
|
|
DELETE FROM release_blocks WHERE info_hash = $1;
|