feat(db): add lidarr_config + lidarr_requests schema (migration 0010)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: albums.sql
|
// source: albums.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: artists.sql
|
// source: artists.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: contextual_likes.sql
|
// source: contextual_likes.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: events.sql
|
// source: events.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: lidarr_config.sql
|
||||||
|
|
||||||
|
package dbq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const getLidarrConfig = `-- name: GetLidarrConfig :one
|
||||||
|
SELECT id, enabled, base_url, api_key, default_quality_profile_id,
|
||||||
|
default_root_folder_path, created_at, updated_at
|
||||||
|
FROM lidarr_config
|
||||||
|
WHERE id = 1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetLidarrConfig(ctx context.Context) (LidarrConfig, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getLidarrConfig)
|
||||||
|
var i LidarrConfig
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Enabled,
|
||||||
|
&i.BaseUrl,
|
||||||
|
&i.ApiKey,
|
||||||
|
&i.DefaultQualityProfileID,
|
||||||
|
&i.DefaultRootFolderPath,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateLidarrConfig = `-- name: UpdateLidarrConfig :one
|
||||||
|
UPDATE lidarr_config
|
||||||
|
SET enabled = $1,
|
||||||
|
base_url = $2,
|
||||||
|
api_key = $3,
|
||||||
|
default_quality_profile_id = $4,
|
||||||
|
default_root_folder_path = $5,
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = 1
|
||||||
|
RETURNING id, enabled, base_url, api_key, default_quality_profile_id,
|
||||||
|
default_root_folder_path, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateLidarrConfigParams struct {
|
||||||
|
Enabled bool
|
||||||
|
BaseUrl *string
|
||||||
|
ApiKey *string
|
||||||
|
DefaultQualityProfileID *int32
|
||||||
|
DefaultRootFolderPath *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateLidarrConfig(ctx context.Context, arg UpdateLidarrConfigParams) (LidarrConfig, error) {
|
||||||
|
row := q.db.QueryRow(ctx, updateLidarrConfig,
|
||||||
|
arg.Enabled,
|
||||||
|
arg.BaseUrl,
|
||||||
|
arg.ApiKey,
|
||||||
|
arg.DefaultQualityProfileID,
|
||||||
|
arg.DefaultRootFolderPath,
|
||||||
|
)
|
||||||
|
var i LidarrConfig
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Enabled,
|
||||||
|
&i.BaseUrl,
|
||||||
|
&i.ApiKey,
|
||||||
|
&i.DefaultQualityProfileID,
|
||||||
|
&i.DefaultRootFolderPath,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,480 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: lidarr_requests.sql
|
||||||
|
|
||||||
|
package dbq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const approveLidarrRequest = `-- name: ApproveLidarrRequest :one
|
||||||
|
UPDATE lidarr_requests
|
||||||
|
SET status = 'approved',
|
||||||
|
quality_profile_id = $2,
|
||||||
|
root_folder_path = $3,
|
||||||
|
decided_at = now(),
|
||||||
|
decided_by = $4,
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = $1 AND status = 'pending'
|
||||||
|
RETURNING id, user_id, status, kind, lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid, artist_name, album_title, track_title, quality_profile_id, root_folder_path, decided_at, decided_by, notes, completed_at, matched_track_id, matched_album_id, matched_artist_id, requested_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type ApproveLidarrRequestParams struct {
|
||||||
|
ID pgtype.UUID
|
||||||
|
QualityProfileID *int32
|
||||||
|
RootFolderPath *string
|
||||||
|
DecidedBy pgtype.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ApproveLidarrRequest(ctx context.Context, arg ApproveLidarrRequestParams) (LidarrRequest, error) {
|
||||||
|
row := q.db.QueryRow(ctx, approveLidarrRequest,
|
||||||
|
arg.ID,
|
||||||
|
arg.QualityProfileID,
|
||||||
|
arg.RootFolderPath,
|
||||||
|
arg.DecidedBy,
|
||||||
|
)
|
||||||
|
var i LidarrRequest
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Kind,
|
||||||
|
&i.LidarrArtistMbid,
|
||||||
|
&i.LidarrAlbumMbid,
|
||||||
|
&i.LidarrTrackMbid,
|
||||||
|
&i.ArtistName,
|
||||||
|
&i.AlbumTitle,
|
||||||
|
&i.TrackTitle,
|
||||||
|
&i.QualityProfileID,
|
||||||
|
&i.RootFolderPath,
|
||||||
|
&i.DecidedAt,
|
||||||
|
&i.DecidedBy,
|
||||||
|
&i.Notes,
|
||||||
|
&i.CompletedAt,
|
||||||
|
&i.MatchedTrackID,
|
||||||
|
&i.MatchedAlbumID,
|
||||||
|
&i.MatchedArtistID,
|
||||||
|
&i.RequestedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelLidarrRequest = `-- name: CancelLidarrRequest :one
|
||||||
|
UPDATE lidarr_requests
|
||||||
|
SET status = 'rejected',
|
||||||
|
notes = 'cancelled by user',
|
||||||
|
decided_at = now(),
|
||||||
|
decided_by = $2,
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = $1 AND user_id = $2 AND status = 'pending'
|
||||||
|
RETURNING id, user_id, status, kind, lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid, artist_name, album_title, track_title, quality_profile_id, root_folder_path, decided_at, decided_by, notes, completed_at, matched_track_id, matched_album_id, matched_artist_id, requested_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CancelLidarrRequestParams struct {
|
||||||
|
ID pgtype.UUID
|
||||||
|
DecidedBy pgtype.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CancelLidarrRequest(ctx context.Context, arg CancelLidarrRequestParams) (LidarrRequest, error) {
|
||||||
|
row := q.db.QueryRow(ctx, cancelLidarrRequest, arg.ID, arg.DecidedBy)
|
||||||
|
var i LidarrRequest
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Kind,
|
||||||
|
&i.LidarrArtistMbid,
|
||||||
|
&i.LidarrAlbumMbid,
|
||||||
|
&i.LidarrTrackMbid,
|
||||||
|
&i.ArtistName,
|
||||||
|
&i.AlbumTitle,
|
||||||
|
&i.TrackTitle,
|
||||||
|
&i.QualityProfileID,
|
||||||
|
&i.RootFolderPath,
|
||||||
|
&i.DecidedAt,
|
||||||
|
&i.DecidedBy,
|
||||||
|
&i.Notes,
|
||||||
|
&i.CompletedAt,
|
||||||
|
&i.MatchedTrackID,
|
||||||
|
&i.MatchedAlbumID,
|
||||||
|
&i.MatchedArtistID,
|
||||||
|
&i.RequestedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const completeLidarrRequest = `-- name: CompleteLidarrRequest :one
|
||||||
|
UPDATE lidarr_requests
|
||||||
|
SET status = 'completed',
|
||||||
|
matched_track_id = $2,
|
||||||
|
matched_album_id = $3,
|
||||||
|
matched_artist_id = $4,
|
||||||
|
completed_at = now(),
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = $1 AND status = 'approved'
|
||||||
|
RETURNING id, user_id, status, kind, lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid, artist_name, album_title, track_title, quality_profile_id, root_folder_path, decided_at, decided_by, notes, completed_at, matched_track_id, matched_album_id, matched_artist_id, requested_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CompleteLidarrRequestParams struct {
|
||||||
|
ID pgtype.UUID
|
||||||
|
MatchedTrackID pgtype.UUID
|
||||||
|
MatchedAlbumID pgtype.UUID
|
||||||
|
MatchedArtistID pgtype.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconciler transitions an approved request to completed when its
|
||||||
|
// target track/album/artist has appeared in the library.
|
||||||
|
func (q *Queries) CompleteLidarrRequest(ctx context.Context, arg CompleteLidarrRequestParams) (LidarrRequest, error) {
|
||||||
|
row := q.db.QueryRow(ctx, completeLidarrRequest,
|
||||||
|
arg.ID,
|
||||||
|
arg.MatchedTrackID,
|
||||||
|
arg.MatchedAlbumID,
|
||||||
|
arg.MatchedArtistID,
|
||||||
|
)
|
||||||
|
var i LidarrRequest
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Kind,
|
||||||
|
&i.LidarrArtistMbid,
|
||||||
|
&i.LidarrAlbumMbid,
|
||||||
|
&i.LidarrTrackMbid,
|
||||||
|
&i.ArtistName,
|
||||||
|
&i.AlbumTitle,
|
||||||
|
&i.TrackTitle,
|
||||||
|
&i.QualityProfileID,
|
||||||
|
&i.RootFolderPath,
|
||||||
|
&i.DecidedAt,
|
||||||
|
&i.DecidedBy,
|
||||||
|
&i.Notes,
|
||||||
|
&i.CompletedAt,
|
||||||
|
&i.MatchedTrackID,
|
||||||
|
&i.MatchedAlbumID,
|
||||||
|
&i.MatchedArtistID,
|
||||||
|
&i.RequestedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const createLidarrRequest = `-- name: CreateLidarrRequest :one
|
||||||
|
INSERT INTO lidarr_requests (
|
||||||
|
user_id, kind,
|
||||||
|
lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid,
|
||||||
|
artist_name, album_title, track_title
|
||||||
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
|
RETURNING id, user_id, status, kind, lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid, artist_name, album_title, track_title, quality_profile_id, root_folder_path, decided_at, decided_by, notes, completed_at, matched_track_id, matched_album_id, matched_artist_id, requested_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateLidarrRequestParams struct {
|
||||||
|
UserID pgtype.UUID
|
||||||
|
Kind LidarrRequestKind
|
||||||
|
LidarrArtistMbid string
|
||||||
|
LidarrAlbumMbid *string
|
||||||
|
LidarrTrackMbid *string
|
||||||
|
ArtistName string
|
||||||
|
AlbumTitle *string
|
||||||
|
TrackTitle *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateLidarrRequest(ctx context.Context, arg CreateLidarrRequestParams) (LidarrRequest, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createLidarrRequest,
|
||||||
|
arg.UserID,
|
||||||
|
arg.Kind,
|
||||||
|
arg.LidarrArtistMbid,
|
||||||
|
arg.LidarrAlbumMbid,
|
||||||
|
arg.LidarrTrackMbid,
|
||||||
|
arg.ArtistName,
|
||||||
|
arg.AlbumTitle,
|
||||||
|
arg.TrackTitle,
|
||||||
|
)
|
||||||
|
var i LidarrRequest
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Kind,
|
||||||
|
&i.LidarrArtistMbid,
|
||||||
|
&i.LidarrAlbumMbid,
|
||||||
|
&i.LidarrTrackMbid,
|
||||||
|
&i.ArtistName,
|
||||||
|
&i.AlbumTitle,
|
||||||
|
&i.TrackTitle,
|
||||||
|
&i.QualityProfileID,
|
||||||
|
&i.RootFolderPath,
|
||||||
|
&i.DecidedAt,
|
||||||
|
&i.DecidedBy,
|
||||||
|
&i.Notes,
|
||||||
|
&i.CompletedAt,
|
||||||
|
&i.MatchedTrackID,
|
||||||
|
&i.MatchedAlbumID,
|
||||||
|
&i.MatchedArtistID,
|
||||||
|
&i.RequestedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLidarrRequestByID = `-- name: GetLidarrRequestByID :one
|
||||||
|
SELECT id, user_id, status, kind, lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid, artist_name, album_title, track_title, quality_profile_id, root_folder_path, decided_at, decided_by, notes, completed_at, matched_track_id, matched_album_id, matched_artist_id, requested_at, updated_at FROM lidarr_requests WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetLidarrRequestByID(ctx context.Context, id pgtype.UUID) (LidarrRequest, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getLidarrRequestByID, id)
|
||||||
|
var i LidarrRequest
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Kind,
|
||||||
|
&i.LidarrArtistMbid,
|
||||||
|
&i.LidarrAlbumMbid,
|
||||||
|
&i.LidarrTrackMbid,
|
||||||
|
&i.ArtistName,
|
||||||
|
&i.AlbumTitle,
|
||||||
|
&i.TrackTitle,
|
||||||
|
&i.QualityProfileID,
|
||||||
|
&i.RootFolderPath,
|
||||||
|
&i.DecidedAt,
|
||||||
|
&i.DecidedBy,
|
||||||
|
&i.Notes,
|
||||||
|
&i.CompletedAt,
|
||||||
|
&i.MatchedTrackID,
|
||||||
|
&i.MatchedAlbumID,
|
||||||
|
&i.MatchedArtistID,
|
||||||
|
&i.RequestedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasNonTerminalRequestForMBID = `-- name: HasNonTerminalRequestForMBID :one
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1 FROM lidarr_requests
|
||||||
|
WHERE status IN ('pending', 'approved', 'completed')
|
||||||
|
AND ((kind = 'artist' AND lidarr_artist_mbid = $1)
|
||||||
|
OR (kind = 'album' AND lidarr_album_mbid = $1)
|
||||||
|
OR (kind = 'track' AND lidarr_track_mbid = $1))
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
// Returns true if any user has a pending/approved/completed request
|
||||||
|
// whose MBID matches at the given level. Used to set the `requested`
|
||||||
|
// flag on /api/lidarr/search responses. Terminal-status (rejected,
|
||||||
|
// failed) rows do not count.
|
||||||
|
func (q *Queries) HasNonTerminalRequestForMBID(ctx context.Context, lidarrArtistMbid string) (bool, error) {
|
||||||
|
row := q.db.QueryRow(ctx, hasNonTerminalRequestForMBID, lidarrArtistMbid)
|
||||||
|
var exists bool
|
||||||
|
err := row.Scan(&exists)
|
||||||
|
return exists, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listApprovedLidarrRequestsForReconcile = `-- name: ListApprovedLidarrRequestsForReconcile :many
|
||||||
|
SELECT id, user_id, status, kind, lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid, artist_name, album_title, track_title, quality_profile_id, root_folder_path, decided_at, decided_by, notes, completed_at, matched_track_id, matched_album_id, matched_artist_id, requested_at, updated_at FROM lidarr_requests
|
||||||
|
WHERE status = 'approved'
|
||||||
|
ORDER BY decided_at ASC
|
||||||
|
LIMIT $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListApprovedLidarrRequestsForReconcile(ctx context.Context, limit int32) ([]LidarrRequest, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listApprovedLidarrRequestsForReconcile, limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []LidarrRequest
|
||||||
|
for rows.Next() {
|
||||||
|
var i LidarrRequest
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Kind,
|
||||||
|
&i.LidarrArtistMbid,
|
||||||
|
&i.LidarrAlbumMbid,
|
||||||
|
&i.LidarrTrackMbid,
|
||||||
|
&i.ArtistName,
|
||||||
|
&i.AlbumTitle,
|
||||||
|
&i.TrackTitle,
|
||||||
|
&i.QualityProfileID,
|
||||||
|
&i.RootFolderPath,
|
||||||
|
&i.DecidedAt,
|
||||||
|
&i.DecidedBy,
|
||||||
|
&i.Notes,
|
||||||
|
&i.CompletedAt,
|
||||||
|
&i.MatchedTrackID,
|
||||||
|
&i.MatchedAlbumID,
|
||||||
|
&i.MatchedArtistID,
|
||||||
|
&i.RequestedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const listLidarrRequestsByStatus = `-- name: ListLidarrRequestsByStatus :many
|
||||||
|
SELECT id, user_id, status, kind, lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid, artist_name, album_title, track_title, quality_profile_id, root_folder_path, decided_at, decided_by, notes, completed_at, matched_track_id, matched_album_id, matched_artist_id, requested_at, updated_at FROM lidarr_requests
|
||||||
|
WHERE status = $1
|
||||||
|
ORDER BY requested_at DESC
|
||||||
|
LIMIT $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListLidarrRequestsByStatusParams struct {
|
||||||
|
Status LidarrRequestStatus
|
||||||
|
Limit int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListLidarrRequestsByStatus(ctx context.Context, arg ListLidarrRequestsByStatusParams) ([]LidarrRequest, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listLidarrRequestsByStatus, arg.Status, arg.Limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []LidarrRequest
|
||||||
|
for rows.Next() {
|
||||||
|
var i LidarrRequest
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Kind,
|
||||||
|
&i.LidarrArtistMbid,
|
||||||
|
&i.LidarrAlbumMbid,
|
||||||
|
&i.LidarrTrackMbid,
|
||||||
|
&i.ArtistName,
|
||||||
|
&i.AlbumTitle,
|
||||||
|
&i.TrackTitle,
|
||||||
|
&i.QualityProfileID,
|
||||||
|
&i.RootFolderPath,
|
||||||
|
&i.DecidedAt,
|
||||||
|
&i.DecidedBy,
|
||||||
|
&i.Notes,
|
||||||
|
&i.CompletedAt,
|
||||||
|
&i.MatchedTrackID,
|
||||||
|
&i.MatchedAlbumID,
|
||||||
|
&i.MatchedArtistID,
|
||||||
|
&i.RequestedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const listLidarrRequestsForUser = `-- name: ListLidarrRequestsForUser :many
|
||||||
|
SELECT id, user_id, status, kind, lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid, artist_name, album_title, track_title, quality_profile_id, root_folder_path, decided_at, decided_by, notes, completed_at, matched_track_id, matched_album_id, matched_artist_id, requested_at, updated_at FROM lidarr_requests
|
||||||
|
WHERE user_id = $1
|
||||||
|
ORDER BY requested_at DESC
|
||||||
|
LIMIT $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListLidarrRequestsForUserParams struct {
|
||||||
|
UserID pgtype.UUID
|
||||||
|
Limit int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListLidarrRequestsForUser(ctx context.Context, arg ListLidarrRequestsForUserParams) ([]LidarrRequest, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listLidarrRequestsForUser, arg.UserID, arg.Limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []LidarrRequest
|
||||||
|
for rows.Next() {
|
||||||
|
var i LidarrRequest
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Kind,
|
||||||
|
&i.LidarrArtistMbid,
|
||||||
|
&i.LidarrAlbumMbid,
|
||||||
|
&i.LidarrTrackMbid,
|
||||||
|
&i.ArtistName,
|
||||||
|
&i.AlbumTitle,
|
||||||
|
&i.TrackTitle,
|
||||||
|
&i.QualityProfileID,
|
||||||
|
&i.RootFolderPath,
|
||||||
|
&i.DecidedAt,
|
||||||
|
&i.DecidedBy,
|
||||||
|
&i.Notes,
|
||||||
|
&i.CompletedAt,
|
||||||
|
&i.MatchedTrackID,
|
||||||
|
&i.MatchedAlbumID,
|
||||||
|
&i.MatchedArtistID,
|
||||||
|
&i.RequestedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const rejectLidarrRequest = `-- name: RejectLidarrRequest :one
|
||||||
|
UPDATE lidarr_requests
|
||||||
|
SET status = 'rejected',
|
||||||
|
notes = $2,
|
||||||
|
decided_at = now(),
|
||||||
|
decided_by = $3,
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = $1 AND status = 'pending'
|
||||||
|
RETURNING id, user_id, status, kind, lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid, artist_name, album_title, track_title, quality_profile_id, root_folder_path, decided_at, decided_by, notes, completed_at, matched_track_id, matched_album_id, matched_artist_id, requested_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type RejectLidarrRequestParams struct {
|
||||||
|
ID pgtype.UUID
|
||||||
|
Notes *string
|
||||||
|
DecidedBy pgtype.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) RejectLidarrRequest(ctx context.Context, arg RejectLidarrRequestParams) (LidarrRequest, error) {
|
||||||
|
row := q.db.QueryRow(ctx, rejectLidarrRequest, arg.ID, arg.Notes, arg.DecidedBy)
|
||||||
|
var i LidarrRequest
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Kind,
|
||||||
|
&i.LidarrArtistMbid,
|
||||||
|
&i.LidarrAlbumMbid,
|
||||||
|
&i.LidarrTrackMbid,
|
||||||
|
&i.ArtistName,
|
||||||
|
&i.AlbumTitle,
|
||||||
|
&i.TrackTitle,
|
||||||
|
&i.QualityProfileID,
|
||||||
|
&i.RootFolderPath,
|
||||||
|
&i.DecidedAt,
|
||||||
|
&i.DecidedBy,
|
||||||
|
&i.Notes,
|
||||||
|
&i.CompletedAt,
|
||||||
|
&i.MatchedTrackID,
|
||||||
|
&i.MatchedAlbumID,
|
||||||
|
&i.MatchedArtistID,
|
||||||
|
&i.RequestedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: likes.sql
|
// source: likes.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
+127
-1
@@ -1,13 +1,104 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type LidarrRequestKind string
|
||||||
|
|
||||||
|
const (
|
||||||
|
LidarrRequestKindArtist LidarrRequestKind = "artist"
|
||||||
|
LidarrRequestKindAlbum LidarrRequestKind = "album"
|
||||||
|
LidarrRequestKindTrack LidarrRequestKind = "track"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *LidarrRequestKind) Scan(src interface{}) error {
|
||||||
|
switch s := src.(type) {
|
||||||
|
case []byte:
|
||||||
|
*e = LidarrRequestKind(s)
|
||||||
|
case string:
|
||||||
|
*e = LidarrRequestKind(s)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported scan type for LidarrRequestKind: %T", src)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullLidarrRequestKind struct {
|
||||||
|
LidarrRequestKind LidarrRequestKind
|
||||||
|
Valid bool // Valid is true if LidarrRequestKind is not NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the Scanner interface.
|
||||||
|
func (ns *NullLidarrRequestKind) Scan(value interface{}) error {
|
||||||
|
if value == nil {
|
||||||
|
ns.LidarrRequestKind, ns.Valid = "", false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ns.Valid = true
|
||||||
|
return ns.LidarrRequestKind.Scan(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (ns NullLidarrRequestKind) Value() (driver.Value, error) {
|
||||||
|
if !ns.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return string(ns.LidarrRequestKind), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type LidarrRequestStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
LidarrRequestStatusPending LidarrRequestStatus = "pending"
|
||||||
|
LidarrRequestStatusApproved LidarrRequestStatus = "approved"
|
||||||
|
LidarrRequestStatusRejected LidarrRequestStatus = "rejected"
|
||||||
|
LidarrRequestStatusCompleted LidarrRequestStatus = "completed"
|
||||||
|
LidarrRequestStatusFailed LidarrRequestStatus = "failed"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *LidarrRequestStatus) Scan(src interface{}) error {
|
||||||
|
switch s := src.(type) {
|
||||||
|
case []byte:
|
||||||
|
*e = LidarrRequestStatus(s)
|
||||||
|
case string:
|
||||||
|
*e = LidarrRequestStatus(s)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported scan type for LidarrRequestStatus: %T", src)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullLidarrRequestStatus struct {
|
||||||
|
LidarrRequestStatus LidarrRequestStatus
|
||||||
|
Valid bool // Valid is true if LidarrRequestStatus is not NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the Scanner interface.
|
||||||
|
func (ns *NullLidarrRequestStatus) Scan(value interface{}) error {
|
||||||
|
if value == nil {
|
||||||
|
ns.LidarrRequestStatus, ns.Valid = "", false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ns.Valid = true
|
||||||
|
return ns.LidarrRequestStatus.Scan(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (ns NullLidarrRequestStatus) Value() (driver.Value, error) {
|
||||||
|
if !ns.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return string(ns.LidarrRequestStatus), nil
|
||||||
|
}
|
||||||
|
|
||||||
type Album struct {
|
type Album struct {
|
||||||
ID pgtype.UUID
|
ID pgtype.UUID
|
||||||
Title string
|
Title string
|
||||||
@@ -65,6 +156,41 @@ type GeneralLikesArtist struct {
|
|||||||
LikedAt pgtype.Timestamptz
|
LikedAt pgtype.Timestamptz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LidarrConfig struct {
|
||||||
|
ID int16
|
||||||
|
Enabled bool
|
||||||
|
BaseUrl *string
|
||||||
|
ApiKey *string
|
||||||
|
DefaultQualityProfileID *int32
|
||||||
|
DefaultRootFolderPath *string
|
||||||
|
CreatedAt pgtype.Timestamptz
|
||||||
|
UpdatedAt pgtype.Timestamptz
|
||||||
|
}
|
||||||
|
|
||||||
|
type LidarrRequest struct {
|
||||||
|
ID pgtype.UUID
|
||||||
|
UserID pgtype.UUID
|
||||||
|
Status LidarrRequestStatus
|
||||||
|
Kind LidarrRequestKind
|
||||||
|
LidarrArtistMbid string
|
||||||
|
LidarrAlbumMbid *string
|
||||||
|
LidarrTrackMbid *string
|
||||||
|
ArtistName string
|
||||||
|
AlbumTitle *string
|
||||||
|
TrackTitle *string
|
||||||
|
QualityProfileID *int32
|
||||||
|
RootFolderPath *string
|
||||||
|
DecidedAt pgtype.Timestamptz
|
||||||
|
DecidedBy pgtype.UUID
|
||||||
|
Notes *string
|
||||||
|
CompletedAt pgtype.Timestamptz
|
||||||
|
MatchedTrackID pgtype.UUID
|
||||||
|
MatchedAlbumID pgtype.UUID
|
||||||
|
MatchedArtistID pgtype.UUID
|
||||||
|
RequestedAt pgtype.Timestamptz
|
||||||
|
UpdatedAt pgtype.Timestamptz
|
||||||
|
}
|
||||||
|
|
||||||
type PlayEvent struct {
|
type PlayEvent struct {
|
||||||
ID pgtype.UUID
|
ID pgtype.UUID
|
||||||
UserID pgtype.UUID
|
UserID pgtype.UUID
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: recommendation.sql
|
// source: recommendation.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: scrobble.sql
|
// source: scrobble.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: sessions.sql
|
// source: sessions.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: similarity.sql
|
// source: similarity.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: tracks.sql
|
// source: tracks.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.31.1
|
||||||
// source: users.sql
|
// source: users.sql
|
||||||
|
|
||||||
package dbq
|
package dbq
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
DROP INDEX IF EXISTS lidarr_requests_album_mbid_idx;
|
||||||
|
DROP INDEX IF EXISTS lidarr_requests_artist_mbid_idx;
|
||||||
|
DROP INDEX IF EXISTS lidarr_requests_status_idx;
|
||||||
|
DROP INDEX IF EXISTS lidarr_requests_user_id_idx;
|
||||||
|
DROP TABLE IF EXISTS lidarr_requests;
|
||||||
|
DROP TYPE IF EXISTS lidarr_request_kind;
|
||||||
|
DROP TYPE IF EXISTS lidarr_request_status;
|
||||||
|
DROP TABLE IF EXISTS lidarr_config;
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
-- M5a: Lidarr integration foundation. Two tables:
|
||||||
|
--
|
||||||
|
-- lidarr_config — singleton (CHECK id=1) holding the operator's Lidarr
|
||||||
|
-- connection. enabled=false is the unconfigured state.
|
||||||
|
--
|
||||||
|
-- lidarr_requests — per-request lifecycle row created by users at
|
||||||
|
-- /discover, transitioned by admin at /admin/requests, and matched
|
||||||
|
-- back to library tracks by the reconciler worker. Three matched_*_id
|
||||||
|
-- FKs (one per kind) instead of polymorphic — clean SQL, ON DELETE
|
||||||
|
-- SET NULL preserves audit even if the matched track is later removed.
|
||||||
|
|
||||||
|
CREATE TABLE lidarr_config (
|
||||||
|
id smallint PRIMARY KEY DEFAULT 1 CHECK (id = 1),
|
||||||
|
enabled boolean NOT NULL DEFAULT false,
|
||||||
|
base_url text,
|
||||||
|
api_key text,
|
||||||
|
default_quality_profile_id int,
|
||||||
|
default_root_folder_path text,
|
||||||
|
created_at timestamptz NOT NULL DEFAULT now(),
|
||||||
|
updated_at timestamptz NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO lidarr_config (id, enabled) VALUES (1, false);
|
||||||
|
|
||||||
|
CREATE TYPE lidarr_request_status AS ENUM (
|
||||||
|
'pending', 'approved', 'rejected', 'completed', 'failed'
|
||||||
|
);
|
||||||
|
CREATE TYPE lidarr_request_kind AS ENUM ('artist', 'album', 'track');
|
||||||
|
|
||||||
|
CREATE TABLE lidarr_requests (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
status lidarr_request_status NOT NULL DEFAULT 'pending',
|
||||||
|
kind lidarr_request_kind NOT NULL,
|
||||||
|
|
||||||
|
lidarr_artist_mbid text NOT NULL,
|
||||||
|
lidarr_album_mbid text,
|
||||||
|
lidarr_track_mbid text,
|
||||||
|
artist_name text NOT NULL,
|
||||||
|
album_title text,
|
||||||
|
track_title text,
|
||||||
|
|
||||||
|
quality_profile_id int,
|
||||||
|
root_folder_path text,
|
||||||
|
|
||||||
|
decided_at timestamptz,
|
||||||
|
decided_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
||||||
|
notes text,
|
||||||
|
|
||||||
|
completed_at timestamptz,
|
||||||
|
matched_track_id uuid REFERENCES tracks(id) ON DELETE SET NULL,
|
||||||
|
matched_album_id uuid REFERENCES albums(id) ON DELETE SET NULL,
|
||||||
|
matched_artist_id uuid REFERENCES artists(id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
requested_at timestamptz NOT NULL DEFAULT now(),
|
||||||
|
updated_at timestamptz NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX lidarr_requests_user_id_idx ON lidarr_requests (user_id);
|
||||||
|
CREATE INDEX lidarr_requests_status_idx ON lidarr_requests (status);
|
||||||
|
CREATE INDEX lidarr_requests_artist_mbid_idx ON lidarr_requests (lidarr_artist_mbid);
|
||||||
|
CREATE INDEX lidarr_requests_album_mbid_idx ON lidarr_requests (lidarr_album_mbid)
|
||||||
|
WHERE lidarr_album_mbid IS NOT NULL;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- name: GetLidarrConfig :one
|
||||||
|
SELECT id, enabled, base_url, api_key, default_quality_profile_id,
|
||||||
|
default_root_folder_path, created_at, updated_at
|
||||||
|
FROM lidarr_config
|
||||||
|
WHERE id = 1;
|
||||||
|
|
||||||
|
-- name: UpdateLidarrConfig :one
|
||||||
|
UPDATE lidarr_config
|
||||||
|
SET enabled = $1,
|
||||||
|
base_url = $2,
|
||||||
|
api_key = $3,
|
||||||
|
default_quality_profile_id = $4,
|
||||||
|
default_root_folder_path = $5,
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = 1
|
||||||
|
RETURNING id, enabled, base_url, api_key, default_quality_profile_id,
|
||||||
|
default_root_folder_path, created_at, updated_at;
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
-- name: CreateLidarrRequest :one
|
||||||
|
INSERT INTO lidarr_requests (
|
||||||
|
user_id, kind,
|
||||||
|
lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid,
|
||||||
|
artist_name, album_title, track_title
|
||||||
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetLidarrRequestByID :one
|
||||||
|
SELECT * FROM lidarr_requests WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: ListLidarrRequestsForUser :many
|
||||||
|
SELECT * FROM lidarr_requests
|
||||||
|
WHERE user_id = $1
|
||||||
|
ORDER BY requested_at DESC
|
||||||
|
LIMIT $2;
|
||||||
|
|
||||||
|
-- name: ListLidarrRequestsByStatus :many
|
||||||
|
SELECT * FROM lidarr_requests
|
||||||
|
WHERE status = $1
|
||||||
|
ORDER BY requested_at DESC
|
||||||
|
LIMIT $2;
|
||||||
|
|
||||||
|
-- name: ListApprovedLidarrRequestsForReconcile :many
|
||||||
|
SELECT * FROM lidarr_requests
|
||||||
|
WHERE status = 'approved'
|
||||||
|
ORDER BY decided_at ASC
|
||||||
|
LIMIT $1;
|
||||||
|
|
||||||
|
-- name: ApproveLidarrRequest :one
|
||||||
|
UPDATE lidarr_requests
|
||||||
|
SET status = 'approved',
|
||||||
|
quality_profile_id = $2,
|
||||||
|
root_folder_path = $3,
|
||||||
|
decided_at = now(),
|
||||||
|
decided_by = $4,
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = $1 AND status = 'pending'
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: RejectLidarrRequest :one
|
||||||
|
UPDATE lidarr_requests
|
||||||
|
SET status = 'rejected',
|
||||||
|
notes = $2,
|
||||||
|
decided_at = now(),
|
||||||
|
decided_by = $3,
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = $1 AND status = 'pending'
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: CancelLidarrRequest :one
|
||||||
|
UPDATE lidarr_requests
|
||||||
|
SET status = 'rejected',
|
||||||
|
notes = 'cancelled by user',
|
||||||
|
decided_at = now(),
|
||||||
|
decided_by = $2,
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = $1 AND user_id = $2 AND status = 'pending'
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: CompleteLidarrRequest :one
|
||||||
|
-- Reconciler transitions an approved request to completed when its
|
||||||
|
-- target track/album/artist has appeared in the library.
|
||||||
|
UPDATE lidarr_requests
|
||||||
|
SET status = 'completed',
|
||||||
|
matched_track_id = $2,
|
||||||
|
matched_album_id = $3,
|
||||||
|
matched_artist_id = $4,
|
||||||
|
completed_at = now(),
|
||||||
|
updated_at = now()
|
||||||
|
WHERE id = $1 AND status = 'approved'
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: HasNonTerminalRequestForMBID :one
|
||||||
|
-- Returns true if any user has a pending/approved/completed request
|
||||||
|
-- whose MBID matches at the given level. Used to set the `requested`
|
||||||
|
-- flag on /api/lidarr/search responses. Terminal-status (rejected,
|
||||||
|
-- failed) rows do not count.
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1 FROM lidarr_requests
|
||||||
|
WHERE status IN ('pending', 'approved', 'completed')
|
||||||
|
AND ((kind = 'artist' AND lidarr_artist_mbid = $1)
|
||||||
|
OR (kind = 'album' AND lidarr_album_mbid = $1)
|
||||||
|
OR (kind = 'track' AND lidarr_track_mbid = $1))
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user