feat: planning sessions foundation (Plan A) #4
@@ -206,6 +206,19 @@ public sealed class TaskRepository
|
||||
|
||||
#endregion
|
||||
|
||||
#region Planning
|
||||
|
||||
public async Task<List<TaskEntity>> GetChildrenAsync(string parentId, CancellationToken ct = default)
|
||||
{
|
||||
return await _context.Tasks
|
||||
.AsNoTracking()
|
||||
.Where(t => t.ParentTaskId == parentId)
|
||||
.OrderBy(t => t.SortOrder).ThenBy(t => t.CreatedAt)
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Queue selection
|
||||
|
||||
public async Task<TaskEntity?> GetNextQueuedAgentTaskAsync(DateTime now, CancellationToken ct = default)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
using ClaudeDo.Data;
|
||||
using ClaudeDo.Data.Models;
|
||||
using ClaudeDo.Data.Repositories;
|
||||
using ClaudeDo.Worker.Tests.Infrastructure;
|
||||
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||
|
||||
namespace ClaudeDo.Worker.Tests.Repositories;
|
||||
|
||||
public sealed class TaskRepositoryPlanningTests : IDisposable
|
||||
{
|
||||
private readonly DbFixture _db = new();
|
||||
private readonly ClaudeDoDbContext _ctx;
|
||||
private readonly TaskRepository _tasks;
|
||||
private readonly ListRepository _lists;
|
||||
private readonly TagRepository _tags;
|
||||
|
||||
public TaskRepositoryPlanningTests()
|
||||
{
|
||||
_ctx = _db.CreateContext();
|
||||
_tasks = new TaskRepository(_ctx);
|
||||
_lists = new ListRepository(_ctx);
|
||||
_tags = new TagRepository(_ctx);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_ctx.Dispose();
|
||||
_db.Dispose();
|
||||
}
|
||||
|
||||
private async Task<string> CreateListAsync(string? id = null)
|
||||
{
|
||||
var listId = id ?? Guid.NewGuid().ToString();
|
||||
await _lists.AddAsync(new ListEntity
|
||||
{
|
||||
Id = listId,
|
||||
Name = "Test List",
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
});
|
||||
return listId;
|
||||
}
|
||||
|
||||
private TaskEntity MakeTask(string listId, TaskStatus status = TaskStatus.Manual, string? parentId = null) => new()
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
ListId = listId,
|
||||
Title = "t",
|
||||
Status = status,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CommitType = "feat",
|
||||
ParentTaskId = parentId,
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public async Task GetChildrenAsync_ReturnsOnlyDirectChildren_Sorted()
|
||||
{
|
||||
var listId = await CreateListAsync();
|
||||
var parent = MakeTask(listId, TaskStatus.Planning);
|
||||
parent.Title = "parent";
|
||||
await _tasks.AddAsync(parent);
|
||||
|
||||
var childA = MakeTask(listId, TaskStatus.Draft, parentId: parent.Id);
|
||||
childA.Title = "a";
|
||||
await _tasks.AddAsync(childA);
|
||||
childA.SortOrder = 1;
|
||||
await _tasks.UpdateAsync(childA);
|
||||
|
||||
var childB = MakeTask(listId, TaskStatus.Draft, parentId: parent.Id);
|
||||
childB.Title = "b";
|
||||
await _tasks.AddAsync(childB);
|
||||
childB.SortOrder = 0;
|
||||
await _tasks.UpdateAsync(childB);
|
||||
|
||||
var unrelated = MakeTask(listId, TaskStatus.Manual);
|
||||
await _tasks.AddAsync(unrelated);
|
||||
|
||||
var children = await _tasks.GetChildrenAsync(parent.Id);
|
||||
|
||||
Assert.Equal(2, children.Count);
|
||||
Assert.Equal("b", children[0].Title);
|
||||
Assert.Equal("a", children[1].Title);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user