feat: db changes to accommodate new cross device syncing logic. (#450)

* 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>
This commit is contained in:
KaiserBh
2024-03-10 06:45:41 +11:00
committed by GitHub
parent 402e579a69
commit 4ae9dbe524
18 changed files with 161 additions and 20 deletions

View File

@ -29,6 +29,7 @@ class ChapterRepositoryImpl(
chapter.sourceOrder,
chapter.dateFetch,
chapter.dateUpload,
chapter.version,
)
val lastInsertId = chaptersQueries.selectLastInsertedRowId().executeAsOne()
chapter.copy(id = lastInsertId)
@ -64,6 +65,8 @@ class ChapterRepositoryImpl(
dateFetch = chapterUpdate.dateFetch,
dateUpload = chapterUpdate.dateUpload,
chapterId = chapterUpdate.id,
version = chapterUpdate.version,
isSyncing = 0,
)
}
}
@ -124,6 +127,7 @@ class ChapterRepositoryImpl(
}
}
@Suppress("LongParameterList")
private fun mapChapter(
id: Long,
mangaId: Long,
@ -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,
@ -152,5 +159,6 @@ class ChapterRepositoryImpl(
chapterNumber = chapterNumber,
scanlator = scanlator,
lastModifiedAt = lastModifiedAt,
version = version,
)
}

View File

@ -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,
@ -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,
@ -51,8 +55,10 @@ object MangaMapper {
initialized = initialized,
lastModifiedAt = lastModifiedAt,
favoriteModifiedAt = favoriteModifiedAt,
version = version,
)
@Suppress("LongParameterList")
fun mapLibraryManga(
id: Long,
source: Long,
@ -76,6 +82,8 @@ object MangaMapper {
calculateInterval: Long,
lastModifiedAt: Long,
favoriteModifiedAt: Long?,
version: Long,
isSyncing: Long,
totalCount: Long,
readCount: Double,
latestUpload: Long,
@ -107,6 +115,8 @@ object MangaMapper {
calculateInterval,
lastModifiedAt,
favoriteModifiedAt,
version,
isSyncing,
),
category = category,
totalChapters = totalCount,

View File

@ -106,6 +106,7 @@ class MangaRepositoryImpl(
coverLastModified = manga.coverLastModified,
dateAdded = manga.dateAdded,
updateStrategy = manga.updateStrategy,
version = manga.version,
)
mangasQueries.selectLastInsertedRowId()
}
@ -155,6 +156,8 @@ class MangaRepositoryImpl(
dateAdded = value.dateAdded,
mangaId = value.id,
updateStrategy = value.updateStrategy?.let(UpdateStrategyColumnAdapter::encode),
version = value.version,
isSyncing = 0,
)
}
}

View File

@ -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
);
@ -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
@ -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
@ -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:

View File

@ -25,7 +25,9 @@ CREATE TABLE mangas(
update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0,
calculate_interval INTEGER DEFAULT 0 NOT NULL,
last_modified_at INTEGER NOT NULL DEFAULT 0,
favorite_modified_at INTEGER
favorite_modified_at INTEGER,
version INTEGER NOT NULL DEFAULT 0,
is_syncing INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX library_favorite_index ON mangas(favorite) WHERE favorite = 1;
@ -48,6 +50,16 @@ BEGIN
WHERE _id = new._id;
END;
CREATE TRIGGER update_manga_version AFTER UPDATE ON mangas
BEGIN
UPDATE mangas SET version = version + 1
WHERE _id = new._id AND new.is_syncing = 0 AND (
new.url != old.url OR
new.description != old.description OR
new.favorite != old.favorite
);
END;
getMangaById:
SELECT *
FROM mangas
@ -104,6 +116,11 @@ resetViewerFlags:
UPDATE mangas
SET viewer = 0;
resetIsSyncing:
UPDATE mangas
SET is_syncing = 0
WHERE is_syncing = 1;
getSourceIdsWithNonLibraryManga:
SELECT source, COUNT(*) AS manga_count
FROM mangas
@ -116,8 +133,8 @@ WHERE favorite = 0
AND source IN :sourceIds;
insert:
INSERT INTO mangas(source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, update_strategy, calculate_interval, last_modified_at)
VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :chapterFlags, :coverLastModified, :dateAdded, :updateStrategy, :calculateInterval, 0);
INSERT INTO mangas(source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, update_strategy, calculate_interval, last_modified_at, version)
VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :chapterFlags, :coverLastModified, :dateAdded, :updateStrategy, :calculateInterval, 0, :version);
update:
UPDATE mangas SET
@ -139,7 +156,9 @@ UPDATE mangas SET
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)
calculate_interval = coalesce(:calculateInterval, calculate_interval),
version = coalesce(:version, version),
is_syncing = coalesce(:isSyncing, is_syncing)
WHERE _id = :mangaId;
selectLastInsertedRowId:

View File

@ -2,25 +2,22 @@ CREATE TABLE mangas_categories(
_id INTEGER NOT NULL PRIMARY KEY,
manga_id INTEGER NOT NULL,
category_id INTEGER NOT NULL,
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)
ON DELETE CASCADE
);
CREATE TRIGGER update_last_modified_at_mangas_categories
AFTER UPDATE ON mangas_categories
FOR EACH ROW
CREATE TRIGGER insert_manga_category_update_version AFTER INSERT ON mangas_categories
BEGIN
UPDATE mangas_categories
SET last_modified_at = strftime('%s', 'now')
WHERE _id = new._id;
UPDATE mangas
SET version = version + 1
WHERE _id = new.manga_id AND (SELECT is_syncing FROM mangas WHERE _id = new.manga_id) = 0;
END;
insert:
INSERT INTO mangas_categories(manga_id, category_id, last_modified_at)
VALUES (:mangaId, :categoryId, 0);
INSERT INTO mangas_categories(manga_id, category_id)
VALUES (:mangaId, :categoryId);
deleteMangaCategoryByMangaId:
DELETE FROM mangas_categories

View File

@ -0,0 +1,46 @@
-- Mangas table
ALTER TABLE mangas ADD COLUMN version INTEGER NOT NULL DEFAULT 0;
ALTER TABLE mangas ADD COLUMN is_syncing INTEGER NOT NULL DEFAULT 0;
-- Chapters table
ALTER TABLE chapters ADD COLUMN version INTEGER NOT NULL DEFAULT 0;
ALTER TABLE chapters ADD COLUMN is_syncing INTEGER NOT NULL DEFAULT 0;
-- Mangas triggers
DROP TRIGGER IF EXISTS update_manga_version;
CREATE TRIGGER update_manga_version AFTER UPDATE ON mangas
BEGIN
UPDATE mangas SET version = version + 1
WHERE _id = new._id AND new.is_syncing = 0 AND (
new.url != old.url OR
new.description != old.description OR
new.favorite != old.favorite
);
END;
-- Chapters triggers
DROP TRIGGER IF EXISTS update_chapter_and_manga_version;
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;
-- manga_categories table
DROP TRIGGER IF EXISTS insert_manga_category_update_version;
CREATE TRIGGER insert_manga_category_update_version AFTER INSERT ON mangas_categories
BEGIN
UPDATE mangas
SET version = version + 1
WHERE _id = new.manga_id AND (SELECT is_syncing FROM mangas WHERE _id = new.manga_id) = 0;
END;