library: keep artist paging off song and album writes

The fallback art reads albums and credits, but a successful sync invalidates through the sources row, so observing those tables only adds refreshes for play, star, and sync writes that do not change artist art.
This commit is contained in:
austinried
2026-10-19 12:39:01 +00:00
parent bb71f4889d
commit 4b3a7d1dfa
2 changed files with 3 additions and 65 deletions
@@ -10,7 +10,6 @@ import androidx.room3.Transaction
import androidx.room3.Upsert import androidx.room3.Upsert
import androidx.room3.paging.PagingSourceDaoReturnTypeConverter import androidx.room3.paging.PagingSourceDaoReturnTypeConverter
import com.subtracks.data.model.Album import com.subtracks.data.model.Album
import com.subtracks.data.model.AlbumArtistRef
import com.subtracks.data.model.AlbumSongItem import com.subtracks.data.model.AlbumSongItem
import com.subtracks.data.model.Artist import com.subtracks.data.model.Artist
import com.subtracks.data.model.Disc import com.subtracks.data.model.Disc
@@ -19,7 +18,6 @@ import com.subtracks.data.model.Playlist
import com.subtracks.data.model.PlaylistSong import com.subtracks.data.model.PlaylistSong
import com.subtracks.data.model.PlaylistSongItem import com.subtracks.data.model.PlaylistSongItem
import com.subtracks.data.model.Song import com.subtracks.data.model.Song
import com.subtracks.data.model.SongArtistRef
import com.subtracks.data.model.Source import com.subtracks.data.model.Source
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@@ -643,16 +641,9 @@ interface LibraryDao {
@RawQuery(observedEntities = [Album::class]) @RawQuery(observedEntities = [Album::class])
fun albumsPaging(query: RoomRawQuery): PagingSource<Int, Album> fun albumsPaging(query: RoomRawQuery): PagingSource<Int, Album>
@RawQuery( // The fallback art reads albums and credits, but a successful sync writes sources after the
observedEntities = [ // library changes, so observing artists and sources avoids invalidating on every song/album write.
Artist::class, @RawQuery(observedEntities = [Artist::class, Source::class])
Source::class,
Album::class,
AlbumArtistRef::class,
Song::class,
SongArtistRef::class,
],
)
fun artistsPaging(query: RoomRawQuery): PagingSource<Int, Artist> fun artistsPaging(query: RoomRawQuery): PagingSource<Int, Artist>
@RawQuery(observedEntities = [Playlist::class]) @RawQuery(observedEntities = [Playlist::class])
@@ -652,59 +652,6 @@ class LibraryDaoTest {
) )
} }
@Test
fun artistArtChangesInvalidateTheArtistPagingSource() =
runTest {
val sourceId = source()
val dao = db.libraryDao()
dao.upsertArtists(listOf(artist(sourceId, "ar-1", "Artist", albumCount = 1)))
dao.upsertAlbums(listOf(album(sourceId, "al-1", "Album", year = null, starred = null)))
val albumInvalidated = AtomicBoolean(false)
val albumPaging = dao.artistsPaging(artistsDefaultQuery(sourceId, 0, "", ArtistSort.Name, false))
albumPaging.registerInvalidatedCallback { albumInvalidated.set(true) }
albumPaging.page()
dao.upsertAlbums(
listOf(album(sourceId, "al-1", "Album", year = null, starred = null).copy(coverArt = "cover")),
)
awaitUntil("artist paging observes album writes") { albumInvalidated.get() }
val songInvalidated = AtomicBoolean(false)
val songPaging = dao.artistsPaging(artistsDefaultQuery(sourceId, 0, "", ArtistSort.Name, false))
songPaging.registerInvalidatedCallback { songInvalidated.set(true) }
songPaging.page()
dao.upsertSongs(listOf(song(sourceId, "s-1", "Song", starred = null)))
awaitUntil("artist paging observes song writes") { songInvalidated.get() }
val albumCreditInvalidated = AtomicBoolean(false)
val albumCreditPaging = dao.artistsPaging(artistsDefaultQuery(sourceId, 0, "", ArtistSort.Name, false))
albumCreditPaging.registerInvalidatedCallback { albumCreditInvalidated.set(true) }
albumCreditPaging.page()
db.useWriterConnection { connection ->
connection.usePrepared(
"INSERT INTO album_artists (sourceId, albumId, position, artistId, name) " +
"VALUES ($sourceId, 'al-1', 0, 'ar-1', 'Artist')",
) { it.step() }
}
awaitUntil("artist paging observes album artist writes") { albumCreditInvalidated.get() }
val songCreditInvalidated = AtomicBoolean(false)
val songCreditPaging = dao.artistsPaging(artistsDefaultQuery(sourceId, 0, "", ArtistSort.Name, false))
songCreditPaging.registerInvalidatedCallback { songCreditInvalidated.set(true) }
songCreditPaging.page()
db.useWriterConnection { connection ->
connection.usePrepared(
"INSERT INTO song_artists (sourceId, songId, position, artistId, name) " +
"VALUES ($sourceId, 's-1', 0, 'ar-1', 'Artist')",
) { it.step() }
}
awaitUntil("artist paging observes song artist writes") { songCreditInvalidated.get() }
}
@Test @Test
fun albumCreditIdsFindCreditsThroughArtistIndexes() = fun albumCreditIdsFindCreditsThroughArtistIndexes() =
runTest { runTest {