Skip to content

Commit

Permalink
feat: db changes to accommodate new cross device syncing logic. (#450)
Browse files Browse the repository at this point in the history
* feat: db changes to accommodate new syncing logic.

Using timestamp to sync is a bit skewed due to system clock etc and therefore there was a lot of issues with it such as removing a manga that shouldn't have been removed. Marking chapters as unread even though it was marked as a read. Hopefully by using versioning system it should eliminate those issues.

* chore: add new line.

* chore: remove isSyncing from Chapter/Manga model.

* chore: remove isSyncing leftover.

* chore: remove isSyncing.

* refactor: remove isSync guard.

Just use it directly to 1 now since we don't have the isSyncing field in Manga or Chapter.

* Lint and stuff

* Add missing ,

---------

Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
  • Loading branch information
kaiserbh and AntsyLich authored Mar 9, 2024
1 parent 402e579 commit 4ae9dbe
Show file tree
Hide file tree
Showing 18 changed files with 161 additions and 20 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ android {
defaultConfig {
applicationId = "app.mihon"

versionCode = 5
versionCode = 6
versionName = "0.16.4"

buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,5 @@ private fun Manga.toBackupManga() =
updateStrategy = this.updateStrategy,
lastModifiedAt = this.lastModifiedAt,
favoriteModifiedAt = this.favoriteModifiedAt,
version = this.version,
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import tachiyomi.domain.chapter.model.Chapter

@Suppress("MagicNumber")
@Serializable
data class BackupChapter(
// in 1.x some of these values have different names
Expand All @@ -21,6 +22,7 @@ data class BackupChapter(
@ProtoNumber(9) var chapterNumber: Float = 0F,
@ProtoNumber(10) var sourceOrder: Long = 0,
@ProtoNumber(11) var lastModifiedAt: Long = 0,
@ProtoNumber(12) var version: Long = 0,
) {
fun toChapterImpl(): Chapter {
return Chapter.create().copy(
Expand All @@ -35,6 +37,7 @@ data class BackupChapter(
dateUpload = this@BackupChapter.dateUpload,
sourceOrder = this@BackupChapter.sourceOrder,
lastModifiedAt = this@BackupChapter.lastModifiedAt,
version = this@BackupChapter.version,
)
}
}
Expand All @@ -53,6 +56,8 @@ val backupChapterMapper = {
dateFetch: Long,
dateUpload: Long,
lastModifiedAt: Long,
version: Long,
_: Long,
->
BackupChapter(
url = url,
Expand All @@ -66,5 +71,6 @@ val backupChapterMapper = {
dateUpload = dateUpload,
sourceOrder = sourceOrder,
lastModifiedAt = lastModifiedAt,
version = version,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import tachiyomi.domain.manga.model.Manga

@Suppress("DEPRECATION")
@Suppress(
"DEPRECATION",
"MagicNumber",
)
@Serializable
data class BackupManga(
// in 1.x some of these values have different names
Expand Down Expand Up @@ -39,6 +42,7 @@ data class BackupManga(
@ProtoNumber(106) var lastModifiedAt: Long = 0,
@ProtoNumber(107) var favoriteModifiedAt: Long? = null,
@ProtoNumber(108) var excludedScanlators: List<String> = emptyList(),
@ProtoNumber(109) var version: Long = 0,
) {
fun getMangaImpl(): Manga {
return Manga.create().copy(
Expand All @@ -58,6 +62,7 @@ data class BackupManga(
updateStrategy = this@BackupManga.updateStrategy,
lastModifiedAt = this@BackupManga.lastModifiedAt,
favoriteModifiedAt = this@BackupManga.favoriteModifiedAt,
version = this@BackupManga.version,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class MangaRestorer(
}

private suspend fun restoreExistingManga(manga: Manga, dbManga: Manga): Manga {
return if (manga.lastModifiedAt > dbManga.lastModifiedAt) {
return if (manga.version > dbManga.version) {
updateManga(dbManga.copyFrom(manga).copy(id = dbManga.id))
} else {
updateManga(manga.copyFrom(dbManga).copy(id = dbManga.id))
Expand All @@ -100,6 +100,7 @@ class MangaRestorer(
thumbnailUrl = newer.thumbnailUrl,
status = newer.status,
initialized = this.initialized || newer.initialized,
version = newer.version,
)
}

Expand All @@ -126,6 +127,8 @@ class MangaRestorer(
dateAdded = manga.dateAdded,
mangaId = manga.id,
updateStrategy = manga.updateStrategy.let(UpdateStrategyColumnAdapter::encode),
version = manga.version,
isSyncing = 1,
)
}
return manga
Expand All @@ -137,6 +140,7 @@ class MangaRestorer(
return manga.copy(
initialized = manga.description != null,
id = insertManga(manga),
version = manga.version,
)
}

Expand Down Expand Up @@ -183,7 +187,7 @@ class MangaRestorer(
}

private fun Chapter.forComparison() =
this.copy(id = 0L, mangaId = 0L, dateFetch = 0L, dateUpload = 0L, lastModifiedAt = 0L)
this.copy(id = 0L, mangaId = 0L, dateFetch = 0L, dateUpload = 0L, lastModifiedAt = 0L, version = 0L)

private suspend fun insertNewChapters(chapters: List<Chapter>) {
handler.await(true) {
Expand All @@ -200,6 +204,7 @@ class MangaRestorer(
chapter.sourceOrder,
chapter.dateFetch,
chapter.dateUpload,
chapter.version,
)
}
}
Expand All @@ -221,6 +226,8 @@ class MangaRestorer(
dateFetch = null,
dateUpload = null,
chapterId = chapter.id,
version = chapter.version,
isSyncing = 0,
)
}
}
Expand Down Expand Up @@ -253,6 +260,7 @@ class MangaRestorer(
coverLastModified = manga.coverLastModified,
dateAdded = manga.dateAdded,
updateStrategy = manga.updateStrategy,
version = manga.version,
)
mangasQueries.selectLastInsertedRowId()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ interface Chapter : SChapter, Serializable {
var source_order: Int

var last_modified: Long

var version: Long
}

fun Chapter.toDomainChapter(): DomainChapter? {
Expand All @@ -39,5 +41,6 @@ fun Chapter.toDomainChapter(): DomainChapter? {
chapterNumber = chapter_number.toDouble(),
scanlator = scanlator,
lastModifiedAt = last_modified,
version = version,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class ChapterImpl : Chapter {

override var last_modified: Long = 0

override var version: Long = 0

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class ChapterRepositoryImpl(
chapter.sourceOrder,
chapter.dateFetch,
chapter.dateUpload,
chapter.version,
)
val lastInsertId = chaptersQueries.selectLastInsertedRowId().executeAsOne()
chapter.copy(id = lastInsertId)
Expand Down Expand Up @@ -64,6 +65,8 @@ class ChapterRepositoryImpl(
dateFetch = chapterUpdate.dateFetch,
dateUpload = chapterUpdate.dateUpload,
chapterId = chapterUpdate.id,
version = chapterUpdate.version,
isSyncing = 0,
)
}
}
Expand Down Expand Up @@ -124,6 +127,7 @@ class ChapterRepositoryImpl(
}
}

@Suppress("LongParameterList")
private fun mapChapter(
id: Long,
mangaId: Long,
Expand All @@ -138,6 +142,9 @@ class ChapterRepositoryImpl(
dateFetch: Long,
dateUpload: Long,
lastModifiedAt: Long,
version: Long,
@Suppress("UNUSED_PARAMETER")
isSyncing: Long,
): Chapter = Chapter(
id = id,
mangaId = mangaId,
Expand All @@ -152,5 +159,6 @@ class ChapterRepositoryImpl(
chapterNumber = chapterNumber,
scanlator = scanlator,
lastModifiedAt = lastModifiedAt,
version = version,
)
}
10 changes: 10 additions & 0 deletions data/src/main/java/tachiyomi/data/manga/MangaMapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.domain.manga.model.Manga

object MangaMapper {
@Suppress("LongParameterList")
fun mapManga(
id: Long,
source: Long,
Expand All @@ -28,6 +29,9 @@ object MangaMapper {
calculateInterval: Long,
lastModifiedAt: Long,
favoriteModifiedAt: Long?,
version: Long,
@Suppress("UNUSED_PARAMETER")
isSyncing: Long,
): Manga = Manga(
id = id,
source = source,
Expand All @@ -51,8 +55,10 @@ object MangaMapper {
initialized = initialized,
lastModifiedAt = lastModifiedAt,
favoriteModifiedAt = favoriteModifiedAt,
version = version,
)

@Suppress("LongParameterList")
fun mapLibraryManga(
id: Long,
source: Long,
Expand All @@ -76,6 +82,8 @@ object MangaMapper {
calculateInterval: Long,
lastModifiedAt: Long,
favoriteModifiedAt: Long?,
version: Long,
isSyncing: Long,
totalCount: Long,
readCount: Double,
latestUpload: Long,
Expand Down Expand Up @@ -107,6 +115,8 @@ object MangaMapper {
calculateInterval,
lastModifiedAt,
favoriteModifiedAt,
version,
isSyncing,
),
category = category,
totalChapters = totalCount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class MangaRepositoryImpl(
coverLastModified = manga.coverLastModified,
dateAdded = manga.dateAdded,
updateStrategy = manga.updateStrategy,
version = manga.version,
)
mangasQueries.selectLastInsertedRowId()
}
Expand Down Expand Up @@ -155,6 +156,8 @@ class MangaRepositoryImpl(
dateAdded = value.dateAdded,
mangaId = value.id,
updateStrategy = value.updateStrategy?.let(UpdateStrategyColumnAdapter::encode),
version = value.version,
isSyncing = 0,
)
}
}
Expand Down
31 changes: 28 additions & 3 deletions data/src/main/sqldelight/tachiyomi/data/chapters.sq
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ CREATE TABLE chapters(
date_fetch INTEGER NOT NULL,
date_upload INTEGER NOT NULL,
last_modified_at INTEGER NOT NULL DEFAULT 0,
version INTEGER NOT NULL DEFAULT 0,
is_syncing INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
ON DELETE CASCADE
);
Expand All @@ -30,6 +32,22 @@ BEGIN
WHERE _id = new._id;
END;

CREATE TRIGGER update_chapter_and_manga_version AFTER UPDATE ON chapters
WHEN new.is_syncing = 0 AND (
new.read != old.read OR
new.bookmark != old.bookmark OR
new.last_page_read != old.last_page_read
)
BEGIN
-- Update the chapter version
UPDATE chapters SET version = version + 1
WHERE _id = new._id;

-- Update the manga version
UPDATE mangas SET version = version + 1
WHERE _id = new.manga_id AND (SELECT is_syncing FROM mangas WHERE _id = new.manga_id) = 0;
END;

getChapterById:
SELECT *
FROM chapters
Expand Down Expand Up @@ -73,9 +91,14 @@ removeChaptersWithIds:
DELETE FROM chapters
WHERE _id IN :chapterIds;

resetIsSyncing:
UPDATE chapters
SET is_syncing = 0
WHERE is_syncing = 1;

insert:
INSERT INTO chapters(manga_id, url, name, scanlator, read, bookmark, last_page_read, chapter_number, source_order, date_fetch, date_upload, last_modified_at)
VALUES (:mangaId, :url, :name, :scanlator, :read, :bookmark, :lastPageRead, :chapterNumber, :sourceOrder, :dateFetch, :dateUpload, 0);
INSERT INTO chapters(manga_id, url, name, scanlator, read, bookmark, last_page_read, chapter_number, source_order, date_fetch, date_upload, last_modified_at, version, is_syncing)
VALUES (:mangaId, :url, :name, :scanlator, :read, :bookmark, :lastPageRead, :chapterNumber, :sourceOrder, :dateFetch, :dateUpload, 0, :version, 0);

update:
UPDATE chapters
Expand All @@ -89,7 +112,9 @@ SET manga_id = coalesce(:mangaId, manga_id),
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_upload = coalesce(:dateUpload, date_upload),
version = coalesce(:version, version),
is_syncing = coalesce(:isSyncing, is_syncing)
WHERE _id = :chapterId;

selectLastInsertedRowId:
Expand Down
Loading

0 comments on commit 4ae9dbe

Please sign in to comment.