diff --git a/persistence/album_repository.go b/persistence/album_repository.go index 144e860de..4217e2cbc 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -226,8 +226,11 @@ func (r *albumRepository) UpdateExternalInfo(al *model.Album) error { func (r *albumRepository) selectAlbum(options ...model.QueryOptions) SelectBuilder { sql := r.newSelect(options...).Columns("album.*", "library.path as library_path", "library.name as library_name", // Folds folder image mtimes into the artwork version: an in-place cover swap moves them without - // touching the album row. Bare column (not max()) keeps the decltype so the driver scans time.Time. - "(select f.images_updated_at from folder f, json_each(album.folder_ids) je where f.id = je.value"+ + // touching the album row. Parents are included for disc-subfolder layouts, where the reader can + // serve the album-root cover. Bare column (not max()) keeps the decltype so time.Time scans. + "(select f.images_updated_at from folder f where f.id in"+ + " (select je.value from json_each(album.folder_ids) je"+ + " union select p.parent_id from folder p, json_each(album.folder_ids) je2 where p.id = je2.value)"+ " order by f.images_updated_at desc limit 1) as folder_images_updated_at"). LeftJoin("library on album.library_id = library.id") sql = r.withAnnotation(sql, "album.id") diff --git a/persistence/album_repository_test.go b/persistence/album_repository_test.go index 7effeca0b..05978af23 100644 --- a/persistence/album_repository_test.go +++ b/persistence/album_repository_test.go @@ -910,7 +910,7 @@ var _ = Describe("AlbumRepository folder images version", func() { Expect(GetDBXBuilder().NewQuery("select folder_ids from album where id = '103'"). Row(&origFolderIDs)).To(Succeed()) DeferCleanup(func() { - _, err := GetDBXBuilder().NewQuery("delete from folder where id = 'fold-blur-1'").Execute() + _, err := GetDBXBuilder().NewQuery("delete from folder where id in ('fold-blur-1', 'fold-blur-root')").Execute() Expect(err).ToNot(HaveOccurred()) _, err = GetDBXBuilder().NewQuery("update album set folder_ids = {:f} where id = '103'"). Bind(map[string]any{"f": origFolderIDs}).Execute() @@ -935,6 +935,23 @@ var _ = Describe("AlbumRepository folder images version", func() { Expect(al.ArtworkUpdatedAt().Equal(imagesAt)).To(BeTrue(), "folder image changes must advance the artwork version") }) + It("includes the parent folder's images (album-root cover with disc subfolders)", func() { + discAt := time.Date(2030, 6, 1, 12, 0, 0, 0, time.UTC) + rootAt := discAt.Add(time.Hour) // the root cover is the newest image + _, err := GetDBXBuilder().NewQuery( + "insert into folder (id, library_id, path, name, parent_id, images_updated_at) values" + + " ('fold-blur-root', 1, '.', 'Album', '', {:root}), ('fold-blur-1', 1, './Album', 'CD1', 'fold-blur-root', {:disc})"). + Bind(map[string]any{"root": rootAt, "disc": discAt}).Execute() + Expect(err).ToNot(HaveOccurred()) + _, err = GetDBXBuilder().NewQuery(`update album set folder_ids = '["fold-blur-1"]' where id = '103'`).Execute() + Expect(err).ToNot(HaveOccurred()) + + al, err := repo.Get("103") + Expect(err).ToNot(HaveOccurred()) + Expect(al.FolderImagesUpdatedAt).ToNot(BeNil()) + Expect(al.FolderImagesUpdatedAt.Equal(rootAt)).To(BeTrue(), "the parent folder's newer cover must win") + }) + It("leaves FolderImagesUpdatedAt nil when the album has no folders", func() { al, err := repo.Get("101") Expect(err).ToNot(HaveOccurred())