diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 74477e52f..0da63e175 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -170,6 +170,7 @@ dependencies { implementation(androidx.paging.compose) implementation(libs.bundles.sqlite) + implementation(libs.sqldelight.primitive.adapters) implementation(kotlinx.reflect) diff --git a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt b/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt index 41cdec738..dbedb3e0b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt @@ -5,8 +5,9 @@ import android.os.Build import androidx.core.content.ContextCompat import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory -import com.squareup.sqldelight.android.AndroidSqliteDriver -import com.squareup.sqldelight.db.SqlDriver +import app.cash.sqldelight.adapter.primitive.FloatColumnAdapter +import app.cash.sqldelight.db.SqlDriver +import app.cash.sqldelight.driver.android.AndroidSqliteDriver import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.track.service.TrackPreferences @@ -37,9 +38,11 @@ import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.provider.AndroidBackupFolderProvider import tachiyomi.core.provider.AndroidDownloadFolderProvider import tachiyomi.data.AndroidDatabaseHandler +import tachiyomi.data.Chapters import tachiyomi.data.Database import tachiyomi.data.DatabaseHandler import tachiyomi.data.History +import tachiyomi.data.Manga_sync import tachiyomi.data.Mangas import tachiyomi.data.dateAdapter import tachiyomi.data.listOfStringsAdapter @@ -90,9 +93,15 @@ class AppModule(val app: Application) : InjektModule { addSingletonFactory { Database( driver = get(), + chaptersAdapter = Chapters.Adapter( + chapter_numberAdapter = FloatColumnAdapter, + ), historyAdapter = History.Adapter( last_readAdapter = dateAdapter, ), + manga_syncAdapter = Manga_sync.Adapter( + scoreAdapter = FloatColumnAdapter, + ), mangasAdapter = Mangas.Adapter( genreAdapter = listOfStringsAdapter, update_strategyAdapter = updateStrategyAdapter, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index d1b7df068..d9b0406df 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -264,7 +264,7 @@ class BackupManager( } if (!found) { // Let the db assign the id - val id = handler.awaitOne { + val id = handler.awaitOneExecutable { categoriesQueries.insert(category.name, category.order, category.flags) categoriesQueries.selectLastInsertedRowId() } @@ -488,7 +488,7 @@ class BackupManager( * @return id of [Manga], null if not found */ private suspend fun insertManga(manga: Manga): Long { - return handler.awaitOne(true) { + return handler.awaitOneExecutable(true) { mangasQueries.insert( source = manga.source, url = manga.url, @@ -526,11 +526,11 @@ class BackupManager( title = manga.title, status = manga.status, thumbnailUrl = manga.thumbnailUrl, - favorite = manga.favorite.toLong(), + favorite = manga.favorite, lastUpdate = manga.lastUpdate, nextUpdate = null, calculateInterval = null, - initialized = manga.initialized.toLong(), + initialized = manga.initialized, viewer = manga.viewerFlags, chapterFlags = manga.chapterFlags, coverLastModified = manga.coverLastModified, @@ -576,8 +576,8 @@ class BackupManager( url = null, name = null, scanlator = null, - read = chapter.read.toLong(), - bookmark = chapter.bookmark.toLong(), + read = chapter.read, + bookmark = chapter.bookmark, lastPageRead = chapter.lastPageRead, chapterNumber = null, sourceOrder = null, diff --git a/data/build.gradle.kts b/data/build.gradle.kts index 19e5281f0..4b2532e8c 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -2,7 +2,7 @@ plugins { id("com.android.library") kotlin("android") kotlin("plugin.serialization") - id("com.squareup.sqldelight") + id("app.cash.sqldelight") } android { @@ -13,10 +13,12 @@ android { } sqldelight { - database("Database") { - packageName = "tachiyomi.data" - dialect = "sqlite:3.24" - schemaOutputDirectory = project.file("./src/main/sqldelight") + databases { + create("Database") { + packageName.set("tachiyomi.data") + dialect(libs.sqldelight.dialects.sql) + schemaOutputDirectory.set(project.file("./src/main/sqldelight")) + } } } } @@ -26,9 +28,7 @@ dependencies { implementation(project(":domain")) implementation(project(":core")) - api(libs.sqldelight.android.driver) - api(libs.sqldelight.coroutines) - api(libs.sqldelight.android.paging) + api(libs.bundles.sqldelight) } tasks { diff --git a/data/src/main/java/tachiyomi/data/AndroidDatabaseHandler.kt b/data/src/main/java/tachiyomi/data/AndroidDatabaseHandler.kt index d359114fa..be74a1102 100644 --- a/data/src/main/java/tachiyomi/data/AndroidDatabaseHandler.kt +++ b/data/src/main/java/tachiyomi/data/AndroidDatabaseHandler.kt @@ -1,12 +1,13 @@ package tachiyomi.data import androidx.paging.PagingSource -import com.squareup.sqldelight.Query -import com.squareup.sqldelight.db.SqlDriver -import com.squareup.sqldelight.runtime.coroutines.asFlow -import com.squareup.sqldelight.runtime.coroutines.mapToList -import com.squareup.sqldelight.runtime.coroutines.mapToOne -import com.squareup.sqldelight.runtime.coroutines.mapToOneOrNull +import app.cash.sqldelight.ExecutableQuery +import app.cash.sqldelight.Query +import app.cash.sqldelight.coroutines.asFlow +import app.cash.sqldelight.coroutines.mapToList +import app.cash.sqldelight.coroutines.mapToOne +import app.cash.sqldelight.coroutines.mapToOneOrNull +import app.cash.sqldelight.db.SqlDriver import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -39,6 +40,13 @@ class AndroidDatabaseHandler( return dispatch(inTransaction) { block(db).executeAsOne() } } + override suspend fun awaitOneExecutable( + inTransaction: Boolean, + block: suspend Database.() -> ExecutableQuery, + ): T { + return dispatch(inTransaction) { block(db).executeAsOne() } + } + override suspend fun awaitOneOrNull( inTransaction: Boolean, block: suspend Database.() -> Query, @@ -46,6 +54,13 @@ class AndroidDatabaseHandler( return dispatch(inTransaction) { block(db).executeAsOneOrNull() } } + override suspend fun awaitOneOrNullExecutable( + inTransaction: Boolean, + block: suspend Database.() -> ExecutableQuery, + ): T? { + return dispatch(inTransaction) { block(db).executeAsOneOrNull() } + } + override fun subscribeToList(block: Database.() -> Query): Flow> { return block(db).asFlow().mapToList(queryDispatcher) } diff --git a/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt b/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt index 75ab0d874..809e96d3d 100644 --- a/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt +++ b/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt @@ -1,6 +1,6 @@ package tachiyomi.data -import com.squareup.sqldelight.ColumnAdapter +import app.cash.sqldelight.ColumnAdapter import eu.kanade.tachiyomi.source.model.UpdateStrategy import java.util.Date diff --git a/data/src/main/java/tachiyomi/data/DatabaseHandler.kt b/data/src/main/java/tachiyomi/data/DatabaseHandler.kt index a300256e0..57f58f790 100644 --- a/data/src/main/java/tachiyomi/data/DatabaseHandler.kt +++ b/data/src/main/java/tachiyomi/data/DatabaseHandler.kt @@ -1,7 +1,8 @@ package tachiyomi.data import androidx.paging.PagingSource -import com.squareup.sqldelight.Query +import app.cash.sqldelight.ExecutableQuery +import app.cash.sqldelight.Query import kotlinx.coroutines.flow.Flow interface DatabaseHandler { @@ -18,11 +19,21 @@ interface DatabaseHandler { block: suspend Database.() -> Query, ): T + suspend fun awaitOneExecutable( + inTransaction: Boolean = false, + block: suspend Database.() -> ExecutableQuery, + ): T + suspend fun awaitOneOrNull( inTransaction: Boolean = false, block: suspend Database.() -> Query, ): T? + suspend fun awaitOneOrNullExecutable( + inTransaction: Boolean = false, + block: suspend Database.() -> ExecutableQuery, + ): T? + fun subscribeToList(block: Database.() -> Query): Flow> fun subscribeToOne(block: Database.() -> Query): Flow diff --git a/data/src/main/java/tachiyomi/data/QueryPagingSource.kt b/data/src/main/java/tachiyomi/data/QueryPagingSource.kt index 0d630c964..321f637bc 100644 --- a/data/src/main/java/tachiyomi/data/QueryPagingSource.kt +++ b/data/src/main/java/tachiyomi/data/QueryPagingSource.kt @@ -2,7 +2,7 @@ package tachiyomi.data import androidx.paging.PagingSource import androidx.paging.PagingState -import com.squareup.sqldelight.Query +import app.cash.sqldelight.Query import kotlin.properties.Delegates class QueryPagingSource( diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt index 69060ecb4..a5c462d77 100644 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt @@ -2,7 +2,6 @@ package tachiyomi.data.chapter import kotlinx.coroutines.flow.Flow import logcat.LogPriority -import tachiyomi.core.util.lang.toLong import tachiyomi.core.util.system.logcat import tachiyomi.data.DatabaseHandler import tachiyomi.domain.chapter.model.Chapter @@ -56,8 +55,8 @@ class ChapterRepositoryImpl( url = chapterUpdate.url, name = chapterUpdate.name, scanlator = chapterUpdate.scanlator, - read = chapterUpdate.read?.toLong(), - bookmark = chapterUpdate.bookmark?.toLong(), + read = chapterUpdate.read, + bookmark = chapterUpdate.bookmark, lastPageRead = chapterUpdate.lastPageRead, chapterNumber = chapterUpdate.chapterNumber?.toDouble(), sourceOrder = chapterUpdate.sourceOrder, diff --git a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt index 249d85d5f..3cc46aa5c 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt @@ -32,7 +32,7 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List?, ) } -val libraryManga: (Long, Long, String, String?, String?, String?, List?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?, Long, Long, Long, Long, Long, Long, Long) -> LibraryManga = +val libraryManga: (Long, Long, String, String?, String?, String?, List?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, 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, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt, totalCount, readCount, latestUpload, chapterFetchedAt, lastRead, bookmarkCount, category -> LibraryManga( manga = mangaMapper( @@ -61,8 +61,8 @@ val libraryManga: (Long, Long, String, String?, String?, String?, List?, ), category = category, totalChapters = totalCount, - readCount = readCount, - bookmarkCount = bookmarkCount, + readCount = readCount.toLong(), + bookmarkCount = bookmarkCount.toLong(), latestUpload = latestUpload, chapterFetchedAt = chapterFetchedAt, lastRead = lastRead, diff --git a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt index d8dacdc3a..d6f93c596 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt @@ -74,7 +74,7 @@ class MangaRepositoryImpl( } override suspend fun insert(manga: Manga): Long? { - return handler.awaitOneOrNull(inTransaction = true) { + return handler.awaitOneOrNullExecutable(inTransaction = true) { mangasQueries.insert( source = manga.source, url = manga.url, @@ -133,11 +133,11 @@ class MangaRepositoryImpl( title = value.title, status = value.status, thumbnailUrl = value.thumbnailUrl, - favorite = value.favorite?.toLong(), + favorite = value.favorite, lastUpdate = value.lastUpdate, nextUpdate = value.nextUpdate, calculateInterval = value.fetchInterval?.toLong(), - initialized = value.initialized?.toLong(), + initialized = value.initialized, viewer = value.viewerFlags, chapterFlags = value.chapterFlags, coverLastModified = value.coverLastModified, diff --git a/data/src/main/sqldelight/tachiyomi/data/chapters.sq b/data/src/main/sqldelight/tachiyomi/data/chapters.sq index e88cd377c..029c36164 100644 --- a/data/src/main/sqldelight/tachiyomi/data/chapters.sq +++ b/data/src/main/sqldelight/tachiyomi/data/chapters.sq @@ -1,3 +1,6 @@ +import kotlin.Boolean; +import kotlin.Float; + CREATE TABLE chapters( _id INTEGER NOT NULL PRIMARY KEY, manga_id INTEGER NOT NULL, @@ -9,9 +12,9 @@ CREATE TABLE chapters( last_page_read INTEGER NOT NULL, chapter_number REAL AS Float NOT NULL, source_order INTEGER NOT NULL, - date_fetch INTEGER AS Long NOT NULL, - date_upload INTEGER AS Long NOT NULL, - last_modified_at INTEGER AS Long NOT NULL DEFAULT 0, + date_fetch INTEGER NOT NULL, + date_upload INTEGER NOT NULL, + last_modified_at INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(manga_id) REFERENCES mangas (_id) ON DELETE CASCADE ); diff --git a/data/src/main/sqldelight/tachiyomi/data/manga_sync.sq b/data/src/main/sqldelight/tachiyomi/data/manga_sync.sq index 63b95da69..bfe1ec8ff 100644 --- a/data/src/main/sqldelight/tachiyomi/data/manga_sync.sq +++ b/data/src/main/sqldelight/tachiyomi/data/manga_sync.sq @@ -1,3 +1,5 @@ +import kotlin.Float; + CREATE TABLE manga_sync( _id INTEGER NOT NULL PRIMARY KEY, manga_id INTEGER NOT NULL, @@ -10,8 +12,8 @@ CREATE TABLE manga_sync( status INTEGER NOT NULL, score REAL AS Float NOT NULL, remote_url TEXT NOT NULL, - start_date INTEGER AS Long NOT NULL, - finish_date INTEGER AS Long NOT NULL, + start_date INTEGER NOT NULL, + finish_date INTEGER NOT NULL, UNIQUE (manga_id, sync_id) ON CONFLICT REPLACE, FOREIGN KEY(manga_id) REFERENCES mangas (_id) ON DELETE CASCADE diff --git a/data/src/main/sqldelight/tachiyomi/data/mangas.sq b/data/src/main/sqldelight/tachiyomi/data/mangas.sq index a76bbcba4..7260332de 100644 --- a/data/src/main/sqldelight/tachiyomi/data/mangas.sq +++ b/data/src/main/sqldelight/tachiyomi/data/mangas.sq @@ -1,6 +1,7 @@ import eu.kanade.tachiyomi.source.model.UpdateStrategy; -import java.lang.String; import kotlin.collections.List; +import kotlin.Boolean; +import kotlin.String; CREATE TABLE mangas( _id INTEGER NOT NULL PRIMARY KEY, @@ -14,17 +15,17 @@ CREATE TABLE mangas( status INTEGER NOT NULL, thumbnail_url TEXT, favorite INTEGER AS Boolean NOT NULL, - last_update INTEGER AS Long, - next_update INTEGER AS Long, + last_update INTEGER, + next_update INTEGER, initialized INTEGER AS Boolean NOT NULL, viewer INTEGER NOT NULL, chapter_flags INTEGER NOT NULL, - cover_last_modified INTEGER AS Long NOT NULL, - date_added INTEGER AS Long NOT NULL, + cover_last_modified INTEGER NOT NULL, + date_added INTEGER NOT NULL, update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0, calculate_interval INTEGER DEFAULT 0 NOT NULL, - last_modified_at INTEGER AS Long NOT NULL DEFAULT 0, - favorite_modified_at INTEGER AS Long + last_modified_at INTEGER NOT NULL DEFAULT 0, + favorite_modified_at INTEGER ); CREATE INDEX library_favorite_index ON mangas(favorite) WHERE favorite = 1; diff --git a/data/src/main/sqldelight/tachiyomi/data/mangas_categories.sq b/data/src/main/sqldelight/tachiyomi/data/mangas_categories.sq index b3082d3a1..5c41843f0 100644 --- a/data/src/main/sqldelight/tachiyomi/data/mangas_categories.sq +++ b/data/src/main/sqldelight/tachiyomi/data/mangas_categories.sq @@ -2,7 +2,7 @@ CREATE TABLE mangas_categories( _id INTEGER NOT NULL PRIMARY KEY, manga_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) ON DELETE CASCADE, FOREIGN KEY(manga_id) REFERENCES mangas (_id) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6a259cef4..a6801f17f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ aboutlib_version = "10.8.3" okhttp_version = "5.0.0-alpha.11" shizuku_version = "12.2.0" sqlite = "2.3.1" -sqldelight = "1.5.5" +sqldelight = "2.0.0" leakcanary = "2.12" voyager = "1.0.0-rc06" richtext = "0.17.0" @@ -77,10 +77,12 @@ shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizu leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-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-coroutines = { module = "com.squareup.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" } -sqldelight-android-paging = { module = "com.squareup.sqldelight:android-paging3-extensions", version.ref = "sqldelight" } -sqldelight-gradle = { module = "com.squareup.sqldelight:gradle-plugin", version.ref = "sqldelight" } +sqldelight-android-driver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } +sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" } +sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", 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" kotest-assertions = "io.kotest:kotest-assertions-core:5.6.2" @@ -99,6 +101,7 @@ js-engine = ["quickjs-android"] sqlite = ["sqlite-framework", "sqlite-ktx", "sqlite-android"] coil = ["coil-core", "coil-gif", "coil-compose"] 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"] richtext = ["richtext-commonmark", "richtext-m3"] test = ["junit", "kotest-assertions", "mockk"] \ No newline at end of file diff --git a/source-api/build.gradle.kts b/source-api/build.gradle.kts index 05e6e791d..020695b6c 100644 --- a/source-api/build.gradle.kts +++ b/source-api/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } kotlin { - android() + androidTarget() sourceSets { val commonMain by getting { dependencies { diff --git a/source-local/build.gradle.kts b/source-local/build.gradle.kts index 19885316c..758f0a864 100644 --- a/source-local/build.gradle.kts +++ b/source-local/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } kotlin { - android() + androidTarget() sourceSets { val commonMain by getting { dependencies {