using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Tiku.Domain.Catalog; using Tiku.Domain.Content; using Tiku.Domain.Identity; using Tiku.Domain.QuestionBanks; namespace Tiku.Infrastructure.Persistence.Configurations; internal sealed class ContentEntryConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureTenantEntity("content_entries"); builder.ConfigureTimestamps(); builder.Property(entity => entity.LegacyId).HasMaxLength(64); builder.Property(entity => entity.EntryKey).HasMaxLength(100); builder.Property(entity => entity.Name).HasMaxLength(300); builder.Property(entity => entity.EntryType).HasSnakeCaseEnum(); builder.Property(entity => entity.Icon).HasMaxLength(100); builder.Property(entity => entity.Route).HasMaxLength(500); builder.Property(entity => entity.Description).HasMaxLength(2000); builder.Property(entity => entity.Visibility).HasSnakeCaseEnum(); builder.Property(entity => entity.AccessRules).IsJson("{}"); builder.Property(entity => entity.LayoutConfig).IsJson("{}"); builder.HasIndex(entity => new { entity.TenantId, entity.EntryKey }).IsUnique(); builder.HasIndex(entity => new { entity.TenantId, entity.LegacyId }).IsUnique(); builder.HasIndex(entity => new { entity.TenantId, entity.RegionId, entity.EntryType, entity.IsActive, entity.SortOrder }); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.RegionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => entity.CreatedBy) .OnDelete(DeleteBehavior.SetNull); builder.HasOne().WithMany() .HasForeignKey(entity => entity.UpdatedBy) .OnDelete(DeleteBehavior.SetNull); } } internal sealed class ContentNodeConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureTenantEntity("content_nodes"); builder.ConfigureTimestamps(); builder.Property(entity => entity.LegacyId).HasMaxLength(64); builder.Property(entity => entity.NodeKey).HasMaxLength(100); builder.Property(entity => entity.Name).HasMaxLength(300); builder.Property(entity => entity.NodeType).HasSnakeCaseEnum(); builder.Property(entity => entity.MarkerType).HasNullableSnakeCaseEnum(); builder.Property(entity => entity.MarkerConfig).IsJson("{}"); builder.Property(entity => entity.Path).HasColumnType("ltree"); builder.Property(entity => entity.AccessRules).IsJson("{}"); builder.Property(entity => entity.Metadata).IsJson("{}"); builder.HasIndex(entity => new { entity.TenantId, entity.LegacyId }).IsUnique(); builder.HasIndex(entity => new { entity.TenantId, entity.EntryId, entity.NodeKey }).IsUnique(); builder.HasIndex(entity => new { entity.TenantId, entity.EntryId, entity.ParentId, entity.SortOrder }); builder.HasIndex(entity => entity.Path).HasMethod("gist"); builder.HasIndex(entity => new { entity.TenantId, entity.MarkerType }) .HasFilter("marker_type is not null"); builder.ToTable(table => { table.HasCheckConstraint("ck_content_nodes_depth", "depth >= 0"); }); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.EntryId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Cascade); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.RegionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.ParentId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Cascade); builder.HasOne().WithMany() .HasForeignKey(entity => entity.CreatedBy) .OnDelete(DeleteBehavior.SetNull); builder.HasOne().WithMany() .HasForeignKey(entity => entity.UpdatedBy) .OnDelete(DeleteBehavior.SetNull); } } internal sealed class QuestionCollectionConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureTenantEntity("question_collections"); builder.ConfigureTimestamps(); builder.Property(entity => entity.LegacyId).HasMaxLength(64); builder.Property(entity => entity.Name).HasMaxLength(300); builder.Property(entity => entity.CollectionType).HasSnakeCaseEnum(); builder.Property(entity => entity.SourceType).HasSnakeCaseEnum(); builder.Property(entity => entity.Filters).IsJson("{}"); builder.Property(entity => entity.AccessRules).IsJson("{}"); builder.Property(entity => entity.TotalScore).HasPrecision(8, 2); builder.Property(entity => entity.Status).HasSnakeCaseEnum(); builder.Property(entity => entity.Metadata).IsJson("{}"); builder.HasIndex(entity => new { entity.TenantId, entity.LegacyId }).IsUnique(); builder.HasIndex(entity => new { entity.TenantId, entity.NodeId, entity.Status, entity.SortOrder }); builder.ToTable(table => { table.HasCheckConstraint( "ck_question_collections_question_count", "question_count >= 0"); table.HasCheckConstraint( "ck_question_collections_duration", "duration_minutes is null or duration_minutes > 0"); }); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.RegionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.EntryId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.NodeId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.SubjectId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.CategoryId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.QuestionBankId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => entity.CreatedBy) .OnDelete(DeleteBehavior.SetNull); builder.HasOne().WithMany() .HasForeignKey(entity => entity.UpdatedBy) .OnDelete(DeleteBehavior.SetNull); } } internal sealed class QuestionCollectionItemConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureTenantEntity("question_collection_items"); builder.ConfigureTimestamps(); builder.Property(entity => entity.SectionKey).HasMaxLength(100); builder.Property(entity => entity.Score).HasPrecision(8, 2); builder.Property(entity => entity.Metadata).IsJson("{}"); builder.HasIndex(entity => new { entity.TenantId, entity.CollectionId, entity.QuestionReferenceId }).IsUnique(); builder.HasIndex(entity => new { entity.TenantId, entity.CollectionId, entity.SectionKey, entity.SortOrder }); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.CollectionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Cascade); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.QuestionReferenceId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Cascade); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.QuestionOwnerTenantId, entity.QuestionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); } } internal sealed class PracticeBlueprintConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureTenantEntity("practice_blueprints"); builder.ConfigureTimestamps(); builder.Property(entity => entity.LegacyId).HasMaxLength(64); builder.Property(entity => entity.Name).HasMaxLength(300); builder.Property(entity => entity.Mode).HasSnakeCaseEnum(); builder.Property(entity => entity.AssemblyType).HasSnakeCaseEnum(); builder.Property(entity => entity.TotalScore).HasPrecision(8, 2); builder.Property(entity => entity.PassScore).HasPrecision(8, 2); builder.Property(entity => entity.Sections).IsJson("[]"); builder.Property(entity => entity.Rules).IsJson("{}"); builder.Property(entity => entity.AccessRules).IsJson("{}"); builder.Property(entity => entity.Status).HasSnakeCaseEnum(); builder.HasIndex(entity => new { entity.TenantId, entity.LegacyId }).IsUnique(); builder.HasIndex(entity => new { entity.TenantId, entity.NodeId, entity.CollectionId, entity.Mode, entity.Status, entity.SortOrder }); builder.ToTable(table => { table.HasCheckConstraint( "ck_practice_blueprints_question_limit", "question_limit is null or question_limit > 0"); table.HasCheckConstraint( "ck_practice_blueprints_duration", "duration_minutes is null or duration_minutes > 0"); }); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.RegionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.EntryId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.NodeId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.CollectionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => entity.CreatedBy) .OnDelete(DeleteBehavior.SetNull); builder.HasOne().WithMany() .HasForeignKey(entity => entity.UpdatedBy) .OnDelete(DeleteBehavior.SetNull); } }