feat: complete filter centralization pattern and document in CLAUDE.md
This commit is contained in:
@@ -70,7 +70,7 @@ func SaveArtistSettings(db *DB, settings *ArtistSettings) error {
|
||||
monitored = excluded.monitored,
|
||||
last_synced = COALESCE(excluded.last_synced, artist_settings.last_synced)
|
||||
`,
|
||||
settings.ID, settings.Name, nullIfEmpty(settings.MBID), settings.IgnoreSingles, settings.IgnoreCompilations, settings.Monitored, settings.ID,
|
||||
settings.ID, settings.Name, nullIfEmpty(settings.MBID), settings.IgnoreSingles, settings.IgnoreCompilations, settings.Monitored, nullIfEmptyTime(settings.LastSynced),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("save artist settings: %w", err)
|
||||
|
||||
@@ -3,6 +3,7 @@ package database
|
||||
import (
|
||||
"database/sql"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestGetArtistSettings_Found verifies retrieving an existing artist.
|
||||
@@ -460,3 +461,134 @@ func TestArtistSettings_MbidInGetAll(t *testing.T) {
|
||||
t.Errorf("artist a2: expected empty MBID, got %q", byID["a2"].MBID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSaveArtistSettings_LastSyncedPreserved verifies that last_synced is preserved
|
||||
// on update when not explicitly provided in the update.
|
||||
func TestSaveArtistSettings_LastSyncedPreserved(t *testing.T) {
|
||||
db, err := New(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Set a fixed time for testing
|
||||
fixedTime := time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)
|
||||
|
||||
// Insert initial row with a specific last_synced time
|
||||
s1 := &ArtistSettings{
|
||||
ID: "artist-1",
|
||||
Name: "Original Name",
|
||||
IgnoreSingles: false,
|
||||
IgnoreCompilations: false,
|
||||
Monitored: true,
|
||||
LastSynced: fixedTime,
|
||||
}
|
||||
if err := SaveArtistSettings(db, s1); err != nil {
|
||||
t.Fatalf("first SaveArtistSettings() error: %v", err)
|
||||
}
|
||||
|
||||
// Verify it was inserted with correct last_synced
|
||||
got, err := GetArtistSettings(db, "artist-1")
|
||||
if err != nil {
|
||||
t.Fatalf("GetArtistSettings() error: %v", err)
|
||||
}
|
||||
if got.LastSynced != fixedTime {
|
||||
t.Fatalf("expected last_synced %v, got %v", fixedTime, got.LastSynced)
|
||||
}
|
||||
|
||||
// Update the row with new values but without specifying last_synced
|
||||
// This should preserve the original last_synced value
|
||||
s2 := &ArtistSettings{
|
||||
ID: "artist-1",
|
||||
Name: "Updated Name",
|
||||
IgnoreSingles: true,
|
||||
IgnoreCompilations: true,
|
||||
Monitored: false,
|
||||
// Note: LastSynced is intentionally left as zero value
|
||||
}
|
||||
if err := SaveArtistSettings(db, s2); err != nil {
|
||||
t.Fatalf("second SaveArtistSettings() error: %v", err)
|
||||
}
|
||||
|
||||
got, err = GetArtistSettings(db, "artist-1")
|
||||
if err != nil {
|
||||
t.Fatalf("GetArtistSettings() error: %v", err)
|
||||
}
|
||||
if got.Name != "Updated Name" {
|
||||
t.Errorf("expected Name 'Updated Name', got %q", got.Name)
|
||||
}
|
||||
if !got.IgnoreSingles {
|
||||
t.Error("expected IgnoreSingles true")
|
||||
}
|
||||
if !got.IgnoreCompilations {
|
||||
t.Error("expected IgnoreCompilations true")
|
||||
}
|
||||
if got.Monitored {
|
||||
t.Error("expected Monitored false")
|
||||
}
|
||||
// Most importantly: last_synced should be preserved
|
||||
if got.LastSynced != fixedTime {
|
||||
t.Errorf("expected last_synced to be preserved as %v, got %v", fixedTime, got.LastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSaveArtistSettings_LastSyncedUpdated verifies that last_synced can be updated
|
||||
// when explicitly provided.
|
||||
func TestSaveArtistSettings_LastSyncedUpdated(t *testing.T) {
|
||||
db, err := New(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Set fixed times for testing
|
||||
oldTime := time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)
|
||||
newTime := time.Date(2023, 12, 31, 23, 59, 59, 0, time.UTC)
|
||||
|
||||
// Insert initial row
|
||||
s1 := &ArtistSettings{
|
||||
ID: "artist-1",
|
||||
Name: "Original Name",
|
||||
IgnoreSingles: false,
|
||||
IgnoreCompilations: false,
|
||||
Monitored: true,
|
||||
LastSynced: oldTime,
|
||||
}
|
||||
if err := SaveArtistSettings(db, s1); err != nil {
|
||||
t.Fatalf("first SaveArtistSettings() error: %v", err)
|
||||
}
|
||||
|
||||
// Update the row with a new last_synced time
|
||||
s2 := &ArtistSettings{
|
||||
ID: "artist-1",
|
||||
Name: "Updated Name",
|
||||
IgnoreSingles: true,
|
||||
IgnoreCompilations: true,
|
||||
Monitored: false,
|
||||
LastSynced: newTime,
|
||||
}
|
||||
if err := SaveArtistSettings(db, s2); err != nil {
|
||||
t.Fatalf("second SaveArtistSettings() error: %v", err)
|
||||
}
|
||||
|
||||
got, err := GetArtistSettings(db, "artist-1")
|
||||
if err != nil {
|
||||
t.Fatalf("GetArtistSettings() error: %v", err)
|
||||
}
|
||||
if got.Name != "Updated Name" {
|
||||
t.Errorf("expected Name 'Updated Name', got %q", got.Name)
|
||||
}
|
||||
if !got.IgnoreSingles {
|
||||
t.Error("expected IgnoreSingles true")
|
||||
}
|
||||
if !got.IgnoreCompilations {
|
||||
t.Error("expected IgnoreCompilations true")
|
||||
}
|
||||
if got.Monitored {
|
||||
t.Error("expected Monitored false")
|
||||
}
|
||||
// last_synced should be updated to the new value
|
||||
if got.LastSynced != newTime {
|
||||
t.Errorf("expected last_synced to be updated to %v, got %v", newTime, got.LastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user