T08: Drift schema mirroring the Room baseline
Three tables with CASCADE foreign keys, indices, WAL, and a real MigrationStrategy from schema version 1. No destructive fallback, ever. Two things needed deliberate handling. SQLite defaults foreign_keys to OFF and Drift, unlike Room, does not enable it -- without the pragma every CASCADE is decorative, so there is now a test that reads the pragma back. And Drift both snake_cases columns and names row classes after tables; build.yaml sets case_from_dart_to_sql: preserve so the schema stays column-for-column identical to Room's, and @DataClassName keeps row types from colliding with the domain models. SchemaTest was instrumented and needed a device; the Drift version is a plain unit test that runs in under a second with no emulator. 16 tests. 95 tests passing, analyze clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -277,3 +277,43 @@ comment in `run.sh` says so explicitly.
|
||||
its ~965 lines of tests, and proven equivalent rather than assumed equivalent.
|
||||
|
||||
Next: **T08 (Drift schema)**, the first task that touches persistence.
|
||||
|
||||
---
|
||||
|
||||
## T08 — Drift schema · **complete**
|
||||
|
||||
`lib/src/data/database.dart` (+ generated `database.g.dart`). **16 tests.**
|
||||
|
||||
Mirrors `app/schemas/com.rippr.data.AppDatabase/2.json`: three tables, CASCADE foreign
|
||||
keys, indices on `tripId` / `segmentId` / `synced`, WAL with `synchronous = NORMAL`.
|
||||
Starts at Dart schema version 1 with a real `MigrationStrategy` — the destructive
|
||||
fallback never comes back.
|
||||
|
||||
### Foreign keys are OFF by default in SQLite
|
||||
|
||||
Room switched them on for us. **Drift does not.** Without `PRAGMA foreign_keys = ON` in
|
||||
`beforeOpen`, every `CASCADE` in the schema is decorative and deleting a trip silently
|
||||
orphans all of its points. There is now a test that reads the pragma back and asserts it
|
||||
is `1`, because this is invisible until data is already wrong.
|
||||
|
||||
### Two collisions worth recording
|
||||
|
||||
**Drift generates row classes named after the table.** `Trips` → `Trip`, colliding with
|
||||
the domain model of the same name and producing 21 confusing analyzer errors of the form
|
||||
*"Trip can't be assigned to Trip"*. Fixed with `@DataClassName('TripRow')` etc. The
|
||||
mapping functions `_toTrip` / `_toSegment` / `_toPoint` convert row → domain, so the
|
||||
domain layer stays unaware Drift exists.
|
||||
|
||||
**Drift snake_cases column names.** `speedKmh` became `speed_kmh`, which broke the one
|
||||
raw-SQL query (the live stats aggregate) with `no such column: speedKmh`. Rather than 30
|
||||
`.named()` annotations, `build.yaml` sets `case_from_dart_to_sql: preserve`. That keeps
|
||||
the schema column-for-column identical to Room's, lets the raw SQL stay byte-identical to
|
||||
the Kotlin DAO query it was ported from, and leaves a Room-file importer possible later.
|
||||
|
||||
### The instrumented-to-unit win, realised
|
||||
|
||||
`SchemaTest` needed a device and an emulator. The Drift equivalent runs on the Dart VM in
|
||||
well under a second with nothing booted. `TripRepositoryTest` and `MergeTest` (441 more
|
||||
lines) should convert the same way in T09.
|
||||
|
||||
**95 tests passing, analyze clean.**
|
||||
|
||||
Reference in New Issue
Block a user