import 'dart:io'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:trainhub_flutter/core/constants/app_constants.dart'; import 'package:trainhub_flutter/data/database/daos/analysis_dao.dart'; import 'package:trainhub_flutter/data/database/daos/chat_dao.dart'; import 'package:trainhub_flutter/data/database/daos/exercise_dao.dart'; import 'package:trainhub_flutter/data/database/daos/knowledge_chunk_dao.dart'; import 'package:trainhub_flutter/data/database/daos/program_dao.dart'; import 'package:trainhub_flutter/data/database/daos/training_plan_dao.dart'; part 'app_database.g.dart'; // --------------------------------------------------------------------------- // Existing tables (unchanged) // --------------------------------------------------------------------------- class Exercises extends Table { TextColumn get id => text()(); TextColumn get name => text()(); TextColumn get instructions => text().nullable()(); TextColumn get enrichment => text().nullable()(); TextColumn get tags => text().nullable()(); TextColumn get videoUrl => text().nullable()(); @override Set get primaryKey => {id}; } class TrainingPlans extends Table { TextColumn get id => text()(); TextColumn get name => text()(); TextColumn get sections => text().nullable()(); @override Set get primaryKey => {id}; } class Programs extends Table { TextColumn get id => text()(); TextColumn get name => text()(); TextColumn get createdAt => text()(); @override Set get primaryKey => {id}; } class ProgramWeeks extends Table { TextColumn get id => text()(); TextColumn get programId => text().references(Programs, #id, onDelete: KeyAction.cascade)(); IntColumn get position => integer()(); TextColumn get notes => text().nullable()(); @override Set get primaryKey => {id}; } class ProgramWorkouts extends Table { TextColumn get id => text()(); TextColumn get weekId => text().references(ProgramWeeks, #id, onDelete: KeyAction.cascade)(); TextColumn get programId => text().references(Programs, #id, onDelete: KeyAction.cascade)(); TextColumn get day => text()(); TextColumn get type => text()(); TextColumn get refId => text().nullable()(); TextColumn get name => text().nullable()(); TextColumn get description => text().nullable()(); BoolColumn get completed => boolean().withDefault(const Constant(false))(); @override Set get primaryKey => {id}; } class AnalysisSessions extends Table { TextColumn get id => text()(); TextColumn get name => text()(); TextColumn get date => text()(); TextColumn get videoPath => text().nullable()(); @override Set get primaryKey => {id}; } class Annotations extends Table { TextColumn get id => text()(); TextColumn get sessionId => text().references(AnalysisSessions, #id, onDelete: KeyAction.cascade)(); RealColumn get startTime => real()(); RealColumn get endTime => real()(); TextColumn get name => text().nullable()(); TextColumn get description => text().nullable()(); TextColumn get color => text().nullable()(); @override Set get primaryKey => {id}; } class ChatSessions extends Table { TextColumn get id => text()(); TextColumn get title => text().nullable()(); TextColumn get createdAt => text()(); TextColumn get updatedAt => text()(); @override Set get primaryKey => {id}; } class ChatMessages extends Table { TextColumn get id => text()(); TextColumn get sessionId => text().references(ChatSessions, #id, onDelete: KeyAction.cascade)(); TextColumn get role => text()(); TextColumn get content => text()(); TextColumn get createdAt => text()(); @override Set get primaryKey => {id}; } // --------------------------------------------------------------------------- // v2: Knowledge base chunks // --------------------------------------------------------------------------- /// Stores text chunks and their JSON-encoded embedding vectors. /// Used for Retrieval-Augmented Generation (RAG) in the AI chat. class KnowledgeChunks extends Table { /// UUID for this individual chunk. TextColumn get id => text()(); /// All chunks from the same `addNote()` call share this ID. TextColumn get sourceId => text()(); /// The raw text of the chunk (max ~500 chars). TextColumn get content => text()(); /// JSON-encoded `List` — the 768-dim Nomic embedding vector. TextColumn get embedding => text()(); TextColumn get createdAt => text()(); @override Set get primaryKey => {id}; } // --------------------------------------------------------------------------- // Database class // --------------------------------------------------------------------------- @DriftDatabase( tables: [ Exercises, TrainingPlans, Programs, ProgramWeeks, ProgramWorkouts, AnalysisSessions, Annotations, ChatSessions, ChatMessages, KnowledgeChunks, // added in schema v2 ], daos: [ ExerciseDao, TrainingPlanDao, ProgramDao, AnalysisDao, ChatDao, KnowledgeChunkDao, // added in schema v2 ], ) class AppDatabase extends _$AppDatabase { AppDatabase() : super(_openConnection()); @override int get schemaVersion => 2; @override MigrationStrategy get migration => MigrationStrategy( onUpgrade: (migrator, from, to) async { // v1 → v2: add knowledge chunks table if (from < 2) { await migrator.createTable(knowledgeChunks); } }, ); } LazyDatabase _openConnection() { return LazyDatabase(() async { final dbFolder = await getApplicationDocumentsDirectory(); final file = File(p.join(dbFolder.path, AppConstants.databaseName)); return NativeDatabase.createInBackground(file); }); }