Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3.23.0 #109

Merged
merged 2 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading