using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Search; using ErsatzTV.Core.Search; using ErsatzTV.Infrastructure.Data; using Microsoft.EntityFrameworkCore; using static ErsatzTV.Application.MediaCollections.Mapper; namespace ErsatzTV.Application.MediaCollections; public class CreateSmartCollectionHandler : IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; private readonly ISearchTargets _searchTargets; private readonly ISmartCollectionCache _smartCollectionCache; public CreateSmartCollectionHandler( IDbContextFactory dbContextFactory, ISearchTargets searchTargets, ISmartCollectionCache smartCollectionCache) { _dbContextFactory = dbContextFactory; _searchTargets = searchTargets; _smartCollectionCache = smartCollectionCache; } public async Task> Handle( CreateSmartCollection 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, SmartCollection smartCollection) { await dbContext.SmartCollections.AddAsync(smartCollection); await dbContext.SaveChangesAsync(); _searchTargets.SearchTargetsChanged(); await _smartCollectionCache.Refresh(); return ProjectToViewModel(smartCollection); } private static Task> Validate( TvContext dbContext, CreateSmartCollection request) => ValidateName(dbContext, request).MapT( name => new SmartCollection { Name = name, Query = request.Query }); private static async Task> ValidateName( TvContext dbContext, CreateSmartCollection createSmartCollection) { List allNames = await dbContext.SmartCollections .Map(c => c.Name) .ToListAsync(); Validation result1 = createSmartCollection.NotEmpty(c => c.Name) .Bind(_ => createSmartCollection.NotLongerThan(50)(c => c.Name)); var result2 = Optional(createSmartCollection.Name) .Where(name => !allNames.Contains(name)) .ToValidation("SmartCollection name must be unique"); return (result1, result2).Apply((_, _) => createSmartCollection.Name); } }