using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Search; using ErsatzTV.Infrastructure.Data; using Microsoft.EntityFrameworkCore; using static ErsatzTV.Application.MediaCollections.Mapper; namespace ErsatzTV.Application.MediaCollections; public class CreateCollectionHandler : IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; private readonly ISearchTargets _searchTargets; public CreateCollectionHandler(IDbContextFactory dbContextFactory, ISearchTargets searchTargets) { _dbContextFactory = dbContextFactory; _searchTargets = searchTargets; } public async Task> Handle( CreateCollection request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); return await validation.Apply(c => PersistCollection(dbContext, c)); } private async Task PersistCollection(TvContext dbContext, Collection collection) { await dbContext.Collections.AddAsync(collection); await dbContext.SaveChangesAsync(); _searchTargets.SearchTargetsChanged(); return ProjectToViewModel(collection); } private static Task> Validate( TvContext dbContext, CreateCollection request) => ValidateName(dbContext, request).MapT( name => new Collection { Name = name, MediaItems = new List() }); private static async Task> ValidateName( TvContext dbContext, CreateCollection createCollection) { List allNames = await dbContext.Collections .Map(c => c.Name) .ToListAsync(); Validation result1 = createCollection.NotEmpty(c => c.Name) .Bind(_ => createCollection.NotLongerThan(50)(c => c.Name)); var result2 = Optional(createCollection.Name) .Where(name => !allNames.Contains(name)) .ToValidation("Collection name must be unique"); return (result1, result2).Apply((_, _) => createCollection.Name); } }