diff --git a/src/MammothCache.InMemory/InMemoryCacheDecorator.cs b/src/MammothCache.InMemory/InMemoryCacheDecorator.cs index 85ada67..c2e239e 100644 --- a/src/MammothCache.InMemory/InMemoryCacheDecorator.cs +++ b/src/MammothCache.InMemory/InMemoryCacheDecorator.cs @@ -1,7 +1,11 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Linq; +using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; @@ -75,10 +79,24 @@ public Task SetAsync(string key, T value, TimeSpan? expiry = null) public void Remove(string key, bool exactMatch = true) { - if (!exactMatch) - throw new NotSupportedException("This action is not supported yet"); + if (exactMatch) + { + Cache.Remove(key); + return; + } + + if (Cache is MemoryCache memoryCache) + { + List entries = GetAllKeys(); + if (entries != null) + { + string pattern = "^" + Regex.Escape(key).Replace("\\*", ".*").Replace("\\?", ".") + "$"; + Regex regex = new(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); - Cache.Remove(key); + foreach (string entry in entries.Where(entry => regex.IsMatch(entry))) + memoryCache.Remove(entry); + } + } } public Task RemoveAsync(string key, bool exactMatch = true) @@ -87,6 +105,27 @@ public Task RemoveAsync(string key, bool exactMatch = true) return Task.CompletedTask; } + private List GetAllKeys() + { + FieldInfo coherentState = typeof(MemoryCache).GetField("_coherentState", BindingFlags.NonPublic | BindingFlags.Instance); + object coherentStateValue = coherentState.GetValue(Cache); + PropertyInfo stringEntriesCollection = coherentStateValue.GetType().GetProperty("StringEntriesCollection", BindingFlags.NonPublic | BindingFlags.Instance); + + List keys = []; + + if (stringEntriesCollection.GetValue(coherentStateValue) is ICollection stringEntriesCollectionValue) + { + foreach (object item in stringEntriesCollectionValue) + { + PropertyInfo methodInfo = item.GetType().GetProperty("Key"); + object val = methodInfo.GetValue(item); + keys.Add(val.ToString()); + } + } + + return keys; + } + public Task RemoveAsync(IEnumerable keys) { foreach (string key in keys) diff --git a/src/MammothCache.InMemory/MammothCache.InMemory.csproj b/src/MammothCache.InMemory/MammothCache.InMemory.csproj index 785af65..d17c6aa 100644 --- a/src/MammothCache.InMemory/MammothCache.InMemory.csproj +++ b/src/MammothCache.InMemory/MammothCache.InMemory.csproj @@ -9,7 +9,7 @@ 1.1.0.0 1.1.0.0 - 1.1.0.0-beta.5 + 1.1.1.0-beta.1 logo.png diff --git a/src/MammothCache.Redis/MammothCache.Redis.csproj b/src/MammothCache.Redis/MammothCache.Redis.csproj index 3d8ba6e..78661f6 100644 --- a/src/MammothCache.Redis/MammothCache.Redis.csproj +++ b/src/MammothCache.Redis/MammothCache.Redis.csproj @@ -11,7 +11,7 @@ 1.1.0.0 1.1.0.0 - 1.1.0-beta.5 + 1.1.1.0-beta.1 net8.0 diff --git a/src/MammothCache.sln b/src/MammothCache.sln index accfa13..cc5c6bd 100644 --- a/src/MammothCache.sln +++ b/src/MammothCache.sln @@ -9,6 +9,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MammothCache.InMemory", "Ma EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MammothCache.Redis", "MammothCache.Redis\MammothCache.Redis.csproj", "{38B1816D-29D7-4D5E-A1FB-1772FC0B044E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MammothCache.InMemory.Tests", "..\test\MammothCache.InMemory.Tests\MammothCache.InMemory.Tests.csproj", "{C7A1EE8B-243B-4668-A884-4ACF91449B52}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,10 +31,17 @@ Global {38B1816D-29D7-4D5E-A1FB-1772FC0B044E}.Debug|Any CPU.Build.0 = Debug|Any CPU {38B1816D-29D7-4D5E-A1FB-1772FC0B044E}.Release|Any CPU.ActiveCfg = Release|Any CPU {38B1816D-29D7-4D5E-A1FB-1772FC0B044E}.Release|Any CPU.Build.0 = Release|Any CPU + {C7A1EE8B-243B-4668-A884-4ACF91449B52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7A1EE8B-243B-4668-A884-4ACF91449B52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7A1EE8B-243B-4668-A884-4ACF91449B52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7A1EE8B-243B-4668-A884-4ACF91449B52}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C7A1EE8B-243B-4668-A884-4ACF91449B52} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BBFF732A-AEFB-4861-9BB6-18E1D577498B} EndGlobalSection diff --git a/src/MammothCache/MammothCache.csproj b/src/MammothCache/MammothCache.csproj index 4889c5d..cdb4f04 100644 --- a/src/MammothCache/MammothCache.csproj +++ b/src/MammothCache/MammothCache.csproj @@ -2,7 +2,7 @@ 1.1.0.0 1.1.0.0 - 1.1.0.0 + 1.1.1.0-beta.1 true diff --git a/test/MammothCache.InMemory.Tests/InMemoryCacheDecoratorTests.cs b/test/MammothCache.InMemory.Tests/InMemoryCacheDecoratorTests.cs new file mode 100644 index 0000000..91d2975 --- /dev/null +++ b/test/MammothCache.InMemory.Tests/InMemoryCacheDecoratorTests.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.Caching.Memory; + +namespace MammothCache.InMemory.Tests +{ + [TestClass] + public sealed class InMemoryCacheDecoratorTests + { + [TestMethod] + public void InMemoryCacheDecorator_Remove_Wildcard_ShouldDeleteAll() + { + InMemoryCacheDecorator cache = new(new MemoryCache(new MemoryCacheOptions())); + cache.Set("key1:suffix1", true); + cache.Set("key1:suffix2", true); + cache.Set("prefix1:key1:suffix2", true); + cache.Set("key2", true); + + cache.Remove("key1:*", false); + + Assert.IsTrue(cache.Get("key1:suffix1") == null); + Assert.IsTrue(cache.Get("key1:suffix2") == null); + Assert.IsTrue(cache.Get("key2") == true); + Assert.IsTrue(cache.Get("prefix1:key1:suffix2") == true); + } + } +} diff --git a/test/MammothCache.InMemory.Tests/MSTestSettings.cs b/test/MammothCache.InMemory.Tests/MSTestSettings.cs new file mode 100644 index 0000000..aaf278c --- /dev/null +++ b/test/MammothCache.InMemory.Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/test/MammothCache.InMemory.Tests/MammothCache.InMemory.Tests.csproj b/test/MammothCache.InMemory.Tests/MammothCache.InMemory.Tests.csproj new file mode 100644 index 0000000..fdd664f --- /dev/null +++ b/test/MammothCache.InMemory.Tests/MammothCache.InMemory.Tests.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + latest + enable + enable + + true + + + + + + +