refactor(db): Migrate mangaCategory queries (that can be migrated) to SQLDelight

This commit is contained in:
Ahmad Ansori Palembani 2024-11-29 19:11:29 +07:00
parent 726613e6d7
commit e8054855ac
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
10 changed files with 71 additions and 24 deletions

View file

@ -20,6 +20,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import yokai.data.DatabaseHandler import yokai.data.DatabaseHandler
import yokai.domain.category.interactor.GetCategories import yokai.domain.category.interactor.GetCategories
import yokai.domain.category.interactor.SetMangaCategories
import yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.GetChapter
import yokai.domain.chapter.interactor.InsertChapter import yokai.domain.chapter.interactor.InsertChapter
import yokai.domain.chapter.interactor.UpdateChapter import yokai.domain.chapter.interactor.UpdateChapter
@ -36,6 +37,7 @@ class MangaBackupRestorer(
private val customMangaManager: CustomMangaManager = Injekt.get(), private val customMangaManager: CustomMangaManager = Injekt.get(),
private val handler: DatabaseHandler = Injekt.get(), private val handler: DatabaseHandler = Injekt.get(),
private val getCategories: GetCategories = Injekt.get(), private val getCategories: GetCategories = Injekt.get(),
private val setMangaCategories: SetMangaCategories = Injekt.get(),
private val getChapter: GetChapter = Injekt.get(), private val getChapter: GetChapter = Injekt.get(),
private val insertChapter: InsertChapter = Injekt.get(), private val insertChapter: InsertChapter = Injekt.get(),
private val updateChapter: UpdateChapter = Injekt.get(), private val updateChapter: UpdateChapter = Injekt.get(),
@ -196,8 +198,7 @@ class MangaBackupRestorer(
// Update database // Update database
if (mangaCategoriesToUpdate.isNotEmpty()) { if (mangaCategoriesToUpdate.isNotEmpty()) {
db.deleteOldMangasCategories(listOf(manga)).executeAsBlocking() setMangaCategories.awaitAll(listOf(manga.id!!), mangaCategoriesToUpdate)
db.insertMangasCategories(mangaCategoriesToUpdate).executeAsBlocking()
} }
} }

View file

@ -10,11 +10,9 @@ import eu.kanade.tachiyomi.domain.manga.models.Manga
interface MangaCategoryQueries : DbProvider { interface MangaCategoryQueries : DbProvider {
fun insertMangaCategory(mangaCategory: MangaCategory) = db.put().`object`(mangaCategory).prepare() private fun insertMangasCategories(mangasCategories: List<MangaCategory>) = db.put().objects(mangasCategories).prepare()
fun insertMangasCategories(mangasCategories: List<MangaCategory>) = db.put().objects(mangasCategories).prepare() private fun deleteOldMangasCategories(mangas: List<Manga>) = db.delete()
fun deleteOldMangasCategories(mangas: List<Manga>) = db.delete()
.byQuery( .byQuery(
DeleteQuery.builder() DeleteQuery.builder()
.table(MangaCategoryTable.TABLE) .table(MangaCategoryTable.TABLE)
@ -24,6 +22,7 @@ interface MangaCategoryQueries : DbProvider {
) )
.prepare() .prepare()
// FIXME: Migrate to SQLDelight, on halt: in StorIO transaction
fun setMangaCategories(mangasCategories: List<MangaCategory>, mangas: List<Manga>) { fun setMangaCategories(mangasCategories: List<MangaCategory>, mangas: List<Manga>) {
db.inTransaction { db.inTransaction {
deleteOldMangasCategories(mangas).executeAsBlocking() deleteOldMangasCategories(mangas).executeAsBlocking()

View file

@ -28,16 +28,17 @@ import eu.kanade.tachiyomi.util.view.checkHeightThen
import eu.kanade.tachiyomi.util.view.expand import eu.kanade.tachiyomi.util.view.expand
import eu.kanade.tachiyomi.widget.E2EBottomSheetDialog import eu.kanade.tachiyomi.widget.E2EBottomSheetDialog
import eu.kanade.tachiyomi.widget.TriStateCheckBox import eu.kanade.tachiyomi.widget.TriStateCheckBox
import uy.kohesive.injekt.injectLazy import java.util.Date
import yokai.i18n.MR import java.util.Locale
import yokai.util.lang.getString
import java.util.*
import kotlin.math.max import kotlin.math.max
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import uy.kohesive.injekt.injectLazy
import yokai.domain.category.interactor.GetCategories import yokai.domain.category.interactor.GetCategories
import yokai.domain.manga.interactor.InsertManga import yokai.domain.category.interactor.SetMangaCategories
import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.interactor.UpdateManga
import yokai.domain.manga.models.MangaUpdate import yokai.domain.manga.models.MangaUpdate
import yokai.i18n.MR
import yokai.util.lang.getString
class SetCategoriesSheet( class SetCategoriesSheet(
private val activity: Activity, private val activity: Activity,
@ -75,6 +76,7 @@ class SetCategoriesSheet(
private val db: DatabaseHelper by injectLazy() private val db: DatabaseHelper by injectLazy()
private val getCategories: GetCategories by injectLazy() private val getCategories: GetCategories by injectLazy()
private val setMangaCategories: SetMangaCategories by injectLazy()
private val updateManga: UpdateManga by injectLazy() private val updateManga: UpdateManga by injectLazy()
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
@ -300,7 +302,7 @@ class SetCategoriesSheet(
Category.lastCategoriesAddedTo = Category.lastCategoriesAddedTo =
addCategories.mapNotNull { it.id }.toSet().ifEmpty { setOf(0) } addCategories.mapNotNull { it.id }.toSet().ifEmpty { setOf(0) }
} }
db.setMangaCategories(mangaCategories, listManga) runBlocking { setMangaCategories.awaitAll(listManga.mapNotNull { it.id }, mangaCategories) }
onMangaAdded() onMangaAdded()
} }
} }

View file

@ -8,7 +8,6 @@ import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Chapter.Companion.copy import eu.kanade.tachiyomi.data.database.models.Chapter.Companion.copy
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.removeCover import eu.kanade.tachiyomi.data.database.models.removeCover
import eu.kanade.tachiyomi.data.database.models.seriesType import eu.kanade.tachiyomi.data.database.models.seriesType
@ -65,6 +64,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import yokai.domain.category.interactor.GetCategories import yokai.domain.category.interactor.GetCategories
import yokai.domain.category.interactor.SetMangaCategories
import yokai.domain.category.interactor.UpdateCategories import yokai.domain.category.interactor.UpdateCategories
import yokai.domain.category.models.CategoryUpdate import yokai.domain.category.models.CategoryUpdate
import yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.GetChapter
@ -93,6 +93,7 @@ class LibraryPresenter(
private val trackManager: TrackManager = Injekt.get(), private val trackManager: TrackManager = Injekt.get(),
) : BaseCoroutinePresenter<LibraryController>(), DownloadQueue.DownloadListener { ) : BaseCoroutinePresenter<LibraryController>(), DownloadQueue.DownloadListener {
private val getCategories: GetCategories by injectLazy() private val getCategories: GetCategories by injectLazy()
private val setMangaCategories: SetMangaCategories by injectLazy()
private val updateCategories: UpdateCategories by injectLazy() private val updateCategories: UpdateCategories by injectLazy()
private val getLibraryManga: GetLibraryManga by injectLazy() private val getLibraryManga: GetLibraryManga by injectLazy()
private val getChapter: GetChapter by injectLazy() private val getChapter: GetChapter by injectLazy()
@ -1384,7 +1385,7 @@ class LibraryPresenter(
val oldCatId = manga.category val oldCatId = manga.category
manga.category = categoryId manga.category = categoryId
val mc = ArrayList<MangaCategory>() val mc = ArrayList<Long>()
val categories = val categories =
if (catId == 0) { if (catId == 0) {
emptyList() emptyList()
@ -1394,10 +1395,10 @@ class LibraryPresenter(
} }
for (cat in categories) { for (cat in categories) {
mc.add(MangaCategory.create(manga, cat)) mc.add(cat.id!!.toLong())
} }
db.setMangaCategories(mc, listOf(manga)) setMangaCategories.await(manga.id!!, mc)
if (category.mangaSort == null) { if (category.mangaSort == null) {
val ids = mangaIds.toMutableList() val ids = mangaIds.toMutableList()

View file

@ -12,7 +12,6 @@ import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.seriesType import eu.kanade.tachiyomi.data.database.models.seriesType
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.EnhancedTrackService import eu.kanade.tachiyomi.data.track.EnhancedTrackService
@ -47,6 +46,7 @@ import kotlinx.coroutines.runBlocking
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import yokai.domain.category.interactor.GetCategories import yokai.domain.category.interactor.GetCategories
import yokai.domain.category.interactor.SetMangaCategories
import yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.GetChapter
import yokai.domain.manga.interactor.GetManga import yokai.domain.manga.interactor.GetManga
import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.interactor.UpdateManga
@ -158,6 +158,7 @@ fun Manga.addOrRemoveToFavorites(
onMangaMoved: () -> Unit, onMangaMoved: () -> Unit,
onMangaDeleted: () -> Unit, onMangaDeleted: () -> Unit,
getCategories: GetCategories = Injekt.get(), getCategories: GetCategories = Injekt.get(),
setMangaCategories: SetMangaCategories = Injekt.get(),
getManga: GetManga = Injekt.get(), getManga: GetManga = Injekt.get(),
updateManga: UpdateManga = Injekt.get(), updateManga: UpdateManga = Injekt.get(),
): Snackbar? { ): Snackbar? {
@ -220,9 +221,8 @@ fun Manga.addOrRemoveToFavorites(
dateAdded = this@addOrRemoveToFavorites.date_added, dateAdded = this@addOrRemoveToFavorites.date_added,
) )
) )
setMangaCategories.await(this@addOrRemoveToFavorites.id!!, listOf(defaultCategory.id!!.toLong()))
} }
val mc = MangaCategory.create(this, defaultCategory)
db.setMangaCategories(listOf(mc), listOf(this))
(activity as? MainActivity)?.showNotificationPermissionPrompt() (activity as? MainActivity)?.showNotificationPermissionPrompt()
onMangaMoved() onMangaMoved()
return view.snack(activity.getString(MR.strings.added_to_, defaultCategory.name)) { return view.snack(activity.getString(MR.strings.added_to_, defaultCategory.name)) {
@ -247,11 +247,8 @@ fun Manga.addOrRemoveToFavorites(
dateAdded = this@addOrRemoveToFavorites.date_added, dateAdded = this@addOrRemoveToFavorites.date_added,
) )
) )
setMangaCategories.await(this@addOrRemoveToFavorites.id!!, lastUsedCategories.map { it.id!!.toLong() })
} }
db.setMangaCategories(
lastUsedCategories.map { MangaCategory.create(this, it) },
listOf(this),
)
(activity as? MainActivity)?.showNotificationPermissionPrompt() (activity as? MainActivity)?.showNotificationPermissionPrompt()
onMangaMoved() onMangaMoved()
return view.snack( return view.snack(
@ -286,8 +283,8 @@ fun Manga.addOrRemoveToFavorites(
dateAdded = this@addOrRemoveToFavorites.date_added, dateAdded = this@addOrRemoveToFavorites.date_added,
) )
) )
setMangaCategories.await(this@addOrRemoveToFavorites.id!!, emptyList())
} }
db.setMangaCategories(emptyList(), listOf(this))
onMangaMoved() onMangaMoved()
(activity as? MainActivity)?.showNotificationPermissionPrompt() (activity as? MainActivity)?.showNotificationPermissionPrompt()
return if (categories.isNotEmpty()) { return if (categories.isNotEmpty()) {

View file

@ -12,6 +12,7 @@ import yokai.domain.category.CategoryRepository
import yokai.domain.category.interactor.DeleteCategories import yokai.domain.category.interactor.DeleteCategories
import yokai.domain.category.interactor.GetCategories import yokai.domain.category.interactor.GetCategories
import yokai.domain.category.interactor.InsertCategories import yokai.domain.category.interactor.InsertCategories
import yokai.domain.category.interactor.SetMangaCategories
import yokai.domain.category.interactor.UpdateCategories import yokai.domain.category.interactor.UpdateCategories
import yokai.domain.chapter.ChapterRepository import yokai.domain.chapter.ChapterRepository
import yokai.domain.chapter.interactor.DeleteChapter import yokai.domain.chapter.interactor.DeleteChapter
@ -75,6 +76,8 @@ fun domainModule() = module {
factory { InsertManga(get()) } factory { InsertManga(get()) }
factory { UpdateManga(get()) } factory { UpdateManga(get()) }
factory { SetMangaCategories(get()) }
single<ChapterRepository> { ChapterRepositoryImpl(get()) } single<ChapterRepository> { ChapterRepositoryImpl(get()) }
factory { DeleteChapter(get()) } factory { DeleteChapter(get()) }
factory { GetAvailableScanlators(get()) } factory { GetAvailableScanlators(get()) }

View file

@ -2,6 +2,7 @@ package yokai.data.manga
import co.touchlab.kermit.Logger import co.touchlab.kermit.Logger
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.mapper import eu.kanade.tachiyomi.data.database.models.mapper
import eu.kanade.tachiyomi.domain.manga.models.Manga import eu.kanade.tachiyomi.domain.manga.models.Manga
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -112,4 +113,20 @@ class MangaRepositoryImpl(private val handler: DatabaseHandler) : MangaRepositor
) )
mangasQueries.selectLastInsertedRowId() mangasQueries.selectLastInsertedRowId()
} }
override suspend fun setCategories(mangaId: Long, categoryIds: List<Long>) =
handler.await(inTransaction = true) {
mangas_categoriesQueries.delete(mangaId)
categoryIds.forEach { id ->
mangas_categoriesQueries.insert(mangaId, id)
}
}
override suspend fun setMultipleMangaCategories(mangaIds: List<Long>, mangaCategories: List<MangaCategory>) =
handler.await(inTransaction = true) {
mangas_categoriesQueries.deleteBulk(mangaIds)
mangaCategories.forEach {
mangas_categoriesQueries.insert(it.manga_id, it.category_id.toLong())
}
}
} }

View file

@ -0,0 +1,12 @@
package yokai.domain.category.interactor
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import yokai.domain.manga.MangaRepository
class SetMangaCategories(
private val mangaRepository: MangaRepository,
) {
suspend fun await(mangaId: Long, categories: List<Long>) = mangaRepository.setCategories(mangaId, categories)
suspend fun awaitAll(mangaIds: List<Long>, mangaCategories: List<MangaCategory>) =
mangaRepository.setMultipleMangaCategories(mangaIds, mangaCategories)
}

View file

@ -1,6 +1,7 @@
package yokai.domain.manga package yokai.domain.manga
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.domain.manga.models.Manga import eu.kanade.tachiyomi.domain.manga.models.Manga
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import yokai.domain.manga.models.MangaUpdate import yokai.domain.manga.models.MangaUpdate
@ -18,4 +19,6 @@ interface MangaRepository {
suspend fun update(update: MangaUpdate): Boolean suspend fun update(update: MangaUpdate): Boolean
suspend fun updateAll(updates: List<MangaUpdate>): Boolean suspend fun updateAll(updates: List<MangaUpdate>): Boolean
suspend fun insert(manga: Manga): Long? suspend fun insert(manga: Manga): Long?
suspend fun setCategories(mangaId: Long, categoryIds: List<Long>)
suspend fun setMultipleMangaCategories(mangaIds: List<Long>, mangaCategories: List<MangaCategory>)
} }

View file

@ -7,3 +7,15 @@ CREATE TABLE mangas_categories(
FOREIGN KEY(manga_id) REFERENCES mangas (_id) FOREIGN KEY(manga_id) REFERENCES mangas (_id)
ON DELETE CASCADE ON DELETE CASCADE
); );
delete:
DELETE FROM mangas_categories
WHERE manga_id = :mangaId;
deleteBulk:
DELETE FROM mangas_categories
WHERE manga_id IN :mangaIds;
insert:
INSERT INTO mangas_categories(manga_id, category_id)
VALUES (:mangaId, :categoryId);