import 'package:drift/drift.dart'; abstract class SyncableTable extends Table { TextColumn get id => text()(); DateTimeColumn get createdAt => dateTime()(); DateTimeColumn get updatedAt => dateTime()(); DateTimeColumn get deletedAt => dateTime().nullable()(); IntColumn get schemaVersion => integer().withDefault(const Constant(1))(); TextColumn get syncState => text().customConstraint( "NOT NULL CHECK (sync_state IN ('localOnly', 'dirty', 'synced', " "'deleted'))", )(); IntColumn get localRevision => integer().customConstraint('NOT NULL CHECK (local_revision >= 0)')(); TextColumn get originDeviceId => text().withLength(min: 1)(); TextColumn get futureOwnerProfileId => text().nullable()(); DateTimeColumn get lastSyncedAt => dateTime().nullable()(); TextColumn get remoteRevision => text().nullable()(); @override Set get primaryKey => {id}; @override List get customConstraints => const []; } class MediaAssets extends SyncableTable { @override String get tableName => 'media_assets'; TextColumn get kind => text()(); TextColumn get localUri => text().withLength(min: 1)(); TextColumn get mimeType => text().nullable()(); IntColumn get sizeBytes => integer().nullable()(); IntColumn get width => integer().nullable()(); IntColumn get height => integer().nullable()(); IntColumn get durationMs => integer().nullable()(); TextColumn get checksum => text().nullable()(); TextColumn get remoteUri => text().nullable()(); TextColumn get thumbnailLocalUri => text().nullable()(); @override List get customConstraints => [ "CHECK (kind IN ('image', 'video'))", 'CHECK (size_bytes IS NULL OR size_bytes >= 0)', 'CHECK (width IS NULL OR width > 0)', 'CHECK (height IS NULL OR height > 0)', 'CHECK (duration_ms IS NULL OR duration_ms >= 0)', ]; } class Exercises extends SyncableTable { @override String get tableName => 'exercises'; TextColumn get name => text().withLength(min: 1)(); TextColumn get description => text().nullable()(); @ReferenceName('exerciseImageReferences') TextColumn get imageMediaId => text().nullable().references(MediaAssets, #id)(); @ReferenceName('exerciseVideoReferences') TextColumn get videoMediaId => text().nullable().references(MediaAssets, #id)(); BoolColumn get hasTimeMeasure => boolean()(); BoolColumn get hasRepsMeasure => boolean()(); BoolColumn get hasScoreMeasure => boolean()(); TextColumn get scoreLabel => text().nullable()(); TextColumn get scoreUnit => text().nullable()(); DateTimeColumn get archivedAt => dateTime().nullable()(); @override List get customConstraints => [ 'CHECK (has_time_measure OR has_reps_measure OR has_score_measure)', 'CHECK (NOT has_score_measure OR (score_label IS NOT NULL ' 'AND length(trim(score_label)) > 0 AND score_unit IS NOT NULL ' 'AND length(trim(score_unit)) > 0))', ]; } class Programs extends SyncableTable { @override String get tableName => 'programs'; TextColumn get name => text().withLength(min: 1)(); IntColumn get defaultRestSeconds => integer()(); @override List get customConstraints => ['CHECK (default_rest_seconds >= 0)']; } class ProgramExercises extends SyncableTable { @override String get tableName => 'program_exercises'; TextColumn get programId => text().references(Programs, #id)(); TextColumn get sourceExerciseId => text().nullable().references(Exercises, #id)(); IntColumn get position => integer()(); TextColumn get exerciseNameSnapshot => text().withLength(min: 1)(); TextColumn get exerciseDescriptionSnapshot => text().nullable()(); @ReferenceName('programExerciseImageSnapshotReferences') TextColumn get exerciseImageMediaIdSnapshot => text().nullable().references(MediaAssets, #id)(); @ReferenceName('programExerciseVideoSnapshotReferences') TextColumn get exerciseVideoMediaIdSnapshot => text().nullable().references(MediaAssets, #id)(); BoolColumn get exerciseArchivedSnapshot => boolean().withDefault(const Constant(false))(); BoolColumn get availableTimeSnapshot => boolean()(); BoolColumn get availableRepsSnapshot => boolean()(); BoolColumn get availableScoreSnapshot => boolean()(); TextColumn get scoreLabelSnapshot => text().nullable()(); TextColumn get scoreUnitSnapshot => text().nullable()(); IntColumn get setsCount => integer()(); BoolColumn get timeEnabled => boolean()(); BoolColumn get repsEnabled => boolean()(); BoolColumn get scoreEnabled => boolean()(); IntColumn get targetTimeSeconds => integer().nullable()(); IntColumn get targetReps => integer().nullable()(); RealColumn get targetScore => real().nullable()(); IntColumn get restSecondsOverride => integer().nullable()(); @override List get customConstraints => [ 'UNIQUE (program_id, position)', 'CHECK (position >= 0)', 'CHECK (sets_count > 0)', 'CHECK (time_enabled OR reps_enabled OR score_enabled)', 'CHECK (NOT time_enabled OR available_time_snapshot)', 'CHECK (NOT reps_enabled OR available_reps_snapshot)', 'CHECK (NOT score_enabled OR available_score_snapshot)', 'CHECK (target_time_seconds IS NULL OR target_time_seconds > 0)', 'CHECK (target_reps IS NULL OR target_reps > 0)', 'CHECK (target_score IS NULL OR target_score >= 0)', 'CHECK (rest_seconds_override IS NULL OR rest_seconds_override >= 0)', 'CHECK (target_time_seconds IS NULL OR time_enabled)', 'CHECK (target_reps IS NULL OR reps_enabled)', 'CHECK (target_score IS NULL OR score_enabled)', 'CHECK (NOT available_score_snapshot OR (score_label_snapshot ' 'IS NOT NULL AND length(trim(score_label_snapshot)) > 0 ' 'AND score_unit_snapshot IS NOT NULL ' 'AND length(trim(score_unit_snapshot)) > 0))', ]; } class WorkoutTemplates extends SyncableTable { @override String get tableName => 'workout_templates'; TextColumn get name => text().withLength(min: 1)(); DateTimeColumn get lastStartedAt => dateTime().nullable()(); } class WorkoutTemplatePrograms extends SyncableTable { @override String get tableName => 'workout_template_programs'; TextColumn get workoutTemplateId => text().references(WorkoutTemplates, #id)(); TextColumn get sourceProgramId => text().nullable().references(Programs, #id)(); IntColumn get position => integer()(); TextColumn get programNameSnapshot => text().withLength(min: 1)(); IntColumn get defaultRestSecondsSnapshot => integer()(); TextColumn get programSnapshotJson => text().withLength(min: 1)(); @override List get customConstraints => [ 'UNIQUE (workout_template_id, position)', 'CHECK (position >= 0)', 'CHECK (default_rest_seconds_snapshot >= 0)', ]; } class WorkoutTemplateExerciseOverrides extends SyncableTable { @override String get tableName => 'workout_template_exercise_overrides'; TextColumn get workoutTemplateProgramId => text().references(WorkoutTemplatePrograms, #id)(); TextColumn get snapshotProgramExerciseId => text().withLength(min: 1)(); IntColumn get setsCountOverride => integer().nullable()(); IntColumn get targetTimeSecondsOverride => integer().nullable()(); IntColumn get targetRepsOverride => integer().nullable()(); RealColumn get targetScoreOverride => real().nullable()(); @override List get customConstraints => [ 'UNIQUE (workout_template_program_id, snapshot_program_exercise_id)', 'CHECK (sets_count_override IS NULL OR sets_count_override > 0)', 'CHECK (target_time_seconds_override IS NULL OR ' 'target_time_seconds_override > 0)', 'CHECK (target_reps_override IS NULL OR target_reps_override > 0)', 'CHECK (target_score_override IS NULL OR target_score_override >= 0)', ]; } class ActiveWorkoutSessions extends SyncableTable { @override String get tableName => 'active_workout_sessions'; TextColumn get sourceWorkoutTemplateId => text().nullable().references(WorkoutTemplates, #id)(); TextColumn get status => text()(); DateTimeColumn get startedAt => dateTime()(); DateTimeColumn get pausedAt => dateTime().nullable()(); DateTimeColumn get endedAt => dateTime().nullable()(); DateTimeColumn get lastPersistedAt => dateTime()(); IntColumn get elapsedActiveMs => integer()(); IntColumn get currentProgramIndex => integer()(); IntColumn get currentExerciseIndex => integer()(); IntColumn get currentSetIndex => integer()(); TextColumn get resolvedTemplateSnapshotJson => text().withLength(min: 1)(); @override List get customConstraints => [ "CHECK (status IN ('running', 'paused', 'savedExit', 'completed', " "'abandoned'))", 'CHECK (elapsed_active_ms >= 0)', 'CHECK (current_program_index >= 0)', 'CHECK (current_exercise_index >= 0)', 'CHECK (current_set_index >= 0)', ]; } class ActiveSetResults extends SyncableTable { @override String get tableName => 'active_set_results'; TextColumn get activeWorkoutSessionId => text().references(ActiveWorkoutSessions, #id)(); TextColumn get programSnapshotId => text().withLength(min: 1)(); TextColumn get exerciseSnapshotId => text().withLength(min: 1)(); IntColumn get programIndex => integer()(); IntColumn get exerciseIndex => integer()(); IntColumn get setIndex => integer()(); DateTimeColumn get startedAt => dateTime().nullable()(); DateTimeColumn get completedAt => dateTime().nullable()(); IntColumn get actualTimeMs => integer().nullable()(); IntColumn get actualReps => integer().nullable()(); RealColumn get actualScore => real().nullable()(); TextColumn get scoreLabelSnapshot => text().nullable()(); TextColumn get scoreUnitSnapshot => text().nullable()(); TextColumn get note => text().nullable()(); @override List get customConstraints => [ 'UNIQUE (active_workout_session_id, program_index, exercise_index, ' 'set_index)', 'CHECK (program_index >= 0)', 'CHECK (exercise_index >= 0)', 'CHECK (set_index >= 0)', 'CHECK (actual_time_ms IS NULL OR actual_time_ms >= 0)', 'CHECK (actual_reps IS NULL OR actual_reps >= 0)', 'CHECK (actual_score IS NULL OR actual_score >= 0)', 'CHECK (actual_score IS NULL OR (score_label_snapshot IS NOT NULL ' 'AND length(trim(score_label_snapshot)) > 0 ' 'AND score_unit_snapshot IS NOT NULL ' 'AND length(trim(score_unit_snapshot)) > 0))', ]; } class ActiveRestStates extends SyncableTable { @override String get tableName => 'active_rest_states'; TextColumn get activeWorkoutSessionId => text().references(ActiveWorkoutSessions, #id)(); IntColumn get afterProgramIndex => integer()(); IntColumn get afterExerciseIndex => integer()(); IntColumn get afterSetIndex => integer()(); IntColumn get plannedRestSeconds => integer()(); IntColumn get adjustedRestSeconds => integer()(); DateTimeColumn get startedAt => dateTime()(); DateTimeColumn get endedAt => dateTime().nullable()(); DateTimeColumn get skippedAt => dateTime().nullable()(); @override List get customConstraints => [ 'CHECK (after_program_index >= 0)', 'CHECK (after_exercise_index >= 0)', 'CHECK (after_set_index >= 0)', 'CHECK (planned_rest_seconds >= 0)', 'CHECK (adjusted_rest_seconds >= 0)', 'CHECK (ended_at IS NULL OR skipped_at IS NULL)', ]; } class WorkoutHistories extends SyncableTable { @override String get tableName => 'workout_history'; TextColumn get sourceWorkoutTemplateId => text().nullable().references(WorkoutTemplates, #id)(); TextColumn get sourceActiveWorkoutSessionId => text().nullable().references(ActiveWorkoutSessions, #id)(); TextColumn get nameSnapshot => text().withLength(min: 1)(); DateTimeColumn get startedAt => dateTime()(); DateTimeColumn get endedAt => dateTime()(); IntColumn get totalActiveMs => integer()(); BoolColumn get completed => boolean()(); TextColumn get historySnapshotJson => text().withLength(min: 1)(); @override List get customConstraints => ['CHECK (total_active_ms >= 0)']; } class WorkoutHistorySetResults extends SyncableTable { @override String get tableName => 'workout_history_set_results'; TextColumn get workoutHistoryId => text().references(WorkoutHistories, #id)(); TextColumn get programSnapshotId => text().withLength(min: 1)(); TextColumn get exerciseSnapshotId => text().withLength(min: 1)(); IntColumn get programIndex => integer()(); IntColumn get exerciseIndex => integer()(); IntColumn get setIndex => integer()(); TextColumn get programNameSnapshot => text().withLength(min: 1)(); TextColumn get exerciseNameSnapshot => text().withLength(min: 1)(); BoolColumn get timeEnabledSnapshot => boolean()(); BoolColumn get repsEnabledSnapshot => boolean()(); BoolColumn get scoreEnabledSnapshot => boolean()(); IntColumn get targetTimeSecondsSnapshot => integer().nullable()(); IntColumn get targetRepsSnapshot => integer().nullable()(); RealColumn get targetScoreSnapshot => real().nullable()(); IntColumn get actualTimeMs => integer().nullable()(); IntColumn get actualReps => integer().nullable()(); RealColumn get actualScore => real().nullable()(); TextColumn get scoreLabelSnapshot => text().nullable()(); TextColumn get scoreUnitSnapshot => text().nullable()(); DateTimeColumn get startedAt => dateTime().nullable()(); DateTimeColumn get completedAt => dateTime().nullable()(); @override List get customConstraints => [ 'UNIQUE (workout_history_id, program_index, exercise_index, ' 'set_index)', 'CHECK (program_index >= 0)', 'CHECK (exercise_index >= 0)', 'CHECK (set_index >= 0)', 'CHECK (time_enabled_snapshot OR reps_enabled_snapshot OR ' 'score_enabled_snapshot)', 'CHECK (target_time_seconds_snapshot IS NULL OR ' 'target_time_seconds_snapshot > 0)', 'CHECK (target_reps_snapshot IS NULL OR target_reps_snapshot > 0)', 'CHECK (target_score_snapshot IS NULL OR target_score_snapshot >= 0)', 'CHECK (actual_time_ms IS NULL OR actual_time_ms >= 0)', 'CHECK (actual_reps IS NULL OR actual_reps >= 0)', 'CHECK (actual_score IS NULL OR actual_score >= 0)', 'CHECK (actual_score IS NULL OR (score_label_snapshot IS NOT NULL ' 'AND length(trim(score_label_snapshot)) > 0 ' 'AND score_unit_snapshot IS NOT NULL ' 'AND length(trim(score_unit_snapshot)) > 0))', ]; } class ChangeLogEntries extends Table { @override String get tableName => 'change_log'; TextColumn get id => text()(); TextColumn get entityType => text().withLength(min: 1)(); TextColumn get entityId => text().withLength(min: 1)(); TextColumn get operation => text()(); TextColumn get payloadHash => text().nullable()(); IntColumn get localRevision => integer()(); TextColumn get originDeviceId => text().withLength(min: 1)(); DateTimeColumn get createdAt => dateTime()(); DateTimeColumn get syncedAt => dateTime().nullable()(); @override Set get primaryKey => {id}; @override List get customConstraints => const [ "CHECK (operation IN ('insert', 'update', 'softDelete', 'restore'))", 'CHECK (local_revision >= 0)', ]; }