Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,13 @@ public static IExpressiveQueryable<TEntity> IgnoreQueryFilters<TEntity>(
public static IExpressiveQueryable<TEntity> TagWith<TEntity>(
this IExpressiveQueryable<TEntity> source,
string tag)
where TEntity : class
=> EntityFrameworkQueryableExtensions.TagWith(source, tag).AsExpressive();

[EditorBrowsable(EditorBrowsableState.Never)]
public static IExpressiveQueryable<TEntity> TagWithCallSite<TEntity>(
this IExpressiveQueryable<TEntity> source,
[System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
[System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
where TEntity : class
=> EntityFrameworkQueryableExtensions.TagWithCallSite(source, filePath, lineNumber).AsExpressive();

// Include / ThenInclude run at runtime, not intercepted.
Expand Down Expand Up @@ -108,7 +106,6 @@ public static Task<bool> AnyAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -117,7 +114,6 @@ public static Task<bool> AllAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -126,7 +122,6 @@ public static Task<int> CountAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -135,7 +130,6 @@ public static Task<long> LongCountAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -144,7 +138,6 @@ public static Task<TEntity> FirstAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -153,7 +146,6 @@ public static Task<TEntity> FirstAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -162,7 +154,6 @@ public static Task<TEntity> LastAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -171,7 +162,6 @@ public static Task<TEntity> LastAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -180,7 +170,6 @@ public static Task<TEntity> SingleAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -189,96 +178,94 @@ public static Task<TEntity> SingleAsync<TEntity>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, bool> predicate,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<int> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, int> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<int> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, int> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<int?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, int?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<int?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, int?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<long> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, long> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<long> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, long> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<long?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, long?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<long?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, long?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<float> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, float> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<float> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, float> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<float?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, float?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<float?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, float?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<double> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, double> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<double> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, double> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<double?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, double?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<double?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, double?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<decimal> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, decimal> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<decimal> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, decimal> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<decimal?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, decimal?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<decimal?> SumAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, decimal?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<double> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, int> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<double> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, int> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<double?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, int?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<double?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, int?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<double> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, long> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<double> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, long> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<double?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, long?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<double?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, long?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<float> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, float> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<float> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, float> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<float?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, float?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<float?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, float?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<double> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, double> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<double> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, double> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<double?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, double?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<double?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, double?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<decimal> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, decimal> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<decimal> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, decimal> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<decimal?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, decimal?> selector, CancellationToken cancellationToken = default) where TEntity : class => throw new UnreachableException(InterceptedMessage);
public static Task<decimal?> AverageAsync<TEntity>(this IExpressiveQueryable<TEntity> source, Func<TEntity, decimal?> selector, CancellationToken cancellationToken = default) => throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<TResult> MinAsync<TEntity, TResult>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, TResult> selector,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);

[PolyfillTarget(typeof(EntityFrameworkQueryableExtensions))]
Expand All @@ -287,6 +274,5 @@ public static Task<TResult> MaxAsync<TEntity, TResult>(
this IExpressiveQueryable<TEntity> source,
Func<TEntity, TResult> selector,
CancellationToken cancellationToken = default)
where TEntity : class
=> throw new UnreachableException(InterceptedMessage);
}
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,25 @@ public async Task ElementAtOrDefaultAsync_OutOfRange_ReturnsNull()

Assert.IsNull(result);
}

[TestMethod]
public async Task SumAsync_OverValueTypeProjection_WithModernSyntax_Executes()
{
var result = await Context.Orders.AsExpressiveDbSet()
.Select(o => o.Price)
.SumAsync(x => x switch { >= 50 => x, _ => 0.0 });

Assert.AreEqual(245.0, result);
}

[TestMethod]
public async Task FirstAsync_OverValueTypeProjection_Executes()
{
var result = await Context.Orders.AsExpressiveDbSet()
.Select(o => o.Id)
.OrderBy(x => x)
.FirstAsync(x => x > 2);

Assert.AreEqual(3, result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ExpressiveSharp.EntityFrameworkCore.IntegrationTests.Tests;

[TestClass]
public class StubSignatureTests
{
[TestMethod]
public void Stubs_TEntityClassConstraint_MatchesEfCoreTargets()
{
var efNamesWithClassConstraint = typeof(EntityFrameworkQueryableExtensions)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(m => m.IsGenericMethodDefinition)
.ToLookup(m => m.Name, HasClassConstraint);

var overConstrained = typeof(ExpressiveQueryableEfCoreExtensions)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(m => m.IsGenericMethodDefinition && efNamesWithClassConstraint.Contains(m.Name))
.Where(m => HasClassConstraint(m) && !efNamesWithClassConstraint[m.Name].Any(c => c))
.Select(m => m.ToString())
.ToList();

Assert.AreEqual(0, overConstrained.Count);
}

private static bool HasClassConstraint(MethodInfo method) =>
method.GetGenericArguments()[0].GenericParameterAttributes
.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint);
}
Loading