Fixes the fatal IllegalStateException: Couldn't read row N from CursorWindow crash (#51), pulled from a connected device.
MessageDao.observeAll() ran SELECT * FROM messages and returned full MessageEntity rows — including the potentially large body/isHtml columns — for every cached message at once. Observing them all drags big HTML bodies through SQLite's shared (~2 MB) CursorWindow, which overflows once enough large bodies are cached, taking down the process.
The mailbox list never renders or searches the body (matchesSearch only looks at sender/subject/snippet), and the reader already loads the body lazily per-message via getById/openMessage when a message is opened — so nothing else needs the body in the list stream.
Changes
MessageSummary (new) — a lightweight projection: every column the list uses, minus body/isHtml.
MessageDao — observeAll(): Flow<List<MessageEntity>> → observeSummaries(): Flow<List<MessageSummary>> with an explicit column projection.
Mappers — added MessageSummary.toDomain() (leaves body = "").
MailRepositoryImpl.observeMessages() — now consumes observeSummaries().
Tests — migrated the unit + DB tests to the new query, and added a regression test in LibreMailDatabaseTest that inserts messages whose bodies exceed the CursorWindow and asserts the list query reads them without crashing.
Verification
Local fast gate green: assembleDebug + testDebugUnitTest + lintDebug, plus compileDebugAndroidTestKotlin (instrumented tests were touched). The regression test is instrumented, so it runs on CI's emulator matrix.
## What & why
Fixes the fatal `IllegalStateException: Couldn't read row N from CursorWindow` crash (#51), pulled from a connected device.
`MessageDao.observeAll()` ran `SELECT * FROM messages` and returned full `MessageEntity` rows — including the potentially large `body`/`isHtml` columns — for **every** cached message at once. Observing them all drags big HTML bodies through SQLite's shared (~2 MB) `CursorWindow`, which overflows once enough large bodies are cached, taking down the process.
The mailbox list never renders or searches the body (`matchesSearch` only looks at sender/subject/snippet), and the reader already loads the body lazily per-message via `getById`/`openMessage` when a message is opened — so nothing else needs the body in the list stream.
## Changes
- **`MessageSummary`** (new) — a lightweight projection: every column the list uses, minus `body`/`isHtml`.
- **`MessageDao`** — `observeAll(): Flow<List<MessageEntity>>` → `observeSummaries(): Flow<List<MessageSummary>>` with an explicit column projection.
- **`Mappers`** — added `MessageSummary.toDomain()` (leaves `body = ""`).
- **`MailRepositoryImpl.observeMessages()`** — now consumes `observeSummaries()`.
- **Tests** — migrated the unit + DB tests to the new query, and added a regression test in `LibreMailDatabaseTest` that inserts messages whose bodies exceed the CursorWindow and asserts the list query reads them without crashing.
## Verification
Local fast gate green: `assembleDebug` + `testDebugUnitTest` + `lintDebug`, plus `compileDebugAndroidTestKotlin` (instrumented tests were touched). The regression test is instrumented, so it runs on CI's emulator matrix.
Closes #51
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What & why
Fixes the fatal
IllegalStateException: Couldn't read row N from CursorWindowcrash (#51), pulled from a connected device.MessageDao.observeAll()ranSELECT * FROM messagesand returned fullMessageEntityrows — including the potentially largebody/isHtmlcolumns — for every cached message at once. Observing them all drags big HTML bodies through SQLite's shared (~2 MB)CursorWindow, which overflows once enough large bodies are cached, taking down the process.The mailbox list never renders or searches the body (
matchesSearchonly looks at sender/subject/snippet), and the reader already loads the body lazily per-message viagetById/openMessagewhen a message is opened — so nothing else needs the body in the list stream.Changes
MessageSummary(new) — a lightweight projection: every column the list uses, minusbody/isHtml.MessageDao—observeAll(): Flow<List<MessageEntity>>→observeSummaries(): Flow<List<MessageSummary>>with an explicit column projection.Mappers— addedMessageSummary.toDomain()(leavesbody = "").MailRepositoryImpl.observeMessages()— now consumesobserveSummaries().LibreMailDatabaseTestthat inserts messages whose bodies exceed the CursorWindow and asserts the list query reads them without crashing.Verification
Local fast gate green:
assembleDebug+testDebugUnitTest+lintDebug, pluscompileDebugAndroidTestKotlin(instrumented tests were touched). The regression test is instrumented, so it runs on CI's emulator matrix.Closes #51