Skip to content
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
17 changes: 17 additions & 0 deletions src/QueryCache.Core/PublicAPI/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
#nullable enable
QueryCache.QueryCacheStore
QueryCache.QueryKey
QueryCache.QueryKey.Equals(QueryCache.QueryKey? other) -> bool
QueryCache.QueryKey.QueryKey(string! text, params System.Collections.Generic.IEnumerable<object?>! values) -> void
const QueryCache.QueryCacheStore.MeterName = "QueryCache" -> string!
override QueryCache.QueryKey.Equals(object? obj) -> bool
override QueryCache.QueryKey.GetHashCode() -> int
override QueryCache.QueryKey.ToString() -> string!
static QueryCache.QueryCacheStore.Capacity.get -> int
static QueryCache.QueryCacheStore.Capacity.set -> void
static QueryCache.QueryCacheStore.GetOrAddAsync<T>(QueryCache.QueryKey! key, System.TimeSpan expiration, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<T>!>! factory, System.Collections.Generic.IReadOnlyCollection<string!>! tags, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.QueryCacheStore.GetOrAddAsync<T>(QueryCache.QueryKey! key, System.TimeSpan expiration, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<T>!>! factory, System.Func<System.Collections.Generic.IReadOnlyCollection<string!>!>! tags, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.QueryCacheStore.GetOrAddAsync<T>(QueryCache.QueryKey! key, System.TimeSpan expiration, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<T>!>! factory, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.QueryCacheStore.HybridCache.get -> Microsoft.Extensions.Caching.Hybrid.HybridCache?
static QueryCache.QueryCacheStore.HybridCache.set -> void
static QueryCache.QueryCacheStore.InvalidateTagsAsync(System.Collections.Generic.IEnumerable<string!>! tags, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
static QueryCache.QueryCacheStore.RemoveAsync<T>(QueryCache.QueryKey! key, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
17 changes: 0 additions & 17 deletions src/QueryCache.Core/PublicAPI/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1 @@
#nullable enable
QueryCache.QueryCacheStore
QueryCache.QueryKey
QueryCache.QueryKey.Equals(QueryCache.QueryKey? other) -> bool
QueryCache.QueryKey.QueryKey(string! text, params System.Collections.Generic.IEnumerable<object?>! values) -> void
const QueryCache.QueryCacheStore.MeterName = "QueryCache" -> string!
override QueryCache.QueryKey.Equals(object? obj) -> bool
override QueryCache.QueryKey.GetHashCode() -> int
override QueryCache.QueryKey.ToString() -> string!
static QueryCache.QueryCacheStore.Capacity.get -> int
static QueryCache.QueryCacheStore.Capacity.set -> void
static QueryCache.QueryCacheStore.GetOrAddAsync<T>(QueryCache.QueryKey! key, System.TimeSpan expiration, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<T>!>! factory, System.Collections.Generic.IReadOnlyCollection<string!>! tags, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.QueryCacheStore.GetOrAddAsync<T>(QueryCache.QueryKey! key, System.TimeSpan expiration, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<T>!>! factory, System.Func<System.Collections.Generic.IReadOnlyCollection<string!>!>! tags, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.QueryCacheStore.GetOrAddAsync<T>(QueryCache.QueryKey! key, System.TimeSpan expiration, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<T>!>! factory, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.QueryCacheStore.HybridCache.get -> Microsoft.Extensions.Caching.Hybrid.HybridCache?
static QueryCache.QueryCacheStore.HybridCache.set -> void
static QueryCache.QueryCacheStore.InvalidateTagsAsync(System.Collections.Generic.IEnumerable<string!>! tags, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
static QueryCache.QueryCacheStore.RemoveAsync<T>(QueryCache.QueryKey! key, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
14 changes: 14 additions & 0 deletions src/QueryCache.Dapper/PublicAPI/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
#nullable enable
QueryCache.Dapper.DapperCacheQuery<T>
QueryCache.Dapper.DapperCacheQuery<T>.DapperCacheQuery(System.Data.Common.DbConnection! connection, Dapper.CommandDefinition command) -> void
QueryCache.Dapper.DapperCacheQuery<T>.Equals(QueryCache.Dapper.DapperCacheQuery<T>? other) -> bool
QueryCache.Dapper.DapperCacheQuery<T>.ExecuteScalarAsync(System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T?>
QueryCache.Dapper.DapperCacheQuery<T>.InvalidateCacheAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
QueryCache.Dapper.DapperCacheQuery<T>.QueryAsync(System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.IReadOnlyList<T>!>
QueryCache.Dapper.DapperCacheQuery<T>.QueryFirstOrDefaultAsync(System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T?>
QueryCache.Dapper.DapperCacheQueryExtensions
override QueryCache.Dapper.DapperCacheQuery<T>.Equals(object? obj) -> bool
override QueryCache.Dapper.DapperCacheQuery<T>.GetHashCode() -> int
override QueryCache.Dapper.DapperCacheQuery<T>.ToString() -> string!
static QueryCache.Dapper.DapperCacheQuery<T>.operator !=(QueryCache.Dapper.DapperCacheQuery<T>? left, QueryCache.Dapper.DapperCacheQuery<T>? right) -> bool
static QueryCache.Dapper.DapperCacheQuery<T>.operator ==(QueryCache.Dapper.DapperCacheQuery<T>? left, QueryCache.Dapper.DapperCacheQuery<T>? right) -> bool
static QueryCache.Dapper.DapperCacheQueryExtensions.ToCacheQuery<T>(this System.Data.Common.DbConnection! connection, Dapper.CommandDefinition command) -> QueryCache.Dapper.DapperCacheQuery<T>!
14 changes: 0 additions & 14 deletions src/QueryCache.Dapper/PublicAPI/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1 @@
#nullable enable
QueryCache.Dapper.DapperCacheQuery<T>
QueryCache.Dapper.DapperCacheQuery<T>.DapperCacheQuery(System.Data.Common.DbConnection! connection, Dapper.CommandDefinition command) -> void
QueryCache.Dapper.DapperCacheQuery<T>.Equals(QueryCache.Dapper.DapperCacheQuery<T>? other) -> bool
QueryCache.Dapper.DapperCacheQuery<T>.ExecuteScalarAsync(System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T?>
QueryCache.Dapper.DapperCacheQuery<T>.InvalidateCacheAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
QueryCache.Dapper.DapperCacheQuery<T>.QueryAsync(System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.IReadOnlyList<T>!>
QueryCache.Dapper.DapperCacheQuery<T>.QueryFirstOrDefaultAsync(System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T?>
QueryCache.Dapper.DapperCacheQueryExtensions
override QueryCache.Dapper.DapperCacheQuery<T>.Equals(object? obj) -> bool
override QueryCache.Dapper.DapperCacheQuery<T>.GetHashCode() -> int
override QueryCache.Dapper.DapperCacheQuery<T>.ToString() -> string!
static QueryCache.Dapper.DapperCacheQuery<T>.operator !=(QueryCache.Dapper.DapperCacheQuery<T>? left, QueryCache.Dapper.DapperCacheQuery<T>? right) -> bool
static QueryCache.Dapper.DapperCacheQuery<T>.operator ==(QueryCache.Dapper.DapperCacheQuery<T>? left, QueryCache.Dapper.DapperCacheQuery<T>? right) -> bool
static QueryCache.Dapper.DapperCacheQueryExtensions.ToCacheQuery<T>(this System.Data.Common.DbConnection! connection, Dapper.CommandDefinition command) -> QueryCache.Dapper.DapperCacheQuery<T>!
16 changes: 16 additions & 0 deletions src/QueryCache.EFCore/PublicAPI/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
#nullable enable
QueryCache.EFCore.QueryCacheInvalidation
QueryCache.EFCore.QueryableCacheExtensions
static QueryCache.EFCore.QueryCacheInvalidation.UseQueryCacheInvalidation(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder! builder) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder!
static QueryCache.EFCore.QueryCacheInvalidation.UseQueryCacheInvalidation<TContext>(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder<TContext!>! builder) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder<TContext!>!
static QueryCache.EFCore.QueryableCacheExtensions.AnyCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<bool>
static QueryCache.EFCore.QueryableCacheExtensions.CountCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<int>
static QueryCache.EFCore.QueryableCacheExtensions.FirstCachedAsync<T>(this System.Linq.IQueryable<T!>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T!>
static QueryCache.EFCore.QueryableCacheExtensions.FirstOrDefaultCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T?>
static QueryCache.EFCore.QueryableCacheExtensions.InvalidateCacheAsync<T>(this System.Linq.IQueryable<T>! query, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
static QueryCache.EFCore.QueryableCacheExtensions.MaxCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.EFCore.QueryableCacheExtensions.SingleOrDefaultCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T?>
static QueryCache.EFCore.QueryableCacheExtensions.SumCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.EFCore.QueryableCacheExtensions.ToDictionaryCachedAsync<T, TKey, TValue>(this System.Linq.IQueryable<T>! query, System.Func<T, TKey>! keySelector, System.Func<T, TValue>! valueSelector, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.Dictionary<TKey, TValue>!>
static QueryCache.EFCore.QueryableCacheExtensions.ToDictionaryCachedAsync<T, TKey>(this System.Linq.IQueryable<T>! query, System.Func<T, TKey>! keySelector, System.Collections.Generic.IEqualityComparer<TKey>! comparer, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.Dictionary<TKey, T>!>
static QueryCache.EFCore.QueryableCacheExtensions.ToDictionaryCachedAsync<T, TKey>(this System.Linq.IQueryable<T>! query, System.Func<T, TKey>! keySelector, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.Dictionary<TKey, T>!>
static QueryCache.EFCore.QueryableCacheExtensions.ToListCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.IReadOnlyList<T>!>
16 changes: 0 additions & 16 deletions src/QueryCache.EFCore/PublicAPI/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1 @@
#nullable enable
QueryCache.EFCore.QueryCacheInvalidation
QueryCache.EFCore.QueryableCacheExtensions
static QueryCache.EFCore.QueryCacheInvalidation.UseQueryCacheInvalidation(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder! builder) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder!
static QueryCache.EFCore.QueryCacheInvalidation.UseQueryCacheInvalidation<TContext>(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder<TContext!>! builder) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder<TContext!>!
static QueryCache.EFCore.QueryableCacheExtensions.AnyCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<bool>
static QueryCache.EFCore.QueryableCacheExtensions.CountCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<int>
static QueryCache.EFCore.QueryableCacheExtensions.FirstCachedAsync<T>(this System.Linq.IQueryable<T!>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T!>
static QueryCache.EFCore.QueryableCacheExtensions.FirstOrDefaultCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T?>
static QueryCache.EFCore.QueryableCacheExtensions.InvalidateCacheAsync<T>(this System.Linq.IQueryable<T>! query, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
static QueryCache.EFCore.QueryableCacheExtensions.MaxCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.EFCore.QueryableCacheExtensions.SingleOrDefaultCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T?>
static QueryCache.EFCore.QueryableCacheExtensions.SumCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<T>
static QueryCache.EFCore.QueryableCacheExtensions.ToDictionaryCachedAsync<T, TKey, TValue>(this System.Linq.IQueryable<T>! query, System.Func<T, TKey>! keySelector, System.Func<T, TValue>! valueSelector, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.Dictionary<TKey, TValue>!>
static QueryCache.EFCore.QueryableCacheExtensions.ToDictionaryCachedAsync<T, TKey>(this System.Linq.IQueryable<T>! query, System.Func<T, TKey>! keySelector, System.Collections.Generic.IEqualityComparer<TKey>! comparer, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.Dictionary<TKey, T>!>
static QueryCache.EFCore.QueryableCacheExtensions.ToDictionaryCachedAsync<T, TKey>(this System.Linq.IQueryable<T>! query, System.Func<T, TKey>! keySelector, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.Dictionary<TKey, T>!>
static QueryCache.EFCore.QueryableCacheExtensions.ToListCachedAsync<T>(this System.Linq.IQueryable<T>! query, System.TimeSpan expiration, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.IReadOnlyList<T>!>
19 changes: 0 additions & 19 deletions src/QueryCache.EFCore/QueryCacheInvalidation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,6 @@ private static ValueTask Saved(DbContext? context)
return QueryCacheStore.InvalidateTagsAsync(tags, CancellationToken.None);
}

private static void Failed(DbContext? context)
{
if (context is not null && States.TryGetValue(context, out var state))
{
state.Saving = [];
}
}

private static ValueTask Ended(DbContext? context, bool committed)
{
if (context is null || !States.TryGetValue(context, out var state))
Expand Down Expand Up @@ -125,17 +117,6 @@ public override async ValueTask<int> SavedChangesAsync(SaveChangesCompletedEvent
await Saved(eventData.Context).ConfigureAwait(false);
return result;
}

public override void SaveChangesFailed(DbContextErrorEventData eventData)
{
Failed(eventData.Context);
}

public override Task SaveChangesFailedAsync(DbContextErrorEventData eventData, CancellationToken cancellationToken = default)
{
Failed(eventData.Context);
return Task.CompletedTask;
}
}

private sealed class TransactionInvalidator : DbTransactionInterceptor
Expand Down
22 changes: 22 additions & 0 deletions tests/QueryCache.IntegrationTests/CacheIntegrationTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Data.Common;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Transactions;
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
Expand Down Expand Up @@ -244,6 +245,27 @@ public async Task Commit_invalidates_what_other_connections_cached_while_the_tra

Assert.Equal(2, (await reader.Items.ToListCachedAsync(Minute, CancellationToken.None)).Count);
}

[Fact]
public async Task Completing_a_TransactionScope_invalidates_what_other_connections_cached_meanwhile()
{
var connectionString = await NewDatabaseAsync(new Item { Id = 1 });
await using var writer = NewDb(connectionString);
await using var reader = NewDb(connectionString);

using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
writer.Items.Add(new Item { Id = 2 });
await writer.SaveChangesAsync();
using (new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled))
{
Assert.Single(await reader.Items.ToListCachedAsync(Minute, CancellationToken.None));
}
scope.Complete();
}

Assert.Equal(2, (await reader.Items.ToListCachedAsync(Minute, CancellationToken.None)).Count);
}
}

public sealed class SqlServerTests(SqlServerServer server) : CacheIntegrationTests<SqlServerServer>(server);
Expand Down
29 changes: 29 additions & 0 deletions tests/QueryCache.Tests/DapperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,35 @@ public void DynamicParameters_with_different_template_values_are_keyed_different
Assert.NotEqual(Key(new DynamicParameters(new { Id = 1 })), Key(new DynamicParameters(new { Id = 2 })));
}

[Fact]
public void DynamicParameters_added_by_name_are_keyed_by_value()
{
static DynamicParameters Params(int id)
{
var parameters = new DynamicParameters();
parameters.Add("Id", id);
return parameters;
}

Assert.Equal(Key(Params(1)), Key(Params(1)));
Assert.NotEqual(Key(Params(1)), Key(Params(2)));
}

[Fact]
public async Task Queries_are_equal_by_connection_sql_and_parameter_values()
{
await using var connection = await NewConnection("create table t(id int);");
await using var other = await NewConnection("create table t(id int);");
var query = Query(connection, new CommandDefinition("select id from t where id = @Id", new { Id = 1 }));

Assert.Equal(query, (object)Query(connection, new CommandDefinition("select id from t where id = @Id", new { Id = 1 })));
Assert.Equal(query.GetHashCode(), Query(connection, new CommandDefinition("select id from t where id = @Id", new { Id = 1 })).GetHashCode());
Assert.True(query != Query(connection, new CommandDefinition("select id from t where id = @Id", new { Id = 2 })));
Assert.True(query != Query(other, new CommandDefinition("select id from t where id = @Id", new { Id = 1 })));
Assert.False(query.Equals((object?)null));
Assert.Contains("select id from t where id = @Id", query.ToString(), StringComparison.Ordinal);
}

[Fact]
public void Dictionary_parameters_are_keyed_by_value()
{
Expand Down
Loading
Loading