Skip to content

Commit

Permalink
v3.23.0 (#109)
Browse files Browse the repository at this point in the history
* v3.23.0
- *Enhancement:* Added `ICacheKey` and updated `RequestCache` accordingly to support, in addition to the existing `IEntityKey`, to enable additional caching key specification.
- *Enhancement:* Added `ItemKeySelector` to `EntityBaseDictionary` to enable automatic inference of the key from an item being added.

* Updated all dependencies.
  • Loading branch information
chullybun authored Jul 26, 2024
1 parent 20fac3b commit 5c1d36d
Show file tree
Hide file tree
Showing 33 changed files with 192 additions and 71 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

Represents the **NuGet** versions.

## v3.23.0
- *Enhancement:* Added `ICacheKey` and updated `RequestCache` accordingly to support, in addition to the existing `IEntityKey`, to enable additional caching key specification.
- *Enhancement:* Added `ItemKeySelector` to `EntityBaseDictionary` to enable automatic inference of the key from an item being added.
- *Fixed:* Updated all dependencies to latest versions.

## v3.22.0
- *Enhancement:* Identifier parsing and `CompositeKey` formatting moved to the `CosmosDbArgs` to enable overriding where required.
- *Enhancement:* Cosmos model constraint softened to allow for `IEntityKey` to support more flexible identifier scenarios.
Expand Down
2 changes: 1 addition & 1 deletion Common.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>3.22.0</Version>
<Version>3.23.0</Version>
<LangVersion>preview</LangVersion>
<Authors>Avanade</Authors>
<Company>Avanade</Company>
Expand Down
2 changes: 1 addition & 1 deletion samples/My.Hr/My.Hr.Api/My.Hr.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.1.1" />
<PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.2.0" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion samples/My.Hr/My.Hr.Database/My.Hr.Database.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="DbEx.SqlServer" Version="2.5.2" />
<PackageReference Include="DbEx.SqlServer" Version="2.5.8" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion samples/My.Hr/My.Hr.UnitTest/My.Hr.UnitTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
12 changes: 6 additions & 6 deletions src/CoreEx.Azure/CoreEx.Azure.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Azure.Data.Tables" Version="12.8.3" />
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.17.5" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.20.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.ServiceBus" Version="5.18.0" />
<PackageReference Include="Azure.Data.Tables" Version="12.9.0" />
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.18.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.21.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.ServiceBus" Version="5.20.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Http" Version="3.2.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="5.16.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="7.2.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="5.16.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="7.3.0" />
</ItemGroup>

<Import Project="..\..\Common.targets" />
Expand Down
4 changes: 2 additions & 2 deletions src/CoreEx.Cosmos/CoreEx.Cosmos.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<Import Project="..\..\Common.targets" />

<ItemGroup>
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.40.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.4.0" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.42.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.4.3" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/CoreEx.Database.MySql/CoreEx.Database.MySql.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<Import Project="..\..\Common.targets" />

<ItemGroup>
<PackageReference Include="MySql.Data" Version="8.4.0" />
<PackageReference Include="MySql.Data" Version="9.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/CoreEx.Dataverse/CoreEx.Dataverse.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<Import Project="..\..\Common.targets" />

<ItemGroup>
<PackageReference Include="Microsoft.PowerPlatform.Dataverse.Client" Version="1.1.22" />
<PackageReference Include="Microsoft.PowerPlatform.Dataverse.Client" Version="1.1.27" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@
<Import Project="..\..\Common.targets" />

<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.31" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.32" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/CoreEx.FluentValidation/CoreEx.FluentValidation.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.9.1" />
<PackageReference Include="FluentValidation" Version="11.9.2" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/CoreEx.Solace/CoreEx.Solace.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SolaceSystems.Solclient.Messaging" Version="10.24.0" />
<PackageReference Include="SolaceSystems.Solclient.Messaging" Version="10.25.0" />
</ItemGroup>

<ItemGroup>
Expand Down
13 changes: 13 additions & 0 deletions src/CoreEx/Abstractions/IUniqueKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/CoreEx

using CoreEx.Entities;
using CoreEx.Caching;

namespace CoreEx.Abstractions
{
/// <summary>
/// Identifies a type as containing a unique key of some sort without enabling the what or how.
/// </summary>
/// <remarks>Should then implement <see cref="IPrimaryKey"/> and/or <see cref="ICacheKey"/>.</remarks>
public interface IUniqueKey { }
}
18 changes: 18 additions & 0 deletions src/CoreEx/Caching/ICacheKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/CoreEx

using CoreEx.Abstractions;
using CoreEx.Entities;

namespace CoreEx.Caching
{
/// <summary>
/// Provides the <see cref="CacheKey"/>.
/// </summary>
public interface ICacheKey : IUniqueKey
{
/// <summary>
/// Gets the cache key.
/// </summary>
public CompositeKey CacheKey { get; }
}
}
21 changes: 21 additions & 0 deletions src/CoreEx/Caching/RequestCache.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/CoreEx

using CoreEx.Abstractions;
using CoreEx.Entities;
using System;
using System.Collections.Concurrent;
Expand All @@ -15,6 +16,26 @@ public class RequestCache : IRequestCache
{
private readonly Lazy<ConcurrentDictionary<(Type, CompositeKey), object?>> _caching = new(true);

/// <summary>
/// Gets the <see cref="CompositeKey"/> from the <paramref name="value"/> based on an order of precedence of <see cref="ICacheKey"/>, then <see cref="IEntityKey"/>, then <see cref="CompositeKey.Empty"/>.
/// </summary>
/// <typeparam name="T">The <paramref name="value"/> <see cref="Type"/>.</typeparam>
/// <param name="value">The value.</param>
/// <returns>The resulting <see cref="CompositeKey"/>.</returns>
/// <remarks>Where the <paramref name="value"/> implements <see cref="ICacheKey"/> then the <see cref="ICacheKey.CacheKey"/> will be returned, then where implements <see cref="IEntityKey"/> then the <see cref="IEntityKey.EntityKey"/>
/// will be returned; otherwise, <see cref="CompositeKey.Empty"/> will be returned.</remarks>
internal static CompositeKey GetKeyFromValue<T>(T value) where T : IUniqueKey
{
if (value is null)
return CompositeKey.Empty;
else if (value is ICacheKey ck)
return ck.CacheKey;
else if (value is IEntityKey ek)
return ek.EntityKey;
else
return CompositeKey.Empty;
}

/// <inheritdoc/>
public bool TryGetValue<T>(CompositeKey key, out T? value)
{
Expand Down
13 changes: 7 additions & 6 deletions src/CoreEx/Caching/RequestCacheExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/CoreEx

using CoreEx.Abstractions;
using CoreEx.Entities;
using System;
using System.Diagnostics.CodeAnalysis;
Expand All @@ -13,14 +14,14 @@ namespace CoreEx.Caching
public static class RequestCacheExtensions
{
/// <summary>
/// Gets the cached value associated with the specified <see cref="Type"/> and <see cref="IEntityKey"/>.
/// Gets the cached value associated with the specified <see cref="Type"/> and <see cref="IUniqueKey"/>.
/// </summary>
/// <typeparam name="T">The value <see cref="Type"/>.</typeparam>
/// <param name="cache">The <see cref="IRequestCache"/>.</param>
/// <param name="key">The key of the value to get.</param>
/// <param name="value">The cached value where found; otherwise, the default value for the <see cref="Type"/>.</param>
/// <returns><c>true</c> where found; otherwise, <c>false</c>.</returns>
public static bool TryGetValue<T>(this IRequestCache cache, IEntityKey key, out T? value) => cache.TryGetValue((key.ThrowIfNull(nameof(key))).EntityKey, out value);
public static bool TryGetValue<T>(this IRequestCache cache, IUniqueKey key, out T? value) => cache.TryGetValue(RequestCache.GetKeyFromValue(key), out value);

/// <summary>
/// Gets the cached value associated with the specified <see cref="Type"/> and <paramref name="key"/> (converted to a <see cref="CompositeKey"/>).
Expand Down Expand Up @@ -73,23 +74,23 @@ public static class RequestCacheExtensions
public static T? SetValue<T>(this IRequestCache cache, object? key, T? value) => cache.SetValue(new CompositeKey(key), value);

/// <summary>
/// Sets (adds or overrides) the cache value for the specified <see cref="IEntityKey"/> <see cref="Type"/> and returns <paramref name="value"/>.
/// Sets (adds or overrides) the cache value for the specified <see cref="IUniqueKey"/> <see cref="Type"/> and returns <paramref name="value"/>.
/// </summary>
/// <typeparam name="T">The value <see cref="Type"/>.</typeparam>
/// <param name="cache">The <see cref="IRequestCache"/>.</param>
/// <param name="value">The value to set.</param>
/// <returns>The <paramref name="value"/>.</returns>
[return: NotNullIfNotNull(nameof(value))]
public static T? SetValue<T>(this IRequestCache cache, T? value) where T : IEntityKey => value is null ? value : cache.SetValue(value.EntityKey, value);
public static T? SetValue<T>(this IRequestCache cache, T? value) where T : IUniqueKey => value is null ? value : cache.SetValue(RequestCache.GetKeyFromValue(value), value);

/// <summary>
/// Removes the cached value associated with the specified <see cref="Type"/> and <see cref="IEntityKey"/>.
/// Removes the cached value associated with the specified <see cref="Type"/> and <see cref="IUniqueKey"/>.
/// </summary>
/// <typeparam name="T">The value <see cref="Type"/>.</typeparam>
/// <param name="cache">The <see cref="IRequestCache"/>.</param>
/// <param name="key">The key of the value to remove.</param>
/// <returns><c>true</c> where found and removed; otherwise, <c>false</c>.</returns>
public static bool Remove<T>(this IRequestCache cache, IEntityKey key) => cache.Remove<T>((key.ThrowIfNull(nameof(key))).EntityKey);
public static bool Remove<T>(this IRequestCache cache, IUniqueKey key) => cache.Remove<T>(RequestCache.GetKeyFromValue(key));

/// <summary>
/// Removes the cached value associated with the specified <see cref="Type"/> and <paramref name="key"/> (converted to a <see cref="CompositeKey"/>).
Expand Down
25 changes: 13 additions & 12 deletions src/CoreEx/Caching/ResultExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/CoreEx

using CoreEx.Abstractions;
using CoreEx.Entities;
using CoreEx.Results;
using System;
Expand Down Expand Up @@ -82,14 +83,14 @@ public static async Task<Result<T>> CacheGetOrAddAsync<T>(this Task<Result> resu
}

/// <summary>
/// Sets (caches) the <see cref="Result{T}.Value"/> into the supplied <paramref name="cache"/> (using the underlying <see cref="IEntityKey.EntityKey"/>).
/// Sets (caches) the <see cref="Result{T}.Value"/> into the supplied <paramref name="cache"/> (using the underlying <see cref="IUniqueKey"/>).
/// </summary>
/// <typeparam name="T">The <see cref="Result{T}"/> <see cref="Type"/> which must be an <see cref="IEntityKey"/>.</typeparam>
/// <typeparam name="T">The <see cref="Result{T}"/> <see cref="Type"/> which must be an <see cref="IUniqueKey"/>.</typeparam>
/// <param name="result">The <see cref="Result{T}"/>.</param>
/// <param name="cache">The <see cref="IRequestCache"/>.</param>
/// <returns>The resulting <see cref="Result{T}"/>.</returns>
/// <remarks>The caching is only performed where the corresponding <paramref name="result"/> has <see cref="IResult.IsSuccess"/>.</remarks>
public static Result<T> CacheSet<T>(this Result<T> result, IRequestCache cache) where T : IEntityKey
public static Result<T> CacheSet<T>(this Result<T> result, IRequestCache cache) where T : IUniqueKey
{
cache.ThrowIfNull(nameof(cache));
return result.Then(r => { cache.SetValue(r); });
Expand All @@ -111,14 +112,14 @@ public static Result<T> CacheSet<T>(this Result<T> result, IRequestCache cache,
}

/// <summary>
/// Sets (caches) the <see cref="Result{T}.Value"/> into the supplied <paramref name="cache"/> (using the underlying <see cref="IEntityKey.EntityKey"/>).
/// Sets (caches) the <see cref="Result{T}.Value"/> into the supplied <paramref name="cache"/> (using the underlying <see cref="IUniqueKey"/>).
/// </summary>
/// <typeparam name="T">The <see cref="Result{T}"/> <see cref="Type"/> which must be an <see cref="IEntityKey"/>.</typeparam>
/// <typeparam name="T">The <see cref="Result{T}"/> <see cref="Type"/> which must be an <see cref="IUniqueKey"/>.</typeparam>
/// <param name="result">The <see cref="Result{T}"/>.</param>
/// <param name="cache">The <see cref="IRequestCache"/>.</param>
/// <returns>The resulting <see cref="Result{T}"/>.</returns>
/// <remarks>The caching is only performed where the corresponding <paramref name="result"/> has <see cref="IResult.IsSuccess"/>.</remarks>
public static Task<Result<T>> CacheSet<T>(this Task<Result<T>> result, IRequestCache cache) where T : IEntityKey
public static Task<Result<T>> CacheSet<T>(this Task<Result<T>> result, IRequestCache cache) where T : IUniqueKey
{
cache.ThrowIfNull(nameof(cache));
return result.Then(r => { cache.SetValue(r); });
Expand Down Expand Up @@ -170,17 +171,17 @@ public static Result CacheRemove<T>(this Result result, IRequestCache cache, obj
}

/// <summary>
/// Removes the cached value associated with the specified <see cref="Type"/> (using the underlying <see cref="IEntityKey.EntityKey"/>).
/// Removes the cached value associated with the specified <see cref="Type"/> (using the underlying <see cref="IUniqueKey"/>).
/// </summary>
/// <typeparam name="T">The cached value <see cref="Type"/>.</typeparam>
/// <param name="result">The <see cref="Result{T}"/>.</param>
/// <param name="cache">The <see cref="IRequestCache"/>.</param>
/// <returns>The resulting <see cref="Result{T}"/>.</returns>
/// <remarks>The caching is only performed where the corresponding <paramref name="result"/> has <see cref="IResult.IsSuccess"/>.</remarks>
public static Result<T> CacheRemove<T>(this Result<T> result, IRequestCache cache) where T : IEntityKey
public static Result<T> CacheRemove<T>(this Result<T> result, IRequestCache cache) where T : IUniqueKey
{
cache.ThrowIfNull(nameof(cache));
return result.Then(r => { cache.Remove<T>(r is null ? CompositeKey.Empty : r.EntityKey); });
return result.Then(r => { cache.Remove<T>(r is null ? CompositeKey.Empty : RequestCache.GetKeyFromValue(r)); });
}

/// <summary>
Expand Down Expand Up @@ -214,17 +215,17 @@ public static Task<Result> CacheRemove<T>(this Task<Result> result, IRequestCach
}

/// <summary>
/// Removes the cached value associated with the specified <see cref="Type"/> (using the underlying <see cref="IEntityKey.EntityKey"/>).
/// Removes the cached value associated with the specified <see cref="Type"/> (using the underlying <see cref="IUniqueKey"/>).
/// </summary>
/// <typeparam name="T">The cached value <see cref="Type"/>.</typeparam>
/// <param name="result">The <see cref="Result{T}"/>.</param>
/// <param name="cache">The <see cref="IRequestCache"/>.</param>
/// <returns>The resulting <see cref="Result{T}"/>.</returns>
/// <remarks>The caching is only performed where the corresponding <paramref name="result"/> has <see cref="IResult.IsSuccess"/>.</remarks>
public static Task<Result<T>> CacheRemove<T>(this Task<Result<T>> result, IRequestCache cache) where T : IEntityKey
public static Task<Result<T>> CacheRemove<T>(this Task<Result<T>> result, IRequestCache cache) where T : IUniqueKey
{
cache.ThrowIfNull(nameof(cache));
return result.Then(r => { cache.Remove<T>(r is null ? CompositeKey.Empty : r.EntityKey); });
return result.Then(r => { cache.Remove<T>(r is null ? CompositeKey.Empty : RequestCache.GetKeyFromValue(r)); });
}
}
}
Loading

0 comments on commit 5c1d36d

Please sign in to comment.