Files
GameTime/lib/infrastructure/local/drift_repositories.dart
Blomios abfbb64de2 feat(data): édition ponctuelle des séries en séance (ticket #21)
Étend le modèle Drift (tables.dart, app_database.dart/.g.dart) et la
couche application (entités, use cases, repositories) pour supporter
l'édition ponctuelle des séries pendant l'exécution d'une séance, sans
modifier le modèle/séance-modèle. build_runner OK, flutter analyze
propre, 30/30 tests verts, build APK debug validé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 00:19:02 +02:00

1169 lines
41 KiB
Dart

import 'package:drift/drift.dart';
import '../../application/application.dart';
import '../../domain/domain.dart' as domain;
import 'app_database.dart' as db;
final class DriftExerciseRepository implements ExerciseRepository {
const DriftExerciseRepository(this.database);
final db.AppDatabase database;
@override
Future<domain.Exercise?> findById(String id) async {
final row = await (database.select(
database.exercises,
)..where((table) => table.id.equals(id))).getSingleOrNull();
return row == null ? null : _exerciseFromRow(row);
}
@override
Future<List<domain.Exercise>> listActive() async {
final rows =
await (database.select(database.exercises)
..where(
(table) => table.deletedAt.isNull() & table.archivedAt.isNull(),
)
..orderBy([(table) => OrderingTerm.asc(table.name)]))
.get();
return rows.map(_exerciseFromRow).toList();
}
@override
Future<bool> isReferencedByProgram(String id) async {
final row =
await (database.select(database.programExercises)
..where(
(table) =>
table.deletedAt.isNull() &
table.sourceExerciseId.equals(id),
)
..limit(1))
.getSingleOrNull();
return row != null;
}
@override
Future<void> save(domain.Exercise exercise) async {
await database
.into(database.exercises)
.insertOnConflictUpdate(_exerciseCompanion(exercise));
}
}
final class DriftMediaAssetRepository implements MediaAssetRepository {
const DriftMediaAssetRepository(this.database);
final db.AppDatabase database;
@override
Future<domain.MediaAsset?> findById(String id) async {
final row = await (database.select(
database.mediaAssets,
)..where((table) => table.id.equals(id))).getSingleOrNull();
return row == null ? null : _mediaAssetFromRow(row);
}
@override
Future<List<domain.MediaAsset>> listActive() async {
final rows = await (database.select(
database.mediaAssets,
)..where((table) => table.deletedAt.isNull())).get();
return rows.map(_mediaAssetFromRow).toList();
}
@override
Future<void> save(domain.MediaAsset mediaAsset) async {
await database
.into(database.mediaAssets)
.insertOnConflictUpdate(_mediaAssetCompanion(mediaAsset));
}
}
final class DriftProgramRepository implements ProgramRepository {
const DriftProgramRepository(this.database);
final db.AppDatabase database;
@override
Future<domain.Program?> findById(String id) async {
final query = database.select(database.programs)
..where((table) => table.id.equals(id) & table.deletedAt.isNull());
final row = await query.getSingleOrNull();
if (row == null) {
return null;
}
final exercises =
await (database.select(database.programExercises)
..where(
(table) =>
table.programId.equals(id) & table.deletedAt.isNull(),
)
..orderBy([(table) => OrderingTerm.asc(table.position)]))
.get();
return _programFromRow(
row,
exercises.map(_programExerciseFromRow).toList(),
);
}
@override
Future<List<domain.Program>> listActive() async {
final rows =
await (database.select(database.programs)
..where((table) => table.deletedAt.isNull())
..orderBy([(table) => OrderingTerm.asc(table.name)]))
.get();
final programs = <domain.Program>[];
for (final row in rows) {
final exercises =
await (database.select(database.programExercises)
..where(
(table) =>
table.programId.equals(row.id) & table.deletedAt.isNull(),
)
..orderBy([(table) => OrderingTerm.asc(table.position)]))
.get();
programs.add(
_programFromRow(row, exercises.map(_programExerciseFromRow).toList()),
);
}
return programs;
}
@override
Future<void> save(domain.Program program) async {
await database
.into(database.programs)
.insertOnConflictUpdate(_programCompanion(program));
for (final exercise in program.exercises) {
await saveExercise(exercise);
}
}
@override
Future<void> saveExercise(domain.ProgramExercise exercise) async {
await database
.into(database.programExercises)
.insertOnConflictUpdate(_programExerciseCompanion(exercise));
}
@override
Future<void> replaceExercises(
domain.Program program,
DateTime deletedAt,
) async {
await database.transaction(() async {
await save(program);
final activeIds = program.exercises
.map((exercise) => exercise.metadata.id)
.toSet();
final update = database.update(database.programExercises);
if (activeIds.isEmpty) {
update.where(
(table) =>
table.programId.equals(program.metadata.id) &
table.deletedAt.isNull(),
);
} else {
update.where(
(table) =>
table.programId.equals(program.metadata.id) &
table.deletedAt.isNull() &
table.id.isNotIn(activeIds),
);
}
await update.write(
db.ProgramExercisesCompanion(
deletedAt: Value(deletedAt),
updatedAt: Value(deletedAt),
),
);
});
}
}
final class DriftWorkoutTemplateRepository
implements WorkoutTemplateRepository {
const DriftWorkoutTemplateRepository(this.database);
final db.AppDatabase database;
@override
Future<domain.WorkoutTemplate?> findById(String id) async {
final row =
await (database.select(
database.workoutTemplates,
)..where((table) => table.id.equals(id) & table.deletedAt.isNull()))
.getSingleOrNull();
if (row == null) {
return null;
}
final programs =
await (database.select(database.workoutTemplatePrograms)
..where(
(table) =>
table.workoutTemplateId.equals(id) &
table.deletedAt.isNull(),
)
..orderBy([(table) => OrderingTerm.asc(table.position)]))
.get();
final programIds = programs.map((program) => program.id).toSet();
final overrides = programIds.isEmpty
? <db.WorkoutTemplateExerciseOverride>[]
: await (database.select(database.workoutTemplateExerciseOverrides)
..where(
(table) =>
table.workoutTemplateProgramId.isIn(programIds) &
table.deletedAt.isNull(),
))
.get();
return _workoutTemplateFromRow(
row,
programs.map(_workoutTemplateProgramFromRow).toList(),
overrides.map(_workoutTemplateExerciseOverrideFromRow).toList(),
);
}
@override
Future<List<domain.WorkoutTemplate>> listActive() async {
final rows =
await (database.select(database.workoutTemplates)
..where((table) => table.deletedAt.isNull())
..orderBy([(table) => OrderingTerm.asc(table.name)]))
.get();
final templates = <domain.WorkoutTemplate>[];
for (final row in rows) {
final template = await findById(row.id);
if (template != null) {
templates.add(template);
}
}
return templates;
}
@override
Future<void> save(domain.WorkoutTemplate template) async {
await database
.into(database.workoutTemplates)
.insertOnConflictUpdate(_workoutTemplateCompanion(template));
for (final program in template.programs) {
await saveProgram(program);
}
for (final override in template.overrides) {
await saveOverride(override);
}
}
@override
Future<void> saveProgram(domain.WorkoutTemplateProgram program) async {
await database
.into(database.workoutTemplatePrograms)
.insertOnConflictUpdate(_workoutTemplateProgramCompanion(program));
}
@override
Future<void> saveOverride(
domain.WorkoutTemplateExerciseOverride override,
) async {
await database
.into(database.workoutTemplateExerciseOverrides)
.insertOnConflictUpdate(
_workoutTemplateExerciseOverrideCompanion(override),
);
}
@override
Future<void> replaceComposition(
domain.WorkoutTemplate template,
DateTime deletedAt,
) async {
await database.transaction(() async {
final previousPrograms =
await (database.select(database.workoutTemplatePrograms)..where(
(table) =>
table.workoutTemplateId.equals(template.metadata.id) &
table.deletedAt.isNull(),
))
.get();
final previousProgramIds = previousPrograms
.map((program) => program.id)
.toSet();
await save(template);
final activeProgramIds = template.programs
.map((program) => program.metadata.id)
.toSet();
final programUpdate = database.update(database.workoutTemplatePrograms);
if (activeProgramIds.isEmpty) {
programUpdate.where(
(table) =>
table.workoutTemplateId.equals(template.metadata.id) &
table.deletedAt.isNull(),
);
} else {
programUpdate.where(
(table) =>
table.workoutTemplateId.equals(template.metadata.id) &
table.deletedAt.isNull() &
table.id.isNotIn(activeProgramIds),
);
}
await programUpdate.write(
db.WorkoutTemplateProgramsCompanion(
deletedAt: Value(deletedAt),
updatedAt: Value(deletedAt),
),
);
final activeOverrideIds = template.overrides
.map((override) => override.metadata.id)
.toSet();
final relevantProgramIds = {...previousProgramIds, ...activeProgramIds};
if (relevantProgramIds.isEmpty) {
return;
}
final overrideUpdate = database.update(
database.workoutTemplateExerciseOverrides,
);
if (activeOverrideIds.isEmpty) {
overrideUpdate.where(
(table) =>
table.workoutTemplateProgramId.isIn(relevantProgramIds) &
table.deletedAt.isNull(),
);
} else {
overrideUpdate.where(
(table) =>
table.workoutTemplateProgramId.isIn(relevantProgramIds) &
table.deletedAt.isNull() &
table.id.isNotIn(activeOverrideIds),
);
}
await overrideUpdate.write(
db.WorkoutTemplateExerciseOverridesCompanion(
deletedAt: Value(deletedAt),
updatedAt: Value(deletedAt),
),
);
});
}
}
final class DriftActiveSessionRepository implements ActiveSessionRepository {
const DriftActiveSessionRepository(this.database);
final db.AppDatabase database;
@override
Future<domain.ActiveWorkoutSession?> findById(String id) async {
final row = await (database.select(
database.activeWorkoutSessions,
)..where((table) => table.id.equals(id))).getSingleOrNull();
return row == null ? null : _activeWorkoutSessionFromRow(row);
}
@override
Future<domain.ActiveWorkoutSession?> findOpen() async {
final row =
await (database.select(database.activeWorkoutSessions)
..where(
(table) =>
table.deletedAt.isNull() &
table.status.isIn(['running', 'paused', 'savedExit']),
)
..orderBy([(table) => OrderingTerm.desc(table.updatedAt)])
..limit(1))
.getSingleOrNull();
return row == null ? null : _activeWorkoutSessionFromRow(row);
}
@override
Future<void> save(domain.ActiveWorkoutSession session) async {
await database
.into(database.activeWorkoutSessions)
.insertOnConflictUpdate(_activeWorkoutSessionCompanion(session));
}
@override
Future<void> saveSetResult(domain.ActiveSetResult result) async {
await database
.into(database.activeSetResults)
.insertOnConflictUpdate(_activeSetResultCompanion(result));
}
@override
Future<void> saveRestState(domain.ActiveRestState restState) async {
await database
.into(database.activeRestStates)
.insertOnConflictUpdate(_activeRestStateCompanion(restState));
}
@override
Future<domain.ActiveRestState?> findRestStateById(String id) async {
final row = await (database.select(
database.activeRestStates,
)..where((table) => table.id.equals(id))).getSingleOrNull();
return row == null ? null : _activeRestStateFromRow(row);
}
@override
Future<List<domain.ActiveSetResult>> listSetResults(String sessionId) async {
final rows =
await (database.select(database.activeSetResults)
..where((table) => table.activeWorkoutSessionId.equals(sessionId))
..orderBy([
(table) => OrderingTerm.asc(table.programIndex),
(table) => OrderingTerm.asc(table.exerciseIndex),
(table) => OrderingTerm.asc(table.setIndex),
]))
.get();
return rows.map(_activeSetResultFromRow).toList();
}
@override
Future<List<domain.ActiveRestState>> listRestStates(String sessionId) async {
final rows =
await (database.select(database.activeRestStates)
..where((table) => table.activeWorkoutSessionId.equals(sessionId))
..orderBy([(table) => OrderingTerm.asc(table.startedAt)]))
.get();
return rows.map(_activeRestStateFromRow).toList();
}
}
final class DriftWorkoutHistoryRepository implements WorkoutHistoryRepository {
const DriftWorkoutHistoryRepository(this.database);
final db.AppDatabase database;
@override
Future<domain.WorkoutHistory?> findById(String id) async {
final row =
await (database.select(
database.workoutHistories,
)..where((table) => table.id.equals(id) & table.deletedAt.isNull()))
.getSingleOrNull();
if (row == null) {
return null;
}
final results =
await (database.select(database.workoutHistorySetResults)
..where(
(table) =>
table.workoutHistoryId.equals(id) &
table.deletedAt.isNull(),
)
..orderBy([
(table) => OrderingTerm.asc(table.programIndex),
(table) => OrderingTerm.asc(table.exerciseIndex),
(table) => OrderingTerm.asc(table.setIndex),
]))
.get();
return _workoutHistoryFromRow(
row,
results.map(_workoutHistorySetResultFromRow).toList(),
);
}
@override
Future<List<domain.WorkoutHistory>> listActive() async {
final rows =
await (database.select(database.workoutHistories)
..where((table) => table.deletedAt.isNull())
..orderBy([(table) => OrderingTerm.desc(table.startedAt)]))
.get();
final histories = <domain.WorkoutHistory>[];
for (final row in rows) {
final history = await findById(row.id);
if (history != null) {
histories.add(history);
}
}
return histories;
}
@override
Future<void> save(domain.WorkoutHistory history) async {
await database
.into(database.workoutHistories)
.insertOnConflictUpdate(_workoutHistoryCompanion(history));
for (final result in history.results) {
await saveSetResult(result);
}
}
@override
Future<void> saveSetResult(domain.WorkoutHistorySetResult result) async {
await database
.into(database.workoutHistorySetResults)
.insertOnConflictUpdate(_workoutHistorySetResultCompanion(result));
}
@override
Future<void> delete(String id, DateTime deletedAt) async {
await database.transaction(() async {
await (database.update(
database.workoutHistories,
)..where((table) => table.id.equals(id))).write(
db.WorkoutHistoriesCompanion(
deletedAt: Value(deletedAt),
updatedAt: Value(deletedAt),
),
);
await (database.update(
database.workoutHistorySetResults,
)..where((table) => table.workoutHistoryId.equals(id))).write(
db.WorkoutHistorySetResultsCompanion(
deletedAt: Value(deletedAt),
updatedAt: Value(deletedAt),
),
);
});
}
}
domain.EntityMetadata _metadataFromRow(dynamic row) {
return domain.EntityMetadata(
id: row.id as String,
createdAt: row.createdAt as DateTime,
updatedAt: row.updatedAt as DateTime,
deletedAt: row.deletedAt as DateTime?,
schemaVersion: row.schemaVersion as int,
syncState: _syncStateFromDb(row.syncState as String),
localRevision: row.localRevision as int,
originDeviceId: row.originDeviceId as String,
futureOwnerProfileId: row.futureOwnerProfileId as String?,
lastSyncedAt: row.lastSyncedAt as DateTime?,
remoteRevision: row.remoteRevision as String?,
);
}
List<dynamic> _metadataValues(domain.EntityMetadata metadata) => [
Value(metadata.id),
Value(metadata.createdAt),
Value(metadata.updatedAt),
Value(metadata.deletedAt),
Value(metadata.schemaVersion),
Value(_syncStateToDb(metadata.syncState)),
Value(metadata.localRevision),
Value(metadata.originDeviceId),
Value(metadata.futureOwnerProfileId),
Value(metadata.lastSyncedAt),
Value(metadata.remoteRevision),
];
db.ExercisesCompanion _exerciseCompanion(domain.Exercise exercise) {
final values = _metadataValues(exercise.metadata);
return db.ExercisesCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
name: Value(exercise.name),
description: Value(exercise.description),
imageMediaId: Value(exercise.imageMediaId),
videoMediaId: Value(exercise.videoMediaId),
hasTimeMeasure: Value(exercise.hasTimeMeasure),
hasRepsMeasure: Value(exercise.hasRepsMeasure),
hasScoreMeasure: Value(exercise.hasScoreMeasure),
scoreLabel: Value(exercise.scoreLabel),
scoreUnit: Value(exercise.scoreUnit),
archivedAt: Value(exercise.archivedAt),
);
}
domain.Exercise _exerciseFromRow(db.Exercise row) {
return domain.Exercise(
metadata: _metadataFromRow(row),
name: row.name,
description: row.description,
imageMediaId: row.imageMediaId,
videoMediaId: row.videoMediaId,
hasTimeMeasure: row.hasTimeMeasure,
hasRepsMeasure: row.hasRepsMeasure,
hasScoreMeasure: row.hasScoreMeasure,
scoreLabel: row.scoreLabel,
scoreUnit: row.scoreUnit,
archivedAt: row.archivedAt,
);
}
db.MediaAssetsCompanion _mediaAssetCompanion(domain.MediaAsset asset) {
final values = _metadataValues(asset.metadata);
return db.MediaAssetsCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
kind: Value(_mediaKindToDb(asset.kind)),
localUri: Value(asset.localUri),
mimeType: Value(asset.mimeType),
sizeBytes: Value(asset.sizeBytes),
width: Value(asset.width),
height: Value(asset.height),
durationMs: Value(asset.durationMs),
checksum: Value(asset.checksum),
remoteUri: Value(asset.remoteUri),
thumbnailLocalUri: Value(asset.thumbnailLocalUri),
);
}
domain.MediaAsset _mediaAssetFromRow(db.MediaAsset row) {
return domain.MediaAsset(
metadata: _metadataFromRow(row),
kind: _mediaKindFromDb(row.kind),
localUri: row.localUri,
mimeType: row.mimeType,
sizeBytes: row.sizeBytes,
width: row.width,
height: row.height,
durationMs: row.durationMs,
checksum: row.checksum,
remoteUri: row.remoteUri,
thumbnailLocalUri: row.thumbnailLocalUri,
);
}
db.ProgramsCompanion _programCompanion(domain.Program program) {
final values = _metadataValues(program.metadata);
return db.ProgramsCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
name: Value(program.name),
defaultRestSeconds: Value(program.defaultRestSeconds),
);
}
domain.Program _programFromRow(
db.Program row,
List<domain.ProgramExercise> exercises,
) {
return domain.Program(
metadata: _metadataFromRow(row),
name: row.name,
defaultRestSeconds: row.defaultRestSeconds,
exercises: exercises,
);
}
db.ProgramExercisesCompanion _programExerciseCompanion(
domain.ProgramExercise exercise,
) {
final values = _metadataValues(exercise.metadata);
return db.ProgramExercisesCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
programId: Value(exercise.programId),
sourceExerciseId: Value(exercise.sourceExerciseId),
position: Value(exercise.position),
exerciseNameSnapshot: Value(exercise.exerciseNameSnapshot),
exerciseDescriptionSnapshot: Value(exercise.exerciseDescriptionSnapshot),
exerciseImageMediaIdSnapshot: Value(exercise.exerciseImageMediaIdSnapshot),
exerciseVideoMediaIdSnapshot: Value(exercise.exerciseVideoMediaIdSnapshot),
exerciseArchivedSnapshot: Value(exercise.exerciseArchivedSnapshot),
availableTimeSnapshot: Value(exercise.availableTimeSnapshot),
availableRepsSnapshot: Value(exercise.availableRepsSnapshot),
availableScoreSnapshot: Value(exercise.availableScoreSnapshot),
scoreLabelSnapshot: Value(exercise.scoreLabelSnapshot),
scoreUnitSnapshot: Value(exercise.scoreUnitSnapshot),
setsCount: Value(exercise.setsCount),
timeEnabled: Value(exercise.timeEnabled),
repsEnabled: Value(exercise.repsEnabled),
scoreEnabled: Value(exercise.scoreEnabled),
targetTimeSeconds: Value(exercise.targetTimeSeconds),
targetReps: Value(exercise.targetReps),
targetScore: Value(exercise.targetScore),
restSecondsOverride: Value(exercise.restSecondsOverride),
);
}
domain.ProgramExercise _programExerciseFromRow(db.ProgramExercise row) {
return domain.ProgramExercise(
metadata: _metadataFromRow(row),
programId: row.programId,
sourceExerciseId: row.sourceExerciseId,
position: row.position,
exerciseNameSnapshot: row.exerciseNameSnapshot,
exerciseDescriptionSnapshot: row.exerciseDescriptionSnapshot,
exerciseImageMediaIdSnapshot: row.exerciseImageMediaIdSnapshot,
exerciseVideoMediaIdSnapshot: row.exerciseVideoMediaIdSnapshot,
exerciseArchivedSnapshot: row.exerciseArchivedSnapshot,
availableTimeSnapshot: row.availableTimeSnapshot,
availableRepsSnapshot: row.availableRepsSnapshot,
availableScoreSnapshot: row.availableScoreSnapshot,
scoreLabelSnapshot: row.scoreLabelSnapshot,
scoreUnitSnapshot: row.scoreUnitSnapshot,
setsCount: row.setsCount,
timeEnabled: row.timeEnabled,
repsEnabled: row.repsEnabled,
scoreEnabled: row.scoreEnabled,
targetTimeSeconds: row.targetTimeSeconds,
targetReps: row.targetReps,
targetScore: row.targetScore,
restSecondsOverride: row.restSecondsOverride,
);
}
db.WorkoutTemplatesCompanion _workoutTemplateCompanion(
domain.WorkoutTemplate template,
) {
final values = _metadataValues(template.metadata);
return db.WorkoutTemplatesCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
name: Value(template.name),
lastStartedAt: Value(template.lastStartedAt),
);
}
domain.WorkoutTemplate _workoutTemplateFromRow(
db.WorkoutTemplate row,
List<domain.WorkoutTemplateProgram> programs,
List<domain.WorkoutTemplateExerciseOverride> overrides,
) {
return domain.WorkoutTemplate(
metadata: _metadataFromRow(row),
name: row.name,
lastStartedAt: row.lastStartedAt,
programs: programs,
overrides: overrides,
);
}
db.WorkoutTemplateProgramsCompanion _workoutTemplateProgramCompanion(
domain.WorkoutTemplateProgram program,
) {
final values = _metadataValues(program.metadata);
return db.WorkoutTemplateProgramsCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
workoutTemplateId: Value(program.workoutTemplateId),
sourceProgramId: Value(program.sourceProgramId),
position: Value(program.position),
programNameSnapshot: Value(program.programNameSnapshot),
defaultRestSecondsSnapshot: Value(program.defaultRestSecondsSnapshot),
programSnapshotJson: Value(program.programSnapshotJson),
);
}
domain.WorkoutTemplateProgram _workoutTemplateProgramFromRow(
db.WorkoutTemplateProgram row,
) {
return domain.WorkoutTemplateProgram(
metadata: _metadataFromRow(row),
workoutTemplateId: row.workoutTemplateId,
sourceProgramId: row.sourceProgramId,
position: row.position,
programNameSnapshot: row.programNameSnapshot,
defaultRestSecondsSnapshot: row.defaultRestSecondsSnapshot,
programSnapshotJson: row.programSnapshotJson,
);
}
db.WorkoutTemplateExerciseOverridesCompanion
_workoutTemplateExerciseOverrideCompanion(
domain.WorkoutTemplateExerciseOverride override,
) {
final values = _metadataValues(override.metadata);
return db.WorkoutTemplateExerciseOverridesCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
workoutTemplateProgramId: Value(override.workoutTemplateProgramId),
snapshotProgramExerciseId: Value(override.snapshotProgramExerciseId),
setsCountOverride: Value(override.setsCountOverride),
targetTimeSecondsOverride: Value(override.targetTimeSecondsOverride),
targetRepsOverride: Value(override.targetRepsOverride),
targetScoreOverride: Value(override.targetScoreOverride),
);
}
domain.WorkoutTemplateExerciseOverride _workoutTemplateExerciseOverrideFromRow(
db.WorkoutTemplateExerciseOverride row,
) {
return domain.WorkoutTemplateExerciseOverride(
metadata: _metadataFromRow(row),
workoutTemplateProgramId: row.workoutTemplateProgramId,
snapshotProgramExerciseId: row.snapshotProgramExerciseId,
setsCountOverride: row.setsCountOverride,
targetTimeSecondsOverride: row.targetTimeSecondsOverride,
targetRepsOverride: row.targetRepsOverride,
targetScoreOverride: row.targetScoreOverride,
);
}
db.ActiveWorkoutSessionsCompanion _activeWorkoutSessionCompanion(
domain.ActiveWorkoutSession session,
) {
final values = _metadataValues(session.metadata);
return db.ActiveWorkoutSessionsCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
sourceWorkoutTemplateId: Value(session.sourceWorkoutTemplateId),
status: Value(_activeStatusToDb(session.status)),
startedAt: Value(session.startedAt),
pausedAt: Value(session.pausedAt),
endedAt: Value(session.endedAt),
lastPersistedAt: Value(session.lastPersistedAt),
elapsedActiveMs: Value(session.elapsedActiveMs),
currentProgramIndex: Value(session.currentProgramIndex),
currentExerciseIndex: Value(session.currentExerciseIndex),
currentSetIndex: Value(session.currentSetIndex),
resolvedTemplateSnapshotJson: Value(session.resolvedTemplateSnapshotJson),
);
}
domain.ActiveWorkoutSession _activeWorkoutSessionFromRow(
db.ActiveWorkoutSession row,
) {
return domain.ActiveWorkoutSession(
metadata: _metadataFromRow(row),
sourceWorkoutTemplateId: row.sourceWorkoutTemplateId,
status: _activeStatusFromDb(row.status),
startedAt: row.startedAt,
pausedAt: row.pausedAt,
endedAt: row.endedAt,
lastPersistedAt: row.lastPersistedAt,
elapsedActiveMs: row.elapsedActiveMs,
currentProgramIndex: row.currentProgramIndex,
currentExerciseIndex: row.currentExerciseIndex,
currentSetIndex: row.currentSetIndex,
resolvedTemplateSnapshotJson: row.resolvedTemplateSnapshotJson,
);
}
db.ActiveSetResultsCompanion _activeSetResultCompanion(
domain.ActiveSetResult result,
) {
final values = _metadataValues(result.metadata);
return db.ActiveSetResultsCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
activeWorkoutSessionId: Value(result.activeWorkoutSessionId),
programSnapshotId: Value(result.programSnapshotId),
exerciseSnapshotId: Value(result.exerciseSnapshotId),
programIndex: Value(result.programIndex),
exerciseIndex: Value(result.exerciseIndex),
setIndex: Value(result.setIndex),
startedAt: Value(result.startedAt),
completedAt: Value(result.completedAt),
actualTimeMs: Value(result.actualTimeMs),
actualReps: Value(result.actualReps),
actualScore: Value(result.actualScore),
scoreLabelSnapshot: Value(result.scoreLabelSnapshot),
scoreUnitSnapshot: Value(result.scoreUnitSnapshot),
note: Value(result.note),
status: Value(_setResultStatusToDb(result.status)),
);
}
domain.ActiveSetResult _activeSetResultFromRow(db.ActiveSetResult row) {
return domain.ActiveSetResult(
metadata: _metadataFromRow(row),
activeWorkoutSessionId: row.activeWorkoutSessionId,
programSnapshotId: row.programSnapshotId,
exerciseSnapshotId: row.exerciseSnapshotId,
programIndex: row.programIndex,
exerciseIndex: row.exerciseIndex,
setIndex: row.setIndex,
startedAt: row.startedAt,
completedAt: row.completedAt,
actualTimeMs: row.actualTimeMs,
actualReps: row.actualReps,
actualScore: row.actualScore,
scoreLabelSnapshot: row.scoreLabelSnapshot,
scoreUnitSnapshot: row.scoreUnitSnapshot,
note: row.note,
status: _setResultStatusFromDb(row.status),
);
}
db.ActiveRestStatesCompanion _activeRestStateCompanion(
domain.ActiveRestState restState,
) {
final values = _metadataValues(restState.metadata);
return db.ActiveRestStatesCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
activeWorkoutSessionId: Value(restState.activeWorkoutSessionId),
afterProgramIndex: Value(restState.afterProgramIndex),
afterExerciseIndex: Value(restState.afterExerciseIndex),
afterSetIndex: Value(restState.afterSetIndex),
plannedRestSeconds: Value(restState.plannedRestSeconds),
adjustedRestSeconds: Value(restState.adjustedRestSeconds),
startedAt: Value(restState.startedAt),
endedAt: Value(restState.endedAt),
skippedAt: Value(restState.skippedAt),
);
}
domain.ActiveRestState _activeRestStateFromRow(db.ActiveRestState row) {
return domain.ActiveRestState(
metadata: _metadataFromRow(row),
activeWorkoutSessionId: row.activeWorkoutSessionId,
afterProgramIndex: row.afterProgramIndex,
afterExerciseIndex: row.afterExerciseIndex,
afterSetIndex: row.afterSetIndex,
plannedRestSeconds: row.plannedRestSeconds,
adjustedRestSeconds: row.adjustedRestSeconds,
startedAt: row.startedAt,
endedAt: row.endedAt,
skippedAt: row.skippedAt,
);
}
db.WorkoutHistoriesCompanion _workoutHistoryCompanion(
domain.WorkoutHistory history,
) {
final values = _metadataValues(history.metadata);
return db.WorkoutHistoriesCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
sourceWorkoutTemplateId: Value(history.sourceWorkoutTemplateId),
sourceActiveWorkoutSessionId: Value(history.sourceActiveWorkoutSessionId),
nameSnapshot: Value(history.nameSnapshot),
startedAt: Value(history.startedAt),
endedAt: Value(history.endedAt),
totalActiveMs: Value(history.totalActiveMs),
completed: Value(history.completed),
historySnapshotJson: Value(history.historySnapshotJson),
);
}
db.WorkoutHistorySetResultsCompanion _workoutHistorySetResultCompanion(
domain.WorkoutHistorySetResult result,
) {
final values = _metadataValues(result.metadata);
return db.WorkoutHistorySetResultsCompanion(
id: values[0] as Value<String>,
createdAt: values[1] as Value<DateTime>,
updatedAt: values[2] as Value<DateTime>,
deletedAt: values[3] as Value<DateTime?>,
schemaVersion: values[4] as Value<int>,
syncState: values[5] as Value<String>,
localRevision: values[6] as Value<int>,
originDeviceId: values[7] as Value<String>,
futureOwnerProfileId: values[8] as Value<String?>,
lastSyncedAt: values[9] as Value<DateTime?>,
remoteRevision: values[10] as Value<String?>,
workoutHistoryId: Value(result.workoutHistoryId),
programSnapshotId: Value(result.programSnapshotId),
exerciseSnapshotId: Value(result.exerciseSnapshotId),
programIndex: Value(result.programIndex),
exerciseIndex: Value(result.exerciseIndex),
setIndex: Value(result.setIndex),
programNameSnapshot: Value(result.programNameSnapshot),
exerciseNameSnapshot: Value(result.exerciseNameSnapshot),
timeEnabledSnapshot: Value(result.timeEnabledSnapshot),
repsEnabledSnapshot: Value(result.repsEnabledSnapshot),
scoreEnabledSnapshot: Value(result.scoreEnabledSnapshot),
targetTimeSecondsSnapshot: Value(result.targetTimeSecondsSnapshot),
targetRepsSnapshot: Value(result.targetRepsSnapshot),
targetScoreSnapshot: Value(result.targetScoreSnapshot),
actualTimeMs: Value(result.actualTimeMs),
actualReps: Value(result.actualReps),
actualScore: Value(result.actualScore),
scoreLabelSnapshot: Value(result.scoreLabelSnapshot),
scoreUnitSnapshot: Value(result.scoreUnitSnapshot),
startedAt: Value(result.startedAt),
completedAt: Value(result.completedAt),
status: Value(_setResultStatusToDb(result.status)),
);
}
domain.WorkoutHistory _workoutHistoryFromRow(
db.WorkoutHistory row,
List<domain.WorkoutHistorySetResult> results,
) {
return domain.WorkoutHistory(
metadata: _metadataFromRow(row),
sourceWorkoutTemplateId: row.sourceWorkoutTemplateId,
sourceActiveWorkoutSessionId: row.sourceActiveWorkoutSessionId,
nameSnapshot: row.nameSnapshot,
startedAt: row.startedAt,
endedAt: row.endedAt,
totalActiveMs: row.totalActiveMs,
completed: row.completed,
historySnapshotJson: row.historySnapshotJson,
results: results,
);
}
domain.WorkoutHistorySetResult _workoutHistorySetResultFromRow(
db.WorkoutHistorySetResult row,
) {
return domain.WorkoutHistorySetResult(
metadata: _metadataFromRow(row),
workoutHistoryId: row.workoutHistoryId,
programSnapshotId: row.programSnapshotId,
exerciseSnapshotId: row.exerciseSnapshotId,
programIndex: row.programIndex,
exerciseIndex: row.exerciseIndex,
setIndex: row.setIndex,
programNameSnapshot: row.programNameSnapshot,
exerciseNameSnapshot: row.exerciseNameSnapshot,
timeEnabledSnapshot: row.timeEnabledSnapshot,
repsEnabledSnapshot: row.repsEnabledSnapshot,
scoreEnabledSnapshot: row.scoreEnabledSnapshot,
targetTimeSecondsSnapshot: row.targetTimeSecondsSnapshot,
targetRepsSnapshot: row.targetRepsSnapshot,
targetScoreSnapshot: row.targetScoreSnapshot,
actualTimeMs: row.actualTimeMs,
actualReps: row.actualReps,
actualScore: row.actualScore,
scoreLabelSnapshot: row.scoreLabelSnapshot,
scoreUnitSnapshot: row.scoreUnitSnapshot,
startedAt: row.startedAt,
completedAt: row.completedAt,
status: _setResultStatusFromDb(row.status),
);
}
String _syncStateToDb(domain.SyncState state) => switch (state) {
domain.SyncState.localOnly => 'localOnly',
domain.SyncState.dirty => 'dirty',
domain.SyncState.synced => 'synced',
domain.SyncState.deleted => 'deleted',
};
domain.SyncState _syncStateFromDb(String value) => switch (value) {
'localOnly' => domain.SyncState.localOnly,
'dirty' => domain.SyncState.dirty,
'synced' => domain.SyncState.synced,
'deleted' => domain.SyncState.deleted,
_ => throw domain.DomainException('Unknown sync state: $value'),
};
String _activeStatusToDb(domain.ActiveWorkoutStatus status) => switch (status) {
domain.ActiveWorkoutStatus.running => 'running',
domain.ActiveWorkoutStatus.paused => 'paused',
domain.ActiveWorkoutStatus.savedExit => 'savedExit',
domain.ActiveWorkoutStatus.completed => 'completed',
domain.ActiveWorkoutStatus.abandoned => 'abandoned',
};
String _mediaKindToDb(domain.MediaKind kind) => switch (kind) {
domain.MediaKind.image => 'image',
domain.MediaKind.video => 'video',
};
domain.MediaKind _mediaKindFromDb(String value) => switch (value) {
'image' => domain.MediaKind.image,
'video' => domain.MediaKind.video,
_ => throw domain.DomainException('Unknown media kind: $value'),
};
String _setResultStatusToDb(domain.SetResultStatus status) => switch (status) {
domain.SetResultStatus.completed => 'completed',
domain.SetResultStatus.skipped => 'skipped',
};
domain.SetResultStatus _setResultStatusFromDb(String value) => switch (value) {
'completed' => domain.SetResultStatus.completed,
'skipped' => domain.SetResultStatus.skipped,
_ => throw domain.DomainException('Unknown set result status: $value'),
};
domain.ActiveWorkoutStatus _activeStatusFromDb(String value) => switch (value) {
'running' => domain.ActiveWorkoutStatus.running,
'paused' => domain.ActiveWorkoutStatus.paused,
'savedExit' => domain.ActiveWorkoutStatus.savedExit,
'completed' => domain.ActiveWorkoutStatus.completed,
'abandoned' => domain.ActiveWorkoutStatus.abandoned,
_ => throw domain.DomainException('Unknown active workout status: $value'),
};