feat(bibliothèque): migration Drift v16, seed basket et seeding au démarrage (ticket #80)
Ajoute la migration Drift v16 (enum ExerciseCategory, champ isExample sur exercises/programs/workout_templates, table local_seed_metadata), le contenu seed basket déterministe (21 exercices, 1 programme, 1 séance- modèle) dans lib/application/starter_content/, les ports StarterSeedStateRepository/StarterContentRepository et le use case SeedStarterContentUseCase branché dans AppBootstrap.create(). Validé GO par QA/Main : dart analyze propre, suite complète 167 tests (4 échecs préexistants sans rapport avec ce lot), 4 nouveaux tests seed tous verts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -18,6 +18,7 @@ part 'app_database.g.dart';
|
||||
Exercises,
|
||||
ExerciseImages,
|
||||
ExerciseSteps,
|
||||
LocalSeedMetadata,
|
||||
MediaAssets,
|
||||
OnlineAccountSessions,
|
||||
PendingShareActions,
|
||||
@ -47,7 +48,7 @@ final class AppDatabase extends _$AppDatabase {
|
||||
}
|
||||
|
||||
@override
|
||||
int get schemaVersion => 15;
|
||||
int get schemaVersion => 16;
|
||||
|
||||
@override
|
||||
MigrationStrategy get migration {
|
||||
@ -55,6 +56,7 @@ final class AppDatabase extends _$AppDatabase {
|
||||
onCreate: (migrator) async {
|
||||
await migrator.createAll();
|
||||
await _migrateToSchema15();
|
||||
await _migrateToSchema16(migrator);
|
||||
await _createIndexes();
|
||||
},
|
||||
onUpgrade: (migrator, from, to) async {
|
||||
@ -108,6 +110,9 @@ final class AppDatabase extends _$AppDatabase {
|
||||
if (from < 15) {
|
||||
await _migrateToSchema15();
|
||||
}
|
||||
if (from < 16) {
|
||||
await _migrateToSchema16(migrator);
|
||||
}
|
||||
await _createIndexes();
|
||||
},
|
||||
beforeOpen: (details) async {
|
||||
@ -148,6 +153,22 @@ final class AppDatabase extends _$AppDatabase {
|
||||
'CREATE INDEX IF NOT EXISTS idx_exercise_steps_exercise_id_position '
|
||||
'ON exercise_steps (exercise_id, position)',
|
||||
);
|
||||
await customStatement(
|
||||
'CREATE INDEX IF NOT EXISTS idx_exercises_category '
|
||||
'ON exercises (category)',
|
||||
);
|
||||
await customStatement(
|
||||
'CREATE INDEX IF NOT EXISTS idx_exercises_is_example '
|
||||
'ON exercises (is_example)',
|
||||
);
|
||||
await customStatement(
|
||||
'CREATE INDEX IF NOT EXISTS idx_programs_is_example '
|
||||
'ON programs (is_example)',
|
||||
);
|
||||
await customStatement(
|
||||
'CREATE INDEX IF NOT EXISTS idx_workout_templates_is_example '
|
||||
'ON workout_templates (is_example)',
|
||||
);
|
||||
await customStatement(
|
||||
'CREATE INDEX IF NOT EXISTS idx_online_account_sessions_logged_in '
|
||||
'ON online_account_sessions (is_logged_in, updated_at)',
|
||||
@ -637,6 +658,57 @@ CREATE TABLE IF NOT EXISTS active_set_timer_states (
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _migrateToSchema16(Migrator migrator) async {
|
||||
await _addColumnIfMissing(
|
||||
tableName: 'exercises',
|
||||
columnName: 'category',
|
||||
definition:
|
||||
"category TEXT NOT NULL DEFAULT 'uncategorized' CHECK "
|
||||
"(category IN ('shoot', 'freeThrows', 'dribble', 'finishing', "
|
||||
"'conditioning', 'defense', 'mobility', 'uncategorized'))",
|
||||
);
|
||||
await _addColumnIfMissing(
|
||||
tableName: 'exercises',
|
||||
columnName: 'is_example',
|
||||
definition:
|
||||
'is_example INTEGER NOT NULL DEFAULT 0 '
|
||||
'CHECK (is_example IN (0, 1))',
|
||||
);
|
||||
await _addColumnIfMissing(
|
||||
tableName: 'programs',
|
||||
columnName: 'is_example',
|
||||
definition:
|
||||
'is_example INTEGER NOT NULL DEFAULT 0 '
|
||||
'CHECK (is_example IN (0, 1))',
|
||||
);
|
||||
await _addColumnIfMissing(
|
||||
tableName: 'workout_templates',
|
||||
columnName: 'is_example',
|
||||
definition:
|
||||
'is_example INTEGER NOT NULL DEFAULT 0 '
|
||||
'CHECK (is_example IN (0, 1))',
|
||||
);
|
||||
await customStatement(
|
||||
'CREATE TABLE IF NOT EXISTS local_seed_metadata ('
|
||||
'key TEXT NOT NULL PRIMARY KEY, '
|
||||
'version INTEGER NOT NULL CHECK (version >= 0), '
|
||||
'applied_at INTEGER NOT NULL'
|
||||
')',
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _addColumnIfMissing({
|
||||
required String tableName,
|
||||
required String columnName,
|
||||
required String definition,
|
||||
}) async {
|
||||
final columns = await customSelect('PRAGMA table_info($tableName)').get();
|
||||
final exists = columns.any((row) => row.data['name'] == columnName);
|
||||
if (!exists) {
|
||||
await customStatement('ALTER TABLE $tableName ADD COLUMN $definition');
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _hasColumn(String tableName, String columnName) async {
|
||||
final rows = await customSelect('PRAGMA table_info($tableName)').get();
|
||||
return rows.any((row) => row.data['name'] == columnName);
|
||||
|
||||
Reference in New Issue
Block a user