using Femto.Common.Domain; using Femto.Common.Infrastructure.Outbox; using Femto.Modules.Auth.Models; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.Logging; namespace Femto.Modules.Auth.Data; internal class AuthContext(DbContextOptions options) : DbContext(options), IOutboxContext { public virtual DbSet Users { get; set; } public virtual DbSet SignupCodes { get; set; } public virtual DbSet LongTermSessions { get; set; } public virtual DbSet Outbox { get; set; } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.HasDefaultSchema("authn"); builder.ApplyConfigurationsFromAssembly(typeof(AuthContext).Assembly); } public override int SaveChanges() { throw new InvalidOperationException("Use SaveChangesAsync instead"); } public override async Task SaveChangesAsync(CancellationToken cancellationToken = default) { await EmitDomainEvents(cancellationToken); return await base.SaveChangesAsync(cancellationToken); } private async Task EmitDomainEvents(CancellationToken cancellationToken) { var logger = this.GetService>(); var publisher = this.GetService(); var domainEvents = this .ChangeTracker.Entries() .SelectMany(e => { var events = e.Entity.DomainEvents; e.Entity.ClearDomainEvents(); return events; }) .ToList(); logger.LogTrace("loaded {Count} domain events", domainEvents.Count); foreach (var domainEvent in domainEvents) { logger.LogTrace( "publishing {Type} domain event {Id}", domainEvent.GetType().Name, domainEvent.EventId ); await publisher.Publish(domainEvent, cancellationToken); } } }