fix(local): corrige contrainte CHECK change_log en fin de serie et contrainte UNIQUE active_exercise_step_progress_states (#190 #191)

Correctifs regroupes: memes hunks de drift_repositories.dart concernes par les deux tickets, decoupage atomique par ticket non applicable proprement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 09:43:48 +02:00
parent 97ad7b79cc
commit e6b6903eb3
2 changed files with 446 additions and 76 deletions

View File

@ -2067,6 +2067,188 @@ CREATE TABLE pending_share_actions (
},
);
test(
'active score states are soft deleted with softDelete change log entries',
() async {
final now = DateTime.utc(2026, 7, 17, 12);
await activeRepository.save(
ActiveWorkoutSession(
metadata: _metadata('session-score-delete', now),
status: ActiveWorkoutStatus.running,
startedAt: now,
lastPersistedAt: now,
elapsedActiveMs: 0,
currentProgramIndex: 0,
currentExerciseIndex: 0,
currentSetIndex: 0,
resolvedTemplateSnapshotJson: _resolvedSnapshot(),
),
);
await activeRepository.saveScoreStopwatchState(
ActiveScoreStopwatchState(
metadata: _metadata('score-stopwatch-delete', now),
activeWorkoutSessionId: 'session-score-delete',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
status: ActiveScoreStopwatchStatus.stopped,
startedAt: now,
accumulatedMs: 12000,
stoppedAt: now.add(const Duration(seconds: 12)),
),
);
await activeRepository.saveManualScoreState(
ActiveManualScoreState(
metadata: _metadata('manual-score-delete', now),
activeWorkoutSessionId: 'session-score-delete',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
value: 3,
updatedAt: now,
),
);
final deletedAt = now.add(const Duration(minutes: 1));
await activeRepository.deleteScoreStopwatchState(
sessionId: 'session-score-delete',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
deletedAt: deletedAt,
);
await activeRepository.deleteManualScoreState(
sessionId: 'session-score-delete',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
deletedAt: deletedAt,
);
final stopwatchRow =
await (database.select(database.activeScoreStopwatchStates)
..where((table) => table.id.equals('score-stopwatch-delete')))
.getSingle();
final manualRow = await (database.select(
database.activeManualScoreStates,
)..where((table) => table.id.equals('manual-score-delete'))).getSingle();
final changes =
await (database.select(database.changeLogEntries)..where(
(table) =>
table.entityId.isIn([
'score-stopwatch-delete',
'manual-score-delete',
]) &
table.localRevision.equals(1),
))
.get();
expect(stopwatchRow.deletedAt?.toUtc(), deletedAt);
expect(stopwatchRow.syncState, 'deleted');
expect(manualRow.deletedAt?.toUtc(), deletedAt);
expect(manualRow.syncState, 'deleted');
expect(changes.map((change) => change.operation), [
'softDelete',
'softDelete',
]);
},
);
test(
'active score states keep stored identity when upserted by position',
() async {
final now = DateTime.utc(2026, 7, 17, 12);
await activeRepository.save(
ActiveWorkoutSession(
metadata: _metadata('session-score-upsert', now),
status: ActiveWorkoutStatus.running,
startedAt: now,
lastPersistedAt: now,
elapsedActiveMs: 0,
currentProgramIndex: 0,
currentExerciseIndex: 0,
currentSetIndex: 0,
resolvedTemplateSnapshotJson: _resolvedSnapshot(),
),
);
await activeRepository.saveScoreStopwatchState(
ActiveScoreStopwatchState(
metadata: _metadata('score-stopwatch-original', now),
activeWorkoutSessionId: 'session-score-upsert',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
status: ActiveScoreStopwatchStatus.running,
startedAt: now,
accumulatedMs: 0,
),
);
await activeRepository.saveManualScoreState(
ActiveManualScoreState(
metadata: _metadata('manual-score-original', now),
activeWorkoutSessionId: 'session-score-upsert',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
value: 1,
updatedAt: now,
),
);
final updatedAt = now.add(const Duration(minutes: 1));
await activeRepository.saveScoreStopwatchState(
ActiveScoreStopwatchState(
metadata: _metadata('score-stopwatch-new-id', updatedAt, 1),
activeWorkoutSessionId: 'session-score-upsert',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
status: ActiveScoreStopwatchStatus.paused,
startedAt: updatedAt,
accumulatedMs: 30000,
stoppedAt: updatedAt,
),
);
await activeRepository.saveManualScoreState(
ActiveManualScoreState(
metadata: _metadata('manual-score-new-id', updatedAt, 1),
activeWorkoutSessionId: 'session-score-upsert',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
value: 4,
updatedAt: updatedAt,
),
);
final stopwatchRow =
await (database.select(database.activeScoreStopwatchStates)
..where((table) => table.id.equals('score-stopwatch-original')))
.getSingle();
final manualRow =
await (database.select(database.activeManualScoreStates)
..where((table) => table.id.equals('manual-score-original')))
.getSingle();
final changes =
await (database.select(database.changeLogEntries)..where(
(table) =>
table.entityId.isIn([
'score-stopwatch-original',
'manual-score-original',
]) &
table.operation.equals('update'),
))
.get();
expect(stopwatchRow.createdAt.toUtc(), now);
expect(stopwatchRow.status, 'paused');
expect(stopwatchRow.accumulatedMs, 30000);
expect(manualRow.createdAt.toUtc(), now);
expect(manualRow.value, 4);
expect(changes.map((change) => change.localRevision), [1, 1]);
},
);
test(
'closing a session stores autonomous history rows with set snapshots',
() async {