perf(audiobooks): skip audiobook_series upsert when unchanged

Reads the current row first; skips the INSERT/UPDATE when name and
index already match. NULL = NULL handled via floatPtrEqual.
This commit is contained in:
RXWatcher
2026-05-27 09:31:06 +02:00
parent 8ff5edb318
commit 01129dc383
2 changed files with 68 additions and 12 deletions
+44 -12
View File
@@ -17,6 +17,7 @@ import (
"github.com/Silo-Server/silo-server/internal/idgen"
"github.com/Silo-Server/silo-server/internal/models"
"github.com/Silo-Server/silo-server/internal/titleutil"
"github.com/jackc/pgx/v5"
)
// audiobookDiskFile is the on-disk projection used by audiobookFolderUnchanged.
@@ -689,33 +690,64 @@ func (s *Scanner) upsertAudiobookSeries(ctx context.Context, contentID string, b
if s.fileRepo == nil {
return fmt.Errorf("fileRepo not configured on Scanner")
}
name := strings.TrimSpace(book.Series)
if name == "" {
_, err := s.fileRepo.Pool().Exec(ctx,
`DELETE FROM audiobook_series WHERE content_id = $1`, contentID)
if err != nil {
return fmt.Errorf("delete audiobook_series row: %w", err)
desiredName := strings.TrimSpace(book.Series)
desiredIdx := parseSeriesIndex(book.SeriesPosition)
// Read current row.
var currentName *string
var currentIdx *float64
err := s.fileRepo.Pool().QueryRow(ctx, `
SELECT series_name, series_index FROM audiobook_series WHERE content_id = $1
`, contentID).Scan(&currentName, &currentIdx)
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
return fmt.Errorf("query audiobook_series: %w", err)
}
if desiredName == "" {
if currentName == nil {
return nil // already absent
}
if _, delErr := s.fileRepo.Pool().Exec(ctx,
`DELETE FROM audiobook_series WHERE content_id = $1`, contentID); delErr != nil {
return fmt.Errorf("delete audiobook_series row: %w", delErr)
}
return nil
}
var idx any
if v := parseSeriesIndex(book.SeriesPosition); v != nil {
idx = *v
if currentName != nil && *currentName == desiredName && floatPtrEqual(currentIdx, desiredIdx) {
return nil // identical row, skip the write
}
_, err := s.fileRepo.Pool().Exec(ctx, `
var idx any
if desiredIdx != nil {
idx = *desiredIdx
}
if _, err := s.fileRepo.Pool().Exec(ctx, `
INSERT INTO audiobook_series (content_id, series_name, series_index, updated_at)
VALUES ($1, $2, $3, NOW())
ON CONFLICT (content_id) DO UPDATE SET
series_name = EXCLUDED.series_name,
series_index = EXCLUDED.series_index,
updated_at = NOW()
`, contentID, name, idx)
if err != nil {
`, contentID, desiredName, idx); err != nil {
return fmt.Errorf("upsert audiobook_series row: %w", err)
}
return nil
}
// floatPtrEqual returns true when two *float64 values represent the same
// state — both nil, or both non-nil and equal. Used to skip audiobook_series
// re-upserts when only the series_index needs to be NULL=NULL compared.
func floatPtrEqual(a, b *float64) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
return *a == *b
}
// parseSeriesIndex extracts a leading numeric value from a freeform tag
// like "5", "1.5", "2 of 8", or "1a". Returns nil when no leading number
// is present so the audiobook_series.series_index column stays NULL rather
+24
View File
@@ -232,3 +232,27 @@ func TestAudiobookPeopleCreditsEqual(t *testing.T) {
})
}
}
func TestFloatPtrEqual(t *testing.T) {
a := 1.5
b := 1.5
c := 2.0
cases := []struct {
name string
x, y *float64
want bool
}{
{"both nil", nil, nil, true},
{"left nil", nil, &a, false},
{"right nil", &a, nil, false},
{"equal", &a, &b, true},
{"unequal", &a, &c, false},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
if got := floatPtrEqual(tt.x, tt.y); got != tt.want {
t.Errorf("got %v, want %v", got, tt.want)
}
})
}
}