Files
minstrel/internal/library/delete.go
T
bvandeusen e6e3f297d6 fix(dbtest,library): include quarantine tables in ResetDB; clarify DeleteTrackFile docstring
- dbtest.ResetDB.dataTables now truncates lidarr_quarantine + lidarr_quarantine_actions
  alongside the other M2-M4 data tables. Without this, M5b service tests would
  inherit residual state across runs.
- DeleteTrackFile godoc spells out the post-file/pre-DB failure window
  reconciles via the next library scan; the function is retry-safe by design,
  not atomic.
2026-04-30 17:32:08 -04:00

53 lines
1.6 KiB
Go

package library
import (
"context"
"errors"
"fmt"
"io/fs"
"os"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgxpool"
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
)
// ErrTrackNotFound is returned when DeleteTrackFile is called with an id
// that has no row in tracks.
var ErrTrackNotFound = errors.New("library: track not found")
// DeleteTrackFile removes a track file from disk and its row from the
// tracks table. Album and artist rows are left untouched.
//
// Steps:
// 1. Look up the track to get its file_path.
// 2. Remove the file from disk. fs.ErrNotExist is OK — already gone.
// 3. Delete the tracks row.
//
// Order matters: file first, then DB. If the file delete fails (permission,
// I/O error), we leave the DB row alone so the admin can retry. The reverse
// failure mode — file gone, DB row still present — is recoverable: the next
// library scan reconciles missing files by removing their tracks rows. So
// the function is retry-safe rather than atomic, by design.
func DeleteTrackFile(ctx context.Context, pool *pgxpool.Pool, trackID pgtype.UUID) error {
q := dbq.New(pool)
track, err := q.GetTrackByID(ctx, trackID)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrTrackNotFound
}
return fmt.Errorf("get track: %w", err)
}
if err := os.Remove(track.FilePath); err != nil && !errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("remove file: %w", err)
}
if _, err := pool.Exec(ctx, "DELETE FROM tracks WHERE id = $1", trackID); err != nil {
return fmt.Errorf("delete row: %w", err)
}
return nil
}