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 OnlineAccountSessions extends Table { @override String get tableName => 'online_account_sessions'; TextColumn get id => text()(); TextColumn get serverUserId => text().withLength(min: 1)(); TextColumn get email => text().withLength(min: 1)(); TextColumn get displayName => text().nullable()(); BoolColumn get isLoggedIn => boolean()(); DateTimeColumn get createdAt => dateTime()(); DateTimeColumn get updatedAt => dateTime()(); DateTimeColumn get lastAuthenticatedAt => dateTime().nullable()(); @override Set get primaryKey => {id}; @override List get customConstraints => [ 'UNIQUE (server_user_id)', 'CHECK (length(trim(email)) > 0)', 'CHECK (display_name IS NULL OR length(trim(display_name)) > 0)', ]; } class SyncMetadataEntries extends Table { @override String get tableName => 'sync_metadata'; TextColumn get id => text().withDefault(const Constant('singleton'))(); TextColumn get serverCursor => text().nullable()(); DateTimeColumn get lastSuccessfulSyncAt => dateTime().nullable()(); DateTimeColumn get lastAttemptAt => dateTime().nullable()(); DateTimeColumn get lastFailureAt => dateTime().nullable()(); TextColumn get status => text().withDefault(const Constant('idle'))(); IntColumn get pendingPushCount => integer().nullable()(); @override Set get primaryKey => {id}; @override List get customConstraints => [ "CHECK (id = 'singleton')", "CHECK (status IN ('idle', 'syncing', 'success', 'failure'))", 'CHECK (pending_push_count IS NULL OR pending_push_count >= 0)', ]; } class RemoteResourceMappings extends Table { @override String get tableName => 'remote_resource_mappings'; TextColumn get id => text()(); TextColumn get resourceType => text()(); TextColumn get clientId => text().withLength(min: 1)(); TextColumn get serverId => text().withLength(min: 1)(); DateTimeColumn get serverUpdatedAt => dateTime()(); @override Set get primaryKey => {id}; @override List get customConstraints => [ "CHECK (resource_type IN ('exercise', 'program', 'workoutTemplate', " "'workoutHistory', 'mediaAsset'))", 'UNIQUE (resource_type, client_id)', ]; } 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('exerciseIconReferences') TextColumn get iconMediaId => 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 scoreInputMode => text().withDefault(const Constant('manual'))(); TextColumn get scoreLabel => text().nullable()(); TextColumn get scoreUnit => text().nullable()(); IntColumn get defaultTargetTimeSeconds => integer().nullable()(); IntColumn get defaultTargetReps => integer().nullable()(); RealColumn get defaultTargetScore => real().nullable()(); IntColumn get defaultTargetScoreTimeMs => integer().nullable()(); DateTimeColumn get archivedAt => dateTime().nullable()(); @override List get customConstraints => [ 'CHECK (has_time_measure OR has_reps_measure OR has_score_measure)', "CHECK (score_input_mode IN ('manual', 'stopwatch'))", "CHECK (has_score_measure OR score_input_mode = 'manual')", "CHECK (score_input_mode != 'manual' OR 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))', 'CHECK (default_target_time_seconds IS NULL OR ' 'default_target_time_seconds > 0)', 'CHECK (default_target_reps IS NULL OR default_target_reps > 0)', 'CHECK (default_target_score IS NULL OR default_target_score > 0)', 'CHECK (default_target_score_time_ms IS NULL OR ' 'default_target_score_time_ms > 0)', ]; } class ExerciseImages extends SyncableTable { @override String get tableName => 'exercise_images'; TextColumn get exerciseId => text().references(Exercises, #id)(); TextColumn get mediaAssetId => text().references(MediaAssets, #id)(); IntColumn get position => integer()(); @override List get customConstraints => [ 'UNIQUE (exercise_id, position)', 'UNIQUE (exercise_id, media_asset_id)', 'CHECK (position >= 0 AND position < 5)', ]; } class ExerciseSteps extends SyncableTable { @override String get tableName => 'exercise_steps'; TextColumn get exerciseId => text().references(Exercises, #id)(); IntColumn get position => integer()(); TextColumn get name => text().withLength(min: 1)(); TextColumn get type => text()(); IntColumn get defaultTargetValue => integer()(); BoolColumn get hasScore => boolean()(); TextColumn get scoreInputMode => text().nullable()(); TextColumn get scoreLabel => text().nullable()(); TextColumn get scoreUnit => text().nullable()(); RealColumn get defaultTargetScore => real().nullable()(); IntColumn get defaultTargetScoreTimeMs => integer().nullable()(); @override List get customConstraints => [ "CHECK (type IN ('time', 'reps'))", 'CHECK (position >= 0 AND position < 8)', 'CHECK (default_target_value > 0)', "CHECK (score_input_mode IS NULL OR score_input_mode IN ('manual', " "'stopwatch'))", 'CHECK (has_score OR (score_input_mode IS NULL ' 'AND score_label IS NULL AND score_unit IS NULL ' 'AND default_target_score IS NULL ' 'AND default_target_score_time_ms IS NULL))', 'CHECK (NOT has_score OR score_input_mode IS NOT NULL)', "CHECK (NOT has_score OR score_input_mode != 'manual' OR " '(score_label IS NOT NULL AND length(trim(score_label)) > 0 ' 'AND score_unit IS NOT NULL AND length(trim(score_unit)) > 0))', 'CHECK (default_target_score IS NULL OR default_target_score >= 0)', 'CHECK (default_target_score_time_ms IS NULL OR ' 'default_target_score_time_ms > 0)', "CHECK (score_input_mode != 'manual' OR " 'default_target_score_time_ms IS NULL)', "CHECK (score_input_mode != 'stopwatch' OR " '(score_label IS NULL AND score_unit IS NULL ' 'AND default_target_score IS NULL))', 'CHECK (default_target_score IS NULL OR ' 'default_target_score_time_ms IS NULL)', ]; } 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)(); TextColumn get exerciseImageMediaIdsSnapshotJson => text().nullable()(); TextColumn get exerciseStepsSnapshotJson => text().nullable()(); @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 scoreInputModeSnapshot => text().withDefault(const Constant('manual'))(); 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 targetScoreTimeMs => integer().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 (target_score_time_ms IS NULL OR target_score_time_ms > 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 (score_input_mode_snapshot IN ('manual', 'stopwatch'))", 'CHECK (target_score IS NULL OR ' "(score_enabled AND score_input_mode_snapshot = 'manual'))", 'CHECK (target_score_time_ms IS NULL OR ' "(score_enabled AND score_input_mode_snapshot = 'stopwatch'))", 'CHECK (target_score IS NULL OR target_score_time_ms IS NULL)', "CHECK (score_input_mode_snapshot != 'manual' OR " '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()(); IntColumn get targetScoreTimeMsOverride => integer().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)', 'CHECK (target_score_time_ms_override IS NULL OR ' 'target_score_time_ms_override > 0)', 'CHECK (target_score_override IS NULL OR ' 'target_score_time_ms_override IS NULL)', ]; } 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()(); IntColumn get actualScoreTimeMs => integer().nullable()(); TextColumn get scoreInputModeSnapshot => text().withDefault(const Constant('manual'))(); TextColumn get scoreLabelSnapshot => text().nullable()(); TextColumn get scoreUnitSnapshot => text().nullable()(); TextColumn get note => text().nullable()(); TextColumn get status => text().withDefault(const Constant('completed'))(); @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_time_ms IS NULL OR actual_score_time_ms >= 0)', "CHECK (status IN ('completed', 'skipped'))", 'CHECK (status != \'skipped\' OR (actual_time_ms IS NULL ' 'AND actual_reps IS NULL AND actual_score IS NULL ' 'AND actual_score_time_ms IS NULL))', "CHECK (score_input_mode_snapshot IN ('manual', 'stopwatch'))", 'CHECK (actual_score IS NULL OR ' "score_input_mode_snapshot = 'manual')", 'CHECK (actual_score_time_ms IS NULL OR ' "score_input_mode_snapshot = 'stopwatch')", 'CHECK (actual_score IS NULL OR actual_score_time_ms IS NULL)', '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 ActiveScoreStopwatchStates extends SyncableTable { @override String get tableName => 'active_score_stopwatch_states'; TextColumn get activeWorkoutSessionId => text().references(ActiveWorkoutSessions, #id)(); IntColumn get programIndex => integer()(); IntColumn get exerciseIndex => integer()(); IntColumn get setIndex => integer()(); TextColumn get status => text()(); DateTimeColumn get startedAt => dateTime()(); IntColumn get accumulatedMs => integer()(); DateTimeColumn get stoppedAt => dateTime().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 (status IN ('running', 'stopped'))", 'CHECK (accumulated_ms >= 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 ActiveExerciseStepProgressStates extends SyncableTable { @override String get tableName => 'active_exercise_step_progress_states'; TextColumn get activeWorkoutSessionId => text().references(ActiveWorkoutSessions, #id)(); IntColumn get programIndex => integer()(); IntColumn get exerciseIndex => integer()(); IntColumn get setIndex => integer()(); IntColumn get currentPassageIndex => integer()(); IntColumn get currentStepIndex => integer()(); TextColumn get currentStepSnapshotId => text().withLength(min: 1)(); TextColumn get status => text()(); DateTimeColumn get startedAt => dateTime().nullable()(); IntColumn get accumulatedMs => integer()(); DateTimeColumn get lastTransitionAt => dateTime()(); @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 (current_passage_index >= 0)', 'CHECK (current_step_index >= 0)', "CHECK (status IN ('notStarted', 'waitingManual', 'runningTimer', " "'pausedTimer', 'stoppedTimer', 'sequenceComplete'))", 'CHECK (status != \'runningTimer\' OR started_at IS NOT NULL)', 'CHECK (accumulated_ms >= 0)', ]; } class ActiveExerciseStepResults extends SyncableTable { @override String get tableName => 'active_exercise_step_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()(); IntColumn get passageIndex => integer()(); IntColumn get stepIndex => integer()(); TextColumn get stepSnapshotId => text().withLength(min: 1)(); TextColumn get stepNameSnapshot => text().withLength(min: 1)(); TextColumn get stepTypeSnapshot => text()(); IntColumn get targetValueSnapshot => integer()(); BoolColumn get hasScoreSnapshot => boolean()(); TextColumn get scoreInputModeSnapshot => text().nullable()(); TextColumn get scoreLabelSnapshot => text().nullable()(); TextColumn get scoreUnitSnapshot => text().nullable()(); RealColumn get targetScoreSnapshot => real().nullable()(); IntColumn get targetScoreTimeMsSnapshot => integer().nullable()(); TextColumn get status => text()(); 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()(); IntColumn get actualScoreTimeMs => integer().nullable()(); TextColumn get note => text().nullable()(); @override List get customConstraints => [ 'UNIQUE (active_workout_session_id, program_index, exercise_index, ' 'set_index, passage_index, step_index)', 'CHECK (program_index >= 0)', 'CHECK (exercise_index >= 0)', 'CHECK (set_index >= 0)', 'CHECK (passage_index >= 0)', 'CHECK (step_index >= 0)', "CHECK (step_type_snapshot IN ('time', 'reps'))", 'CHECK (target_value_snapshot > 0)', "CHECK (score_input_mode_snapshot IS NULL OR " "score_input_mode_snapshot IN ('manual', 'stopwatch'))", "CHECK (status IN ('completed', 'skipped'))", '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_time_ms IS NULL OR actual_score_time_ms >= 0)', 'CHECK (actual_time_ms IS NULL OR step_type_snapshot = \'time\')', 'CHECK (actual_reps IS NULL OR step_type_snapshot = \'reps\')', 'CHECK (status != \'skipped\' OR (actual_time_ms IS NULL ' 'AND actual_reps IS NULL AND actual_score IS NULL ' 'AND actual_score_time_ms IS NULL))', 'CHECK (target_score_snapshot IS NULL OR ' "(has_score_snapshot AND score_input_mode_snapshot = 'manual'))", 'CHECK (target_score_time_ms_snapshot IS NULL OR ' "(has_score_snapshot AND score_input_mode_snapshot = 'stopwatch'))", 'CHECK (actual_score IS NULL OR ' "(has_score_snapshot AND score_input_mode_snapshot = 'manual'))", 'CHECK (actual_score_time_ms IS NULL OR ' "(has_score_snapshot AND score_input_mode_snapshot = 'stopwatch'))", 'CHECK (actual_score IS NULL OR actual_score_time_ms IS NULL)', 'CHECK (target_score_snapshot IS NULL OR ' 'target_score_time_ms_snapshot 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()(); TextColumn get scoreInputModeSnapshot => text().withDefault(const Constant('manual'))(); IntColumn get targetTimeSecondsSnapshot => integer().nullable()(); IntColumn get targetRepsSnapshot => integer().nullable()(); RealColumn get targetScoreSnapshot => real().nullable()(); IntColumn get targetScoreTimeMsSnapshot => integer().nullable()(); IntColumn get actualTimeMs => integer().nullable()(); IntColumn get actualReps => integer().nullable()(); RealColumn get actualScore => real().nullable()(); IntColumn get actualScoreTimeMs => integer().nullable()(); TextColumn get scoreLabelSnapshot => text().nullable()(); TextColumn get scoreUnitSnapshot => text().nullable()(); DateTimeColumn get startedAt => dateTime().nullable()(); DateTimeColumn get completedAt => dateTime().nullable()(); TextColumn get status => text().withDefault(const Constant('completed'))(); @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 (target_score_time_ms_snapshot IS NULL OR ' 'target_score_time_ms_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_time_ms IS NULL OR actual_score_time_ms >= 0)', "CHECK (status IN ('completed', 'skipped'))", 'CHECK (status != \'skipped\' OR (actual_time_ms IS NULL ' 'AND actual_reps IS NULL AND actual_score IS NULL ' 'AND actual_score_time_ms IS NULL))', "CHECK (score_input_mode_snapshot IN ('manual', 'stopwatch'))", 'CHECK (target_score_snapshot IS NULL OR ' "(score_enabled_snapshot AND score_input_mode_snapshot = 'manual'))", 'CHECK (target_score_time_ms_snapshot IS NULL OR ' "(score_enabled_snapshot AND score_input_mode_snapshot = 'stopwatch'))", 'CHECK (target_score_snapshot IS NULL OR ' 'target_score_time_ms_snapshot IS NULL)', 'CHECK (actual_score IS NULL OR ' "score_input_mode_snapshot = 'manual')", 'CHECK (actual_score_time_ms IS NULL OR ' "score_input_mode_snapshot = 'stopwatch')", 'CHECK (actual_score IS NULL OR actual_score_time_ms IS NULL)', '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 WorkoutHistoryStepResults extends SyncableTable { @override String get tableName => 'workout_history_step_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()(); IntColumn get passageIndex => integer()(); IntColumn get stepIndex => integer()(); TextColumn get stepSnapshotId => text().withLength(min: 1)(); TextColumn get stepNameSnapshot => text().withLength(min: 1)(); TextColumn get stepTypeSnapshot => text()(); IntColumn get targetValueSnapshot => integer()(); BoolColumn get hasScoreSnapshot => boolean()(); TextColumn get scoreInputModeSnapshot => text().nullable()(); TextColumn get scoreLabelSnapshot => text().nullable()(); TextColumn get scoreUnitSnapshot => text().nullable()(); RealColumn get targetScoreSnapshot => real().nullable()(); IntColumn get targetScoreTimeMsSnapshot => integer().nullable()(); TextColumn get status => text()(); 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()(); IntColumn get actualScoreTimeMs => integer().nullable()(); TextColumn get note => text().nullable()(); @override List get customConstraints => [ 'UNIQUE (workout_history_id, program_index, exercise_index, set_index, ' 'passage_index, step_index)', 'CHECK (program_index >= 0)', 'CHECK (exercise_index >= 0)', 'CHECK (set_index >= 0)', 'CHECK (passage_index >= 0)', 'CHECK (step_index >= 0)', "CHECK (step_type_snapshot IN ('time', 'reps'))", 'CHECK (target_value_snapshot > 0)', "CHECK (score_input_mode_snapshot IS NULL OR " "score_input_mode_snapshot IN ('manual', 'stopwatch'))", "CHECK (status IN ('completed', 'skipped'))", '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_time_ms IS NULL OR actual_score_time_ms >= 0)', 'CHECK (actual_time_ms IS NULL OR step_type_snapshot = \'time\')', 'CHECK (actual_reps IS NULL OR step_type_snapshot = \'reps\')', 'CHECK (status != \'skipped\' OR (actual_time_ms IS NULL ' 'AND actual_reps IS NULL AND actual_score IS NULL ' 'AND actual_score_time_ms IS NULL))', 'CHECK (target_score_snapshot IS NULL OR ' "(has_score_snapshot AND score_input_mode_snapshot = 'manual'))", 'CHECK (target_score_time_ms_snapshot IS NULL OR ' "(has_score_snapshot AND score_input_mode_snapshot = 'stopwatch'))", 'CHECK (actual_score IS NULL OR ' "(has_score_snapshot AND score_input_mode_snapshot = 'manual'))", 'CHECK (actual_score_time_ms IS NULL OR ' "(has_score_snapshot AND score_input_mode_snapshot = 'stopwatch'))", 'CHECK (actual_score IS NULL OR actual_score_time_ms IS NULL)', 'CHECK (target_score_snapshot IS NULL OR ' 'target_score_time_ms_snapshot IS NULL)', ]; } 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)', ]; }