using Microsoft.EntityFrameworkCore; using Nexus.Api.Data; namespace Nexus.Api.Repositories; public sealed class TaskRepository(NexusDbContext db) : ITaskRepository { public Task> GetAllAsync(CancellationToken ct = default) => db.Tasks.AsNoTracking().OrderByDescending(x => x.UpdatedAt).ToListAsync(ct); public ValueTask GetByIdAsync(Guid id, CancellationToken ct = default) => db.Tasks.FindAsync([id], ct); public Task> GetPendingApprovalAsync(CancellationToken ct = default) { var threshold = DateTimeOffset.UtcNow.AddHours(-1); return db.Tasks.AsNoTracking() .Where(x => x.State == TaskStateHelper.ToStateString(TaskState.InProgress) && x.UpdatedAt <= threshold) .OrderByDescending(x => x.UpdatedAt) .ToListAsync(ct); } public async Task AddAsync(WorkTask task, CancellationToken ct = default) { db.Tasks.Add(task); await db.SaveChangesAsync(ct); return task; } public async Task TryResetStaleInProgressToBacklogAsync( Guid id, DateTimeOffset staleBefore, DateTimeOffset updatedAt, CancellationToken ct = default) { if (!db.Database.IsRelational()) { var task = await db.Tasks .FirstOrDefaultAsync(task => task.Id == id && task.State == TaskStateHelper.ToStateString(TaskState.InProgress) && task.UpdatedAt < staleBefore, ct); if (task is null) { return false; } task.State = TaskStateHelper.ToStateString(TaskState.Backlog); task.UpdatedAt = updatedAt; await db.SaveChangesAsync(ct); return true; } var affectedRows = await db.Tasks .Where(task => task.Id == id && task.State == TaskStateHelper.ToStateString(TaskState.InProgress) && task.UpdatedAt < staleBefore) .ExecuteUpdateAsync(setters => setters .SetProperty(task => task.State, TaskStateHelper.ToStateString(TaskState.Backlog)) .SetProperty(task => task.UpdatedAt, updatedAt), ct); return affectedRows > 0; } public async Task UpdateAsync(WorkTask task, CancellationToken ct = default) { task.UpdatedAt = DateTimeOffset.UtcNow; db.Tasks.Update(task); await db.SaveChangesAsync(ct); } public async Task DeleteAsync(WorkTask task, CancellationToken ct = default) { db.Tasks.Remove(task); await db.SaveChangesAsync(ct); } public Task CountAsync(CancellationToken ct = default) => db.Tasks.CountAsync(ct); public Task CountByStateAsync(string state, CancellationToken ct = default) => db.Tasks.CountAsync(x => x.State == state, ct); public Task GetLastBlockedAsync(CancellationToken ct = default) => db.Tasks.AsNoTracking() .Where(x => x.State == TaskStateHelper.ToStateString(TaskState.Blocked)) .OrderByDescending(x => x.UpdatedAt) .FirstOrDefaultAsync(ct); }