using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Infrastructure.Data; using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Application.Resolutions; public class CreateCustomResolutionHandler : IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; public CreateCustomResolutionHandler(IDbContextFactory dbContextFactory) => _dbContextFactory = dbContextFactory; public async Task> Handle(CreateCustomResolution request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); return await validation.Match( r => PersistResolution(dbContext, r, cancellationToken), error => Task.FromResult>(error.Join())); } private static async Task> PersistResolution( TvContext dbContext, Resolution resolution, CancellationToken cancellationToken) { try { await dbContext.Resolutions.AddAsync(resolution, cancellationToken); await dbContext.SaveChangesAsync(cancellationToken); return Option.None; } catch (Exception ex) { return BaseError.New(ex.Message); } } private static Task> Validate( TvContext dbContext, CreateCustomResolution request) => ResolutionMustBeUnique(dbContext, request) .MapT( _ => new Resolution { Name = $"{request.Width}x{request.Height}", Width = request.Width, Height = request.Height, IsCustom = true }); private static async Task> ResolutionMustBeUnique( TvContext dbContext, CreateCustomResolution request) { Option maybeExisting = await dbContext.Resolutions .FirstOrDefaultAsync(r => r.Height == request.Height && r.Width == request.Width) .Map(Optional); if (maybeExisting.IsSome) { return BaseError.New("Resolution width and height must be unique"); } if (request.Height <= 0 || request.Width <= 0) { return BaseError.New("Resolution width or height is invalid"); } return Unit.Default; } }