Drop the legacy chapter model and narrow last page read to an Int

eu.kanade.tachiyomi.data.database.models.Chapter predates SQLDelight. It
survived because it implements SChapter, so ReaderChapter could hand the
same object to the database and to the source.

ReaderChapter now holds the domain Chapter and converts at the three
points that actually need a source model: getPageList, getFormat and
getChapterUrl. The domain model is immutable, so the reader replaces the
chapter rather than writing through it, behind an update function so the
field cannot be reassigned from outside. Equality stays on the chapter it
was loaded with, which keeps the identity comparisons in the viewers
stable while progress is recorded against it.

updateChapterProgress no longer mutates the chapter and reads the values
straight back out to build the update it persists; it computes them once
and passes them. Marking a chapter read moves out of the function named
for completing it and into the same place the page is recorded.

Removing the interface also drops the nullable id it carried, along with
three non-null assertions and a Float to Double conversion that the
compiler had been warning about.

A page position is an index into a chapter's pages, so it cannot exceed
Int range, but SQLite has one integer type and the column came back as a
Long. That width reached the domain model and then every caller either
carried it or converted, and the viewers had to narrow it again to index
a list with.

Declaring the column INTEGER AS Int moves the narrowing into a column
adapter, so it happens once where the value stops being a database
number. No migration: SQLite still stores an INTEGER, only the type
SQLDelight generates changes.

Backups are the exception and keep converting, because the field is on
the wire as int64 and has to stay that way. That is also the only place
the value arrives from outside the app, where a malformed file could
carry something that does not fit and truncate to a negative index, so
it is clamped rather than cast.
This commit is contained in:
AntsyLich
2026-10-10 17:37:44 +06:00
parent e42e01049d
commit e21414b229
23 changed files with 71 additions and 169 deletions
@@ -35,3 +35,10 @@ object MemoColumnAdapter : ColumnAdapter<JsonObject, ByteArray> {
override fun decode(databaseValue: ByteArray): JsonObject = databaseValue.toJsonObject()
override fun encode(value: JsonObject): ByteArray = value.toByteArray()
}
// SQLite has one integer type, so a column holding a value that cannot exceed Int range narrows
// here rather than at every call site that reads or writes it.
object IntColumnAdapter : ColumnAdapter<Int, Long> {
override fun decode(databaseValue: Long): Int = databaseValue.toInt()
override fun encode(value: Int): Long = value.toLong()
}
@@ -81,6 +81,7 @@ object DatabaseBindings {
chapterAdapter = Chapter.Adapter(
remote_date_uploadAdapter = InstantColumnAdapter,
remote_memoAdapter = MemoColumnAdapter,
user_last_page_readAdapter = IntColumnAdapter,
state_date_fetchAdapter = InstantColumnAdapter,
),
manga_trackAdapter = Manga_track.Adapter(
@@ -164,7 +164,7 @@ class ChapterRepositoryImpl(
remoteMemo: JsonObject,
userRead: Boolean,
userBookmark: Boolean,
userLastPageRead: Long,
userLastPageRead: Int,
stateDateFetch: Instant,
): Chapter = Chapter(
id = id,
@@ -91,7 +91,7 @@ class UpdatesRepositoryImpl(
chapterUrl: String,
read: Boolean,
bookmark: Boolean,
lastPageRead: Long,
lastPageRead: Int,
sourceId: Long,
favorite: Boolean,
thumbnailUrl: String?,
@@ -1,4 +1,5 @@
import kotlin.Boolean;
import kotlin.Int;
import kotlin.time.Instant;
import kotlinx.serialization.json.JsonObject;
@@ -14,7 +15,7 @@ CREATE TABLE chapter(
remote_memo BLOB AS JsonObject NOT NULL,
user_read INTEGER AS Boolean NOT NULL,
user_bookmark INTEGER AS Boolean NOT NULL,
user_last_page_read INTEGER NOT NULL,
user_last_page_read INTEGER AS Int NOT NULL,
state_date_fetch INTEGER AS Instant NOT NULL,
UNIQUE(manga_id, remote_url),
FOREIGN KEY(manga_id) REFERENCES manga (id)
@@ -1,3 +1,5 @@
import kotlin.Int;
CREATE VIEW updatesView AS
SELECT
manga.id AS mangaId,