Upgrade to SQLDelight 2

(cherry picked from commit 6a558ad119ff35336c2141deefc5da4b49cf4553)

# Conflicts:
#	app/build.gradle.kts
#	app/src/main/java/eu/kanade/tachiyomi/AppModule.kt
#	data/src/main/java/tachiyomi/data/manga/MangaMapper.kt
#	data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt
#	data/src/main/sqldelight/tachiyomi/data/mangas.sq
This commit is contained in:
arkon 2023-06-24 22:49:36 -04:00 committed by Jobobby04
parent bc898118b8
commit af41e65b3d
31 changed files with 169 additions and 91 deletions

View File

@ -168,6 +168,7 @@ dependencies {
implementation(androidx.paging.compose) implementation(androidx.paging.compose)
implementation(libs.bundles.sqlite) implementation(libs.bundles.sqlite)
implementation(libs.sqldelight.primitive.adapters)
// SY --> // SY -->
implementation(libs.sqlcipher) implementation(libs.sqlcipher)
// SY <-- // SY <--

View File

@ -5,8 +5,10 @@ import android.os.Build
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import com.squareup.sqldelight.android.AndroidSqliteDriver import app.cash.sqldelight.adapter.primitive.FloatColumnAdapter
import com.squareup.sqldelight.db.SqlDriver import app.cash.sqldelight.adapter.primitive.IntColumnAdapter
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.base.BasePreferences
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.domain.track.service.TrackPreferences
@ -42,13 +44,16 @@ import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.provider.AndroidBackupFolderProvider import tachiyomi.core.provider.AndroidBackupFolderProvider
import tachiyomi.core.provider.AndroidDownloadFolderProvider import tachiyomi.core.provider.AndroidDownloadFolderProvider
import tachiyomi.data.AndroidDatabaseHandler import tachiyomi.data.AndroidDatabaseHandler
import tachiyomi.data.Categories import tachiyomi.data.Chapters
import tachiyomi.data.Database import tachiyomi.data.Database
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.data.History import tachiyomi.data.History
import tachiyomi.data.Manga_sync
import tachiyomi.data.Mangas import tachiyomi.data.Mangas
import tachiyomi.data.Search_metadata
import tachiyomi.data.Search_tags
import tachiyomi.data.Search_titles
import tachiyomi.data.dateAdapter import tachiyomi.data.dateAdapter
import tachiyomi.data.listOfLongsAdapter
import tachiyomi.data.listOfStringsAdapter import tachiyomi.data.listOfStringsAdapter
import tachiyomi.data.listOfStringsAndAdapter import tachiyomi.data.listOfStringsAndAdapter
import tachiyomi.data.updateStrategyAdapter import tachiyomi.data.updateStrategyAdapter
@ -122,9 +127,15 @@ class AppModule(val app: Application) : InjektModule {
addSingletonFactory { addSingletonFactory {
Database( Database(
driver = get(), driver = get(),
chaptersAdapter = Chapters.Adapter(
chapter_numberAdapter = FloatColumnAdapter,
),
historyAdapter = History.Adapter( historyAdapter = History.Adapter(
last_readAdapter = dateAdapter, last_readAdapter = dateAdapter,
), ),
manga_syncAdapter = Manga_sync.Adapter(
scoreAdapter = FloatColumnAdapter,
),
mangasAdapter = Mangas.Adapter( mangasAdapter = Mangas.Adapter(
genreAdapter = listOfStringsAdapter, genreAdapter = listOfStringsAdapter,
update_strategyAdapter = updateStrategyAdapter, update_strategyAdapter = updateStrategyAdapter,
@ -132,11 +143,15 @@ class AppModule(val app: Application) : InjektModule {
filtered_scanlatorsAdapter = listOfStringsAndAdapter, filtered_scanlatorsAdapter = listOfStringsAndAdapter,
// SY <-- // SY <--
), ),
// SY --> search_metadataAdapter = Search_metadata.Adapter(
categoriesAdapter = Categories.Adapter( extra_versionAdapter = IntColumnAdapter,
manga_orderAdapter = listOfLongsAdapter, ),
search_tagsAdapter = Search_tags.Adapter(
typeAdapter = IntColumnAdapter,
),
search_titlesAdapter = Search_titles.Adapter(
typeAdapter = IntColumnAdapter,
), ),
// SY <--
) )
} }
addSingletonFactory<DatabaseHandler> { AndroidDatabaseHandler(get(), get()) } addSingletonFactory<DatabaseHandler> { AndroidDatabaseHandler(get(), get()) }

View File

@ -333,7 +333,7 @@ class BackupManager(
} }
if (!found) { if (!found) {
// Let the db assign the id // Let the db assign the id
val id = handler.awaitOne { val id = handler.awaitOneExecutable {
categoriesQueries.insert(category.name, category.order, category.flags) categoriesQueries.insert(category.name, category.order, category.flags)
categoriesQueries.selectLastInsertedRowId() categoriesQueries.selectLastInsertedRowId()
} }
@ -557,7 +557,7 @@ class BackupManager(
* @return id of [Manga], null if not found * @return id of [Manga], null if not found
*/ */
private suspend fun insertManga(manga: Manga): Long { private suspend fun insertManga(manga: Manga): Long {
return handler.awaitOne(true) { return handler.awaitOneExecutable(true) {
mangasQueries.insert( mangasQueries.insert(
source = manga.source, source = manga.source,
url = manga.url, url = manga.url,
@ -598,11 +598,11 @@ class BackupManager(
title = manga.title, title = manga.title,
status = manga.status, status = manga.status,
thumbnailUrl = manga.thumbnailUrl, thumbnailUrl = manga.thumbnailUrl,
favorite = manga.favorite.toLong(), favorite = manga.favorite,
lastUpdate = manga.lastUpdate, lastUpdate = manga.lastUpdate,
nextUpdate = null, nextUpdate = null,
calculateInterval = null, calculateInterval = null,
initialized = manga.initialized.toLong(), initialized = manga.initialized,
viewer = manga.viewerFlags, viewer = manga.viewerFlags,
chapterFlags = manga.chapterFlags, chapterFlags = manga.chapterFlags,
coverLastModified = manga.coverLastModified, coverLastModified = manga.coverLastModified,
@ -651,8 +651,8 @@ class BackupManager(
url = null, url = null,
name = null, name = null,
scanlator = null, scanlator = null,
read = chapter.read.toLong(), read = chapter.read,
bookmark = chapter.bookmark.toLong(), bookmark = chapter.bookmark,
lastPageRead = chapter.lastPageRead, lastPageRead = chapter.lastPageRead,
chapterNumber = null, chapterNumber = null,
sourceOrder = null, sourceOrder = null,

View File

@ -2,7 +2,7 @@ plugins {
id("com.android.library") id("com.android.library")
kotlin("android") kotlin("android")
kotlin("plugin.serialization") kotlin("plugin.serialization")
id("com.squareup.sqldelight") id("app.cash.sqldelight")
} }
android { android {
@ -13,10 +13,12 @@ android {
} }
sqldelight { sqldelight {
database("Database") { databases {
packageName = "tachiyomi.data" create("Database") {
dialect = "sqlite:3.24" packageName.set("tachiyomi.data")
schemaOutputDirectory = project.file("./src/main/sqldelight") dialect(libs.sqldelight.dialects.sql)
schemaOutputDirectory.set(project.file("./src/main/sqldelight"))
}
} }
} }
} }
@ -26,9 +28,7 @@ dependencies {
implementation(project(":domain")) implementation(project(":domain"))
implementation(project(":core")) implementation(project(":core"))
api(libs.sqldelight.android.driver) api(libs.bundles.sqldelight)
api(libs.sqldelight.coroutines)
api(libs.sqldelight.android.paging)
} }
tasks { tasks {

View File

@ -1,12 +1,13 @@
package tachiyomi.data package tachiyomi.data
import androidx.paging.PagingSource import androidx.paging.PagingSource
import com.squareup.sqldelight.Query import app.cash.sqldelight.ExecutableQuery
import com.squareup.sqldelight.db.SqlDriver import app.cash.sqldelight.Query
import com.squareup.sqldelight.runtime.coroutines.asFlow import app.cash.sqldelight.coroutines.asFlow
import com.squareup.sqldelight.runtime.coroutines.mapToList import app.cash.sqldelight.coroutines.mapToList
import com.squareup.sqldelight.runtime.coroutines.mapToOne import app.cash.sqldelight.coroutines.mapToOne
import com.squareup.sqldelight.runtime.coroutines.mapToOneOrNull import app.cash.sqldelight.coroutines.mapToOneOrNull
import app.cash.sqldelight.db.SqlDriver
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -32,6 +33,15 @@ class AndroidDatabaseHandler(
return dispatch(inTransaction) { block(db).executeAsList() } return dispatch(inTransaction) { block(db).executeAsList() }
} }
// SY -->
override suspend fun <T : Any> awaitListExecutable(
inTransaction: Boolean,
block: suspend Database.() -> ExecutableQuery<T>,
): List<T> {
return dispatch(inTransaction) { block(db).executeAsList() }
}
// SY <--
override suspend fun <T : Any> awaitOne( override suspend fun <T : Any> awaitOne(
inTransaction: Boolean, inTransaction: Boolean,
block: suspend Database.() -> Query<T>, block: suspend Database.() -> Query<T>,
@ -39,6 +49,13 @@ class AndroidDatabaseHandler(
return dispatch(inTransaction) { block(db).executeAsOne() } return dispatch(inTransaction) { block(db).executeAsOne() }
} }
override suspend fun <T : Any> awaitOneExecutable(
inTransaction: Boolean,
block: suspend Database.() -> ExecutableQuery<T>,
): T {
return dispatch(inTransaction) { block(db).executeAsOne() }
}
override suspend fun <T : Any> awaitOneOrNull( override suspend fun <T : Any> awaitOneOrNull(
inTransaction: Boolean, inTransaction: Boolean,
block: suspend Database.() -> Query<T>, block: suspend Database.() -> Query<T>,
@ -46,6 +63,13 @@ class AndroidDatabaseHandler(
return dispatch(inTransaction) { block(db).executeAsOneOrNull() } return dispatch(inTransaction) { block(db).executeAsOneOrNull() }
} }
override suspend fun <T : Any> awaitOneOrNullExecutable(
inTransaction: Boolean,
block: suspend Database.() -> ExecutableQuery<T>,
): T? {
return dispatch(inTransaction) { block(db).executeAsOneOrNull() }
}
override fun <T : Any> subscribeToList(block: Database.() -> Query<T>): Flow<List<T>> { override fun <T : Any> subscribeToList(block: Database.() -> Query<T>): Flow<List<T>> {
return block(db).asFlow().mapToList(queryDispatcher) return block(db).asFlow().mapToList(queryDispatcher)
} }

View File

@ -1,6 +1,6 @@
package tachiyomi.data package tachiyomi.data
import com.squareup.sqldelight.ColumnAdapter import app.cash.sqldelight.ColumnAdapter
import eu.kanade.tachiyomi.source.model.UpdateStrategy import eu.kanade.tachiyomi.source.model.UpdateStrategy
import java.util.Date import java.util.Date

View File

@ -1,7 +1,8 @@
package tachiyomi.data package tachiyomi.data
import androidx.paging.PagingSource import androidx.paging.PagingSource
import com.squareup.sqldelight.Query import app.cash.sqldelight.ExecutableQuery
import app.cash.sqldelight.Query
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
interface DatabaseHandler { interface DatabaseHandler {
@ -13,16 +14,33 @@ interface DatabaseHandler {
block: suspend Database.() -> Query<T>, block: suspend Database.() -> Query<T>,
): List<T> ): List<T>
// SY -->
suspend fun <T : Any> awaitListExecutable(
inTransaction: Boolean = false,
block: suspend Database.() -> ExecutableQuery<T>,
): List<T>
// SY <--
suspend fun <T : Any> awaitOne( suspend fun <T : Any> awaitOne(
inTransaction: Boolean = false, inTransaction: Boolean = false,
block: suspend Database.() -> Query<T>, block: suspend Database.() -> Query<T>,
): T ): T
suspend fun <T : Any> awaitOneExecutable(
inTransaction: Boolean = false,
block: suspend Database.() -> ExecutableQuery<T>,
): T
suspend fun <T : Any> awaitOneOrNull( suspend fun <T : Any> awaitOneOrNull(
inTransaction: Boolean = false, inTransaction: Boolean = false,
block: suspend Database.() -> Query<T>, block: suspend Database.() -> Query<T>,
): T? ): T?
suspend fun <T : Any> awaitOneOrNullExecutable(
inTransaction: Boolean = false,
block: suspend Database.() -> ExecutableQuery<T>,
): T?
fun <T : Any> subscribeToList(block: Database.() -> Query<T>): Flow<List<T>> fun <T : Any> subscribeToList(block: Database.() -> Query<T>): Flow<List<T>>
fun <T : Any> subscribeToOne(block: Database.() -> Query<T>): Flow<T> fun <T : Any> subscribeToOne(block: Database.() -> Query<T>): Flow<T>

View File

@ -1,9 +1,9 @@
package tachiyomi.data package tachiyomi.data
import com.squareup.sqldelight.Query import app.cash.sqldelight.ExecutableQuery
import com.squareup.sqldelight.db.SqlCursor import app.cash.sqldelight.db.QueryResult
import com.squareup.sqldelight.db.SqlDriver import app.cash.sqldelight.db.SqlCursor
import com.squareup.sqldelight.internal.copyOnWriteList import app.cash.sqldelight.db.SqlDriver
import exh.source.MERGED_SOURCE_ID import exh.source.MERGED_SOURCE_ID
import tachiyomi.view.LibraryView import tachiyomi.view.LibraryView
@ -33,11 +33,11 @@ private val mapper = { cursor: SqlCursor ->
last_modified_at = cursor.getLong(21)!!, last_modified_at = cursor.getLong(21)!!,
favorite_modified_at = cursor.getLong(22), favorite_modified_at = cursor.getLong(22),
totalCount = cursor.getLong(23)!!, totalCount = cursor.getLong(23)!!,
readCount = cursor.getLong(24)!!, readCount = cursor.getDouble(24)!!,
latestUpload = cursor.getLong(25)!!, latestUpload = cursor.getLong(25)!!,
chapterFetchedAt = cursor.getLong(26)!!, chapterFetchedAt = cursor.getLong(26)!!,
lastRead = cursor.getLong(27)!!, lastRead = cursor.getLong(27)!!,
bookmarkCount = cursor.getLong(28)!!, bookmarkCount = cursor.getDouble(28)!!,
category = cursor.getLong(29)!!, category = cursor.getLong(29)!!,
) )
} }
@ -45,8 +45,9 @@ private val mapper = { cursor: SqlCursor ->
class LibraryQuery( class LibraryQuery(
val driver: SqlDriver, val driver: SqlDriver,
val condition: String = "M.favorite = 1", val condition: String = "M.favorite = 1",
) : Query<LibraryView>(copyOnWriteList(), mapper) { ) : ExecutableQuery<LibraryView>(mapper) {
override fun execute(): SqlCursor {
override fun <R> execute(mapper: (SqlCursor) -> QueryResult<R>): QueryResult<R> {
return driver.executeQuery( return driver.executeQuery(
null, null,
""" """
@ -116,7 +117,8 @@ class LibraryQuery(
ON MC.manga_id = M._id ON MC.manga_id = M._id
WHERE $condition AND M.source = $MERGED_SOURCE_ID; WHERE $condition AND M.source = $MERGED_SOURCE_ID;
""".trimIndent(), """.trimIndent(),
1, mapper,
parameters = 0,
) )
} }

View File

@ -2,7 +2,7 @@ package tachiyomi.data
import androidx.paging.PagingSource import androidx.paging.PagingSource
import androidx.paging.PagingState import androidx.paging.PagingState
import com.squareup.sqldelight.Query import app.cash.sqldelight.Query
import kotlin.properties.Delegates import kotlin.properties.Delegates
class QueryPagingSource<RowType : Any>( class QueryPagingSource<RowType : Any>(

View File

@ -1,9 +1,9 @@
package tachiyomi.data package tachiyomi.data
import com.squareup.sqldelight.Query import app.cash.sqldelight.ExecutableQuery
import com.squareup.sqldelight.db.SqlCursor import app.cash.sqldelight.db.QueryResult
import com.squareup.sqldelight.db.SqlDriver import app.cash.sqldelight.db.SqlCursor
import com.squareup.sqldelight.internal.copyOnWriteList import app.cash.sqldelight.db.SqlDriver
import exh.source.MERGED_SOURCE_ID import exh.source.MERGED_SOURCE_ID
import tachiyomi.view.UpdatesView import tachiyomi.view.UpdatesView
@ -26,8 +26,8 @@ private val mapper = { cursor: SqlCursor ->
) )
} }
class UpdatesQuery(val driver: SqlDriver, val after: Long, val limit: Long) : Query<UpdatesView>(copyOnWriteList(), mapper) { class UpdatesQuery(val driver: SqlDriver, val after: Long, val limit: Long) : ExecutableQuery<UpdatesView>(mapper) {
override fun execute(): SqlCursor { override fun <R> execute(mapper: (SqlCursor) -> QueryResult<R>): QueryResult<R> {
return driver.executeQuery( return driver.executeQuery(
null, null,
""" """
@ -82,6 +82,7 @@ class UpdatesQuery(val driver: SqlDriver, val after: Long, val limit: Long) : Qu
ORDER BY datefetch DESC ORDER BY datefetch DESC
LIMIT :limit; LIMIT :limit;
""".trimIndent(), """.trimIndent(),
mapper,
2, 2,
binders = { binders = {
bindLong(1, after) bindLong(1, after)

View File

@ -37,7 +37,7 @@ class CategoryRepositoryImpl(
// SY --> // SY -->
override suspend fun insert(category: Category): Long { override suspend fun insert(category: Category): Long {
return handler.awaitOne(true) { return handler.awaitOneExecutable(true) {
categoriesQueries.insert( categoriesQueries.insert(
name = category.name, name = category.name,
order = category.order, order = category.order,

View File

@ -2,7 +2,6 @@ package tachiyomi.data.chapter
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.util.lang.toLong
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.Chapter
@ -56,8 +55,8 @@ class ChapterRepositoryImpl(
url = chapterUpdate.url, url = chapterUpdate.url,
name = chapterUpdate.name, name = chapterUpdate.name,
scanlator = chapterUpdate.scanlator, scanlator = chapterUpdate.scanlator,
read = chapterUpdate.read?.toLong(), read = chapterUpdate.read,
bookmark = chapterUpdate.bookmark?.toLong(), bookmark = chapterUpdate.bookmark,
lastPageRead = chapterUpdate.lastPageRead, lastPageRead = chapterUpdate.lastPageRead,
chapterNumber = chapterUpdate.chapterNumber?.toDouble(), chapterNumber = chapterUpdate.chapterNumber?.toDouble(),
sourceOrder = chapterUpdate.sourceOrder, sourceOrder = chapterUpdate.sourceOrder,

View File

@ -38,7 +38,7 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?,
) )
} }
val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, List<String>?, UpdateStrategy, Long, Long, Long?, Long, Long, Long, Long, Long, Long, Long) -> LibraryManga = val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, List<String>?, UpdateStrategy, Long, Long, Long?, Long, Double, Long, Long, Long, Double, Long) -> LibraryManga =
{ id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, filteredScanlators, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt, totalCount, readCount, latestUpload, chapterFetchedAt, lastRead, bookmarkCount, category -> { id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, filteredScanlators, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt, totalCount, readCount, latestUpload, chapterFetchedAt, lastRead, bookmarkCount, category ->
LibraryManga( LibraryManga(
manga = mangaMapper( manga = mangaMapper(
@ -70,8 +70,8 @@ val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?,
), ),
category = category, category = category,
totalChapters = totalCount, totalChapters = totalCount,
readCount = readCount, readCount = readCount.toLong(),
bookmarkCount = bookmarkCount, bookmarkCount = bookmarkCount.toLong(),
latestUpload = latestUpload, latestUpload = latestUpload,
chapterFetchedAt = chapterFetchedAt, chapterFetchedAt = chapterFetchedAt,
lastRead = lastRead, lastRead = lastRead,
@ -101,14 +101,14 @@ val libraryViewMapper: (LibraryView) -> LibraryManga = {
updateStrategy = it.update_strategy, updateStrategy = it.update_strategy,
initialized = it.initialized, initialized = it.initialized,
filteredScanlators = it.filtered_scanlators, filteredScanlators = it.filtered_scanlators,
calculateInterval = it.calculate_interval.toInt(), fetchInterval = it.calculate_interval.toInt(),
lastModifiedAt = it.last_modified_at, lastModifiedAt = it.last_modified_at,
favoriteModifiedAt = it.favorite_modified_at, favoriteModifiedAt = it.favorite_modified_at,
), ),
category = it.category, category = it.category,
totalChapters = it.totalCount, totalChapters = it.totalCount,
readCount = it.readCount, readCount = it.readCount.toLong(),
bookmarkCount = it.bookmarkCount, bookmarkCount = it.bookmarkCount.toLong(),
latestUpload = it.latestUpload, latestUpload = it.latestUpload,
chapterFetchedAt = it.chapterFetchedAt, chapterFetchedAt = it.chapterFetchedAt,
lastRead = it.lastRead, lastRead = it.lastRead,

View File

@ -2,7 +2,6 @@ package tachiyomi.data.manga
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.util.lang.toLong
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
@ -63,9 +62,9 @@ class MangaMergeRepositoryImpl(
values.forEach { value -> values.forEach { value ->
mergedQueries.updateSettingsById( mergedQueries.updateSettingsById(
id = value.id, id = value.id,
getChapterUpdates = value.getChapterUpdates?.toLong(), getChapterUpdates = value.getChapterUpdates,
downloadChapters = value.downloadChapters?.toLong(), downloadChapters = value.downloadChapters,
infoManga = value.isInfoManga?.toLong(), infoManga = value.isInfoManga,
chapterPriority = value.chapterPriority?.toLong(), chapterPriority = value.chapterPriority?.toLong(),
chapterSortMode = value.chapterSortMode?.toLong(), chapterSortMode = value.chapterSortMode?.toLong(),
) )
@ -74,7 +73,7 @@ class MangaMergeRepositoryImpl(
} }
override suspend fun insert(reference: MergedMangaReference): Long? { override suspend fun insert(reference: MergedMangaReference): Long? {
return handler.awaitOneOrNull { return handler.awaitOneOrNullExecutable {
mergedQueries.insert( mergedQueries.insert(
infoManga = reference.isInfoManga, infoManga = reference.isInfoManga,
getChapterUpdates = reference.getChapterUpdates, getChapterUpdates = reference.getChapterUpdates,

View File

@ -3,7 +3,6 @@ package tachiyomi.data.manga
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.util.lang.toLong
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.data.AndroidDatabaseHandler import tachiyomi.data.AndroidDatabaseHandler
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
@ -40,7 +39,7 @@ class MangaRepositoryImpl(
} }
override suspend fun getLibraryManga(): List<LibraryManga> { override suspend fun getLibraryManga(): List<LibraryManga> {
return handler.awaitList { (handler as AndroidDatabaseHandler).getLibraryQuery() }.map(libraryViewMapper) return handler.awaitListExecutable { (handler as AndroidDatabaseHandler).getLibraryQuery() }.map(libraryViewMapper)
// return handler.awaitList { libraryViewQueries.library(libraryManga) } // return handler.awaitList { libraryViewQueries.library(libraryManga) }
} }
@ -81,10 +80,10 @@ class MangaRepositoryImpl(
} }
override suspend fun insert(manga: Manga): Long? { override suspend fun insert(manga: Manga): Long? {
return handler.awaitOneOrNull(inTransaction = true) { return handler.awaitOneOrNullExecutable(inTransaction = true) {
// SY --> // SY -->
if (mangasQueries.getIdByUrlAndSource(manga.url, manga.source).executeAsOneOrNull() != null) { if (mangasQueries.getIdByUrlAndSource(manga.url, manga.source).executeAsOneOrNull() != null) {
return@awaitOneOrNull mangasQueries.getIdByUrlAndSource(manga.url, manga.source) return@awaitOneOrNullExecutable mangasQueries.getIdByUrlAndSource(manga.url, manga.source)
} }
// SY <-- // SY <--
mangasQueries.insert( mangasQueries.insert(
@ -148,11 +147,11 @@ class MangaRepositoryImpl(
title = value.title, title = value.title,
status = value.status, status = value.status,
thumbnailUrl = value.thumbnailUrl, thumbnailUrl = value.thumbnailUrl,
favorite = value.favorite?.toLong(), favorite = value.favorite,
lastUpdate = value.lastUpdate, lastUpdate = value.lastUpdate,
nextUpdate = value.nextUpdate, nextUpdate = value.nextUpdate,
calculateInterval = value.fetchInterval?.toLong(), calculateInterval = value.fetchInterval?.toLong(),
initialized = value.initialized?.toLong(), initialized = value.initialized,
viewer = value.viewerFlags, viewer = value.viewerFlags,
chapterFlags = value.chapterFlags, chapterFlags = value.chapterFlags,
coverLastModified = value.coverLastModified, coverLastModified = value.coverLastModified,
@ -181,7 +180,7 @@ class MangaRepositoryImpl(
} }
override suspend fun getReadMangaNotInLibrary(): List<LibraryManga> { override suspend fun getReadMangaNotInLibrary(): List<LibraryManga> {
return handler.awaitList { return handler.awaitListExecutable {
(handler as AndroidDatabaseHandler).getLibraryQuery("M.favorite = 0 AND C.readCount != 0") (handler as AndroidDatabaseHandler).getLibraryQuery("M.favorite = 0 AND C.readCount != 0")
}.map(libraryViewMapper) }.map(libraryViewMapper)
} }

View File

@ -47,7 +47,7 @@ class FeedSavedSearchRepositoryImpl(
} }
override suspend fun insert(feedSavedSearch: FeedSavedSearch): Long { override suspend fun insert(feedSavedSearch: FeedSavedSearch): Long {
return handler.awaitOne(true) { return handler.awaitOneExecutable(true) {
feed_saved_searchQueries.insert( feed_saved_searchQueries.insert(
feedSavedSearch.source, feedSavedSearch.source,
feedSavedSearch.savedSearch, feedSavedSearch.savedSearch,

View File

@ -26,7 +26,7 @@ class SavedSearchRepositoryImpl(
} }
override suspend fun insert(savedSearch: SavedSearch): Long { override suspend fun insert(savedSearch: SavedSearch): Long {
return handler.awaitOne(true) { return handler.awaitOneExecutable(true) {
saved_searchQueries.insert( saved_searchQueries.insert(
savedSearch.source, savedSearch.source,
savedSearch.name, savedSearch.name,

View File

@ -25,7 +25,7 @@ class UpdatesRepositoryImpl(
return databaseHandler.subscribeToList { return databaseHandler.subscribeToList {
updatesViewQueries.getRecentUpdates(after, limit, updateWithRelationMapper) updatesViewQueries.getRecentUpdates(after, limit, updateWithRelationMapper)
}.map { }.map {
databaseHandler.awaitList { (databaseHandler as AndroidDatabaseHandler).getUpdatesQuery(after, limit) } databaseHandler.awaitListExecutable { (databaseHandler as AndroidDatabaseHandler).getUpdatesQuery(after, limit) }
.map(updatesViewMapper) .map(updatesViewMapper)
} }
} }

View File

@ -1,3 +1,4 @@
import kotlin.Long;
import kotlin.collections.List; import kotlin.collections.List;
CREATE TABLE categories( CREATE TABLE categories(

View File

@ -1,3 +1,6 @@
import kotlin.Boolean;
import kotlin.Float;
CREATE TABLE chapters( CREATE TABLE chapters(
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
manga_id INTEGER NOT NULL, manga_id INTEGER NOT NULL,
@ -9,9 +12,9 @@ CREATE TABLE chapters(
last_page_read INTEGER NOT NULL, last_page_read INTEGER NOT NULL,
chapter_number REAL AS Float NOT NULL, chapter_number REAL AS Float NOT NULL,
source_order INTEGER NOT NULL, source_order INTEGER NOT NULL,
date_fetch INTEGER AS Long NOT NULL, date_fetch INTEGER NOT NULL,
date_upload INTEGER AS Long NOT NULL, date_upload INTEGER NOT NULL,
last_modified_at INTEGER AS Long NOT NULL DEFAULT 0, last_modified_at INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY(manga_id) REFERENCES mangas (_id) FOREIGN KEY(manga_id) REFERENCES mangas (_id)
ON DELETE CASCADE ON DELETE CASCADE
); );

View File

@ -1,3 +1,5 @@
import kotlin.Boolean;
CREATE TABLE feed_saved_search ( CREATE TABLE feed_saved_search (
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
source INTEGER NOT NULL, source INTEGER NOT NULL,

View File

@ -1,3 +1,5 @@
import kotlin.Float;
CREATE TABLE manga_sync( CREATE TABLE manga_sync(
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
manga_id INTEGER NOT NULL, manga_id INTEGER NOT NULL,
@ -10,8 +12,8 @@ CREATE TABLE manga_sync(
status INTEGER NOT NULL, status INTEGER NOT NULL,
score REAL AS Float NOT NULL, score REAL AS Float NOT NULL,
remote_url TEXT NOT NULL, remote_url TEXT NOT NULL,
start_date INTEGER AS Long NOT NULL, start_date INTEGER NOT NULL,
finish_date INTEGER AS Long NOT NULL, finish_date INTEGER NOT NULL,
UNIQUE (manga_id, sync_id) ON CONFLICT REPLACE, UNIQUE (manga_id, sync_id) ON CONFLICT REPLACE,
FOREIGN KEY(manga_id) REFERENCES mangas (_id) FOREIGN KEY(manga_id) REFERENCES mangas (_id)
ON DELETE CASCADE ON DELETE CASCADE

View File

@ -1,6 +1,7 @@
import eu.kanade.tachiyomi.source.model.UpdateStrategy; import eu.kanade.tachiyomi.source.model.UpdateStrategy;
import java.lang.String;
import kotlin.collections.List; import kotlin.collections.List;
import kotlin.Boolean;
import kotlin.String;
CREATE TABLE mangas( CREATE TABLE mangas(
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
@ -14,18 +15,18 @@ CREATE TABLE mangas(
status INTEGER NOT NULL, status INTEGER NOT NULL,
thumbnail_url TEXT, thumbnail_url TEXT,
favorite INTEGER AS Boolean NOT NULL, favorite INTEGER AS Boolean NOT NULL,
last_update INTEGER AS Long, last_update INTEGER,
next_update INTEGER AS Long, next_update INTEGER,
initialized INTEGER AS Boolean NOT NULL, initialized INTEGER AS Boolean NOT NULL,
viewer INTEGER NOT NULL, viewer INTEGER NOT NULL,
chapter_flags INTEGER NOT NULL, chapter_flags INTEGER NOT NULL,
cover_last_modified INTEGER AS Long NOT NULL, cover_last_modified INTEGER NOT NULL,
date_added INTEGER AS Long NOT NULL, date_added INTEGER NOT NULL,
filtered_scanlators TEXT AS List<String>, filtered_scanlators TEXT AS List<String>,
update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0, update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0,
calculate_interval INTEGER DEFAULT 0 NOT NULL, calculate_interval INTEGER DEFAULT 0 NOT NULL,
last_modified_at INTEGER AS Long NOT NULL DEFAULT 0, last_modified_at INTEGER NOT NULL DEFAULT 0,
favorite_modified_at INTEGER AS Long favorite_modified_at INTEGER
); );
CREATE INDEX library_favorite_index ON mangas(favorite) WHERE favorite = 1; CREATE INDEX library_favorite_index ON mangas(favorite) WHERE favorite = 1;

View File

@ -2,7 +2,7 @@ CREATE TABLE mangas_categories(
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
manga_id INTEGER NOT NULL, manga_id INTEGER NOT NULL,
category_id INTEGER NOT NULL, category_id INTEGER NOT NULL,
last_modified_at INTEGER AS Long NOT NULL DEFAULT 0, last_modified_at INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY(category_id) REFERENCES categories (_id) FOREIGN KEY(category_id) REFERENCES categories (_id)
ON DELETE CASCADE, ON DELETE CASCADE,
FOREIGN KEY(manga_id) REFERENCES mangas (_id) FOREIGN KEY(manga_id) REFERENCES mangas (_id)

View File

@ -1,3 +1,5 @@
import kotlin.Boolean;
CREATE TABLE merged( CREATE TABLE merged(
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
info_manga INTEGER AS Boolean NOT NULL, info_manga INTEGER AS Boolean NOT NULL,

View File

@ -1,3 +1,5 @@
import kotlin.Int;
CREATE TABLE search_metadata ( CREATE TABLE search_metadata (
manga_id INTEGER NOT NULL PRIMARY KEY, manga_id INTEGER NOT NULL PRIMARY KEY,
uploader TEXT, uploader TEXT,

View File

@ -1,3 +1,5 @@
import kotlin.Int;
CREATE TABLE search_tags ( CREATE TABLE search_tags (
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
manga_id INTEGER NOT NULL, manga_id INTEGER NOT NULL,

View File

@ -1,3 +1,5 @@
import kotlin.Int;
CREATE TABLE search_titles ( CREATE TABLE search_titles (
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
manga_id INTEGER NOT NULL, manga_id INTEGER NOT NULL,

View File

@ -3,7 +3,7 @@ aboutlib_version = "10.8.3"
okhttp_version = "5.0.0-alpha.11" okhttp_version = "5.0.0-alpha.11"
shizuku_version = "12.2.0" shizuku_version = "12.2.0"
sqlite = "2.3.1" sqlite = "2.3.1"
sqldelight = "1.5.5" sqldelight = "2.0.0"
leakcanary = "2.12" leakcanary = "2.12"
voyager = "1.0.0-rc06" voyager = "1.0.0-rc06"
richtext = "0.17.0" richtext = "0.17.0"
@ -80,10 +80,12 @@ shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizu
leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" } leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" }
leakcanary-plumber = { module = "com.squareup.leakcanary:plumber-android", version.ref = "leakcanary" } leakcanary-plumber = { module = "com.squareup.leakcanary:plumber-android", version.ref = "leakcanary" }
sqldelight-android-driver = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-android-driver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
sqldelight-coroutines = { module = "com.squareup.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" } sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" }
sqldelight-android-paging = { module = "com.squareup.sqldelight:android-paging3-extensions", version.ref = "sqldelight" } sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" }
sqldelight-gradle = { module = "com.squareup.sqldelight:gradle-plugin", version.ref = "sqldelight" } sqldelight-primitive-adapters = { module = "app.cash.sqldelight:primitive-adapters", version.ref = "sqldelight" }
sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" }
sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" }
junit = "org.junit.jupiter:junit-jupiter:5.10.0" junit = "org.junit.jupiter:junit-jupiter:5.10.0"
kotest-assertions = "io.kotest:kotest-assertions-core:5.6.2" kotest-assertions = "io.kotest:kotest-assertions-core:5.6.2"
@ -102,6 +104,7 @@ js-engine = ["quickjs-android"]
sqlite = ["sqlite-framework", "sqlite-ktx", "sqlite-android"] sqlite = ["sqlite-framework", "sqlite-ktx", "sqlite-android"]
coil = ["coil-core", "coil-gif", "coil-compose"] coil = ["coil-core", "coil-gif", "coil-compose"]
shizuku = ["shizuku-api", "shizuku-provider"] shizuku = ["shizuku-api", "shizuku-provider"]
sqldelight = ["sqldelight-android-driver", "sqldelight-coroutines", "sqldelight-android-paging", "sqldelight-primitive-adapters"]
voyager = ["voyager-navigator", "voyager-tab-navigator", "voyager-transitions"] voyager = ["voyager-navigator", "voyager-tab-navigator", "voyager-transitions"]
richtext = ["richtext-commonmark", "richtext-m3"] richtext = ["richtext-commonmark", "richtext-m3"]
test = ["junit", "kotest-assertions", "mockk"] test = ["junit", "kotest-assertions", "mockk"]

View File

@ -6,7 +6,7 @@ plugins {
} }
kotlin { kotlin {
android() androidTarget()
sourceSets { sourceSets {
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {

View File

@ -4,7 +4,7 @@ plugins {
} }
kotlin { kotlin {
android() androidTarget()
sourceSets { sourceSets {
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {