CleanupDao -> DatabaseCleaner

This commit is contained in:
Conny Duck 2024-05-03 15:13:56 +02:00
parent a78433adcc
commit a6e9fc1a4d
No known key found for this signature in database
6 changed files with 80 additions and 75 deletions

View File

@ -28,7 +28,6 @@ import androidx.sqlite.db.SupportSQLiteDatabase;
import com.keylesspalace.tusky.TabDataKt;
import com.keylesspalace.tusky.components.conversation.ConversationEntity;
import com.keylesspalace.tusky.db.dao.AccountDao;
import com.keylesspalace.tusky.db.dao.CleanupDao;
import com.keylesspalace.tusky.db.dao.DraftDao;
import com.keylesspalace.tusky.db.dao.InstanceDao;
import com.keylesspalace.tusky.db.dao.NotificationsDao;
@ -83,7 +82,6 @@ public abstract class AppDatabase extends RoomDatabase {
@NonNull public abstract NotificationsDao notificationsDao();
@NonNull public abstract TimelineStatusDao timelineStatusDao();
@NonNull public abstract TimelineAccountDao timelineAccountDao();
@NonNull public abstract CleanupDao cleanupDao();
public static final Migration MIGRATION_2_3 = new Migration(2, 3) {
@Override

View File

@ -0,0 +1,66 @@
/* Copyright 2024 Tusky Contributors
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.db
import androidx.room.withTransaction
import com.keylesspalace.tusky.db.entity.HomeTimelineEntity
import com.keylesspalace.tusky.db.entity.NotificationEntity
import com.keylesspalace.tusky.db.entity.NotificationReportEntity
import com.keylesspalace.tusky.db.entity.TimelineAccountEntity
import com.keylesspalace.tusky.db.entity.TimelineStatusEntity
import javax.inject.Inject
class DatabaseCleaner @Inject constructor(
private val db: AppDatabase
) {
/**
* Cleans the [HomeTimelineEntity], [TimelineStatusEntity], [TimelineAccountEntity], [NotificationEntity] and [NotificationReportEntity] tables from old entries.
* Should be regularly run to prevent the database from growing too big.
* @param tuskyAccountId id of the account for which to clean tables
* @param timelineLimit how many timeline items to keep
* @param notificationLimit how many notifications to keep
*/
suspend fun cleanupOldData(
tuskyAccountId: Long,
timelineLimit: Int,
notificationLimit: Int
) {
db.withTransaction {
// the order here is important - foreign key constraints must not be violated
db.notificationsDao().cleanupNotifications(tuskyAccountId, notificationLimit)
db.notificationsDao().cleanupReports(tuskyAccountId)
db.timelineDao().cleanupHomeTimeline(tuskyAccountId, timelineLimit)
db.timelineStatusDao().cleanupStatuses(tuskyAccountId)
db.timelineAccountDao().cleanupAccounts(tuskyAccountId)
}
}
/**
* Deletes everything from the [HomeTimelineEntity], [TimelineStatusEntity], [TimelineAccountEntity], [NotificationEntity] and [NotificationReportEntity] tables for one user.
* Intended to be used when a user logs out.
* @param tuskyAccountId id of the account for which to clean tables
*/
suspend fun cleanupEverything(tuskyAccountId: Long) {
db.withTransaction {
// the order here is important - foreign key constraints must not be violated
db.notificationsDao().removeAllNotifications(tuskyAccountId)
db.notificationsDao().removeAllReports(tuskyAccountId)
db.timelineDao().removeAllHomeTimelineItems(tuskyAccountId)
db.timelineStatusDao().removeAllStatuses(tuskyAccountId)
db.timelineAccountDao().removeAllAccounts(tuskyAccountId)
}
}
}

View File

@ -1,60 +0,0 @@
/* Copyright 2024 Tusky Contributors
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.db.dao
import androidx.room.Dao
import androidx.room.Transaction
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.entity.HomeTimelineEntity
import com.keylesspalace.tusky.db.entity.NotificationEntity
import com.keylesspalace.tusky.db.entity.NotificationReportEntity
import com.keylesspalace.tusky.db.entity.TimelineAccountEntity
import com.keylesspalace.tusky.db.entity.TimelineStatusEntity
@Dao
abstract class CleanupDao(
private val db: AppDatabase
) {
/**
* Cleans the [HomeTimelineEntity], [TimelineStatusEntity], [TimelineAccountEntity], [NotificationEntity] and [NotificationReportEntity] tables from old entries.
* @param tuskyAccountId id of the account for which to clean tables
* @param timelineLimit how many timeline items to keep
* @param notificationLimit how many notifications to keep
*/
@Transaction
open suspend fun cleanupOldData(
tuskyAccountId: Long,
timelineLimit: Int,
notificationLimit: Int
) {
// the order here is important - foreign key constraints must not be violated
db.notificationsDao().cleanupNotifications(tuskyAccountId, notificationLimit)
db.notificationsDao().cleanupReports(tuskyAccountId)
db.timelineDao().cleanupHomeTimeline(tuskyAccountId, timelineLimit)
db.timelineStatusDao().cleanupStatuses(tuskyAccountId)
db.timelineAccountDao().cleanupAccounts(tuskyAccountId)
}
@Transaction
open suspend fun cleanupEverything(tuskyAccountId: Long) {
// the order here is important - foreign key constraints must not be violated
db.notificationsDao().removeAllNotifications(tuskyAccountId)
db.notificationsDao().removeAllReports(tuskyAccountId)
db.timelineDao().removeAllHomeTimelineItems(tuskyAccountId)
db.timelineStatusDao().removeAllStatuses(tuskyAccountId)
db.timelineAccountDao().removeAllAccounts(tuskyAccountId)
}
}

View File

@ -5,7 +5,7 @@ import com.keylesspalace.tusky.components.drafts.DraftHelper
import com.keylesspalace.tusky.components.systemnotifications.NotificationHelper
import com.keylesspalace.tusky.components.systemnotifications.disableUnifiedPushNotificationsForAccount
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.DatabaseCleaner
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.ShareShortcutHelper
import javax.inject.Inject
@ -13,7 +13,7 @@ import javax.inject.Inject
class LogoutUsecase @Inject constructor(
private val context: Context,
private val api: MastodonApi,
private val db: AppDatabase,
private val databaseCleaner: DatabaseCleaner,
private val accountManager: AccountManager,
private val draftHelper: DraftHelper,
private val shareShortcutHelper: ShareShortcutHelper
@ -53,7 +53,7 @@ class LogoutUsecase @Inject constructor(
val otherAccountAvailable = accountManager.logActiveAccountOut() != null
// clear the database - this could trigger network calls so do it last when all tokens are gone
db.cleanupDao().cleanupEverything(activeAccount.id)
databaseCleaner.cleanupEverything(activeAccount.id)
draftHelper.deleteAllDraftsAndAttachmentsForAccount(activeAccount.id)
// remove shortcut associated with the account

View File

@ -28,14 +28,14 @@ import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.systemnotifications.NotificationHelper
import com.keylesspalace.tusky.components.systemnotifications.NotificationHelper.NOTIFICATION_ID_PRUNE_CACHE
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.DatabaseCleaner
import javax.inject.Inject
/** Prune the database cache of old statuses. */
class PruneCacheWorker(
appContext: Context,
workerParams: WorkerParameters,
private val appDatabase: AppDatabase,
private val databaseCleaner: DatabaseCleaner,
private val accountManager: AccountManager
) : CoroutineWorker(appContext, workerParams) {
val notification: Notification = NotificationHelper.createWorkerNotification(
@ -46,7 +46,7 @@ class PruneCacheWorker(
override suspend fun doWork(): Result {
for (account in accountManager.accounts) {
Log.d(TAG, "Pruning database using account ID: ${account.id}")
appDatabase.cleanupDao().cleanupOldData(account.id, MAX_HOMETIMELINE_ITEMS_IN_CACHE, MAX_NOTIFICATIONS_IN_CACHE)
databaseCleaner.cleanupOldData(account.id, MAX_HOMETIMELINE_ITEMS_IN_CACHE, MAX_NOTIFICATIONS_IN_CACHE)
}
return Result.success()
}
@ -64,11 +64,11 @@ class PruneCacheWorker(
}
class Factory @Inject constructor(
private val appDatabase: AppDatabase,
private val databaseCleaner: DatabaseCleaner,
private val accountManager: AccountManager
) : ChildWorkerFactory {
override fun createWorker(appContext: Context, params: WorkerParameters): ListenableWorker {
return PruneCacheWorker(appContext, params, appDatabase, accountManager)
return PruneCacheWorker(appContext, params, databaseCleaner, accountManager)
}
}
}

View File

@ -12,6 +12,7 @@ import com.keylesspalace.tusky.components.timeline.fakeStatus
import com.keylesspalace.tusky.components.timeline.insert
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.Converters
import com.keylesspalace.tusky.db.DatabaseCleaner
import com.keylesspalace.tusky.db.entity.HomeTimelineEntity
import com.keylesspalace.tusky.db.entity.NotificationEntity
import com.keylesspalace.tusky.db.entity.NotificationReportEntity
@ -29,9 +30,9 @@ import org.robolectric.annotation.Config
@Config(sdk = [28])
@RunWith(AndroidJUnit4::class)
class CleanupDaoTest {
class DatabaseCleanerTest {
private lateinit var timelineDao: TimelineDao
private lateinit var cleanupDao: CleanupDao
private lateinit var dbCleaner: DatabaseCleaner
private lateinit var db: AppDatabase
private val moshi = NetworkModule.providesMoshi()
@ -44,7 +45,7 @@ class CleanupDaoTest {
.allowMainThreadQueries()
.build()
timelineDao = db.timelineDao()
cleanupDao = db.cleanupDao()
dbCleaner = DatabaseCleaner(db)
}
@After
@ -56,7 +57,7 @@ class CleanupDaoTest {
fun cleanupOldData() = runTest {
fillDatabase()
cleanupDao.cleanupOldData(tuskyAccountId = 1, timelineLimit = 3, notificationLimit = 3)
dbCleaner.cleanupOldData(tuskyAccountId = 1, timelineLimit = 3, notificationLimit = 3)
// all but 3 timeline items and notifications and all references items should be gone for Tusky account 1
// items of Tusky account 2 should be untouched
@ -117,7 +118,7 @@ class CleanupDaoTest {
fun cleanupEverything() = runTest {
fillDatabase()
cleanupDao.cleanupEverything(tuskyAccountId = 1)
dbCleaner.cleanupEverything(tuskyAccountId = 1)
// everything from Tusky account 1 should be gone
// items of Tusky account 2 should be untouched