feat(train): the person's workouts, sealed and synced (ADR 0030, D14)
WorkoutRepository keeps a workout with its series, sealed with the person's key: a workout for its row, a series chunk for its row and its workout, so the instance can neither read them nor move a chunk to another workout. A readable or changed row shows locked, never as the person's; a device without the account's keys saves nothing. On the device's database a workout and its series are written in one transaction, and a deleted one is blanked before it goes, so the sync engine's tombstones hold nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
61fc5c5f7c
commit
d1daec9c0b
1 changed files with 801 additions and 0 deletions
|
|
@ -0,0 +1,58 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:halkyon_app/halkyon_app.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/workout/data/workout_gateway.dart';
|
||||
|
||||
/// [WorkoutGateway] in memory, whose rows a test changes as an instance
|
||||
/// could; it records the envelopes written, so a test sees what reached it.
|
||||
/// Blanking before a delete is the sync gateway's.
|
||||
class MemoryWorkoutGateway() implements WorkoutGateway {
|
||||
final workoutRows = <String, Envelope>{};
|
||||
final seriesRows = <SeriesRow>[];
|
||||
|
||||
/// Every envelope ever written, in order.
|
||||
final written = <Envelope>[];
|
||||
|
||||
final _remote = StreamController<void>.broadcast();
|
||||
|
||||
/// As a sync bringing others' changes.
|
||||
void bringRemoteChanges() => _remote.add(null);
|
||||
|
||||
@override
|
||||
Future<List<WorkoutRow>> workouts() async => [
|
||||
for (final MapEntry(:key, :value) in workoutRows.entries)
|
||||
(id: key, envelope: value),
|
||||
];
|
||||
|
||||
@override
|
||||
Future<List<SeriesRow>> seriesOf(String workoutId) async => [
|
||||
for (final row in seriesRows)
|
||||
if (row.workoutId == workoutId) row,
|
||||
];
|
||||
|
||||
@override
|
||||
Future<void> insert(WorkoutRow workout, List<SeriesRow> series) async {
|
||||
workoutRows[workout.id] = workout.envelope;
|
||||
seriesRows.addAll(series);
|
||||
written
|
||||
..add(workout.envelope)
|
||||
..addAll(series.map((row) => row.envelope));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> update(String id, Envelope envelope) async {
|
||||
if (workoutRows.containsKey(id)) {
|
||||
workoutRows[id] = envelope;
|
||||
written.add(envelope);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> delete(String id) async {
|
||||
seriesRows.removeWhere((row) => row.workoutId == id);
|
||||
workoutRows.remove(id);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<void> get remoteChanges => _remote.stream;
|
||||
}
|
||||
Loading…
Reference in a new issue