mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	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:
		| @@ -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, | ||||
|     ) | ||||
| } | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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, | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										46
									
								
								data/src/main/sqldelight/tachiyomi/migrations/2.sqm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								data/src/main/sqldelight/tachiyomi/migrations/2.sqm
									
									
									
									
									
										Normal 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; | ||||
		Reference in New Issue
	
	Block a user