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.upsertChanged("song_artists", songArtistKey, artists) { it.columns() }
|
||||||
|
connection.recordPlaylistOrigins(batch.filter { previousStates[it.id] == null }.map { it.id })
|
||||||
batch.forEach { song ->
|
batch.forEach { song ->
|
||||||
val previous = previousStates[song.id]
|
val previous = previousStates[song.id]
|
||||||
val next = nextStates.getValue(song.id)
|
val next = nextStates.getValue(song.id)
|
||||||
@@ -242,7 +243,9 @@ class SyncService(
|
|||||||
ids.forEach { changedOrigins += origin(QueueKind.Song, it) }
|
ids.forEach { changedOrigins += origin(QueueKind.Song, it) }
|
||||||
db.useWriterConnection { connection ->
|
db.useWriterConnection { connection ->
|
||||||
connection.immediateTransaction {
|
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, "")
|
if (connection.completedDownloadIds(ids.toList()).isNotEmpty()) changedOrigins += origin(QueueKind.Downloaded, "")
|
||||||
db.libraryDao().deleteSongs(source.id, ids)
|
db.libraryDao().deleteSongs(source.id, ids)
|
||||||
connection.persistPendingOrigins()
|
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(
|
private suspend fun PooledConnection.recordSongOrigins(
|
||||||
previous: SongSyncState?,
|
previous: SongSyncState?,
|
||||||
next: 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)
|
val states = listOfNotNull(previous, next)
|
||||||
states.mapTo(changedOrigins) { origin(QueueKind.Song, it.id) }
|
states.mapTo(changedOrigins) { origin(QueueKind.Song, it.id) }
|
||||||
states.mapNotNullTo(changedOrigins) { it.albumId?.let { id -> origin(QueueKind.Album, 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")))
|
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
|
@Test
|
||||||
fun downloadedSongSortChangesReportDownloadedOrigins() =
|
fun downloadedSongSortChangesReportDownloadedOrigins() =
|
||||||
runTest {
|
runTest {
|
||||||
|
|||||||
Reference in New Issue
Block a user