diff --git a/server/src/db/migrations.ts b/server/src/db/migrations.ts index 5763547da..5a1087b56 100644 --- a/server/src/db/migrations.ts +++ b/server/src/db/migrations.ts @@ -4927,7 +4927,12 @@ function runMigrations(db: Database.Database): void { * already there instead of writing a duplicate beside it. */ () => { - db.exec('ALTER TABLE journey_entries ADD COLUMN source_assignment_id INTEGER'); + const hasColumn = db + .prepare("SELECT 1 FROM pragma_table_info('journey_entries') WHERE name = 'source_assignment_id'") + .get(); + if (!hasColumn) db.exec('ALTER TABLE journey_entries ADD COLUMN source_assignment_id INTEGER'); + // `source_assignment_id IS NULL` keeps the replay from re-resolving a row that + // has since followed its stop to another day. db.exec(` UPDATE journey_entries SET source_assignment_id = ( @@ -4938,7 +4943,7 @@ function runMigrations(db: Database.Database): void { ORDER BY d.day_number ASC, d.date ASC, da.order_index ASC, da.id ASC LIMIT 1 ) - WHERE source_place_id IS NOT NULL + WHERE source_place_id IS NOT NULL AND source_assignment_id IS NULL `); db.exec( 'CREATE INDEX IF NOT EXISTS idx_journey_entries_source_assignment ON journey_entries(source_place_id, source_assignment_id)', diff --git a/server/tests/e2e/trips.e2e.test.ts b/server/tests/e2e/trips.e2e.test.ts index 16915c91b..f70c761dd 100644 --- a/server/tests/e2e/trips.e2e.test.ts +++ b/server/tests/e2e/trips.e2e.test.ts @@ -39,7 +39,7 @@ const { db } = vi.hoisted(() => { created_at DATETIME DEFAULT CURRENT_TIMESTAMP);`); // deleteTrip cleans up synced journey entries before dropping the trip row. tmp.exec(`CREATE TABLE journey_entries (id INTEGER PRIMARY KEY AUTOINCREMENT, journey_id INTEGER, - source_trip_id INTEGER, source_place_id INTEGER, type TEXT NOT NULL);`); + source_trip_id INTEGER, source_place_id INTEGER, source_assignment_id INTEGER, type TEXT NOT NULL);`); // bundle()'s todoItems now runs TodoService's real SQL (DI-injected, no mock). tmp.exec(`CREATE TABLE todo_items (id INTEGER PRIMARY KEY AUTOINCREMENT, trip_id INTEGER NOT NULL, name TEXT NOT NULL, checked INTEGER NOT NULL DEFAULT 0, category TEXT, sort_order INTEGER NOT NULL DEFAULT 0,