using adas_core.Application.Services.Interfaces; using adas_core.Domain.Enums; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.GroupedObservations; using adas_core.Domain.Utils; using MongoDB.Bson; namespace adas_core.Application.Services.Caching { /// /// Orquestador de caché. Selecciona el backend (Redis, InMemory, None) /// según CacheSettings y la entidad del key. /// Implementa ICacheService y delega en el backend elegido. /// public class CacheDispatcher( RedisService redis, CacheService memory, NoCacheService noop, CacheSettings cacheSettings) : ICacheService { // Selección de backend private ICacheService SelectBackend(string key) { var entity = CacheKeyClassifier.Classify(key); var mode = entity switch { CacheEnum.EntityType.Patients => cacheSettings.Patients, CacheEnum.EntityType.Displays => cacheSettings.Displays, CacheEnum.EntityType.PumpObservations => cacheSettings.PumpObservations, CacheEnum.EntityType.Appointments => cacheSettings.Appointments, CacheEnum.EntityType.GroupedObservations => cacheSettings.GroupedObservations, _ => CacheEnum.Mode.Cache }; return mode switch { CacheEnum.Mode.Redis => redis, CacheEnum.Mode.Cache => memory, _ => noop }; } // Para GroupedObservations generamos la misma clave compuesta que el resto de servicios, // de modo que el clasificador y la política de TTL funcionen igual. private static string BuildGroupedKey(GroupedField gf, ObjectId patientId) => $"GroupedObs:{patientId}:{gf.Name}"; private ICacheService SelectBackend(GroupedField groupedField, ObjectId patientId) => SelectBackend(BuildGroupedKey(groupedField, patientId)); // GetOrSet (KEY string) public Task GetOrSetObjectAsync( string key, Func> factory, TimeSpan? ttl = null, CancellationToken cancellationToken = default) => SelectBackend(key).GetOrSetObjectAsync(key, factory, ttl, cancellationToken); public Task GetOrSetValueAsync( string key, Func> loader, TimeSpan? ttl = null) => SelectBackend(key).GetOrSetValueAsync(key, loader, ttl); // GetOrSet (GroupedField + PatientId) public Task GetOrSetObjectAsync( GroupedField groupedField, ObjectId patientId, Func> factory, TimeSpan? ttl = null, CancellationToken cancellationToken = default) => SelectBackend(groupedField, patientId) .GetOrSetObjectAsync(groupedField, patientId, factory, ttl, cancellationToken); // Set/Get básicos public void SetValue(string key, string value) => SelectBackend(key).SetValue(key, value); public string? GetValue(string key) => SelectBackend(key).GetValue(key); public Task GetObjectAsync(string key, bool upd = true) => SelectBackend(key).GetObjectAsync(key, upd); public Task SetObjectAsync(string key, T obj, bool upd = true) => SelectBackend(key).SetObjectAsync(key, obj, upd); public Task GetObjectAsync(string key, TimeSpan? ttl, bool upd) => SelectBackend(key).GetObjectAsync(key, ttl, upd); public Task SetObjectAsync(string key, T obj, TimeSpan? ttl, bool upd) => SelectBackend(key).SetObjectAsync(key, obj, ttl, upd); public Task DeleteObjectAsync(string key) => SelectBackend(key).DeleteObjectAsync(key); public async Task DeleteByPatternAsync(string pattern) => await redis.DeleteByPatternAsync(pattern) + await memory.DeleteByPatternAsync(pattern); public void CleanCache() { memory.CleanCache(); redis.CleanCache(); } } }