Browse Source

Convert clear database queries to SQLDelight

arkon 2 years ago
parent
commit
e15a867106

+ 2 - 2
app/src/main/java/eu/kanade/data/chapter/ChapterRepositoryImpl.kt

@@ -8,12 +8,12 @@ import eu.kanade.tachiyomi.util.system.logcat
 import logcat.LogPriority
 
 class ChapterRepositoryImpl(
-    private val databaseHandler: DatabaseHandler,
+    private val handler: DatabaseHandler,
 ) : ChapterRepository {
 
     override suspend fun update(chapterUpdate: ChapterUpdate) {
         try {
-            databaseHandler.await {
+            handler.await {
                 chaptersQueries.update(
                     chapterUpdate.mangaId,
                     chapterUpdate.url,

+ 3 - 3
app/src/main/java/eu/kanade/data/manga/MangaRepositoryImpl.kt

@@ -8,16 +8,16 @@ import kotlinx.coroutines.flow.Flow
 import logcat.LogPriority
 
 class MangaRepositoryImpl(
-    private val databaseHandler: DatabaseHandler,
+    private val handler: DatabaseHandler,
 ) : MangaRepository {
 
     override fun getFavoritesBySourceId(sourceId: Long): Flow<List<Manga>> {
-        return databaseHandler.subscribeToList { mangasQueries.getFavoriteBySourceId(sourceId, mangaMapper) }
+        return handler.subscribeToList { mangasQueries.getFavoriteBySourceId(sourceId, mangaMapper) }
     }
 
     override suspend fun resetViewerFlags(): Boolean {
         return try {
-            databaseHandler.await { mangasQueries.resetViewerFlags() }
+            handler.await { mangasQueries.resetViewerFlags() }
             true
         } catch (e: Exception) {
             logcat(LogPriority.ERROR, e)

+ 12 - 1
app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt

@@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.source.LocalSource
 import eu.kanade.tachiyomi.source.SourceManager
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.map
+import eu.kanade.tachiyomi.source.Source as LoadedSource
 
 class SourceRepositoryImpl(
     private val sourceManager: SourceManager,
@@ -29,13 +30,23 @@ class SourceRepositoryImpl(
         val sourceIdWithFavoriteCount = handler.subscribeToList { mangasQueries.getSourceIdWithFavoriteCount() }
         return sourceIdWithFavoriteCount.map { sourceIdsWithCount ->
             sourceIdsWithCount
+                .filterNot { it.source == LocalSource.ID }
                 .map { (sourceId, count) ->
                     val source = sourceManager.getOrStub(sourceId).run {
                         sourceMapper(this)
                     }
                     source to count
                 }
-                .filterNot { it.first.id == LocalSource.ID }
+        }
+    }
+
+    override fun getSourcesWithNonLibraryManga(): Flow<List<Pair<LoadedSource, Long>>> {
+        val sourceIdWithNonLibraryManga = handler.subscribeToList { mangasQueries.getSourceIdsWithNonLibraryManga() }
+        return sourceIdWithNonLibraryManga.map { sourceId ->
+            sourceId.map { (sourceId, count) ->
+                val source = sourceManager.getOrStub(sourceId)
+                source to count
+            }
         }
     }
 }

+ 5 - 3
app/src/main/java/eu/kanade/domain/DomainModule.kt

@@ -23,6 +23,7 @@ import eu.kanade.domain.manga.repository.MangaRepository
 import eu.kanade.domain.source.interactor.GetEnabledSources
 import eu.kanade.domain.source.interactor.GetLanguagesWithSources
 import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
+import eu.kanade.domain.source.interactor.GetSourcesWithNonLibraryManga
 import eu.kanade.domain.source.interactor.SetMigrateSorting
 import eu.kanade.domain.source.interactor.ToggleLanguage
 import eu.kanade.domain.source.interactor.ToggleSource
@@ -58,12 +59,13 @@ class DomainModule : InjektModule {
         addFactory { GetExtensionLanguages(get(), get()) }
 
         addSingletonFactory<SourceRepository> { SourceRepositoryImpl(get(), get()) }
-        addFactory { GetLanguagesWithSources(get(), get()) }
         addFactory { GetEnabledSources(get(), get()) }
-        addFactory { ToggleSource(get()) }
-        addFactory { ToggleSourcePin(get()) }
+        addFactory { GetLanguagesWithSources(get(), get()) }
         addFactory { GetSourcesWithFavoriteCount(get(), get()) }
+        addFactory { GetSourcesWithNonLibraryManga(get()) }
         addFactory { SetMigrateSorting(get()) }
         addFactory { ToggleLanguage(get()) }
+        addFactory { ToggleSource(get()) }
+        addFactory { ToggleSourcePin(get()) }
     }
 }

+ 14 - 0
app/src/main/java/eu/kanade/domain/source/interactor/GetSourcesWithNonLibraryManga.kt

@@ -0,0 +1,14 @@
+package eu.kanade.domain.source.interactor
+
+import eu.kanade.domain.source.repository.SourceRepository
+import eu.kanade.tachiyomi.source.Source
+import kotlinx.coroutines.flow.Flow
+
+class GetSourcesWithNonLibraryManga(
+    private val repository: SourceRepository,
+) {
+
+    fun subscribe(): Flow<List<Pair<Source, Long>>> {
+        return repository.getSourcesWithNonLibraryManga()
+    }
+}

+ 3 - 0
app/src/main/java/eu/kanade/domain/source/repository/SourceRepository.kt

@@ -2,6 +2,7 @@ package eu.kanade.domain.source.repository
 
 import eu.kanade.domain.source.model.Source
 import kotlinx.coroutines.flow.Flow
+import eu.kanade.tachiyomi.source.Source as LoadedSource
 
 interface SourceRepository {
 
@@ -10,4 +11,6 @@ interface SourceRepository {
     fun getOnlineSources(): Flow<List<Source>>
 
     fun getSourcesWithFavoriteCount(): Flow<List<Pair<Source, Long>>>
+
+    fun getSourcesWithNonLibraryManga(): Flow<List<Pair<LoadedSource, Long>>>
 }

+ 0 - 3
app/src/main/java/eu/kanade/tachiyomi/data/database/models/SourceIdMangaCount.kt

@@ -1,3 +0,0 @@
-package eu.kanade.tachiyomi.data.database.models
-
-data class SourceIdMangaCount(val source: Long, val count: Int)

+ 0 - 25
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt

@@ -1,20 +1,16 @@
 package eu.kanade.tachiyomi.data.database.queries
 
-import com.pushtorefresh.storio.Queries
 import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects
-import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
 import com.pushtorefresh.storio.sqlite.queries.Query
 import com.pushtorefresh.storio.sqlite.queries.RawQuery
 import eu.kanade.tachiyomi.data.database.DbProvider
 import eu.kanade.tachiyomi.data.database.models.LibraryManga
 import eu.kanade.tachiyomi.data.database.models.Manga
-import eu.kanade.tachiyomi.data.database.models.SourceIdMangaCount
 import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver
 import eu.kanade.tachiyomi.data.database.resolvers.MangaCoverLastModifiedPutResolver
 import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver
 import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
 import eu.kanade.tachiyomi.data.database.resolvers.MangaLastUpdatedPutResolver
-import eu.kanade.tachiyomi.data.database.resolvers.SourceIdMangaCountGetResolver
 import eu.kanade.tachiyomi.data.database.tables.CategoryTable
 import eu.kanade.tachiyomi.data.database.tables.ChapterTable
 import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
@@ -86,17 +82,6 @@ interface MangaQueries : DbProvider {
         )
         .prepare()
 
-    fun getSourceIdsWithNonLibraryManga() = db.get()
-        .listOfObjects(SourceIdMangaCount::class.java)
-        .withQuery(
-            RawQuery.builder()
-                .query(getSourceIdsWithNonLibraryMangaQuery())
-                .observesTables(MangaTable.TABLE)
-                .build(),
-        )
-        .withGetResolver(SourceIdMangaCountGetResolver.INSTANCE)
-        .prepare()
-
     fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
 
     fun insertMangas(mangas: List<Manga>) = db.put().objects(mangas).prepare()
@@ -131,16 +116,6 @@ interface MangaQueries : DbProvider {
         .withPutResolver(MangaCoverLastModifiedPutResolver())
         .prepare()
 
-    fun deleteMangasNotInLibraryBySourceIds(sourceIds: List<Long>) = db.delete()
-        .byQuery(
-            DeleteQuery.builder()
-                .table(MangaTable.TABLE)
-                .where("${MangaTable.COL_FAVORITE} = ? AND ${MangaTable.COL_SOURCE} IN (${Queries.placeholders(sourceIds.size)})")
-                .whereArgs(0, *sourceIds.toTypedArray())
-                .build(),
-        )
-        .prepare()
-
     fun getLastReadManga() = db.get()
         .listOfObjects(Manga::class.java)
         .withQuery(

+ 0 - 12
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt

@@ -1,6 +1,5 @@
 package eu.kanade.tachiyomi.data.database.queries
 
-import eu.kanade.tachiyomi.data.database.resolvers.SourceIdMangaCountGetResolver
 import eu.kanade.tachiyomi.data.database.tables.CategoryTable as Category
 import eu.kanade.tachiyomi.data.database.tables.ChapterTable as Chapter
 import eu.kanade.tachiyomi.data.database.tables.HistoryTable as History
@@ -113,14 +112,3 @@ fun getCategoriesForMangaQuery() =
     ${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID}
     WHERE ${MangaCategory.COL_MANGA_ID} = ?
 """
-
-/** Query to get the list of sources in the database that have
- * non-library manga, and how many
- */
-fun getSourceIdsWithNonLibraryMangaQuery() =
-    """
-    SELECT ${Manga.COL_SOURCE}, COUNT(*) as ${SourceIdMangaCountGetResolver.COL_COUNT}
-    FROM ${Manga.TABLE}
-    WHERE ${Manga.COL_FAVORITE} = 0
-    GROUP BY ${Manga.COL_SOURCE}
-    """

+ 0 - 23
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/SourceIdMangaCountGetResolver.kt

@@ -1,23 +0,0 @@
-package eu.kanade.tachiyomi.data.database.resolvers
-
-import android.annotation.SuppressLint
-import android.database.Cursor
-import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
-import eu.kanade.tachiyomi.data.database.models.SourceIdMangaCount
-import eu.kanade.tachiyomi.data.database.tables.MangaTable
-
-class SourceIdMangaCountGetResolver : DefaultGetResolver<SourceIdMangaCount>() {
-
-    companion object {
-        val INSTANCE = SourceIdMangaCountGetResolver()
-        const val COL_COUNT = "manga_count"
-    }
-
-    @SuppressLint("Range")
-    override fun mapFromCursor(cursor: Cursor): SourceIdMangaCount {
-        val sourceID = cursor.getLong(cursor.getColumnIndexOrThrow(MangaTable.COL_SOURCE))
-        val count = cursor.getInt(cursor.getColumnIndexOrThrow(COL_COUNT))
-
-        return SourceIdMangaCount(sourceID, count)
-    }
-}

+ 20 - 26
app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabasePresenter.kt

@@ -1,43 +1,37 @@
 package eu.kanade.tachiyomi.ui.setting.database
 
 import android.os.Bundle
+import eu.kanade.domain.source.interactor.GetSourcesWithNonLibraryManga
 import eu.kanade.tachiyomi.Database
-import eu.kanade.tachiyomi.data.database.DatabaseHelper
-import eu.kanade.tachiyomi.source.SourceManager
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
-import rx.Observable
-import rx.android.schedulers.AndroidSchedulers
-import rx.schedulers.Schedulers
+import eu.kanade.tachiyomi.util.lang.launchIO
+import eu.kanade.tachiyomi.util.lang.withUIContext
+import kotlinx.coroutines.flow.collectLatest
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 
-class ClearDatabasePresenter : BasePresenter<ClearDatabaseController>() {
-
-    private val db = Injekt.get<DatabaseHelper>()
-    private val database = Injekt.get<Database>()
-
-    private val sourceManager = Injekt.get<SourceManager>()
+class ClearDatabasePresenter(
+    private val database: Database = Injekt.get(),
+    private val getSourcesWithNonLibraryManga: GetSourcesWithNonLibraryManga = Injekt.get(),
+) : BasePresenter<ClearDatabaseController>() {
 
     override fun onCreate(savedState: Bundle?) {
         super.onCreate(savedState)
-        getDatabaseSourcesObservable()
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .subscribeLatestCache(ClearDatabaseController::setItems)
+
+        presenterScope.launchIO {
+            getSourcesWithNonLibraryManga.subscribe()
+                .collectLatest { list ->
+                    val items = list
+                        .map { (source, count) -> ClearDatabaseSourceItem(source, count) }
+                        .sortedBy { it.source.name }
+
+                    withUIContext { view?.setItems(items) }
+                }
+        }
     }
 
     fun clearDatabaseForSourceIds(sources: List<Long>) {
-        db.deleteMangasNotInLibraryBySourceIds(sources).executeAsBlocking()
+        database.mangasQueries.deleteMangasNotInLibraryBySourceIds(sources)
         database.historyQueries.removeResettedHistory()
     }
-
-    private fun getDatabaseSourcesObservable(): Observable<List<ClearDatabaseSourceItem>> {
-        return db.getSourceIdsWithNonLibraryManga().asRxObservable()
-            .map { sourceCounts ->
-                sourceCounts.map {
-                    val sourceObj = sourceManager.getOrStub(it.source)
-                    ClearDatabaseSourceItem(sourceObj, it.count)
-                }.sortedBy { it.source.name }
-            }
-    }
 }

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseSourceItem.kt

@@ -13,7 +13,7 @@ import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.source.SourceManager
 import eu.kanade.tachiyomi.source.icon
 
-data class ClearDatabaseSourceItem(val source: Source, private val mangaCount: Int) : AbstractFlexibleItem<ClearDatabaseSourceItem.Holder>() {
+data class ClearDatabaseSourceItem(val source: Source, private val mangaCount: Long) : AbstractFlexibleItem<ClearDatabaseSourceItem.Holder>() {
 
     override fun getLayoutRes(): Int {
         return R.layout.clear_database_source_item
@@ -31,7 +31,7 @@ data class ClearDatabaseSourceItem(val source: Source, private val mangaCount: I
 
         private val binding = ClearDatabaseSourceItemBinding.bind(view)
 
-        fun bind(source: Source, count: Int) {
+        fun bind(source: Source, count: Long) {
             binding.title.text = source.toString()
             binding.description.text = itemView.context.getString(R.string.clear_database_source_item_count, count)
 

+ 11 - 1
app/src/main/sqldelight/data/mangas.sq

@@ -46,4 +46,14 @@ AND source = :sourceId;
 
 resetViewerFlags:
 UPDATE mangas
-SET viewer = 0;
+SET viewer = 0;
+
+getSourceIdsWithNonLibraryManga:
+SELECT source, COUNT(*) AS manga_count
+FROM mangas
+WHERE favorite = 0
+GROUP BY source;
+
+deleteMangasNotInLibraryBySourceIds:
+DELETE FROM mangas
+WHERE favorite = 0 AND source IN :sourceIds;