using EntityFramework.Exceptions.PostgreSQL; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Extensions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.EntityFrameworkCore.Diagnostics; using Npgsql; namespace Foxnouns.Backend.Database; public class DatabaseContext : DbContext { private readonly NpgsqlDataSource _dataSource; private readonly ILoggerFactory? _loggerFactory; public DbSet Users { get; set; } public DbSet Members { get; set; } public DbSet AuthMethods { get; set; } public DbSet FediverseApplications { get; set; } public DbSet Tokens { get; set; } public DbSet Applications { get; set; } public DbSet TemporaryKeys { get; set; } public DatabaseContext(Config config, ILoggerFactory? loggerFactory) { var connString = new NpgsqlConnectionStringBuilder(config.Database.Url) { Timeout = config.Database.Timeout ?? 5, MaxPoolSize = config.Database.MaxPoolSize ?? 50, }.ConnectionString; var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString); dataSourceBuilder.UseNodaTime(); _dataSource = dataSourceBuilder.Build(); _loggerFactory = loggerFactory; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .ConfigureWarnings(c => c.Ignore(CoreEventId.ManyServiceProvidersCreatedWarning) .Ignore(CoreEventId.SaveChangesFailed)) .UseNpgsql(_dataSource, o => o.UseNodaTime()) .UseSnakeCaseNamingConvention() .UseLoggerFactory(_loggerFactory) .UseExceptionProcessor(); protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { // Snowflakes are stored as longs configurationBuilder.Properties().HaveConversion(); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().HasIndex(u => u.Username).IsUnique(); modelBuilder.Entity().HasIndex(m => new { m.UserId, m.Name }).IsUnique(); modelBuilder.Entity().HasIndex(k => k.Key).IsUnique(); modelBuilder.Entity() .OwnsOne(u => u.Fields, f => f.ToJson()) .OwnsOne(u => u.Names, n => n.ToJson()) .OwnsOne(u => u.Pronouns, p => p.ToJson()); modelBuilder.Entity() .OwnsOne(m => m.Fields, f => f.ToJson()) .OwnsOne(m => m.Names, n => n.ToJson()) .OwnsOne(m => m.Pronouns, p => p.ToJson()); } } public class DesignTimeDatabaseContextFactory : IDesignTimeDbContextFactory { public DatabaseContext CreateDbContext(string[] args) { // Read the configuration file var config = new ConfigurationBuilder() .AddConfiguration() .Build() // Get the configuration as our config class .Get() ?? new(); return new DatabaseContext(config, null); } }