perf(db): covering index for unified-inbox summary scans #285

Merged
JMR-dev merged 13 commits from perf-187-covering-index into main 2026-07-05 19:31:22 +00:00
13 Commits
Author SHA1 Message Date
github-actions[bot] 1cd0d66fa4 Merge main into perf-187-covering-index 2026-07-05 18:48:15 +00:00
github-actions[bot] 33217c6cb2 Merge main into perf-187-covering-index 2026-07-05 18:10:50 +00:00
JMR-devandClaude Opus 4.8 46bc0e2258 Merge main into perf-187-covering-index
Resolve DatabaseModule conflict from #320: main replaced the explicit .addMigrations(...) chain with .addMigrations(*ALL_MIGRATIONS) plus an introspectable ALL_MIGRATIONS list guarded by databaseModuleRegistersEveryDeclaredMigration (registered == declared). Add MIGRATION_19_20 to ALL_MIGRATIONS so the unified-inbox covering-index migration (cache schema v19->v20) is both registered on the Room builder and satisfies that safety-net test. Schema 20.json, the v20 @Database version, and DatabaseEncryptionTest's schema-version assertion (20) are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 13:05:07 -05:00
JMR-devandClaude Opus 4.8 e4457cfec1 test(db): expect schema v20 in encryption round-trip after v19->v20 bump
MIGRATION_19_20 (issue #187) bumped the Room cache schema to version 20,
but DatabaseEncryptionTest.schemaVersionIsCarriedOntoTheEncryptedFile still
asserted the plaintext -> encrypted conversion carried version 19, so it
failed across all E2E levels after the rebase onto main.

DatabaseEncryption.migrate() carries PRAGMA user_version dynamically
(userVersion = source.version -> target.version = userVersion), and a fresh
Room open now stamps 20, so v20 genuinely survives the conversion. Update the
expected constant to 20; the assertion's intent (the version survives the
round-trip) is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 03:53:46 -05:00
Jason Ross 2289f402e5 Merge main into perf-187-covering-index 2026-07-04 03:01:21 -05:00
Jason Ross 1d4bd6346c Merge main into perf-187-covering-index 2026-07-04 02:44:59 -05:00
Jason Ross df57dcd18d Merge main into perf-187-covering-index 2026-07-04 02:26:52 -05:00
Jason Ross 8230dd0341 Merge main into perf-187-covering-index 2026-07-04 01:56:44 -05:00
Jason Ross 5c34b01bf0 Merge main into perf-187-covering-index 2026-07-04 01:22:27 -05:00
Jason Ross f4a95a6051 Merge main into perf-187-covering-index 2026-07-04 00:59:28 -05:00
Jason Ross 991f9b77e4 Merge main into perf-187-covering-index 2026-07-04 00:38:29 -05:00
Jason Ross bdb49f996f Merge main into perf-187-covering-index 2026-07-04 00:17:05 -05:00
JMR-devandClaude Opus 4.8 5a3669f017 perf(db): covering index for unified-inbox summary scans
The paged "All inboxes" query (MessageDao.pagingUnifiedFolderSummaries:
WHERE folder = ? AND inInbox = 1 ORDER BY timestampMillis DESC) had no
folder-leading index, so it SCANned the whole messages table via
index_messages_timestampMillis and filtered folder/inInbox per row.

Add a (folder, inInbox, timestampMillis) index so the two equality
predicates become an index seek and the ORDER BY is supplied by the
index. EXPLAIN QUERY PLAN for the query goes from
  SCAN messages USING INDEX index_messages_timestampMillis
to
  SEARCH messages USING INDEX index_messages_folder_inInbox_timestampMillis (folder=? AND inInbox=?)
with no temp B-tree sort.

Pure additive index (no column/table change): bump the Room DB to v20
with MIGRATION_19_20 (CREATE INDEX IF NOT EXISTS), register it in
DatabaseModule, export 20.json, and add a MigrationTest that runs the
migration and asserts the index shape plus the SEARCH plan on real
Android SQLite.

Closes #187

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 00:14:39 -05:00