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.
This commit is contained in:
AntsyLich
2026-09-27 21:50:38 +06:00
parent c67a33f3d4
commit a4abb6292b
14 changed files with 158 additions and 111 deletions
@@ -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<Chapter>()
val updatedChapters = mutableListOf<Chapter>()
val updatedChapters = mutableListOf<ChapterRemoteUpdate>()
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(
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)
@@ -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<Chapter>) {
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,
)
@@ -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,
@@ -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<ChapterRemoteUpdate>) {
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,
)
}
}
@@ -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,
)
}
}
@@ -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;
@@ -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(
@@ -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<ChapterRemoteUpdate>) {
try {
chapterRepository.updateAllRemote(chapterUpdates)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
}
}
}
@@ -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,
)
@@ -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,
)
}
@@ -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<ChapterUpdate>)
suspend fun updateAllRemote(chapterUpdates: List<ChapterRemoteUpdate>)
suspend fun removeChaptersWithIds(chapterIds: List<Long>)
suspend fun getChapterByMangaId(mangaId: Long, applyScanlatorFilter: Boolean = false): List<Chapter>
@@ -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<String>?,
val status: Long,
val thumbnailUrl: String?,
val updateStrategy: UpdateStrategy,
val memo: JsonObject,
val initialized: Boolean,
val coverLastModified: Long?,
)
@@ -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<String>? = 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,
)
}
@@ -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<MangaUpdate>): Boolean
suspend fun insertNetworkManga(manga: List<Manga>): List<Manga>