refactor(persistence): simplify the artwork dangling-row purge helper

purgeDangling took a bound executeSQL method value and a table name only because
its two callers live on unrelated types. Neither parameter was load-bearing:
executeSQL is a value receiver on sqlRepository that never reads tableName, and
both callers already hold an sqlRepository whose tableName is the table being
purged. Taking that struct collapses both parameters into the receiver.

itemArtworkSQL wrapped sqlRepository without adding a single method, so the items
field becomes a plain sqlRepository.

danglingItemArtworkKinds is also read by EnqueueAllMissing, which enqueues
entities that have no artwork row yet - neither a purge nor anything specific to
item_artwork. Renamed to artworkOwnerTables to describe both of its uses.
This commit is contained in:
Deluan 2026-08-01 20:43:08 -04:00
parent 9c20c83617
commit a48bdefdc7
2 changed files with 11 additions and 15 deletions

View File

@ -51,7 +51,7 @@ func (r *artworkQueueRepository) EnqueueStaleAbsent(kind model.Kind, attemptedBe
}
func (r *artworkQueueRepository) EnqueueAllMissing(kind model.Kind, priority int) (int64, error) {
entityTable, ok := danglingItemArtworkKinds[kind]
entityTable, ok := artworkOwnerTables[kind]
if !ok {
return 0, fmt.Errorf("artwork queue: no entity table for kind %q", kind.Prefix())
}
@ -137,7 +137,7 @@ func (r *artworkQueueRepository) DeleteIfUnchanged(kind, id, imageType string, r
}
func (r *artworkQueueRepository) PurgeDangling() (int64, error) {
return purgeDangling(r.executeSQL, r.tableName)
return purgeDangling(r.sqlRepository)
}
func (r *artworkQueueRepository) Count() (int64, error) {

View File

@ -16,13 +16,9 @@ const (
artworkBatchSize = 200
)
type itemArtworkSQL struct {
sqlRepository
}
type artworkRepository struct {
sqlRepository
items itemArtworkSQL
items sqlRepository
}
func NewArtworkRepository(ctx context.Context, db dbx.Builder) model.ArtworkRepository {
@ -116,8 +112,8 @@ func (r *artworkRepository) DeleteOrphans(createdBefore time.Time, hashes []stri
return nil
}
// danglingItemArtworkKinds maps an artwork kind to the table that owns the entity.
var danglingItemArtworkKinds = map[model.Kind]string{
// artworkOwnerTables maps an artwork kind to the table that owns the entity.
var artworkOwnerTables = map[model.Kind]string{
model.KindAlbumArtwork: "album",
model.KindArtistArtwork: "artist",
model.KindPlaylistArtwork: "playlist",
@ -125,15 +121,15 @@ var danglingItemArtworkKinds = map[model.Kind]string{
model.KindMediaFileArtwork: "media_file",
}
// purgeDangling deletes rows in table whose owning entity is gone, one statement per kind.
func purgeDangling(execute func(Sqlizer) (int64, error), table string) (int64, error) {
// purgeDangling deletes rows in r's table whose owning entity is gone, one statement per kind.
func purgeDangling(r sqlRepository) (int64, error) {
var total int64
for kind, entityTable := range danglingItemArtworkKinds {
del := Delete(table).Where(And{
for kind, entityTable := range artworkOwnerTables {
del := Delete(r.tableName).Where(And{
Eq{"item_kind": kind.Prefix()},
Expr("item_id NOT IN (SELECT id FROM " + entityTable + ")"),
})
c, err := execute(del)
c, err := r.executeSQL(del)
if err != nil {
return total, err
}
@ -143,7 +139,7 @@ func purgeDangling(execute func(Sqlizer) (int64, error), table string) (int64, e
}
func (r *artworkRepository) PurgeDanglingItemArtwork() (int64, error) {
return purgeDangling(r.items.executeSQL, itemArtworkTable)
return purgeDangling(r.items)
}
func (r *artworkRepository) GetItemArtwork(kind model.Kind, id, imageType string) (*model.ItemArtwork, error) {