mirror of https://github.com/ErsatzTV/ErsatzTV.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
2.6 KiB
91 lines
2.6 KiB
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; } |
|
} |
|
}
|
|
|