mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-15 00:42:54 +01:00
sync: batch playlist origin lookups
This commit is contained in:
@@ -219,6 +219,7 @@ class SyncService(
|
||||
}
|
||||
}
|
||||
connection.upsertChanged("song_artists", songArtistKey, artists) { it.columns() }
|
||||
connection.recordPlaylistOrigins(batch.filter { previousStates[it.id] == null }.map { it.id })
|
||||
batch.forEach { song ->
|
||||
val previous = previousStates[song.id]
|
||||
val next = nextStates.getValue(song.id)
|
||||
@@ -242,7 +243,9 @@ class SyncService(
|
||||
ids.forEach { changedOrigins += origin(QueueKind.Song, it) }
|
||||
db.useWriterConnection { connection ->
|
||||
connection.immediateTransaction {
|
||||
connection.storedSongSyncStates(ids.toList()).values.forEach { recordSongOrigins(it, null) }
|
||||
val previousStates = connection.storedSongSyncStates(ids.toList())
|
||||
connection.recordPlaylistOrigins(previousStates.keys)
|
||||
previousStates.values.forEach { recordSongOrigins(it, null) }
|
||||
if (connection.completedDownloadIds(ids.toList()).isNotEmpty()) changedOrigins += origin(QueueKind.Downloaded, "")
|
||||
db.libraryDao().deleteSongs(source.id, ids)
|
||||
connection.persistPendingOrigins()
|
||||
@@ -250,18 +253,19 @@ class SyncService(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun PooledConnection.recordPlaylistOrigins(songIds: Collection<String>) {
|
||||
readSourceIds(
|
||||
songIds,
|
||||
{ "SELECT playlistId FROM playlist_songs WHERE sourceId = ? AND songId IN ($it)" },
|
||||
) { statement ->
|
||||
changedOrigins += origin(QueueKind.Playlist, statement.getText(0))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun PooledConnection.recordSongOrigins(
|
||||
previous: SongSyncState?,
|
||||
next: SongSyncState?,
|
||||
) {
|
||||
if ((previous == null) != (next == null)) {
|
||||
val songId = (previous ?: next)!!.id
|
||||
usePrepared("SELECT playlistId FROM playlist_songs WHERE sourceId = ? AND songId = ?") { statement ->
|
||||
statement.bindLong(1, source.id)
|
||||
statement.bindText(2, songId)
|
||||
while (statement.step()) changedOrigins += origin(QueueKind.Playlist, statement.getText(0))
|
||||
}
|
||||
}
|
||||
val states = listOfNotNull(previous, next)
|
||||
states.mapTo(changedOrigins) { origin(QueueKind.Song, it.id) }
|
||||
states.mapNotNullTo(changedOrigins) { it.albumId?.let { id -> origin(QueueKind.Album, id) } }
|
||||
|
||||
@@ -2034,6 +2034,54 @@ class SyncServiceTest {
|
||||
assertTrue(restored.changedOrigins.contains(QueueOrigin(QueueKind.Playlist, 1, "p1")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun songPresenceChangesBatchPlaylistMembershipQueries() =
|
||||
runTest {
|
||||
val executions = Collections.synchronizedList(mutableListOf<SqlExecution>())
|
||||
val loggingDb = createTestDatabase(LoggingSQLiteDriver(BundledSQLiteDriver()) { executions += it })
|
||||
try {
|
||||
loggingDb.sourcesDao().upsertSource(
|
||||
Source(id = 1, name = "test", address = "http://localhost", isActive = true, createdAt = 0),
|
||||
)
|
||||
val songs = listOf(song("s1"), song("s2"), song("s3"))
|
||||
val source =
|
||||
FakeMusicSource(
|
||||
songs = songs,
|
||||
playlists = listOf(playlist("p1")),
|
||||
playlistSongs = songs.mapIndexed { index, song -> PlaylistSong(1, "p1", song.id, index.toLong()) },
|
||||
)
|
||||
|
||||
fun membershipQueryCount() =
|
||||
synchronized(executions) {
|
||||
executions.count {
|
||||
it.sql.startsWith("SELECT playlistId FROM playlist_songs WHERE sourceId = ? AND songId")
|
||||
}
|
||||
}
|
||||
|
||||
SyncService(loggingDb, source).sync()
|
||||
val initialQueries = membershipQueryCount()
|
||||
loggingDb.queueDao().clearPendingSyncOrigins(1)
|
||||
synchronized(executions) { executions.clear() }
|
||||
|
||||
source.songs = emptyList()
|
||||
val deleted = SyncService(loggingDb, source).sync()
|
||||
val deletionQueries = membershipQueryCount()
|
||||
assertTrue(deleted.changedOrigins.contains(QueueOrigin(QueueKind.Playlist, 1, "p1")))
|
||||
assertTrue(loggingDb.queueDao().pendingSyncOrigins(1).any { it.kind == QueueKind.Playlist && it.refId == "p1" })
|
||||
loggingDb.queueDao().clearPendingSyncOrigins(1)
|
||||
synchronized(executions) { executions.clear() }
|
||||
|
||||
source.songs = songs
|
||||
val restored = SyncService(loggingDb, source).sync()
|
||||
val restorationQueries = membershipQueryCount()
|
||||
assertTrue(restored.changedOrigins.contains(QueueOrigin(QueueKind.Playlist, 1, "p1")))
|
||||
assertTrue(loggingDb.queueDao().pendingSyncOrigins(1).any { it.kind == QueueKind.Playlist && it.refId == "p1" })
|
||||
assertEquals(listOf(1, 1, 1), listOf(initialQueries, deletionQueries, restorationQueries))
|
||||
} finally {
|
||||
loggingDb.close()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun downloadedSongSortChangesReportDownloadedOrigins() =
|
||||
runTest {
|
||||
|
||||
Reference in New Issue
Block a user