using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Tiku.Domain.Identity; using Tiku.Domain.Learning; using Tiku.Domain.QuestionBanks; using Tiku.Domain.Tenancy; namespace Tiku.Infrastructure.Persistence.Configurations; internal sealed class PracticeSessionConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureTenantEntity("practice_sessions"); builder.HasAlternateKey(entity => new { entity.TenantId, entity.UserId, entity.Id }); builder.Property(entity => entity.Mode).HasMaxLength(50); builder.Property(entity => entity.TargetType).HasMaxLength(50); builder.Property(entity => entity.StartedAt).HasDefaultValueSql("now()"); builder.Property(entity => entity.Metadata).IsJson("{}"); builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.StartedAt }); builder.HasOne().WithMany() .HasForeignKey(entity => entity.UserId) .OnDelete(DeleteBehavior.Cascade); } } internal sealed class AnswerRecordConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureTenantEntity("answer_records"); builder.Property(entity => entity.LegacyId).HasMaxLength(64); builder.Property(entity => entity.LegacyQuestionId).HasMaxLength(64); builder.Property(entity => entity.LegacyCategoryId).HasMaxLength(64); builder.Property(entity => entity.SelectedOptions).IsJson("[]"); builder.Property(entity => entity.AnsweredAt).HasDefaultValueSql("now()"); builder.Property(entity => entity.CreatedAt).HasDefaultValueSql("now()"); builder.HasIndex(entity => new { entity.TenantId, entity.LegacyId }).IsUnique(); builder.HasIndex(entity => new { entity.TenantId, entity.QuestionId }); builder.HasIndex(entity => new { entity.TenantId, entity.QuestionId, entity.QuestionVersionId }); builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.PracticeSessionId }); builder.ToTable(table => table.HasCheckConstraint( "ck_answer_records_version_requires_question", "question_version_id is null or question_id is not null")); builder.HasOne().WithMany() .HasForeignKey(entity => entity.UserId) .OnDelete(DeleteBehavior.Cascade); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.QuestionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.QuestionId, entity.QuestionVersionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.QuestionId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.UserId, entity.PracticeSessionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.UserId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); } } internal sealed class FavoriteQuestionConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ToTable("favorite_questions"); builder.HasKey(entity => new { entity.TenantId, entity.UserId, entity.QuestionId }); builder.Property(entity => entity.Source).HasMaxLength(50); builder.Property(entity => entity.CreatedAt).HasDefaultValueSql("now()"); builder.HasOne().WithMany() .HasForeignKey(entity => entity.TenantId) .OnDelete(DeleteBehavior.Cascade); builder.HasOne().WithMany() .HasForeignKey(entity => entity.UserId) .OnDelete(DeleteBehavior.Cascade); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.QuestionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Cascade); } } internal sealed class WrongQuestionConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ToTable("wrong_questions"); builder.HasKey(entity => new { entity.TenantId, entity.UserId, entity.QuestionId }); builder.Property(entity => entity.WrongCount).HasDefaultValue(1); builder.Property(entity => entity.LastWrongAt).HasDefaultValueSql("now()"); builder.HasOne().WithMany() .HasForeignKey(entity => entity.TenantId) .OnDelete(DeleteBehavior.Cascade); builder.HasOne().WithMany() .HasForeignKey(entity => entity.UserId) .OnDelete(DeleteBehavior.Cascade); builder.HasOne().WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.QuestionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Cascade); } } internal sealed class RecentPracticeConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureTenantEntity("recent_practices"); builder.ConfigureTimestamps(); builder.Property(entity => entity.LegacyId).HasMaxLength(64); builder.Property(entity => entity.PracticeType).HasMaxLength(50); builder.Property(entity => entity.TargetLegacyId).HasMaxLength(64); builder.Property(entity => entity.TargetName).HasMaxLength(300); builder.Property(entity => entity.Color).HasMaxLength(50); builder.Property(entity => entity.Metadata).IsJson("{}"); builder.HasIndex(entity => new { entity.TenantId, entity.LegacyId }).IsUnique(); builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.LastAccessAt }); builder.HasOne().WithMany() .HasForeignKey(entity => entity.UserId) .OnDelete(DeleteBehavior.Cascade); } }