From e9759364c312f26ccae6de7b91546cc6f5a584ee Mon Sep 17 00:00:00 2001 From: Jakub Kurlowicz Date: Wed, 6 Dec 2023 20:33:32 +0100 Subject: [PATCH] Added Set and Get methods to ICacheService --- CacheDrive.ExampleConsoleApp/App.cs | 18 ++-- CacheDrive.Tests/CachingSimpleTypesTests.cs | 96 +++++++++++++++++++-- CacheDrive/Services/ICacheService.cs | 18 ++++ CacheDrive/Services/MemoryCacheService.cs | 53 ++++++++++-- 4 files changed, 165 insertions(+), 20 deletions(-) diff --git a/CacheDrive.ExampleConsoleApp/App.cs b/CacheDrive.ExampleConsoleApp/App.cs index d023843..3daaabc 100644 --- a/CacheDrive.ExampleConsoleApp/App.cs +++ b/CacheDrive.ExampleConsoleApp/App.cs @@ -6,12 +6,20 @@ public class App(ICacheService cacheService) { public async Task Run() { - string cacheKey = "testKey"; + // SetAsync, GetAsync and TryGetValue + string cacheKey1 = "testKey"; + await cacheService.SetAsync(cacheKey1, "test text..."); + var cachedValue1 = await cacheService.GetAsync(cacheKey1); + Console.WriteLine($"GetAsync - cached value: {cachedValue1}"); - await cacheService.SetAsync(cacheKey, "test text..."); + Console.WriteLine(cacheService.TryGetValue(cacheKey1, out string cachedValue2) + ? $"TryGetValue OK - cached value: {cachedValue2}" + : $"TryGetValue NOK - cached value: {cachedValue2}"); - Console.WriteLine(cacheService.TryGetValue(cacheKey, out string cachedValue) - ? $"OK: cached value - {cachedValue}" - : $"NOK: cached value - {cachedValue}"); + // Set, Get + string cacheKey2 = "testKey2"; + cacheService.Set(cacheKey2, 1234567); + int cachedValue3 = cacheService.Get(cacheKey2); + Console.WriteLine($"Get - cached value: {cachedValue3} "); } } \ No newline at end of file diff --git a/CacheDrive.Tests/CachingSimpleTypesTests.cs b/CacheDrive.Tests/CachingSimpleTypesTests.cs index efadbd7..26b1d5c 100644 --- a/CacheDrive.Tests/CachingSimpleTypesTests.cs +++ b/CacheDrive.Tests/CachingSimpleTypesTests.cs @@ -9,7 +9,7 @@ namespace CacheDrive.Tests; public class CachingSimpleTypesTests { [Test] - public async Task SimpleTypesShouldBeProperlyCachedAndRestoredFromTheMemory() + public async Task SimpleTypesShouldBeProperlyCachedAndRestoredFromTheMemoryAsync() { // Arrange ServiceProvider serviceProvider = TestHelper.CreateServiceProvider( @@ -22,19 +22,19 @@ public async Task SimpleTypesShouldBeProperlyCachedAndRestoredFromTheMemory() ICacheService cacheService = serviceProvider.GetRequiredService(); // Act - (string key, int value) intItem = ("int_test", 10); + (string key, int value) intItem = ("int_test_async", 10); await cacheService.SetAsync(intItem.key, intItem.value); - (string key, char value) charItem = ("char_test", 'p'); + (string key, char value) charItem = ("char_test_async", 'p'); await cacheService.SetAsync(charItem.key, charItem.value); - (string key, float value) floatItem = ("float_test", 4.8f); + (string key, float value) floatItem = ("float_test_async", 4.8f); await cacheService.SetAsync(floatItem.key, floatItem.value); - (string key, double value) doubleItem = ("double_test", 6.8d); + (string key, double value) doubleItem = ("double_test_async", 6.8d); await cacheService.SetAsync(doubleItem.key, doubleItem.value); - (string key, bool value) boolItem = ("bool_test", true); + (string key, bool value) boolItem = ("bool_test_async", true); await cacheService.SetAsync(boolItem.key, boolItem.value); int cachedIntItem = await cacheService.GetAsync(intItem.key); @@ -50,9 +50,87 @@ public async Task SimpleTypesShouldBeProperlyCachedAndRestoredFromTheMemory() cachedDoubleItem.Should().Be(doubleItem.value); cachedBoolItem.Should().Be(boolItem.value); } + + [Test] + public void SimpleTypesShouldBeProperlyCachedAndRestoredFromTheMemory() + { + // Arrange + ServiceProvider serviceProvider = TestHelper.CreateServiceProvider( + DateTime.Now, + cacheEnabled: true, + cacheExpirationType: CacheExpirationType.Hours, + cacheExpiration: 2, + cacheType: CacheType.Memory); + + ICacheService cacheService = serviceProvider.GetRequiredService(); + + // Act + (string key, int value) intItem = ("int_test", 10); + cacheService.Set(intItem.key, intItem.value); + + (string key, char value) charItem = ("char_test", 'p'); + cacheService.Set(charItem.key, charItem.value); + + (string key, float value) floatItem = ("float_test", 4.8f); + cacheService.Set(floatItem.key, floatItem.value); + + (string key, double value) doubleItem = ("double_test", 6.8d); + cacheService.Set(doubleItem.key, doubleItem.value); + + (string key, bool value) boolItem = ("bool_test", true); + cacheService.Set(boolItem.key, boolItem.value); + + int cachedIntItem = cacheService.Get(intItem.key); + char cachedCharItem = cacheService.Get(charItem.key); + float cachedFloatItem = cacheService.Get(floatItem.key); + double cachedDoubleItem = cacheService.Get(doubleItem.key); + bool cachedBoolItem = cacheService.Get(boolItem.key); + + // Assert + cachedIntItem.Should().Be(intItem.value); + cachedCharItem.Should().Be(charItem.value); + cachedFloatItem.Should().Be(floatItem.value); + cachedDoubleItem.Should().Be(doubleItem.value); + cachedBoolItem.Should().Be(boolItem.value); + } [Test] - public async Task SimpleTypesShouldBeProperlyDeletedFromTheMemoryCache() + public async Task SimpleTypesShouldBeProperlyDeletedFromTheMemoryCacheAsync() + { + // Arrange + ServiceProvider serviceProvider = TestHelper.CreateServiceProvider( + DateTime.Now, + cacheEnabled: true, + cacheExpirationType: CacheExpirationType.Hours, + cacheExpiration: 2, + cacheType: CacheType.Memory); + + ICacheService cacheService = serviceProvider.GetRequiredService(); + + // Act + + // Add 50 items + for (int i = 0; i < 50; i++) + { + await cacheService.SetAsync($"test_{i}_async", i); + } + + // Delete every second element + for (int i = 0; i < 50; i++) + { + if ((i + 1) % 2 == 0) + { + await cacheService.DeleteAsync($"test_{i}_async"); + } + } + + // // Assert + int countCachedItems = cacheService.CountCachedItems(); + countCachedItems.Should().Be(25); + } + + [Test] + public void SimpleTypesShouldBeProperlyDeletedFromTheMemoryCache() { // Arrange ServiceProvider serviceProvider = TestHelper.CreateServiceProvider( @@ -69,7 +147,7 @@ public async Task SimpleTypesShouldBeProperlyDeletedFromTheMemoryCache() // Add 50 items for (int i = 0; i < 50; i++) { - await cacheService.SetAsync($"test_{i}", i); + cacheService.Set($"test_{i}", i); } // Delete every second element @@ -77,7 +155,7 @@ public async Task SimpleTypesShouldBeProperlyDeletedFromTheMemoryCache() { if ((i + 1) % 2 == 0) { - await cacheService.DeleteAsync($"test_{i}"); + cacheService.Delete($"test_{i}"); } } diff --git a/CacheDrive/Services/ICacheService.cs b/CacheDrive/Services/ICacheService.cs index cb9bcc7..1a5b642 100644 --- a/CacheDrive/Services/ICacheService.cs +++ b/CacheDrive/Services/ICacheService.cs @@ -36,6 +36,15 @@ public interface ICacheService /// /// true if the key was found in the cache, otherwise, false. bool TryGetValue(string key, out T value); + + /// + /// Get the value associated with the specified key from the cache. + /// + /// The key of the value to get. + /// The value contains the object from the cache with the specified + /// key or the default value of T, if the operation failed. + /// + T Get(string key); /// /// Get the value associated with the specified key from the cache. @@ -46,6 +55,15 @@ public interface ICacheService /// Task GetAsync(string key); + /// + /// Adds a value to the cache if the key does not already exist, or updates if the key already exists. + /// + /// The key to be added or whose value should be updated. + /// The value to add or update. + /// After how many seconds a given value will expire in the cache. Optional parameter. + /// By default, the value is taken from the configuration. + void Set(string key, T value, int expirySeconds = 0); + /// /// Adds a value to the cache if the key does not already exist, or updates if the key already exists. /// diff --git a/CacheDrive/Services/MemoryCacheService.cs b/CacheDrive/Services/MemoryCacheService.cs index 901cde6..52fb1da 100644 --- a/CacheDrive/Services/MemoryCacheService.cs +++ b/CacheDrive/Services/MemoryCacheService.cs @@ -84,6 +84,18 @@ private bool TryGetCacheableValue(string key, out T value) where T : ICacheab return true; } + public T Get(string key) + { + CacheableItem cachedItem = GetCacheable>(key); + + if (cachedItem is null) + { + return default; + } + + return cachedItem.Value; + } + public async Task GetAsync(string key) { CacheableItem cachedItem = await GetCacheableAsync>(key); @@ -113,8 +125,36 @@ private async Task GetCacheableAsync(string key) where T : ICacheable return cachedItem.Unwrap(); } + + private T GetCacheable(string key) where T : ICacheable + { + string cacheKey = T.GetCacheKey(key); + + CachedItem cachedItem = Get(cacheKey); + + if (cachedItem is null) + return default; + + if (cachedItem.Expired(_dateService)) + { + Delete(cachedItem); + return default; + } - private void Set(T item, int expirySeconds = 0) where T : ICacheable + return cachedItem.Unwrap(); + } + + public void Set(string key, T value, int expirySeconds = 0) + { + SetCacheableItem(CacheableItem.Create(key, value), expirySeconds); + } + + public Task SetAsync(string key, T value, int expirySeconds = 0) + { + return SetAsync(CacheableItem.Create(key, value), expirySeconds); + } + + private void SetCacheableItem(T item, int expirySeconds = 0) where T : ICacheable { TimeSpan length = GetExpirationLength(expirySeconds); @@ -131,11 +171,6 @@ private void Set(T item, int expirySeconds = 0) where T : ICacheable Set(cachedItem); } - public Task SetAsync(string key, T value, int expirySeconds = 0) - { - return SetAsync(CacheableItem.Create(key, value), expirySeconds); - } - private Task SetAsync(T item, int expirySeconds = 0) where T : ICacheable { CachedItem cached = Get(item); @@ -176,8 +211,14 @@ public Task DeleteAsync(string key) private Task DeleteAsync(string key) => key is null ? Task.FromResult(false) : Task.FromResult(Storage.TryRemove(key, out _)); + private bool Delete(string key) + => key is not null && Storage.TryRemove(key, out _); + private Task DeleteAsync(CachedItem item) => DeleteAsync(item.Key); + + private bool Delete(CachedItem item) + => Delete(item.Key); public int CountCachedItems() => Storage.Count;