From a4abb6292bd73b6b2ab407d08573a009a603332a Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:50:38 +0600 Subject: [PATCH] Split the universal update queries into case-specific ones Source-owned fields move out of MangaUpdate/ChapterUpdate into MangaRemoteUpdate/ChapterRemoteUpdate, which only UpdateMangaFromRemote and SyncChaptersWithSource write. Backup restore gets its own updateFromBackup queries for entries and chapters, writing only what a backup carries. --- .../interactor/SyncChaptersWithSource.kt | 28 +++++++-------- .../backup/restore/restorers/MangaRestorer.kt | 16 ++------- .../interactor/UpdateMangaFromRemote.kt | 6 ++-- .../data/chapter/ChapterRepositoryImpl.kt | 24 +++++++++---- .../data/manga/MangaRepositoryImpl.kt | 36 ++++++++++++------- .../sqldelight/tachiyomi/data/chapters.sq | 25 +++++++++---- .../main/sqldelight/tachiyomi/data/mangas.sq | 32 ++++++++++++++--- .../chapter/interactor/UpdateChapter.kt | 9 +++++ .../chapter/model/ChapterRemoteUpdate.kt | 13 +++++++ .../domain/chapter/model/ChapterUpdate.kt | 28 ++++----------- .../chapter/repository/ChapterRepository.kt | 3 ++ .../domain/manga/model/MangaRemoteUpdate.kt | 19 ++++++++++ .../domain/manga/model/MangaUpdate.kt | 27 -------------- .../manga/repository/MangaRepository.kt | 3 ++ 14 files changed, 158 insertions(+), 111 deletions(-) create mode 100644 domain/src/main/java/tachiyomi/domain/chapter/model/ChapterRemoteUpdate.kt create mode 100644 domain/src/main/java/tachiyomi/domain/manga/model/MangaRemoteUpdate.kt diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt index 9231cbac4..fe855dc23 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt @@ -19,8 +19,8 @@ import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter import tachiyomi.domain.chapter.interactor.UpdateChapter import tachiyomi.domain.chapter.model.Chapter +import tachiyomi.domain.chapter.model.ChapterRemoteUpdate import tachiyomi.domain.chapter.model.NoChaptersException -import tachiyomi.domain.chapter.model.toChapterUpdate import tachiyomi.domain.chapter.repository.ChapterRepository import tachiyomi.domain.chapter.service.ChapterRecognition import tachiyomi.domain.library.service.LibraryPreferences @@ -78,7 +78,7 @@ class SyncChaptersWithSource( val dbChapters = getChaptersByMangaId.await(manga.id) val newChapters = mutableListOf() - val updatedChapters = mutableListOf() + val updatedChapters = mutableListOf() val removedChapters = dbChapters.filterNot { dbChapter -> sourceChapters.any { sourceChapter -> dbChapter.url == sourceChapter.url @@ -130,18 +130,17 @@ class SyncChaptersWithSource( downloadManager.renameChapter(source, manga, dbChapter, chapter) } - var toChangeChapter = dbChapter.copy( - name = chapter.name, - chapterNumber = chapter.chapterNumber, - scanlator = chapter.scanlator, - sourceOrder = chapter.sourceOrder, - memo = chapter.memo, + updatedChapters.add( + ChapterRemoteUpdate( + id = dbChapter.id, + name = chapter.name, + chapterNumber = chapter.chapterNumber, + scanlator = chapter.scanlator, + sourceOrder = chapter.sourceOrder, + dateUpload = chapter.dateUpload.takeIf { it != 0L }, + memo = chapter.memo, + ), ) - - if (chapter.dateUpload != 0L) { - toChangeChapter = toChangeChapter.copy(dateUpload = chapter.dateUpload) - } - updatedChapters.add(toChangeChapter) } } } @@ -221,8 +220,7 @@ class SyncChaptersWithSource( } if (updatedChapters.isNotEmpty()) { - val chapterUpdates = updatedChapters.map { it.toChapterUpdate() } - updateChapter.awaitAll(chapterUpdates) + updateChapter.awaitAllRemote(updatedChapters) } updateManga.awaitUpdateFetchInterval(manga, timeZone, now, fetchWindow) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt index 0175139f5..0f891bfcc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt @@ -107,9 +107,7 @@ class MangaRestorer( } private suspend fun updateManga(manga: Manga): Manga { - database.mangasQueries.update( - source = manga.source, - url = manga.url, + database.mangasQueries.updateFromBackup( artist = manga.artist, author = manga.author, description = manga.description, @@ -119,8 +117,6 @@ class MangaRestorer( thumbnailUrl = manga.thumbnailUrl, favorite = manga.favorite, lastUpdate = manga.lastUpdate, - nextUpdate = null, - calculateInterval = null, initialized = manga.initialized, viewer = manga.viewerFlags, chapterFlags = manga.chapterFlags, @@ -205,18 +201,10 @@ class MangaRestorer( private suspend fun updateExistingChapters(chapters: List) { database.transaction { chapters.forEach { chapter -> - database.chaptersQueries.update( - mangaId = null, - url = null, - name = null, - scanlator = null, + database.chaptersQueries.updateFromBackup( read = chapter.read, bookmark = chapter.bookmark, lastPageRead = chapter.lastPageRead, - chapterNumber = null, - sourceOrder = null, - dateFetch = null, - dateUpload = null, chapterId = chapter.id, memo = chapter.memo, ) diff --git a/app/src/main/java/mihon/domain/source/interactor/UpdateMangaFromRemote.kt b/app/src/main/java/mihon/domain/source/interactor/UpdateMangaFromRemote.kt index cb047d69f..05a7b4d99 100644 --- a/app/src/main/java/mihon/domain/source/interactor/UpdateMangaFromRemote.kt +++ b/app/src/main/java/mihon/domain/source/interactor/UpdateMangaFromRemote.kt @@ -17,7 +17,7 @@ import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.repository.ChapterRepository import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.manga.model.Manga -import tachiyomi.domain.manga.model.MangaUpdate +import tachiyomi.domain.manga.model.MangaRemoteUpdate import tachiyomi.domain.manga.repository.MangaRepository import tachiyomi.domain.source.service.SourceManager import tachiyomi.source.local.isLocal @@ -122,8 +122,8 @@ class UpdateMangaFromRemote( val thumbnailUrl = remoteManga.thumbnail_url?.takeIf { it.isNotEmpty() } - val success = mangaRepository.update( - MangaUpdate( + val success = mangaRepository.updateRemote( + MangaRemoteUpdate( id = localManga.id, title = title, coverLastModified = coverLastModified, diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt index 4608cbd99..11ff79288 100644 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt @@ -15,6 +15,7 @@ import tachiyomi.core.common.util.system.logcat import tachiyomi.data.Database import tachiyomi.data.subscribeToList import tachiyomi.domain.chapter.model.Chapter +import tachiyomi.domain.chapter.model.ChapterRemoteUpdate import tachiyomi.domain.chapter.model.ChapterUpdate import tachiyomi.domain.chapter.repository.ChapterRepository @@ -61,23 +62,32 @@ class ChapterRepositoryImpl( partialUpdate(*chapterUpdates.toTypedArray()) } + override suspend fun updateAllRemote(chapterUpdates: List) { + database.transaction { + chapterUpdates.forEach { chapterUpdate -> + database.chaptersQueries.updateRemote( + name = chapterUpdate.name, + scanlator = chapterUpdate.scanlator, + chapterNumber = chapterUpdate.chapterNumber, + sourceOrder = chapterUpdate.sourceOrder, + dateUpload = chapterUpdate.dateUpload, + chapterId = chapterUpdate.id, + memo = chapterUpdate.memo, + ) + } + } + } + private suspend fun partialUpdate(vararg chapterUpdates: ChapterUpdate) { database.transaction { chapterUpdates.forEach { chapterUpdate -> database.chaptersQueries.update( mangaId = chapterUpdate.mangaId, - url = chapterUpdate.url, - name = chapterUpdate.name, - scanlator = chapterUpdate.scanlator, read = chapterUpdate.read, bookmark = chapterUpdate.bookmark, lastPageRead = chapterUpdate.lastPageRead, - chapterNumber = chapterUpdate.chapterNumber, - sourceOrder = chapterUpdate.sourceOrder, dateFetch = chapterUpdate.dateFetch, - dateUpload = chapterUpdate.dateUpload, chapterId = chapterUpdate.id, - memo = chapterUpdate.memo, ) } } diff --git a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt index bb5f5a645..cd1a2972c 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt @@ -19,6 +19,7 @@ import tachiyomi.data.subscribeToOne import tachiyomi.data.subscribeToOneOrNull import tachiyomi.domain.library.model.LibraryManga import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.manga.model.MangaRemoteUpdate import tachiyomi.domain.manga.model.MangaUpdate import tachiyomi.domain.manga.model.MangaWithChapterCount import tachiyomi.domain.manga.repository.MangaRepository @@ -185,32 +186,43 @@ class MangaRepositoryImpl( } } + override suspend fun updateRemote(update: MangaRemoteUpdate): Boolean { + return try { + database.mangasQueries.updateRemote( + artist = update.artist, + author = update.author, + description = update.description, + genre = update.genre, + title = update.title, + status = update.status, + thumbnailUrl = update.thumbnailUrl, + initialized = update.initialized, + coverLastModified = update.coverLastModified, + updateStrategy = update.updateStrategy, + memo = update.memo, + mangaId = update.id, + ) + true + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + false + } + } + private suspend fun partialUpdate(vararg mangaUpdates: MangaUpdate) { database.transaction { mangaUpdates.forEach { value -> database.mangasQueries.update( - source = value.source, - url = value.url, - artist = value.artist, - author = value.author, - description = value.description, - genre = value.genre, - title = value.title, - status = value.status, - thumbnailUrl = value.thumbnailUrl, favorite = value.favorite, lastUpdate = value.lastUpdate, nextUpdate = value.nextUpdate, calculateInterval = value.fetchInterval?.toLong(), - initialized = value.initialized, viewer = value.viewerFlags, chapterFlags = value.chapterFlags, coverLastModified = value.coverLastModified, dateAdded = value.dateAdded, mangaId = value.id, - updateStrategy = value.updateStrategy, notes = value.notes, - memo = value.memo, ) } } diff --git a/data/src/main/sqldelight/tachiyomi/data/chapters.sq b/data/src/main/sqldelight/tachiyomi/data/chapters.sq index 91ed4e32a..563704021 100644 --- a/data/src/main/sqldelight/tachiyomi/data/chapters.sq +++ b/data/src/main/sqldelight/tachiyomi/data/chapters.sq @@ -80,15 +80,26 @@ RETURNING _id; update: UPDATE chapters SET manga_id = coalesce(:mangaId, manga_id), - url = coalesce(:url, url), - name = coalesce(:name, name), - scanlator = coalesce(:scanlator, scanlator), read = coalesce(:read, read), bookmark = coalesce(:bookmark, bookmark), last_page_read = coalesce(:lastPageRead, last_page_read), - chapter_number = coalesce(:chapterNumber, chapter_number), - source_order = coalesce(:sourceOrder, source_order), - date_fetch = coalesce(:dateFetch, date_fetch), - date_upload = coalesce(:dateUpload, date_upload), + date_fetch = coalesce(:dateFetch, date_fetch) +WHERE _id = :chapterId; + +updateFromBackup: +UPDATE chapters +SET read = coalesce(:read, read), + bookmark = coalesce(:bookmark, bookmark), + last_page_read = coalesce(:lastPageRead, last_page_read), memo = coalesce(:memo, memo) WHERE _id = :chapterId; + +updateRemote: +UPDATE chapters +SET name = :name, + scanlator = coalesce(:scanlator, scanlator), + chapter_number = :chapterNumber, + source_order = :sourceOrder, + date_upload = coalesce(:dateUpload, date_upload), + memo = :memo +WHERE _id = :chapterId; diff --git a/data/src/main/sqldelight/tachiyomi/data/mangas.sq b/data/src/main/sqldelight/tachiyomi/data/mangas.sq index 06d4c4f74..1f44449f8 100644 --- a/data/src/main/sqldelight/tachiyomi/data/mangas.sq +++ b/data/src/main/sqldelight/tachiyomi/data/mangas.sq @@ -203,8 +203,19 @@ RETURNING _id; update: UPDATE mangas SET - source = coalesce(:source, source), - url = coalesce(:url, url), + favorite = coalesce(:favorite, favorite), + last_update = coalesce(:lastUpdate, last_update), + next_update = coalesce(:nextUpdate, next_update), + viewer = coalesce(:viewer, viewer), + chapter_flags = coalesce(:chapterFlags, chapter_flags), + cover_last_modified = coalesce(:coverLastModified, cover_last_modified), + date_added = coalesce(:dateAdded, date_added), + calculate_interval = coalesce(:calculateInterval, calculate_interval), + notes = coalesce(:notes, notes) +WHERE _id = :mangaId; + +updateFromBackup: +UPDATE mangas SET artist = coalesce(:artist, artist), author = coalesce(:author, author), description = coalesce(:description, description), @@ -214,18 +225,31 @@ UPDATE mangas SET thumbnail_url = coalesce(:thumbnailUrl, thumbnail_url), favorite = coalesce(:favorite, favorite), last_update = coalesce(:lastUpdate, last_update), - next_update = coalesce(:nextUpdate, next_update), initialized = coalesce(:initialized, initialized), viewer = coalesce(:viewer, viewer), chapter_flags = coalesce(:chapterFlags, chapter_flags), cover_last_modified = coalesce(:coverLastModified, cover_last_modified), date_added = coalesce(:dateAdded, date_added), update_strategy = coalesce(:updateStrategy, update_strategy), - calculate_interval = coalesce(:calculateInterval, calculate_interval), notes = coalesce(:notes, notes), memo = coalesce(:memo, memo) WHERE _id = :mangaId; +updateRemote: +UPDATE mangas SET + artist = coalesce(:artist, artist), + author = coalesce(:author, author), + description = coalesce(:description, description), + genre = coalesce(:genre, genre), + title = coalesce(:title, title), + status = :status, + thumbnail_url = coalesce(:thumbnailUrl, thumbnail_url), + initialized = :initialized, + cover_last_modified = coalesce(:coverLastModified, cover_last_modified), + update_strategy = :updateStrategy, + memo = :memo +WHERE _id = :mangaId; + insertNetworkManga { -- Insert the manga if it doesn't exist already INSERT INTO mangas( diff --git a/domain/src/main/java/tachiyomi/domain/chapter/interactor/UpdateChapter.kt b/domain/src/main/java/tachiyomi/domain/chapter/interactor/UpdateChapter.kt index 8401e8f76..7965f08d5 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/interactor/UpdateChapter.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/interactor/UpdateChapter.kt @@ -3,6 +3,7 @@ package tachiyomi.domain.chapter.interactor import dev.zacsweers.metro.Inject import logcat.LogPriority import tachiyomi.core.common.util.system.logcat +import tachiyomi.domain.chapter.model.ChapterRemoteUpdate import tachiyomi.domain.chapter.model.ChapterUpdate import tachiyomi.domain.chapter.repository.ChapterRepository @@ -26,4 +27,12 @@ class UpdateChapter( logcat(LogPriority.ERROR, e) } } + + suspend fun awaitAllRemote(chapterUpdates: List) { + try { + chapterRepository.updateAllRemote(chapterUpdates) + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + } + } } diff --git a/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterRemoteUpdate.kt b/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterRemoteUpdate.kt new file mode 100644 index 000000000..125d5daac --- /dev/null +++ b/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterRemoteUpdate.kt @@ -0,0 +1,13 @@ +package tachiyomi.domain.chapter.model + +import kotlinx.serialization.json.JsonObject + +data class ChapterRemoteUpdate( + val id: Long, + val name: String, + val scanlator: String?, + val chapterNumber: Double, + val dateUpload: Long?, + val sourceOrder: Long, + val memo: JsonObject, +) diff --git a/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterUpdate.kt b/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterUpdate.kt index 92296b011..61a54472d 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterUpdate.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterUpdate.kt @@ -1,7 +1,5 @@ package tachiyomi.domain.chapter.model -import kotlinx.serialization.json.JsonObject - data class ChapterUpdate( val id: Long, val mangaId: Long? = null, @@ -9,29 +7,15 @@ data class ChapterUpdate( val bookmark: Boolean? = null, val lastPageRead: Long? = null, val dateFetch: Long? = null, - val sourceOrder: Long? = null, - val url: String? = null, - val name: String? = null, - val dateUpload: Long? = null, - val chapterNumber: Double? = null, - val scanlator: String? = null, - val memo: JsonObject? = null, ) fun Chapter.toChapterUpdate(): ChapterUpdate { return ChapterUpdate( - id, - mangaId, - read, - bookmark, - lastPageRead, - dateFetch, - sourceOrder, - url, - name, - dateUpload, - chapterNumber, - scanlator, - memo, + id = id, + mangaId = mangaId, + read = read, + bookmark = bookmark, + lastPageRead = lastPageRead, + dateFetch = dateFetch, ) } diff --git a/domain/src/main/java/tachiyomi/domain/chapter/repository/ChapterRepository.kt b/domain/src/main/java/tachiyomi/domain/chapter/repository/ChapterRepository.kt index ae4af5106..d9b8641a9 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/repository/ChapterRepository.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/repository/ChapterRepository.kt @@ -2,6 +2,7 @@ package tachiyomi.domain.chapter.repository import kotlinx.coroutines.flow.Flow import tachiyomi.domain.chapter.model.Chapter +import tachiyomi.domain.chapter.model.ChapterRemoteUpdate import tachiyomi.domain.chapter.model.ChapterUpdate interface ChapterRepository { @@ -12,6 +13,8 @@ interface ChapterRepository { suspend fun updateAll(chapterUpdates: List) + suspend fun updateAllRemote(chapterUpdates: List) + suspend fun removeChaptersWithIds(chapterIds: List) suspend fun getChapterByMangaId(mangaId: Long, applyScanlatorFilter: Boolean = false): List diff --git a/domain/src/main/java/tachiyomi/domain/manga/model/MangaRemoteUpdate.kt b/domain/src/main/java/tachiyomi/domain/manga/model/MangaRemoteUpdate.kt new file mode 100644 index 000000000..70225ba58 --- /dev/null +++ b/domain/src/main/java/tachiyomi/domain/manga/model/MangaRemoteUpdate.kt @@ -0,0 +1,19 @@ +package tachiyomi.domain.manga.model + +import eu.kanade.tachiyomi.source.model.UpdateStrategy +import kotlinx.serialization.json.JsonObject + +data class MangaRemoteUpdate( + val id: Long, + val title: String?, + val author: String?, + val artist: String?, + val description: String?, + val genre: List?, + val status: Long, + val thumbnailUrl: String?, + val updateStrategy: UpdateStrategy, + val memo: JsonObject, + val initialized: Boolean, + val coverLastModified: Long?, +) diff --git a/domain/src/main/java/tachiyomi/domain/manga/model/MangaUpdate.kt b/domain/src/main/java/tachiyomi/domain/manga/model/MangaUpdate.kt index b2f5ca3c0..052ada530 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/model/MangaUpdate.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/model/MangaUpdate.kt @@ -1,11 +1,7 @@ package tachiyomi.domain.manga.model -import eu.kanade.tachiyomi.source.model.UpdateStrategy -import kotlinx.serialization.json.JsonObject - data class MangaUpdate( val id: Long, - val source: Long? = null, val favorite: Boolean? = null, val lastUpdate: Long? = null, val nextUpdate: Long? = null, @@ -14,24 +10,12 @@ data class MangaUpdate( val viewerFlags: Long? = null, val chapterFlags: Long? = null, val coverLastModified: Long? = null, - val url: String? = null, - val title: String? = null, - val artist: String? = null, - val author: String? = null, - val description: String? = null, - val genre: List? = null, - val status: Long? = null, - val thumbnailUrl: String? = null, - val updateStrategy: UpdateStrategy? = null, - val initialized: Boolean? = null, val notes: String? = null, - val memo: JsonObject? = null, ) fun Manga.toMangaUpdate(): MangaUpdate { return MangaUpdate( id = id, - source = source, favorite = favorite, lastUpdate = lastUpdate, nextUpdate = nextUpdate, @@ -40,17 +24,6 @@ fun Manga.toMangaUpdate(): MangaUpdate { viewerFlags = viewerFlags, chapterFlags = chapterFlags, coverLastModified = coverLastModified, - url = url, - title = title, - artist = artist, - author = author, - description = description, - genre = genre, - status = status, - thumbnailUrl = thumbnailUrl, - updateStrategy = updateStrategy, - initialized = initialized, notes = notes, - memo = memo, ) } diff --git a/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt b/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt index 68363df03..14cbfd249 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt @@ -3,6 +3,7 @@ package tachiyomi.domain.manga.repository import kotlinx.coroutines.flow.Flow import tachiyomi.domain.library.model.LibraryManga import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.manga.model.MangaRemoteUpdate import tachiyomi.domain.manga.model.MangaUpdate import tachiyomi.domain.manga.model.MangaWithChapterCount @@ -40,6 +41,8 @@ interface MangaRepository { suspend fun update(update: MangaUpdate): Boolean + suspend fun updateRemote(update: MangaRemoteUpdate): Boolean + suspend fun updateAll(mangaUpdates: List): Boolean suspend fun insertNetworkManga(manga: List): List