using ClaudeDo.Data.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using TaskStatus = ClaudeDo.Data.Models.TaskStatus; namespace ClaudeDo.Data.Configuration; public class TaskEntityConfiguration : IEntityTypeConfiguration { private static string StatusToString(TaskStatus v) => v == TaskStatus.Manual ? "manual" : v == TaskStatus.Queued ? "queued" : v == TaskStatus.Running ? "running" : v == TaskStatus.Done ? "done" : v == TaskStatus.Failed ? "failed" : throw new ArgumentOutOfRangeException(nameof(v)); private static TaskStatus StatusFromString(string v) => v == "manual" ? TaskStatus.Manual : v == "queued" ? TaskStatus.Queued : v == "running" ? TaskStatus.Running : v == "done" ? TaskStatus.Done : v == "failed" ? TaskStatus.Failed : throw new ArgumentOutOfRangeException(nameof(v)); private static readonly ValueConverter StatusConverter = new(v => StatusToString(v), v => StatusFromString(v)); public void Configure(EntityTypeBuilder builder) { builder.ToTable("tasks"); builder.HasKey(t => t.Id); builder.Property(t => t.Id).HasColumnName("id"); builder.Property(t => t.ListId).HasColumnName("list_id").IsRequired(); builder.Property(t => t.Title).HasColumnName("title").IsRequired(); builder.Property(t => t.Description).HasColumnName("description"); builder.Property(t => t.Status).HasColumnName("status").IsRequired() .HasConversion(StatusConverter); builder.Property(t => t.ScheduledFor).HasColumnName("scheduled_for"); builder.Property(t => t.Result).HasColumnName("result"); builder.Property(t => t.LogPath).HasColumnName("log_path"); builder.Property(t => t.CreatedAt).HasColumnName("created_at").IsRequired(); builder.Property(t => t.StartedAt).HasColumnName("started_at"); builder.Property(t => t.FinishedAt).HasColumnName("finished_at"); builder.Property(t => t.CommitType).HasColumnName("commit_type").IsRequired().HasDefaultValue("chore"); builder.Property(t => t.Model).HasColumnName("model"); builder.Property(t => t.SystemPrompt).HasColumnName("system_prompt"); builder.Property(t => t.AgentPath).HasColumnName("agent_path"); builder.Property(t => t.IsStarred).HasColumnName("is_starred").HasDefaultValue(false); builder.Property(t => t.IsMyDay).HasColumnName("is_my_day").HasDefaultValue(false); builder.Property(t => t.Notes).HasColumnName("notes"); builder.HasOne(t => t.List) .WithMany(l => l.Tasks) .HasForeignKey(t => t.ListId) .OnDelete(DeleteBehavior.Cascade); builder.HasOne(t => t.Worktree) .WithOne(w => w.Task) .HasForeignKey(w => w.TaskId); builder.HasMany(t => t.Tags) .WithMany(tag => tag.Tasks) .UsingEntity("task_tags", l => l.HasOne(typeof(TagEntity)).WithMany().HasForeignKey("tag_id").OnDelete(DeleteBehavior.Cascade), r => r.HasOne(typeof(TaskEntity)).WithMany().HasForeignKey("task_id").OnDelete(DeleteBehavior.Cascade), j => { j.HasKey("task_id", "tag_id"); j.ToTable("task_tags"); }); builder.HasIndex(t => t.ListId).HasDatabaseName("idx_tasks_list_id"); builder.HasIndex(t => t.Status).HasDatabaseName("idx_tasks_status"); } }