61 lines
2.2 KiB
C#
61 lines
2.2 KiB
C#
using MealPlan.Api.Data;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace MealPlan.Api.Services.Generators;
|
|
|
|
public interface ICatalogMatchingService
|
|
{
|
|
Task<int?> ResolveCatalogItemIdAsync(string nameOrCatalogName, CancellationToken ct = default);
|
|
}
|
|
|
|
public class CatalogMatchingService : ICatalogMatchingService
|
|
{
|
|
private readonly AppDbContext _db;
|
|
private List<CatalogEntry>? _cache;
|
|
|
|
public CatalogMatchingService(AppDbContext db) => _db = db;
|
|
|
|
public async Task<int?> ResolveCatalogItemIdAsync(string nameOrCatalogName, CancellationToken ct = default)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(nameOrCatalogName)) return null;
|
|
|
|
var cache = await GetCacheAsync(ct);
|
|
var key = Normalize(nameOrCatalogName);
|
|
|
|
var exact = cache.FirstOrDefault(c =>
|
|
c.NameKey == key || c.NamePlKey == key || c.CatalogNameKey == key);
|
|
if (exact is not null) return exact.Id;
|
|
|
|
return cache
|
|
.Where(c => key.Contains(c.NameKey, StringComparison.Ordinal) ||
|
|
c.NameKey.Contains(key, StringComparison.Ordinal) ||
|
|
(!string.IsNullOrEmpty(c.NamePlKey) &&
|
|
(key.Contains(c.NamePlKey, StringComparison.Ordinal) ||
|
|
c.NamePlKey.Contains(key, StringComparison.Ordinal))))
|
|
.OrderBy(c => Math.Abs(c.NameKey.Length - key.Length))
|
|
.FirstOrDefault()
|
|
?.Id;
|
|
}
|
|
|
|
private async Task<List<CatalogEntry>> GetCacheAsync(CancellationToken ct)
|
|
{
|
|
if (_cache is not null) return _cache;
|
|
|
|
_cache = await _db.IngredientNutritionCatalog.AsNoTracking()
|
|
.Where(i => i.IsActive)
|
|
.Select(i => new CatalogEntry(i.Id, i.Name, i.NamePl))
|
|
.ToListAsync(ct);
|
|
|
|
return _cache;
|
|
}
|
|
|
|
private static string Normalize(string value) => value.Trim().ToLowerInvariant();
|
|
|
|
private sealed record CatalogEntry(int Id, string Name, string? NamePl)
|
|
{
|
|
public string NameKey { get; } = Name.Trim().ToLowerInvariant();
|
|
public string NamePlKey { get; } = NamePl?.Trim().ToLowerInvariant() ?? string.Empty;
|
|
public string CatalogNameKey { get; } = Name.Trim().ToLowerInvariant();
|
|
}
|
|
}
|