=== Summary: 675 files | 7 generated | 484 fresh | 4605 untracked | 4268 adopted | 355 marked | 466 validated-ok | 2+0 stale (sig+body) | 0 skipped | 0 failed | elapsed 11:08:11.442 (40091.44s) ===

This commit is contained in:
julian
2026-06-28 02:50:05 -07:00
parent a19fb90902
commit 586f02a2ca
654 changed files with 5260 additions and 0 deletions
@@ -10,6 +10,7 @@ namespace adas_core.Application.Services.Caching
/// mediante LockManagerService + InMemoryLockProvider.
/// Compatible con la interfaz ICacheService incluyendo GetOrSet.
/// </summary>
/// <!-- aidoc:v1 sig=53daded -->
public class CacheService(LockManagerService lockManager) : ICacheService
{
private readonly ConcurrentDictionary<string, object> _mem = new();
@@ -21,6 +22,7 @@ namespace adas_core.Application.Services.Caching
/// <param name="gf">The grouped field whose name is included in the key.</param>
/// <param name="patientId">The identifier of the patient the key is scoped to.</param>
/// <returns>A formatted key string in the form <c>GroupedObs:{patientId}:{gf.Name}</c>.</returns>
/// <!-- aidoc:v1 sig=72c65a6 -->
private static string BuildGroupedKey(GroupedField gf, ObjectId patientId)
=> $"GroupedObs:{patientId}:{gf.Name}";
@@ -34,6 +36,8 @@ namespace adas_core.Application.Services.Caching
/// <param name="ttl">Optional time-to-live associated with the cached object.</param>
/// <param name="cancellationToken">A token to observe for cancellation requests.</param>
/// <returns>The cached or newly created object of type <typeparamref name="T"/>.</returns>
/// <!-- aidoc-review:v1 severity=high kind=mentions_removed_behavior
/// "The `ttl` parameter is documented as 'Optional time-to-live associated with the cached object', but the method body never uses `ttl`—the cache assignment `_mem[key] = created;` has no TTL/expiration handling, so readers will be misled into believing the TTL is honored." -->
public async Task<T> GetOrSetObjectAsync<T>(
string key,
Func<Task<T>> factory,
@@ -71,6 +75,8 @@ namespace adas_core.Application.Services.Caching
/// <param name="loader">The asynchronous function invoked to load the value when no cached entry exists for the key.</param>
/// <param name="ttlOverride">An optional time span that overrides the default time-to-live for the cached value.</param>
/// <returns>The cached or newly loaded string value, or <c>null</c> when the underlying cache entry is absent or cannot be cast to a string.</returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "The <returns> text claims the method returns null 'when the underlying cache entry ... cannot be cast to a string', but the explicit cast (string?)result would throw InvalidCastException rather than yield null in that case." -->
public async Task<string?> GetOrSetValueAsync(
string key,
Func<Task<string>> loader,
@@ -94,6 +100,8 @@ namespace adas_core.Application.Services.Caching
/// <param name="ttl">Optional time-to-live for the cached entry.</param>
/// <param name="cancellationToken">Token used to cancel the asynchronous operation.</param>
/// <returns>A task containing the cached or newly created object.</returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_param_role
/// "The `ttl` parameter is documented as 'Optional time-to-live for the cached entry', but it is never referenced in the method body — no TTL is applied to the stored entry, and the lock timeout is hardcoded to 5 seconds. A reader would expect their TTL value to be honored, but it is effectively ignored." -->
public async Task<T> GetOrSetObjectAsync<T>(
GroupedField groupedField,
ObjectId patientId,
@@ -131,6 +139,7 @@ namespace adas_core.Application.Services.Caching
/// </summary>
/// <param name="key">The key that identifies where the value will be stored.</param>
/// <param name="value">The value to associate with the specified key.</param>
/// <!-- aidoc:v1 sig=f3491fe -->
public void SetValue(string key, string value)
=> _mem[key] = value;
@@ -140,6 +149,7 @@ namespace adas_core.Application.Services.Caching
/// </summary>
/// <param name="key">The key used to look up the value in the underlying store.</param>
/// <returns>The string representation of the stored value if the key exists; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=7a34703 -->
public string? GetValue(string key)
=> _mem.TryGetValue(key, out var v) ? v.ToString() : null;
@@ -150,6 +160,7 @@ namespace adas_core.Application.Services.Caching
/// <param name="key">The cache key used to look up the stored object.</param>
/// <param name="updateExpiration">Indicates whether the entry's expiration should be refreshed on access. Not currently used by this implementation.</param>
/// <returns>A <see cref="Task{T}"/> containing the cached value cast to <typeparamref name="T"/>, or <c>null</c> if no entry exists for the given key.</returns>
/// <!-- aidoc:v1 sig=5046896 body=6902631 -->
public Task<T?> GetObjectAsync<T>(string key, bool updateExpiration = true)
{
return Task.FromResult(
@@ -163,6 +174,8 @@ namespace adas_core.Application.Services.Caching
/// <param name="key">The cache key under which the object will be stored.</param>
/// <param name="obj">The object to store in the cache.</param>
/// <param name="updateExpiration">Indicates whether the cache entry's expiration should be refreshed.</param>
/// <!-- aidoc-review:v1 severity=medium kind=mentions_removed_behavior
/// "The updateExpiration parameter is documented as indicating whether the cache entry's expiration should be refreshed, but the method body never references this parameter, so the documented behavior does not occur." -->
public Task SetObjectAsync<T>(string key, T obj, bool updateExpiration = true)
{
_mem[key] = obj!;
@@ -176,6 +189,7 @@ namespace adas_core.Application.Services.Caching
/// <param name="ttlOverride">An optional time-to-live override accepted by this overload but ignored when delegating to the underlying retrieval call.</param>
/// <param name="upd">A flag indicating whether the retrieval should trigger an update on the stored object.</param>
/// <returns>A task that represents the asynchronous operation, containing the retrieved object of type <typeparamref name="T"/> or <c>null</c> if no object is found for the given key.</returns>
/// <!-- aidoc:v1 sig=773648d -->
public Task<T?> GetObjectAsync<T>(string key, TimeSpan? ttlOverride, bool upd)
=> GetObjectAsync<T>(key, upd);
@@ -187,6 +201,7 @@ namespace adas_core.Application.Services.Caching
/// <param name="ttlOverride">An optional time-to-live override for the stored entry; not applied by this overload.</param>
/// <param name="upd">A flag indicating whether the operation should update an existing entry.</param>
/// <returns>A task that represents the asynchronous set operation.</returns>
/// <!-- aidoc:v1 sig=874b6ce -->
public Task SetObjectAsync<T>(string key, T obj, TimeSpan? ttlOverride, bool upd)
=> SetObjectAsync(key, obj, upd);
@@ -196,6 +211,7 @@ namespace adas_core.Application.Services.Caching
/// Asynchronously removes the object associated with the specified key from the in-memory store. The operation succeeds silently whether or not the key exists.
/// </summary>
/// <param name="key">The identifier of the object to delete.</param>
/// <!-- aidoc:v1 sig=93555f0 body=00affc5 -->
public Task DeleteObjectAsync(string key)
{
_mem.TryRemove(key, out _);
@@ -207,6 +223,7 @@ namespace adas_core.Application.Services.Caching
/// </summary>
/// <param name="pattern">The pattern to match against cache keys. Asterisk (*) characters are removed and the remaining text is used as a substring match.</param>
/// <returns>A task that represents the asynchronous operation, containing the count of entries that were removed.</returns>
/// <!-- aidoc:v1 sig=a8cca2e body=81413d3 -->
public Task<long> DeleteByPatternAsync(string pattern)
{
var p = pattern.Replace("*", "");
@@ -223,6 +240,7 @@ namespace adas_core.Application.Services.Caching
/// <summary>
/// Clears all entries from the in-memory cache, removing any previously stored data.
/// </summary>
/// <!-- aidoc:v1 sig=8762842 -->
public void CleanCache() => _mem.Clear();
}
}