using Cleanuparr.Domain.Enums; using Cleanuparr.Persistence.Converters; using Cleanuparr.Persistence.Models.Configuration; using Cleanuparr.Persistence.Models.Configuration.Arr; using Cleanuparr.Persistence.Models.Configuration.ContentBlocker; using Cleanuparr.Persistence.Models.Configuration.DownloadCleaner; using Cleanuparr.Persistence.Models.Configuration.General; using Cleanuparr.Persistence.Models.Configuration.Notification; using Cleanuparr.Persistence.Models.Configuration.QueueCleaner; using Cleanuparr.Shared.Helpers; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Cleanuparr.Persistence; /// /// Database context for configuration data /// public class DataContext : DbContext { public static SemaphoreSlim Lock { get; } = new(1, 1); public DbSet GeneralConfigs { get; set; } public DbSet DownloadClients { get; set; } public DbSet QueueCleanerConfigs { get; set; } public DbSet ContentBlockerConfigs { get; set; } public DbSet DownloadCleanerConfigs { get; set; } public DbSet CleanCategories { get; set; } public DbSet ArrConfigs { get; set; } public DbSet ArrInstances { get; set; } public DbSet AppriseConfigs { get; set; } public DbSet NotifiarrConfigs { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (optionsBuilder.IsConfigured) { return; } var dbPath = Path.Combine(ConfigurationPathProvider.GetConfigPath(), "cleanuparr.db"); optionsBuilder .UseSqlite($"Data Source={dbPath}") .UseLowerCaseNamingConvention() .UseSnakeCaseNamingConvention(); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity(entity => { entity.ComplexProperty(e => e.FailedImport); entity.ComplexProperty(e => e.Stalled); entity.ComplexProperty(e => e.Slow); }); modelBuilder.Entity(entity => { entity.ComplexProperty(e => e.Sonarr, cp => { cp.Property(s => s.BlocklistType).HasConversion>(); }); entity.ComplexProperty(e => e.Radarr, cp => { cp.Property(s => s.BlocklistType).HasConversion>(); }); entity.ComplexProperty(e => e.Lidarr, cp => { cp.Property(s => s.BlocklistType).HasConversion>(); }); }); // Configure ArrConfig -> ArrInstance relationship modelBuilder.Entity(entity => { entity.HasMany(a => a.Instances) .WithOne(i => i.ArrConfig) .HasForeignKey(i => i.ArrConfigId) .OnDelete(DeleteBehavior.Cascade); }); foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { var enumProperties = entityType.ClrType.GetProperties() .Where(p => p.PropertyType.IsEnum || (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) && p.PropertyType.GetGenericArguments()[0].IsEnum)); foreach (var property in enumProperties) { var enumType = property.PropertyType.IsEnum ? property.PropertyType : property.PropertyType.GetGenericArguments()[0]; var converterType = typeof(LowercaseEnumConverter<>).MakeGenericType(enumType); var converter = Activator.CreateInstance(converterType); modelBuilder.Entity(entityType.ClrType) .Property(property.Name) .HasConversion((ValueConverter)converter!); } } } }