using API.Schema.Jobs; using API.Schema.LibraryConnectors; using API.Schema.MangaConnectors; using API.Schema.NotificationConnectors; using Microsoft.EntityFrameworkCore; namespace API.Schema; public class PgsqlContext(DbContextOptions options) : DbContext(options) { public DbSet Jobs { get; set; } public DbSet MangaConnectors { get; set; } public DbSet Mangas { get; set; } public DbSet LocalLibraries { get; set; } public DbSet Chapters { get; set; } public DbSet Authors { get; set; } public DbSet Tags { get; set; } public DbSet LibraryConnectors { get; set; } public DbSet NotificationConnectors { get; set; } public DbSet Notifications { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { //Job Types modelBuilder.Entity() .HasDiscriminator(j => j.JobType) .HasValue(JobType.MoveFileOrFolderJob) .HasValue(JobType.MoveMangaLibraryJob) .HasValue(JobType.DownloadAvailableChaptersJob) .HasValue(JobType.DownloadSingleChapterJob) .HasValue(JobType.DownloadMangaCoverJob) .HasValue(JobType.RetrieveChaptersJob) .HasValue(JobType.UpdateFilesDownloadedJob); //Job specification modelBuilder.Entity() .HasOne(j => j.Manga) .WithMany() .HasForeignKey(j => j.MangaId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .Navigation(j => j.Manga) .AutoInclude(); modelBuilder.Entity() .HasOne(j => j.Manga) .WithMany() .HasForeignKey(j => j.MangaId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .Navigation(j => j.Manga) .AutoInclude(); modelBuilder.Entity() .HasOne(j => j.Chapter) .WithMany() .HasForeignKey(j => j.ChapterId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .Navigation(j => j.Chapter) .AutoInclude(); modelBuilder.Entity() .HasOne(j => j.Manga) .WithMany() .HasForeignKey(j => j.MangaId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .Navigation(j => j.Manga) .AutoInclude(); modelBuilder.Entity() .HasOne(j => j.ToLibrary) .WithMany() .HasForeignKey(j => j.ToLibraryId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .Navigation(j => j.ToLibrary) .AutoInclude(); modelBuilder.Entity() .HasOne(j => j.Manga) .WithMany() .HasForeignKey(j => j.MangaId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .Navigation(j => j.Manga) .AutoInclude(); //Job has possible ParentJob modelBuilder.Entity() .HasMany() .WithOne(childJob => childJob.ParentJob) .HasForeignKey(childjob => childjob.ParentJobId) .IsRequired(false) .OnDelete(DeleteBehavior.Cascade); //Job might be dependent on other Jobs modelBuilder.Entity() .HasMany(root => root.DependsOnJobs) .WithMany(); modelBuilder.Entity() .Navigation(root => root.DependsOnJobs) .AutoInclude(false); //MangaConnector Types modelBuilder.Entity() .HasDiscriminator(c => c.Name) .HasValue("Global") .HasValue("MangaDex"); //MangaConnector is responsible for many Manga modelBuilder.Entity() .HasMany() .WithOne(m => m.MangaConnector) .HasForeignKey(m => m.MangaConnectorName) .IsRequired() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .Navigation(m => m.MangaConnector) .AutoInclude(); //Manga has many Chapters modelBuilder.Entity() .HasMany(m => m.Chapters) .WithOne(c => c.ParentManga) .HasForeignKey(c => c.ParentMangaId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .Navigation(c => c.ParentManga) .AutoInclude(); //Manga owns MangaAltTitles modelBuilder.Entity() .OwnsMany(m => m.AltTitles) .WithOwner(); //Manga owns Links modelBuilder.Entity() .OwnsMany(m => m.Links) .WithOwner(); //Manga has many Tags associated with many Manga modelBuilder.Entity() .HasMany(m => m.MangaTags) .WithMany() .UsingEntity("MangaTagToManga", l=> l.HasOne(typeof(MangaTag)).WithMany().HasForeignKey("MangaTagIds").HasPrincipalKey(nameof(MangaTag.Tag)), r => r.HasOne(typeof(Manga)).WithMany().HasForeignKey("MangaIds").HasPrincipalKey(nameof(Manga.MangaId)), j => j.HasKey("MangaTagIds", "MangaIds") ); //Manga has many Authors associated with many Manga modelBuilder.Entity() .HasMany(m => m.Authors) .WithMany() .UsingEntity("AuthorToManga", l=> l.HasOne(typeof(Author)).WithMany().HasForeignKey("AuthorIds").HasPrincipalKey(nameof(Author.AuthorId)), r => r.HasOne(typeof(Manga)).WithMany().HasForeignKey("MangaIds").HasPrincipalKey(nameof(Manga.MangaId)), j => j.HasKey("AuthorIds", "MangaIds") ); //LocalLibrary has many Mangas modelBuilder.Entity() .HasMany() .WithOne(m => m.Library) .HasForeignKey(m => m.LibraryId) .OnDelete(DeleteBehavior.SetNull); //LibraryConnector Types modelBuilder.Entity() .HasDiscriminator(l => l.LibraryType) .HasValue(LibraryType.Komga) .HasValue(LibraryType.Kavita); } }