using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; namespace MiniWiki.Data.Users; public class UsersCachingRepository(UsersDatabaseRepository inner, IMemoryCache cache) : IUsersRepository { public async Task GetByIdAsync(string id) { if (cache.TryGetValue(IdKey(id), out User? user)) return user; var dbUser = await inner.GetByIdAsync(id); CacheUser(dbUser); return dbUser; } public async Task GetMultiple(IEnumerable ids) { ConcurrentBag users = []; await Parallel.ForEachAsync(ids, async (id, _) => { var user = await GetByIdAsync(id); if (user is not null) users.Add(user); }); return [.. users]; } public async Task GetByEmailAsync(string email) { if (cache.TryGetValue(EmailKey(email), out User? user)) return user; var dbUser = await inner.GetByEmailAsync(email); CacheUser(dbUser); return dbUser; } public Task GetUserCount() => inner.GetUserCount(); public async Task CreateAsync(User user) { var dbUser = await inner.CreateAsync(user); CacheUser(dbUser); return dbUser; } public async Task UpdateAsync(User user) { await inner.UpdateAsync(user); CacheUser(user); } private void CacheUser(User? user) { cache.Set(IdKey(user?.Id), user, TimeSpan.FromMinutes(5)); cache.Set(EmailKey(user?.Email), user, TimeSpan.FromMinutes(5)); } private static string IdKey(string? id) => $"users:id:{id}"; private static string EmailKey(string? email) => $"users:email:{email}"; }