using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ErsatzTV.Core.AggregateModels; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using LanguageExt; using Microsoft.EntityFrameworkCore; using static LanguageExt.Prelude; namespace ErsatzTV.Infrastructure.Data.Repositories { public class MediaCollectionRepository : IMediaCollectionRepository { private readonly TvContext _dbContext; public MediaCollectionRepository(TvContext dbContext) => _dbContext = dbContext; public async Task Add(SimpleMediaCollection collection) { await _dbContext.SimpleMediaCollections.AddAsync(collection); await _dbContext.SaveChangesAsync(); return collection; } public Task> Get(int id) => _dbContext.MediaCollections.SingleOrDefaultAsync(c => c.Id == id).Map(Optional); public Task> GetSimpleMediaCollection(int id) => Get(id).Map(c => c.OfType().HeadOrNone()); public Task> GetTelevisionMediaCollection(int id) => Get(id).Map(c => c.OfType().HeadOrNone()); public Task> GetSimpleMediaCollections() => _dbContext.SimpleMediaCollections.ToListAsync(); public Task> GetAll() => _dbContext.MediaCollections.ToListAsync(); public Task> GetSummaries(string searchString) => _dbContext.MediaCollectionSummaries.FromSqlRaw( @"SELECT mc.Id, mc.Name, Count(mismc.ItemsId) AS ItemCount, true AS IsSimple FROM MediaCollections mc INNER JOIN SimpleMediaCollections smc ON smc.Id = mc.Id LEFT OUTER JOIN MediaItemSimpleMediaCollection mismc ON mismc.SimpleMediaCollectionsId = mc.Id WHERE mc.Name LIKE {0} GROUP BY mc.Id, mc.Name UNION ALL SELECT mc.Id, mc.Name, Count(mi.Id) AS ItemCount, false AS IsSimple FROM MediaCollections mc INNER JOIN TelevisionMediaCollections tmc ON tmc.Id = mc.Id LEFT OUTER JOIN MediaItems mi ON (tmc.SeasonNumber IS NULL OR mi.Metadata_SeasonNumber = tmc.SeasonNumber) AND mi.Metadata_Title = tmc.ShowTitle WHERE mc.Name LIKE {0} GROUP BY mc.Id, mc.Name", $"%{searchString}%").ToListAsync(); public Task>> GetItems(int id) => Get(id).MapT( collection => collection switch { SimpleMediaCollection s => SimpleItems(s), TelevisionMediaCollection t => TelevisionItems(t) }).Bind(x => x.Sequence()); public Task>> GetSimpleMediaCollectionItems(int id) => GetSimpleMediaCollection(id).MapT(SimpleItems).Bind(x => x.Sequence()); public Task>> GetTelevisionMediaCollectionItems(int id) => GetTelevisionMediaCollection(id).MapT(TelevisionItems).Bind(x => x.Sequence()); public Task Update(SimpleMediaCollection collection) { _dbContext.SimpleMediaCollections.Update(collection); return _dbContext.SaveChangesAsync(); } public async Task InsertOrIgnore(TelevisionMediaCollection collection) { if (!_dbContext.TelevisionMediaCollections.Any( existing => existing.ShowTitle == collection.ShowTitle && existing.SeasonNumber == collection.SeasonNumber)) { await _dbContext.TelevisionMediaCollections.AddAsync(collection); await _dbContext.SaveChangesAsync(); } } public Task ReplaceItems(int collectionId, List mediaItems) => GetSimpleMediaCollection(collectionId).IfSomeAsync( async c => { await SimpleItems(c); c.Items.Clear(); foreach (MediaItem mediaItem in mediaItems) { c.Items.Add(mediaItem); } _dbContext.SimpleMediaCollections.Update(c); await _dbContext.SaveChangesAsync(); }); public async Task Delete(int mediaCollectionId) { MediaCollection mediaCollection = await _dbContext.MediaCollections.FindAsync(mediaCollectionId); _dbContext.MediaCollections.Remove(mediaCollection); await _dbContext.SaveChangesAsync(); } public async Task DeleteEmptyTelevisionCollections() { List ids = await _dbContext.GenericIntegerIds.FromSqlRaw( @"SELECT mc.Id FROM MediaCollections mc INNER JOIN TelevisionMediaCollections t on mc.Id = t.Id WHERE NOT EXISTS (SELECT 1 FROM MediaItems mi WHERE t.ShowTitle = mi.Metadata_Title AND (t.SeasonNumber IS NULL OR t.SeasonNumber = mi.Metadata_SeasonNumber))") .Map(i => i.Id) .ToListAsync(); List toDelete = await _dbContext.MediaCollections.Where(mc => ids.Contains(mc.Id)).ToListAsync(); _dbContext.MediaCollections.RemoveRange(toDelete); await _dbContext.SaveChangesAsync(); } private async Task> SimpleItems(SimpleMediaCollection collection) { await _dbContext.Entry(collection).Collection(c => c.Items).LoadAsync(); return collection.Items.ToList(); } private Task> TelevisionItems(TelevisionMediaCollection collection) => _dbContext.MediaItems .Filter(c => c.Metadata.Title == collection.ShowTitle) .Filter(c => collection.SeasonNumber == null || c.Metadata.SeasonNumber == collection.SeasonNumber) .ToListAsync(); } }