Files
ersatztv/ErsatzTV.Infrastructure/Search/SmartCollectionCache.cs
T
Jason DoveandGitHub 7e30444857 dependencies and code cleanup (#2117)
* fix validation in new form layout

* pin mediatr to last oss version

* update dependencies

* cleanup code in core

* cleanup code in ffmpeg

* cleanup code in infra

* cleanup code in scanner

* cleanup code in application

* cleanup main code

* cleanup test code

* solution-wide code cleanup
2025-07-06 15:56:17 +00:00

89 lines
2.6 KiB
C#

using System.Text.RegularExpressions;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Infrastructure.Search;
public sealed class SmartCollectionCache(IDbContextFactory<TvContext> dbContextFactory)
: ISmartCollectionCache, IDisposable
{
private readonly Dictionary<string, SmartCollectionData> _data = new(StringComparer.OrdinalIgnoreCase);
private readonly AdjGraph _graph = new();
private readonly SemaphoreSlim _semaphoreSlim = new(1, 1);
public void Dispose() => _semaphoreSlim.Dispose();
public async Task Refresh()
{
await _semaphoreSlim.WaitAsync();
try
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync();
List<SmartCollection> smartCollections = await dbContext.SmartCollections
.AsNoTracking()
.ToListAsync();
_data.Clear();
_graph.Clear();
foreach (SmartCollection smartCollection in smartCollections)
{
var data = new SmartCollectionData(smartCollection.Query);
_data.Add(smartCollection.Name, data);
foreach (Match match in SearchQueryParser.SmartCollectionRegex().Matches(smartCollection.Query))
{
string otherCollectionName = match.Groups[1].Value;
_graph.AddEdge(smartCollection.Name, otherCollectionName);
}
}
foreach (SmartCollection smartCollection in smartCollections)
{
SmartCollectionData data = _data[smartCollection.Name];
data.HasCycle = _graph.HasCycle(smartCollection.Name);
}
}
finally
{
_semaphoreSlim.Release();
}
}
public async Task<bool> HasCycle(string name)
{
await _semaphoreSlim.WaitAsync();
try
{
return _data.TryGetValue(name, out SmartCollectionData data) && data.HasCycle;
}
finally
{
_semaphoreSlim.Release();
}
}
public async Task<Option<string>> GetQuery(string name)
{
await _semaphoreSlim.WaitAsync();
try
{
return _data.TryGetValue(name, out SmartCollectionData data) ? data.Query : Option<string>.None;
}
finally
{
_semaphoreSlim.Release();
}
}
private record SmartCollectionData(string Query)
{
public bool HasCycle { get; set; }
}
}