import 'package:drift/drift.dart'; import 'package:drift_postgres/drift_postgres.dart'; import '../database.dart'; part 'task_dao.g.dart'; @DriftAccessor() class TaskDao extends DatabaseAccessor with _$TaskDaoMixin { TaskDao(super.db); // ==================== Tasks ==================== /// Получить задачу по ID Future getTaskById(String id) { return (select(db.tasks)..where((t) => t.id.equals(id))).getSingleOrNull(); } /// Получить все задачи Future> getAllTasks() { return select(db.tasks).get(); } /// Создать задачу Future createTask(TasksCompanion task) async { final inserted = await into(db.tasks).insertReturning(task); return inserted.id; } /// Обновить задачу Future updateTask(Task task) { return update(db.tasks).replace(task); } /// Обновить время последнего выполнения Future updateLastExecution(String taskId) { final now = PgDateTime(DateTime.now()); return (update(db.tasks)..where((t) => t.id.equals(taskId))) .write(TasksCompanion( lastExecution: Value(now), updatedAt: Value(now), )); } // ==================== UserTasks ==================== /// Получить задачу пользователя по ID Future getUserTaskById(String id) { return (select(db.userTasks)..where((ut) => ut.id.equals(id))).getSingleOrNull(); } /// Получить все задачи пользователей (для системных задач) Future> getAllUserTasks() { return select(db.userTasks).get(); } /// Получить задачи пользователя Future> getUserTasks(String userId, { String? status, bool activeOnly = false, }) { final query = select(db.userTasks); // Note: UserTasks table doesn't have userId column, so we can't filter by userId // This method may need to be refactored if userId filtering is required if (status != null) { query.where((ut) => ut.status.equals(status)); } if (activeOnly) { final now = PgDateTime(DateTime.now()); query.where((ut) => ut.expiresAt.isBiggerThanValue(now)); } query.orderBy([(ut) => OrderingTerm.desc(ut.createdAt)]); return query.get(); } /// Создать задачу пользователя Future createUserTask(UserTasksCompanion task) async { final inserted = await into(db.userTasks).insertReturning(task); return inserted.id; } /// Создать задачу пользователя или игнорировать, если уже существует /// Возвращает true, если задача была создана, false если уже существовала /// /// Если task.id.present == true, проверяет существование перед вставкой Future createUserTaskOrIgnore(UserTasksCompanion task) async { // Если ID указан, проверяем существование перед вставкой if (task.id.present) { final existing = await getUserTaskById(task.id.value); if (existing != null) { return false; // Задача уже существует } } try { await into(db.userTasks).insert( task, mode: InsertMode.insertOrIgnore, ); return true; // Задача была создана } catch (e) { // PostgreSQL error code 23505 = unique_violation (duplicate key) // Это может произойти в редких случаях race condition final errorString = e.toString(); if (errorString.contains('23505') || errorString.contains('duplicate key') || errorString.contains('unique constraint')) { return false; // Задача уже существует } // Пробрасываем другие ошибки rethrow; } } /// Обновить задачу пользователя Future updateUserTask(UserTask task) { return update(db.userTasks).replace(task); } /// Завершить задачу пользователя Future completeUserTask(String taskId) { final now = PgDateTime(DateTime.now()); return (update(db.userTasks)..where((ut) => ut.id.equals(taskId))) .write(UserTasksCompanion( status: const Value('completed'), completedAt: Value(now), updatedAt: Value(now), )); } /// Подсчитать задачи пользователя Future countUserTasks(String userId, {String? status}) async { final countExpr = db.userTasks.id.count(); final query = selectOnly(db.userTasks)..addColumns([countExpr]); if (status != null) { query.where(db.userTasks.status.equals(status)); } return await query.map((row) => row.read(countExpr)!).getSingle(); } // ==================== UserTaskProgresses ==================== /// Получить прогресс задачи пользователя Future getTaskProgress(String userId, String taskId) { return (select(db.userTaskProgresses) ..where((utp) => utp.userId.equals(userId) & utp.taskId.equals(taskId)) ).getSingleOrNull(); } /// Создать прогресс задачи Future createTaskProgress(UserTaskProgressesCompanion progress) async { final inserted = await into(db.userTaskProgresses).insertReturning(progress); return inserted.id; } /// Обновить прогресс задачи Future updateTaskProgress(UserTaskProgressesData progress) { return update(db.userTaskProgresses).replace(progress); } // ==================== UserTaskResults ==================== /// Получить результаты задач пользователя Future> getTaskResults(String userId) { return (select(db.userTaskResults) ..where((utr) => utr.userId.equals(userId)) ..orderBy([(utr) => OrderingTerm.desc(utr.completedAt)]) ).get(); } /// Создать результат задачи Future createTaskResult(UserTaskResultsCompanion result) async { final inserted = await into(db.userTaskResults).insertReturning(result); return inserted.id; } }