| 1 | using AgentForge.Data.Entities; |
| 2 | using Microsoft.EntityFrameworkCore; |
| 3 | |
| 4 | namespace AgentForge.Data; |
| 5 | |
| 6 | public sealed class ForgeDbContext(DbContextOptions<ForgeDbContext> options) : DbContext(options) |
| 7 | { |
| 8 | public DbSet<ForgeRepoEntity> Repos => Set<ForgeRepoEntity>(); |
| 9 | |
| 10 | public DbSet<ForgeOrgEntity> Orgs => Set<ForgeOrgEntity>(); |
| 11 | |
| 12 | public DbSet<ForgeOrgMemberEntity> OrgMembers => Set<ForgeOrgMemberEntity>(); |
| 13 | |
| 14 | public DbSet<ForgeInstanceAdminEntity> InstanceAdmins => Set<ForgeInstanceAdminEntity>(); |
| 15 | |
| 16 | public DbSet<ForgeRepoGroupEntity> RepoGroups => Set<ForgeRepoGroupEntity>(); |
| 17 | |
| 18 | public DbSet<ForgeIssueEntity> Issues => Set<ForgeIssueEntity>(); |
| 19 | |
| 20 | public DbSet<ForgeIssueCommentEntity> IssueComments => Set<ForgeIssueCommentEntity>(); |
| 21 | |
| 22 | public DbSet<ForgeMergeRequestEntity> MergeRequests => Set<ForgeMergeRequestEntity>(); |
| 23 | |
| 24 | public DbSet<ForgeMergeRequestCommentEntity> MergeRequestComments => Set<ForgeMergeRequestCommentEntity>(); |
| 25 | |
| 26 | public DbSet<ForgeCiRunEntity> CiRuns => Set<ForgeCiRunEntity>(); |
| 27 | |
| 28 | public DbSet<ForgeCiDefinitionEntity> CiDefinitions => Set<ForgeCiDefinitionEntity>(); |
| 29 | |
| 30 | public DbSet<ForgeCiPipelineRunEntity> CiPipelineRuns => Set<ForgeCiPipelineRunEntity>(); |
| 31 | |
| 32 | public DbSet<ForgeCiStepRunEntity> CiStepRuns => Set<ForgeCiStepRunEntity>(); |
| 33 | |
| 34 | public DbSet<ForgeApiTokenEntity> ApiTokens => Set<ForgeApiTokenEntity>(); |
| 35 | |
| 36 | public DbSet<ForgeDeviceLoginEntity> DeviceLogins => Set<ForgeDeviceLoginEntity>(); |
| 37 | |
| 38 | public DbSet<ForgeOAuthStateEntity> OAuthStates => Set<ForgeOAuthStateEntity>(); |
| 39 | |
| 40 | public DbSet<ForgeIdentityEntity> Identities => Set<ForgeIdentityEntity>(); |
| 41 | |
| 42 | public DbSet<ForgeCommitProvenanceEntity> CommitProvenance => Set<ForgeCommitProvenanceEntity>(); |
| 43 | |
| 44 | protected override void OnModelCreating(ModelBuilder modelBuilder) |
| 45 | { |
| 46 | modelBuilder.Entity<ForgeOrgEntity>(e => |
| 47 | { |
| 48 | e.ToTable("orgs"); |
| 49 | e.HasKey(x => x.Id); |
| 50 | e.HasIndex(x => x.Slug).IsUnique(); |
| 51 | e.Property(x => x.DefaultVisibility).HasConversion(ForgeValueConverters.RepoVisibility); |
| 52 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 53 | }); |
| 54 | |
| 55 | modelBuilder.Entity<ForgeOrgMemberEntity>(e => |
| 56 | { |
| 57 | e.ToTable("org_members"); |
| 58 | e.HasKey(x => x.Id); |
| 59 | e.HasIndex(x => new { x.OrgId, x.IdentityId }).IsUnique(); |
| 60 | e.Property(x => x.Role).HasConversion(ForgeValueConverters.ForgeOrgRole); |
| 61 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 62 | e.HasOne(x => x.Org).WithMany(x => x.Members).HasForeignKey(x => x.OrgId); |
| 63 | e.HasOne(x => x.Identity).WithMany().HasForeignKey(x => x.IdentityId); |
| 64 | }); |
| 65 | |
| 66 | modelBuilder.Entity<ForgeInstanceAdminEntity>(e => |
| 67 | { |
| 68 | e.ToTable("instance_admins"); |
| 69 | e.HasKey(x => x.Id); |
| 70 | e.HasIndex(x => x.IdentityId).IsUnique(); |
| 71 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 72 | e.HasOne(x => x.Identity).WithMany().HasForeignKey(x => x.IdentityId); |
| 73 | }); |
| 74 | |
| 75 | modelBuilder.Entity<ForgeRepoEntity>(e => |
| 76 | { |
| 77 | e.ToTable("repos"); |
| 78 | e.HasKey(x => x.Id); |
| 79 | e.HasIndex(x => x.Name).IsUnique(); |
| 80 | e.Property(x => x.DriveMode).HasConversion(ForgeValueConverters.DriveMode); |
| 81 | e.Property(x => x.Visibility).HasConversion(ForgeValueConverters.RepoVisibility); |
| 82 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 83 | e.HasOne(x => x.Org).WithMany(x => x.Repos).HasForeignKey(x => x.OrgId); |
| 84 | e.HasOne(x => x.Group).WithMany(x => x.Repos).HasForeignKey(x => x.GroupId); |
| 85 | }); |
| 86 | |
| 87 | modelBuilder.Entity<ForgeRepoGroupEntity>(e => |
| 88 | { |
| 89 | e.ToTable("repo_groups"); |
| 90 | e.HasKey(x => x.Id); |
| 91 | e.HasIndex(x => new { x.OrgId, x.ParentGroupKey, x.Slug }).IsUnique(); |
| 92 | e.Property(x => x.DefaultVisibility).HasConversion(ForgeValueConverters.NullableRepoVisibility); |
| 93 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 94 | e.HasOne(x => x.Org).WithMany(x => x.RepoGroups).HasForeignKey(x => x.OrgId); |
| 95 | e.HasOne(x => x.Parent).WithMany(x => x.Children).HasForeignKey(x => x.ParentGroupId); |
| 96 | }); |
| 97 | |
| 98 | modelBuilder.Entity<ForgeIssueEntity>(e => |
| 99 | { |
| 100 | e.ToTable("issues"); |
| 101 | e.HasKey(x => x.Id); |
| 102 | e.HasIndex(x => new { x.RepoId, x.Number }).IsUnique(); |
| 103 | e.HasIndex(x => x.RepoId); |
| 104 | e.Property(x => x.Status).HasConversion(ForgeValueConverters.IssueStatus); |
| 105 | e.Property(x => x.Anchors).HasConversion(ForgeValueConverters.Anchors); |
| 106 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 107 | e.HasOne(x => x.Repo).WithMany(x => x.Issues).HasForeignKey(x => x.RepoId); |
| 108 | }); |
| 109 | |
| 110 | modelBuilder.Entity<ForgeIssueCommentEntity>(e => |
| 111 | { |
| 112 | e.ToTable("issue_comments"); |
| 113 | e.HasKey(x => x.Id); |
| 114 | e.HasIndex(x => x.IssueId); |
| 115 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 116 | e.HasOne(x => x.Issue).WithMany(x => x.Comments).HasForeignKey(x => x.IssueId); |
| 117 | }); |
| 118 | |
| 119 | modelBuilder.Entity<ForgeMergeRequestEntity>(e => |
| 120 | { |
| 121 | e.ToTable("merge_requests"); |
| 122 | e.HasKey(x => x.Id); |
| 123 | e.HasIndex(x => new { x.RepoId, x.Number }).IsUnique(); |
| 124 | e.HasIndex(x => x.RepoId); |
| 125 | e.Property(x => x.Status).HasConversion(ForgeValueConverters.MergeRequestStatus); |
| 126 | e.Property(x => x.Anchors).HasConversion(ForgeValueConverters.Anchors); |
| 127 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 128 | e.HasOne(x => x.Repo).WithMany(x => x.MergeRequests).HasForeignKey(x => x.RepoId); |
| 129 | }); |
| 130 | |
| 131 | modelBuilder.Entity<ForgeMergeRequestCommentEntity>(e => |
| 132 | { |
| 133 | e.ToTable("merge_request_comments"); |
| 134 | e.HasKey(x => x.Id); |
| 135 | e.HasIndex(x => x.MergeRequestId); |
| 136 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 137 | e.HasOne(x => x.MergeRequest).WithMany(x => x.Comments).HasForeignKey(x => x.MergeRequestId); |
| 138 | }); |
| 139 | |
| 140 | modelBuilder.Entity<ForgeCiRunEntity>(e => |
| 141 | { |
| 142 | e.ToTable("ci_runs"); |
| 143 | e.HasKey(x => x.Id); |
| 144 | e.HasIndex(x => new { x.RepoId, x.MrNumber }); |
| 145 | e.Property(x => x.Status).HasConversion(ForgeValueConverters.CiRunStatus); |
| 146 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 147 | e.Property(x => x.UpdatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 148 | e.HasOne(x => x.Repo).WithMany().HasForeignKey(x => x.RepoId); |
| 149 | }); |
| 150 | |
| 151 | modelBuilder.Entity<ForgeCiDefinitionEntity>(e => |
| 152 | { |
| 153 | e.ToTable("ci_definitions"); |
| 154 | e.HasKey(x => x.Id); |
| 155 | e.HasIndex(x => new { x.RepoId, x.Name }).IsUnique(); |
| 156 | e.HasIndex(x => x.RepoId); |
| 157 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 158 | e.Property(x => x.UpdatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 159 | e.HasOne(x => x.Repo).WithMany().HasForeignKey(x => x.RepoId); |
| 160 | }); |
| 161 | |
| 162 | modelBuilder.Entity<ForgeCiPipelineRunEntity>(e => |
| 163 | { |
| 164 | e.ToTable("ci_pipeline_runs"); |
| 165 | e.HasKey(x => x.Id); |
| 166 | e.HasIndex(x => x.RepoId); |
| 167 | e.HasIndex(x => new { x.RepoId, x.CreatedAt }); |
| 168 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 169 | e.Property(x => x.UpdatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 170 | e.Property(x => x.StartedAt).HasConversion(ForgeValueConverters.NullableTimestamp); |
| 171 | e.Property(x => x.FinishedAt).HasConversion(ForgeValueConverters.NullableTimestamp); |
| 172 | e.HasOne(x => x.Repo).WithMany().HasForeignKey(x => x.RepoId); |
| 173 | e.HasMany(x => x.Steps).WithOne(x => x.Run).HasForeignKey(x => x.RunId); |
| 174 | }); |
| 175 | |
| 176 | modelBuilder.Entity<ForgeCiStepRunEntity>(e => |
| 177 | { |
| 178 | e.ToTable("ci_step_runs"); |
| 179 | e.HasKey(x => x.Id); |
| 180 | e.HasIndex(x => x.RunId); |
| 181 | e.HasIndex(x => new { x.RunId, x.OrderIndex }).IsUnique(); |
| 182 | e.Property(x => x.StartedAt).HasConversion(ForgeValueConverters.NullableTimestamp); |
| 183 | e.Property(x => x.FinishedAt).HasConversion(ForgeValueConverters.NullableTimestamp); |
| 184 | }); |
| 185 | |
| 186 | modelBuilder.Entity<ForgeApiTokenEntity>(e => |
| 187 | { |
| 188 | e.ToTable("api_tokens"); |
| 189 | e.HasKey(x => x.Id); |
| 190 | e.HasIndex(x => x.TokenHash).IsUnique(); |
| 191 | e.Property(x => x.Scopes).HasConversion(ForgeValueConverters.ForgeScope); |
| 192 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 193 | e.Property(x => x.RevokedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 194 | }); |
| 195 | |
| 196 | modelBuilder.Entity<ForgeDeviceLoginEntity>(e => |
| 197 | { |
| 198 | e.ToTable("device_logins"); |
| 199 | e.HasKey(x => x.Id); |
| 200 | e.HasIndex(x => x.DeviceCodeHash).IsUnique(); |
| 201 | e.HasIndex(x => x.UserCode); |
| 202 | e.Property(x => x.Status).HasConversion<int>(); |
| 203 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 204 | e.Property(x => x.ExpiresAt).HasConversion(ForgeValueConverters.Timestamp); |
| 205 | e.Property(x => x.ApprovedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 206 | }); |
| 207 | |
| 208 | modelBuilder.Entity<ForgeOAuthStateEntity>(e => |
| 209 | { |
| 210 | e.ToTable("oauth_states"); |
| 211 | e.HasKey(x => x.Id); |
| 212 | e.HasIndex(x => x.State).IsUnique(); |
| 213 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 214 | e.Property(x => x.ExpiresAt).HasConversion(ForgeValueConverters.Timestamp); |
| 215 | }); |
| 216 | |
| 217 | modelBuilder.Entity<ForgeIdentityEntity>(e => |
| 218 | { |
| 219 | e.ToTable("identities"); |
| 220 | e.HasKey(x => x.Id); |
| 221 | e.HasIndex(x => new { x.Provider, x.SubjectId }).IsUnique(); |
| 222 | e.Property(x => x.CreatedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 223 | e.Property(x => x.LastLoginAt).HasConversion(ForgeValueConverters.Timestamp); |
| 224 | }); |
| 225 | |
| 226 | modelBuilder.Entity<ForgeCommitProvenanceEntity>(e => |
| 227 | { |
| 228 | e.ToTable("commit_provenance"); |
| 229 | e.HasKey(x => x.Id); |
| 230 | e.HasIndex(x => new { x.RepoId, x.Sha }).IsUnique(); |
| 231 | e.HasIndex(x => x.RepoId); |
| 232 | e.Property(x => x.IssueNumbers).HasConversion(ForgeValueConverters.IntList); |
| 233 | e.Property(x => x.Anchors).HasConversion(ForgeValueConverters.Anchors); |
| 234 | e.Property(x => x.RecordedAt).HasConversion(ForgeValueConverters.Timestamp); |
| 235 | e.HasOne(x => x.Repo).WithMany().HasForeignKey(x => x.RepoId); |
| 236 | }); |
| 237 | } |
| 238 | } |
| 239 | |