Merge claudedo/1891227787ae4085a52c112bd1dcd75a
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
using System.Linq.Expressions;
|
||||
using ClaudeDo.Data.Models;
|
||||
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||
|
||||
namespace ClaudeDo.Data.Filtering.Filters;
|
||||
|
||||
public sealed class ReviewFilter : ITaskListFilter
|
||||
public sealed class ReviewFilter : TaskListFilterBase
|
||||
{
|
||||
public string Id => "virtual:review";
|
||||
public bool Matches(TaskEntity t) =>
|
||||
t.Status == TaskStatus.WaitingForReview;
|
||||
public bool ShouldCount(TaskEntity t) => Matches(t);
|
||||
public bool MatchesAsContext(TaskEntity t, IReadOnlyList<TaskEntity> all) => false;
|
||||
public override string Id => "virtual:review";
|
||||
protected override Expression<Func<TaskEntity, bool>> MatchExpr => t => t.Status == TaskStatus.WaitingForReview;
|
||||
public override bool ShouldCount(TaskEntity t) => Matches(t);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq.Expressions;
|
||||
using ClaudeDo.Data.Models;
|
||||
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||
|
||||
@@ -7,10 +8,11 @@ namespace ClaudeDo.Data.Filtering.Filters;
|
||||
/// Filter for a smart list keyed off a boolean/nullable task flag
|
||||
/// (My Day, Important, Planned). Counts only non-done matches.
|
||||
/// </summary>
|
||||
public sealed class SmartFlagFilter(string id, Func<TaskEntity, bool> flag) : ITaskListFilter
|
||||
public sealed class SmartFlagFilter(string id, Expression<Func<TaskEntity, bool>> flag) : TaskListFilterBase
|
||||
{
|
||||
public string Id => id;
|
||||
public bool Matches(TaskEntity t) => flag(t);
|
||||
public bool ShouldCount(TaskEntity t) => flag(t) && t.Status != TaskStatus.Done;
|
||||
public bool MatchesAsContext(TaskEntity t, IReadOnlyList<TaskEntity> all) => false;
|
||||
private readonly Func<TaskEntity, bool> _flag = flag.Compile();
|
||||
|
||||
public override string Id => id;
|
||||
protected override Expression<Func<TaskEntity, bool>> MatchExpr => flag;
|
||||
public override bool ShouldCount(TaskEntity t) => _flag(t) && t.Status != TaskStatus.Done;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq.Expressions;
|
||||
using ClaudeDo.Data.Models;
|
||||
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||
|
||||
@@ -7,12 +8,12 @@ namespace ClaudeDo.Data.Filtering.Filters;
|
||||
/// Virtual list filter matching tasks by a single status (Queued, Running).
|
||||
/// Planning parents appear contextually when they host a matching child.
|
||||
/// </summary>
|
||||
public sealed class StatusFilter(string id, TaskStatus status) : ITaskListFilter
|
||||
public sealed class StatusFilter(string id, TaskStatus status) : TaskListFilterBase
|
||||
{
|
||||
public string Id => id;
|
||||
public bool Matches(TaskEntity t) => t.Status == status;
|
||||
public bool ShouldCount(TaskEntity t) => t.Status == status;
|
||||
public bool MatchesAsContext(TaskEntity t, IReadOnlyList<TaskEntity> all) =>
|
||||
public override string Id => id;
|
||||
protected override Expression<Func<TaskEntity, bool>> MatchExpr => t => t.Status == status;
|
||||
public override bool ShouldCount(TaskEntity t) => t.Status == status;
|
||||
public override bool MatchesAsContext(TaskEntity t, IReadOnlyList<TaskEntity> all) =>
|
||||
PlanningRules.IsPlanningParent(t) &&
|
||||
PlanningRules.HasMatchingChild(t, all, c => c.Status == status);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Linq.Expressions;
|
||||
using ClaudeDo.Data.Models;
|
||||
|
||||
namespace ClaudeDo.Data.Filtering.Filters;
|
||||
|
||||
/// <summary>
|
||||
/// Base for <see cref="ITaskListFilter"/> implementations: subclasses express their
|
||||
/// primary-match condition once as an expression tree (<see cref="MatchExpr"/>), which
|
||||
/// doubles as a SQL-translatable predicate (<see cref="MatchExpression"/>) and, compiled
|
||||
/// on first use, as the in-memory <see cref="Matches"/> predicate.
|
||||
/// </summary>
|
||||
public abstract class TaskListFilterBase : ITaskListFilter
|
||||
{
|
||||
private Func<TaskEntity, bool>? _compiled;
|
||||
|
||||
public abstract string Id { get; }
|
||||
|
||||
protected abstract Expression<Func<TaskEntity, bool>> MatchExpr { get; }
|
||||
|
||||
public Expression<Func<TaskEntity, bool>> MatchExpression => MatchExpr;
|
||||
|
||||
public bool Matches(TaskEntity t) => (_compiled ??= MatchExpr.Compile())(t);
|
||||
|
||||
public abstract bool ShouldCount(TaskEntity t);
|
||||
|
||||
public virtual bool MatchesAsContext(TaskEntity t, IReadOnlyList<TaskEntity> all) => false;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq.Expressions;
|
||||
using ClaudeDo.Data.Models;
|
||||
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||
|
||||
@@ -7,7 +8,7 @@ namespace ClaudeDo.Data.Filtering.Filters;
|
||||
/// Filter for any user-defined list. Constructed on demand from the list id —
|
||||
/// one instance per list.
|
||||
/// </summary>
|
||||
public sealed class UserListFilter : ITaskListFilter
|
||||
public sealed class UserListFilter : TaskListFilterBase
|
||||
{
|
||||
private readonly string _listId;
|
||||
|
||||
@@ -17,8 +18,7 @@ public sealed class UserListFilter : ITaskListFilter
|
||||
Id = $"user:{listId}";
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
public bool Matches(TaskEntity t) => t.ListId == _listId;
|
||||
public bool ShouldCount(TaskEntity t) => t.ListId == _listId && t.Status != TaskStatus.Done;
|
||||
public bool MatchesAsContext(TaskEntity t, IReadOnlyList<TaskEntity> all) => false;
|
||||
public override string Id { get; }
|
||||
protected override Expression<Func<TaskEntity, bool>> MatchExpr => t => t.ListId == _listId;
|
||||
public override bool ShouldCount(TaskEntity t) => t.ListId == _listId && t.Status != TaskStatus.Done;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq.Expressions;
|
||||
using ClaudeDo.Data.Models;
|
||||
|
||||
namespace ClaudeDo.Data.Filtering;
|
||||
@@ -15,6 +16,9 @@ public interface ITaskListFilter
|
||||
/// <summary>True if <paramref name="t"/> is a primary citizen of this list — appears as a row.</summary>
|
||||
bool Matches(TaskEntity t);
|
||||
|
||||
/// <summary>The primary-match predicate as an expression tree, so EF Core can push it into SQL.</summary>
|
||||
Expression<Func<TaskEntity, bool>> MatchExpression { get; }
|
||||
|
||||
/// <summary>True if <paramref name="t"/> should be counted in this list's badge.</summary>
|
||||
bool ShouldCount(TaskEntity t);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user