From e25f3301183e8fc9eae0023d6954027c477cb41d Mon Sep 17 00:00:00 2001 From: Ahmad Ansori Palembani Date: Fri, 29 Nov 2024 15:08:42 +0700 Subject: [PATCH] refactor(db): Migrate getChapters query to SQLDelight --- .../data/database/queries/ChapterQueries.kt | 7 +++--- .../data/database/queries/HistoryQueries.kt | 12 ---------- .../tachiyomi/data/track/TrackService.kt | 20 ++++++++++------ .../tachiyomi/ui/library/LibraryPresenter.kt | 8 ++++--- .../manga/process/MigrationProcessHolder.kt | 7 ++++-- .../tachiyomi/ui/more/stats/StatsHelper.kt | 4 +++- .../tachiyomi/ui/more/stats/StatsPresenter.kt | 6 ++++- .../stats/details/StatsDetailsPresenter.kt | 23 +++++++++++-------- .../controllers/SettingsAdvancedController.kt | 7 +++--- .../sqldelight/tachiyomi/data/history.sq | 3 +++ 10 files changed, 54 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt index 07566e2e64..ea6bab0664 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt @@ -8,15 +8,14 @@ import eu.kanade.tachiyomi.domain.manga.models.Manga interface ChapterQueries : DbProvider { - fun getChapters(manga: Manga) = getChapters(manga.id) - - fun getChapters(mangaId: Long?) = db.get() + // FIXME: Migrate to SQLDelight, on halt: in StorIO transaction + fun getChapters(manga: Manga) = db.get() .listOfObjects(Chapter::class.java) .withQuery( Query.builder() .table(ChapterTable.TABLE) .where("${ChapterTable.COL_MANGA_ID} = ?") - .whereArgs(mangaId) + .whereArgs(manga.id) .build(), ) .prepare() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt index 60325a0d92..cacfe9435f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt @@ -79,18 +79,6 @@ interface HistoryQueries : DbProvider { ) .prepare() - fun getTotalReadDuration(): Long { - val cursor = db.lowLevel() - .rawQuery( - RawQuery.builder() - .query("SELECT SUM(${HistoryTable.COL_TIME_READ}) FROM ${HistoryTable.TABLE}") - .observesTables(HistoryTable.TABLE) - .build(), - ) - cursor.moveToFirst() - return cursor.getLong(0) - } - /** * Updates the history last read. * Inserts history object if not yet in database diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt index ee8f2100f7..c5cc59d97f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt @@ -8,16 +8,22 @@ import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.isOneShotOrCompleted import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.NetworkHelper -import eu.kanade.tachiyomi.util.system.executeOnIO import kotlinx.collections.immutable.ImmutableList import okhttp3.OkHttpClient import uy.kohesive.injekt.injectLazy +import yokai.domain.chapter.interactor.GetChapter +import yokai.domain.history.interactor.GetHistory +import yokai.domain.manga.interactor.GetManga abstract class TrackService(val id: Long) { val trackPreferences: TrackPreferences by injectLazy() val networkService: NetworkHelper by injectLazy() val db: DatabaseHelper by injectLazy() + val getChapter: GetChapter by injectLazy() + val getManga: GetManga by injectLazy() + val getHistory: GetHistory by injectLazy() + open fun canRemoveFromService() = false open val client: OkHttpClient get() = networkService.client @@ -110,9 +116,9 @@ abstract class TrackService(val id: Long) { } suspend fun TrackService.updateNewTrackInfo(track: Track) { - val manga = db.getManga(track.manga_id).executeOnIO() + val manga = getManga.awaitById(track.manga_id) val allRead = manga?.isOneShotOrCompleted() == true && - db.getChapters(track.manga_id).executeOnIO().all { it.read } + getChapter.awaitAll(track.manga_id, false).all { it.read } if (supportsReadingDates) { track.started_reading_date = getStartDate(track) track.finished_reading_date = getCompletedDate(track, allRead) @@ -129,8 +135,8 @@ suspend fun TrackService.updateNewTrackInfo(track: Track) { } suspend fun TrackService.getStartDate(track: Track): Long { - if (db.getChapters(track.manga_id).executeOnIO().any { it.read }) { - val chapters = db.getHistoryByMangaId(track.manga_id).executeOnIO().filter { it.last_read > 0 } + if (getChapter.awaitAll(track.manga_id, false).any { it.read }) { + val chapters = getHistory.awaitAllByMangaId(track.manga_id).filter { it.last_read > 0 } val date = chapters.minOfOrNull { it.last_read } ?: return 0L return if (date <= 0L) 0L else date } @@ -139,7 +145,7 @@ suspend fun TrackService.getStartDate(track: Track): Long { suspend fun TrackService.getCompletedDate(track: Track, allRead: Boolean): Long { if (allRead) { - val chapters = db.getHistoryByMangaId(track.manga_id).executeOnIO() + val chapters = getHistory.awaitAllByMangaId(track.manga_id) val date = chapters.maxOfOrNull { it.last_read } ?: return 0L return if (date <= 0L) 0L else date } @@ -147,7 +153,7 @@ suspend fun TrackService.getCompletedDate(track: Track, allRead: Boolean): Long } suspend fun TrackService.getLastChapterRead(track: Track): Float { - val chapters = db.getChapters(track.manga_id).executeOnIO() + val chapters = getChapter.awaitAll(track.manga_id, false) val lastChapterRead = chapters.filter { it.read }.minByOrNull { it.source_order } return lastChapterRead?.takeIf { it.isRecognizedNumber }?.chapter_number ?: 0f } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 58ffd0e425..f142bd6b2b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -70,6 +70,7 @@ import yokai.domain.category.models.CategoryUpdate import yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.UpdateChapter import yokai.domain.chapter.models.ChapterUpdate +import yokai.domain.history.interactor.GetHistory import yokai.domain.manga.interactor.GetLibraryManga import yokai.domain.manga.interactor.GetManga import yokai.domain.manga.interactor.UpdateManga @@ -98,6 +99,7 @@ class LibraryPresenter( private val updateChapter: UpdateChapter by injectLazy() private val updateManga: UpdateManga by injectLazy() private val getTrack: GetTrack by injectLazy() + private val getHistory: GetHistory by injectLazy() private val context = preferences.context private val viewContext @@ -544,9 +546,9 @@ class LibraryPresenter( return if (scoresList.isEmpty()) -1 else scoresList.average().roundToInt().coerceIn(1..10) } - private fun LibraryManga.getStartYear(): Int { - if (db.getChapters(id).executeAsBlocking().any { it.read }) { - val chapters = db.getHistoryByMangaId(id!!).executeAsBlocking().filter { it.last_read > 0 } + private suspend fun LibraryManga.getStartYear(): Int { + if (getChapter.awaitAll(id!!, false).any { it.read }) { + val chapters = getHistory.awaitAllByMangaId(id!!).filter { it.last_read > 0 } val date = chapters.minOfOrNull { it.last_read } ?: return -1 val cal = Calendar.getInstance().apply { timeInMillis = date } return if (date <= 0L) -1 else cal.get(Calendar.YEAR) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt index 150009ebda..e080010e2d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt @@ -24,6 +24,7 @@ import java.text.DecimalFormat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import uy.kohesive.injekt.injectLazy +import yokai.domain.chapter.interactor.GetChapter import yokai.domain.manga.models.cover import yokai.i18n.MR import yokai.presentation.core.util.coil.loadManga @@ -35,6 +36,8 @@ class MigrationProcessHolder( ) : BaseFlexibleViewHolder(view, adapter) { private val db: DatabaseHelper by injectLazy() + private val getChapter: GetChapter by injectLazy() + private val sourceManager: SourceManager by injectLazy() private var item: MigrationProcessItem? = null private val binding = MigrationProcessItemBinding.bind(view) @@ -142,7 +145,7 @@ class MigrationProcessHolder( root.setOnClickListener(null) } - private fun MangaGridItemBinding.attachManga(manga: Manga, source: Source) { + private suspend fun MangaGridItemBinding.attachManga(manga: Manga, source: Source) { (root.layoutParams as ConstraintLayout.LayoutParams).verticalBias = 1f progress.isVisible = false @@ -159,7 +162,7 @@ class MigrationProcessHolder( gradient.isVisible = true title.text = source.toString() - val mangaChapters = db.getChapters(manga).executeAsBlocking() + val mangaChapters = getChapter.awaitAll(manga, false) unreadDownloadBadge.badgeView.setChapters(mangaChapters.size) val latestChapter = mangaChapters.maxOfOrNull { it.chapter_number } ?: -1f diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/StatsHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/StatsHelper.kt index d8b3042c37..f4dcb3b135 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/StatsHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/StatsHelper.kt @@ -80,7 +80,9 @@ object StatsHelper { 201..Int.MAX_VALUE, ) - fun Long.getReadDuration(blankValue: String = "0"): String { + fun Long?.getReadDuration(blankValue: String = "0"): String { + if (this == null) return blankValue + val days = TimeUnit.MILLISECONDS.toDays(this) val hours = TimeUnit.MILLISECONDS.toHours(this) % 24 val minutes = TimeUnit.MILLISECONDS.toMinutes(this) % 60 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/StatsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/StatsPresenter.kt index c54cda1f3d..841c6d2869 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/StatsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/StatsPresenter.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.runBlocking import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy +import yokai.data.DatabaseHandler import yokai.domain.manga.interactor.GetLibraryManga import yokai.domain.track.interactor.GetTrack import yokai.i18n.MR @@ -35,6 +36,7 @@ class StatsPresenter( private val downloadManager: DownloadManager = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(), ): BaseCoroutinePresenter() { + private val handler: DatabaseHandler by injectLazy() private val getLibraryManga: GetLibraryManga by injectLazy() private val getTrack: GetTrack by injectLazy() @@ -86,7 +88,9 @@ class StatsPresenter( } fun getReadDuration(): String { - val chaptersTime = db.getTotalReadDuration() + val chaptersTime = runBlocking { + handler.awaitOneOrNull { historyQueries.getTotalReadDuration() }?.sum?.toLong() + } return chaptersTime.getReadDuration(prefs.context.getString(MR.strings.none)) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/details/StatsDetailsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/details/StatsDetailsPresenter.kt index 3690e4b0f4..e5daafc6a1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/details/StatsDetailsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/details/StatsDetailsPresenter.kt @@ -29,18 +29,21 @@ import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.roundToTwoDecimal import eu.kanade.tachiyomi.util.system.withUIContext +import java.util.Calendar +import java.util.Locale +import java.util.concurrent.TimeUnit +import kotlin.math.roundToInt import kotlinx.coroutines.runBlocking import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy +import yokai.domain.category.interactor.GetCategories +import yokai.domain.chapter.interactor.GetChapter +import yokai.domain.history.interactor.GetHistory import yokai.domain.manga.interactor.GetLibraryManga +import yokai.domain.track.interactor.GetTrack import yokai.i18n.MR import yokai.util.lang.getString -import java.util.* -import java.util.concurrent.* -import kotlin.math.roundToInt -import yokai.domain.category.interactor.GetCategories -import yokai.domain.track.interactor.GetTrack class StatsDetailsPresenter( private val db: DatabaseHelper = Injekt.get(), @@ -49,8 +52,10 @@ class StatsDetailsPresenter( private val sourceManager: SourceManager = Injekt.get(), ) : BaseCoroutinePresenter() { private val getCategories: GetCategories by injectLazy() + private val getChapter: GetChapter by injectLazy() private val getLibraryManga: GetLibraryManga by injectLazy() private val getTrack: GetTrack by injectLazy() + private val getHistory: GetHistory by injectLazy() private val context get() = view?.view?.context ?: prefs.context @@ -357,7 +362,7 @@ class StatsDetailsPresenter( currentStats = currentStats?.take(100)?.let { ArrayList(it) } } - private fun setupStartYear() { + private suspend fun setupStartYear() { currentStats = ArrayList() val libraryFormat = mangasDistinct.filterByChip().groupBy { it.getStartYear() } @@ -537,9 +542,9 @@ class StatsDetailsPresenter( return service?.get10PointScore(this.score) } - private fun LibraryManga.getStartYear(): Int? { - if (db.getChapters(id).executeAsBlocking().any { it.read }) { - val chapters = db.getHistoryByMangaId(id!!).executeAsBlocking().filter { it.last_read > 0 } + private suspend fun LibraryManga.getStartYear(): Int? { + if (getChapter.awaitAll(id!!, false).any { it.read }) { + val chapters = getHistory.awaitAllByMangaId(id!!).filter { it.last_read > 0 } val date = chapters.minOfOrNull { it.last_read } ?: return null val cal = Calendar.getInstance().apply { timeInMillis = date } return if (date <= 0L) null else cal.get(Calendar.YEAR) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/controllers/SettingsAdvancedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/controllers/SettingsAdvancedController.kt index fb37f90bf3..0b465852db 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/controllers/SettingsAdvancedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/controllers/SettingsAdvancedController.kt @@ -18,7 +18,6 @@ import co.touchlab.kermit.Logger import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadProvider import eu.kanade.tachiyomi.data.library.LibraryUpdateJob @@ -87,6 +86,7 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import yokai.domain.base.BasePreferences.ExtensionInstaller +import yokai.domain.chapter.interactor.GetChapter import yokai.domain.extension.interactor.TrustExtension import yokai.domain.manga.interactor.GetManga import yokai.domain.source.SourcePreferences @@ -104,8 +104,7 @@ class SettingsAdvancedController : SettingsLegacyController() { private val readerPreferences: ReaderPreferences by injectLazy() private val sourcePreferences: SourcePreferences by injectLazy() - private val db: DatabaseHelper by injectLazy() - + private val getChapter: GetChapter by injectLazy() private val getManga: GetManga by injectLazy() private val downloadManager: DownloadManager by injectLazy() @@ -511,7 +510,7 @@ class SettingsAdvancedController : SettingsLegacyController() { } continue } - val chapterList = db.getChapters(manga).executeAsBlocking() + val chapterList = getChapter.awaitAll(manga, false) foldersCleared += downloadManager.cleanupChapters(chapterList, manga, source, removeRead, removeNonFavorite) } } diff --git a/data/src/commonMain/sqldelight/tachiyomi/data/history.sq b/data/src/commonMain/sqldelight/tachiyomi/data/history.sq index 3d37157c8e..2daeafd44f 100644 --- a/data/src/commonMain/sqldelight/tachiyomi/data/history.sq +++ b/data/src/commonMain/sqldelight/tachiyomi/data/history.sq @@ -42,6 +42,9 @@ JOIN chapters ON history.history_chapter_id = chapters._id WHERE chapters.url = :chapterUrl AND history.history_chapter_id = chapters._id; +getTotalReadDuration: +SELECT sum(history_time_read) FROM history; + getRecentsUngrouped: SELECT M.*,