92 lines
2.6 KiB
C#
92 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 SemaphoreSlim _semaphoreSlim = new(1, 1);
|
|
private readonly AdjGraph _graph = new();
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_semaphoreSlim.Dispose();
|
|
}
|
|
|
|
private record SmartCollectionData(string Query)
|
|
{
|
|
public bool HasCycle { get; set; }
|
|
}
|
|
}
|