import 'package:drift/drift.dart'; import 'package:drift_flutter/drift_flutter.dart'; import 'package:uto_manager/infrastructure/database/daos/personnel_dao.dart'; import 'package:uto_manager/infrastructure/database/daos/position_slot_dao.dart'; import 'package:uto_manager/infrastructure/database/daos/soldier_positions_dao.dart'; import 'package:uto_manager/infrastructure/database/daos/template_dao.dart'; import 'package:uto_manager/infrastructure/database/daos/unit_dao.dart'; part 'app_database.g.dart'; // --------------------------------------------------------------------------- // Table Definitions // --------------------------------------------------------------------------- /// Drift table for organizational unit nodes. class Units extends Table { TextColumn get unitId => text().named('unit_id')(); TextColumn get echelon => text()(); TextColumn get branch => text()(); TextColumn get parentUnitId => text().named('parent_unit_id').nullable()(); TextColumn get name => text()(); BoolColumn get isKeyLeader => boolean().named('is_key_leader')(); @override Set get primaryKey => {unitId}; } /// Drift table for authorized duty position slots. class PositionSlots extends Table { TextColumn get slotId => text().named('slot_id')(); TextColumn get unitId => text().named('unit_id').references(Units, #unitId)(); TextColumn get positionTitle => text().named('position_title')(); TextColumn get dutyMos => text().named('duty_mos')(); TextColumn get authorizedRank => text().named('authorized_rank')(); BoolColumn get isKeyLeader => boolean().named('is_key_leader')(); TextColumn get assignedPersonnelId => text().named('assigned_personnel_id').nullable()(); @override Set get primaryKey => {slotId}; } /// Drift table for soldier personnel records. class Personnel extends Table { TextColumn get soldierId => text().named('soldier_id')(); TextColumn get name => text().nullable()(); TextColumn get positionTitle => text().named('position_title').nullable()(); TextColumn get primaryMos => text().named('primary_mos')(); TextColumn get payGrade => text().named('pay_grade')(); TextColumn get qualifications => text()(); // JSON-encoded list TextColumn get readinessState => text().named('readiness_state')(); TextColumn get assignedSlotId => text().named('assigned_slot_id').nullable()(); @override Set get primaryKey => {soldierId}; } /// Drift table for user-managed soldier duty positions. class SoldierPositions extends Table { TextColumn get positionId => text().named('position_id')(); TextColumn get title => text()(); BoolColumn get isBuiltIn => boolean().named('is_built_in').withDefault(const Constant(false))(); @override Set get primaryKey => {positionId}; } /// Drift table for serialized unit tree templates. class Templates extends Table { TextColumn get templateId => text().named('template_id')(); TextColumn get name => text()(); TextColumn get bctType => text().named('bct_type')(); TextColumn get jsonData => text().named('json_data')(); DateTimeColumn get createdAt => dateTime().named('created_at')(); DateTimeColumn get updatedAt => dateTime().named('updated_at')(); @override Set get primaryKey => {templateId}; } // --------------------------------------------------------------------------- // Database // --------------------------------------------------------------------------- /// The main Drift database for the UTO Manager application. /// /// Manages all core tables: units, position_slots, personnel, soldier_positions, templates. /// Supports SQLite on Windows/Android and IndexedDB on Web via drift_web. @DriftDatabase( tables: [Units, PositionSlots, Personnel, SoldierPositions, Templates], daos: [UnitDao, PersonnelDao, PositionSlotDao, SoldierPositionsDao, TemplateDao], ) class AppDatabase extends _$AppDatabase { /// Creates the production database backed by SQLite on disk. AppDatabase() : super(_openConnection()); /// Constructor for in-memory database (used in tests). AppDatabase.forTesting(super.executor); @override int get schemaVersion => 2; @override MigrationStrategy get migration => MigrationStrategy( onCreate: (m) async { await m.createAll(); }, onUpgrade: (m, from, to) async { if (from < 2) { // v1 → v2: make Personnel.name nullable, add position_title column, // and create the new soldier_positions table. await m.addColumn(personnel, personnel.positionTitle); await m.createTable(soldierPositions); } }, ); } /// Opens a platform-adaptive database connection. /// /// Uses SQLite via FFI on Windows/Android and WASM/IndexedDB on Web. QueryExecutor _openConnection() { return driftDatabase( name: 'uto_manager', web: DriftWebOptions( sqlite3Wasm: Uri.parse('sqlite3.wasm'), driftWorker: Uri.parse('drift_worker.js'), ), ); }