using Microsoft.EntityFrameworkCore; using Npgsql; namespace RegexBot.Data; /// /// Represents a database connection using the settings defined in the bot's global configuration. /// public class BotDatabaseContext : DbContext { private static readonly string _connectionString; static BotDatabaseContext() { // Get our own config loaded just for the SQL stuff // TODO this should probably be cached, or otherwise loaded in a better way var conf = new Configuration(); _connectionString = new NpgsqlConnectionStringBuilder() { #if DEBUG IncludeErrorDetail = true, #endif Host = conf.Host ?? "localhost", // default to localhost Database = conf.Database, Username = conf.Username, Password = conf.Password }.ToString(); } /// /// Retrieves the user cache. /// public DbSet UserCache { get; set; } = null!; /// /// Retrieves the guild user cache. /// public DbSet GuildUserCache { get; set; } = null!; /// /// Retrieves the guild message cache. /// public DbSet GuildMessageCache { get; set; } = null!; /// /// Retrieves the moderator logs. /// public DbSet ModLogs { get; set; } = null!; /// protected sealed override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseNpgsql(_connectionString) .UseSnakeCaseNamingConvention(); /// protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity(entity => entity.Property(e => e.Discriminator).HasMaxLength(4).IsFixedLength()); modelBuilder.Entity(e => { e.HasKey(p => new { p.GuildId, p.UserId }); e.Property(p => p.FirstSeenTime).HasDefaultValueSql("now()"); }); modelBuilder.Entity(e => e.Property(p => p.CreatedAt).HasDefaultValueSql("now()")); modelBuilder.HasPostgresEnum(); modelBuilder.Entity(e => { e.Property(p => p.Timestamp).HasDefaultValueSql("now()"); e.HasOne(entry => entry.User) .WithMany(gu => gu.Logs) .HasForeignKey(entry => new { entry.GuildId, entry.UserId }); }); } }