Improve timeline dao (#2353)

* improve TimelineDao methods

* remove @Transaction from cleanup methods
This commit is contained in:
Konrad Pozniak 2022-03-02 20:40:06 +01:00 committed by GitHub
parent a6335e6bcd
commit 497b434663
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 26 deletions

View file

@ -3,9 +3,7 @@ package com.keylesspalace.tusky.appstore
import com.google.gson.Gson import com.google.gson.Gson
import com.keylesspalace.tusky.db.AccountManager import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.AppDatabase import com.keylesspalace.tusky.db.AppDatabase
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import javax.inject.Inject import javax.inject.Inject
class CacheUpdater @Inject constructor( class CacheUpdater @Inject constructor(
@ -47,12 +45,7 @@ class CacheUpdater @Inject constructor(
this.disposable.dispose() this.disposable.dispose()
} }
fun clearForUser(accountId: Long) { suspend fun clearForUser(accountId: Long) {
Single.fromCallable { appDatabase.timelineDao().removeAll(accountId)
appDatabase.timelineDao().removeAllForAccount(accountId)
appDatabase.timelineDao().removeAllUsersForAccount(accountId)
}
.subscribeOn(Schedulers.io())
.subscribe()
} }
} }

View file

@ -70,7 +70,7 @@ class CachedTimelineViewModel @Inject constructor(
override val statuses = Pager( override val statuses = Pager(
config = PagingConfig(pageSize = LOAD_AT_ONCE), config = PagingConfig(pageSize = LOAD_AT_ONCE),
remoteMediator = CachedTimelineRemoteMediator(accountManager, api, db, gson), remoteMediator = CachedTimelineRemoteMediator(accountManager, api, db, gson),
pagingSourceFactory = { db.timelineDao().getStatusesForAccount(accountManager.activeAccount!!.id) } pagingSourceFactory = { db.timelineDao().getStatuses(accountManager.activeAccount!!.id) }
).flow ).flow
.map { pagingData -> .map { pagingData ->
pagingData.map { timelineStatus -> pagingData.map { timelineStatus ->
@ -214,10 +214,7 @@ class CachedTimelineViewModel @Inject constructor(
override fun fullReload() { override fun fullReload() {
viewModelScope.launch { viewModelScope.launch {
val activeAccount = accountManager.activeAccount!! val activeAccount = accountManager.activeAccount!!
db.runInTransaction { db.timelineDao().removeAll(activeAccount.id)
db.timelineDao().removeAllForAccount(activeAccount.id)
db.timelineDao().removeAllUsersForAccount(activeAccount.id)
}
} }
} }

View file

@ -51,7 +51,7 @@ LEFT JOIN TimelineAccountEntity rb ON (s.timelineUserId = rb.timelineUserId AND
WHERE s.timelineUserId = :account WHERE s.timelineUserId = :account
ORDER BY LENGTH(s.serverId) DESC, s.serverId DESC""" ORDER BY LENGTH(s.serverId) DESC, s.serverId DESC"""
) )
abstract fun getStatusesForAccount(account: Long): PagingSource<Int, TimelineStatusWithAccount> abstract fun getStatuses(account: Long): PagingSource<Int, TimelineStatusWithAccount>
@Query( @Query(
"""DELETE FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND """DELETE FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND
@ -86,11 +86,20 @@ WHERE timelineUserId = :accountId AND (serverId = :statusId OR reblogServerId =
) )
abstract fun removeAllByUser(accountId: Long, userId: String) abstract fun removeAllByUser(accountId: Long, userId: String)
/**
* Removes everything in the TimelineStatusEntity and TimelineAccountEntity tables for one user account
* @param accountId id of the account for which to clean tables
*/
suspend fun removeAll(accountId: Long) {
removeAllStatuses(accountId)
removeAllAccounts(accountId)
}
@Query("DELETE FROM TimelineStatusEntity WHERE timelineUserId = :accountId") @Query("DELETE FROM TimelineStatusEntity WHERE timelineUserId = :accountId")
abstract fun removeAllForAccount(accountId: Long) abstract suspend fun removeAllStatuses(accountId: Long)
@Query("DELETE FROM TimelineAccountEntity WHERE timelineUserId = :accountId") @Query("DELETE FROM TimelineAccountEntity WHERE timelineUserId = :accountId")
abstract fun removeAllUsersForAccount(accountId: Long) abstract suspend fun removeAllAccounts(accountId: Long)
@Query( @Query(
"""DELETE FROM TimelineStatusEntity WHERE timelineUserId = :accountId """DELETE FROM TimelineStatusEntity WHERE timelineUserId = :accountId
@ -98,6 +107,16 @@ AND serverId = :statusId"""
) )
abstract fun delete(accountId: Long, statusId: String) abstract fun delete(accountId: Long, statusId: String)
/**
* Cleans the TimelineStatusEntity and TimelineAccountEntity tables from old entries.
* @param accountId id of the account for which to clean tables
* @param limit how many statuses to keep
*/
suspend fun cleanup(accountId: Long, limit: Int) {
cleanupStatuses(accountId, limit)
cleanupAccounts(accountId)
}
/** /**
* Cleans the TimelineStatusEntity table from old status entries. * Cleans the TimelineStatusEntity table from old status entries.
* @param accountId id of the account for which to clean statuses * @param accountId id of the account for which to clean statuses
@ -108,7 +127,7 @@ AND serverId = :statusId"""
(SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT :limit) (SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT :limit)
""" """
) )
abstract suspend fun cleanup(accountId: Long, limit: Int) abstract suspend fun cleanupStatuses(accountId: Long, limit: Int)
/** /**
* Cleans the TimelineAccountEntity table from accounts that are no longer referenced in the TimelineStatusEntity table * Cleans the TimelineAccountEntity table from accounts that are no longer referenced in the TimelineStatusEntity table

View file

@ -514,7 +514,7 @@ class CachedTimelineRemoteMediatorTest {
expected: List<TimelineStatusWithAccount>, expected: List<TimelineStatusWithAccount>,
forAccount: Long = 1 forAccount: Long = 1
) { ) {
val pagingSource = timelineDao().getStatusesForAccount(forAccount) val pagingSource = timelineDao().getStatuses(forAccount)
val loadResult = runBlocking { val loadResult = runBlocking {
pagingSource.load(PagingSource.LoadParams.Refresh(null, 100, false)) pagingSource.load(PagingSource.LoadParams.Refresh(null, 100, false))

View file

@ -53,7 +53,7 @@ class TimelineDaoTest {
timelineDao.insertStatus(status) timelineDao.insertStatus(status)
} }
val pagingSource = timelineDao.getStatusesForAccount(setOne.first.timelineUserId) val pagingSource = timelineDao.getStatuses(setOne.first.timelineUserId)
val loadResult = pagingSource.load(PagingSource.LoadParams.Refresh(null, 2, false)) val loadResult = pagingSource.load(PagingSource.LoadParams.Refresh(null, 2, false))
@ -96,7 +96,7 @@ class TimelineDaoTest {
val loadParams: PagingSource.LoadParams<Int> = PagingSource.LoadParams.Refresh(null, 100, false) val loadParams: PagingSource.LoadParams<Int> = PagingSource.LoadParams.Refresh(null, 100, false)
val loadedStatuses = (timelineDao.getStatusesForAccount(1).load(loadParams) as PagingSource.LoadResult.Page).data val loadedStatuses = (timelineDao.getStatuses(1).load(loadParams) as PagingSource.LoadResult.Page).data
assertStatuses(statusesAfterCleanup, loadedStatuses) assertStatuses(statusesAfterCleanup, loadedStatuses)
@ -157,7 +157,7 @@ class TimelineDaoTest {
// make sure status 2 is no longer in db // make sure status 2 is no longer in db
val pagingSource = timelineDao.getStatusesForAccount(1) val pagingSource = timelineDao.getStatuses(1)
val loadResult = pagingSource.load(PagingSource.LoadParams.Refresh(null, 100, false)) val loadResult = pagingSource.load(PagingSource.LoadParams.Refresh(null, 100, false))
@ -197,8 +197,8 @@ class TimelineDaoTest {
val loadParams: PagingSource.LoadParams<Int> = PagingSource.LoadParams.Refresh(null, 100, false) val loadParams: PagingSource.LoadParams<Int> = PagingSource.LoadParams.Refresh(null, 100, false)
val statusesAccount1 = (timelineDao.getStatusesForAccount(1).load(loadParams) as PagingSource.LoadResult.Page).data val statusesAccount1 = (timelineDao.getStatuses(1).load(loadParams) as PagingSource.LoadResult.Page).data
val statusesAccount2 = (timelineDao.getStatusesForAccount(2).load(loadParams) as PagingSource.LoadResult.Page).data val statusesAccount2 = (timelineDao.getStatuses(2).load(loadParams) as PagingSource.LoadResult.Page).data
val remainingStatusesAccount1 = listOf( val remainingStatusesAccount1 = listOf(
makeStatus(statusId = 100), makeStatus(statusId = 100),
@ -269,8 +269,8 @@ class TimelineDaoTest {
val loadParams: PagingSource.LoadParams<Int> = PagingSource.LoadParams.Refresh(null, 100, false) val loadParams: PagingSource.LoadParams<Int> = PagingSource.LoadParams.Refresh(null, 100, false)
val statusesAccount1 = (timelineDao.getStatusesForAccount(1).load(loadParams) as PagingSource.LoadResult.Page).data val statusesAccount1 = (timelineDao.getStatuses(1).load(loadParams) as PagingSource.LoadResult.Page).data
val statusesAccount2 = (timelineDao.getStatusesForAccount(2).load(loadParams) as PagingSource.LoadResult.Page).data val statusesAccount2 = (timelineDao.getStatuses(2).load(loadParams) as PagingSource.LoadResult.Page).data
assertStatuses(listOf(statusWithBlueDomain, statusWithGreenDomain), statusesAccount1) assertStatuses(listOf(statusWithBlueDomain, statusWithGreenDomain), statusesAccount1)
assertStatuses(listOf(statusWithRedDomainOtherAccount, statusWithBlueDomainOtherAccount), statusesAccount2) assertStatuses(listOf(statusWithRedDomainOtherAccount, statusWithBlueDomainOtherAccount), statusesAccount2)