Skip to content

Commit

Permalink
Consolidate method and parameter names in evaluator APIs. (#19)
Browse files Browse the repository at this point in the history
* Fixed minor incosistencies in tests.

* Consolidated method and parameter names in evaluator APIs.
  • Loading branch information
fiseni authored Sep 28, 2024
1 parent f75dc2d commit bfbc523
Show file tree
Hide file tree
Showing 38 changed files with 206 additions and 233 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ public class AsNoTrackingEvaluator : IEvaluator
private AsNoTrackingEvaluator() { }
public static AsNoTrackingEvaluator Instance = new();

public IQueryable<T> GetQuery<T>(IQueryable<T> query, Specification<T> specification) where T : class
public IQueryable<T> Evaluate<T>(IQueryable<T> source, Specification<T> specification) where T : class
{
if (specification.AsNoTracking)
{
query = query.AsNoTracking();
source = source.AsNoTracking();
}

return query;
return source;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ public class AsNoTrackingWithIdentityResolutionEvaluator : IEvaluator
private AsNoTrackingWithIdentityResolutionEvaluator() { }
public static AsNoTrackingWithIdentityResolutionEvaluator Instance = new();

public IQueryable<T> GetQuery<T>(IQueryable<T> query, Specification<T> specification) where T : class
public IQueryable<T> Evaluate<T>(IQueryable<T> source, Specification<T> specification) where T : class
{
if (specification.AsNoTrackingWithIdentityResolution)
{
query = query.AsNoTrackingWithIdentityResolution();
source = source.AsNoTrackingWithIdentityResolution();
}

return query;
return source;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ public class AsSplitQueryEvaluator : IEvaluator
private AsSplitQueryEvaluator() { }
public static AsSplitQueryEvaluator Instance = new();

public IQueryable<T> GetQuery<T>(IQueryable<T> query, Specification<T> specification) where T : class
public IQueryable<T> Evaluate<T>(IQueryable<T> source, Specification<T> specification) where T : class
{
if (specification.AsSplitQuery)
{
query = query.AsSplitQuery();
source = source.AsSplitQuery();
}

return query;
return source;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ public class IgnoreQueryFiltersEvaluator : IEvaluator
private IgnoreQueryFiltersEvaluator() { }
public static IgnoreQueryFiltersEvaluator Instance = new();

public IQueryable<T> GetQuery<T>(IQueryable<T> query, Specification<T> specification) where T : class
public IQueryable<T> Evaluate<T>(IQueryable<T> source, Specification<T> specification) where T : class
{
if (specification.IgnoreQueryFilters)
{
query = query.IgnoreQueryFilters();
source = source.IgnoreQueryFilters();
}

return query;
return source;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,49 +38,51 @@ private static readonly MethodInfo _thenIncludeAfterEnumerableMethodInfo
private IncludeEvaluator() { }
public static IncludeEvaluator Instance = new();

public IQueryable<T> GetQuery<T>(IQueryable<T> query, Specification<T> specification) where T : class
public IQueryable<T> Evaluate<T>(IQueryable<T> source, Specification<T> specification) where T : class
{
foreach (var includeString in specification.IncludeStrings)
{
query = query.Include(includeString);
source = source.Include(includeString);
}

foreach (var includeExpression in specification.IncludeExpressions)
{
if (includeExpression.Type == IncludeTypeEnum.Include)
{
query = BuildInclude<T>(query, includeExpression);
source = BuildInclude<T>(source, includeExpression);
}
else if (includeExpression.Type == IncludeTypeEnum.ThenInclude)
{
query = BuildThenInclude<T>(query, includeExpression);
source = BuildThenInclude<T>(source, includeExpression);
}
}

return query;
return source;
}

private static IQueryable<T> BuildInclude<T>(IQueryable query, IncludeExpression includeExpression)
private static IQueryable<T> BuildInclude<T>(IQueryable source, IncludeExpression includeExpression)
{
ArgumentNullException.ThrowIfNull(includeExpression);

var result = _includeMethodInfo.MakeGenericMethod(includeExpression.EntityType, includeExpression.PropertyType).Invoke(null, [query, includeExpression.LambdaExpression]);
var result = _includeMethodInfo
.MakeGenericMethod(includeExpression.EntityType, includeExpression.PropertyType)
.Invoke(null, [source, includeExpression.LambdaExpression]);

Debug.Assert(result is not null);

return (IQueryable<T>)result;
}

private static IQueryable<T> BuildThenInclude<T>(IQueryable query, IncludeExpression includeExpression)
private static IQueryable<T> BuildThenInclude<T>(IQueryable source, IncludeExpression includeExpression)
{
ArgumentNullException.ThrowIfNull(includeExpression);
ArgumentNullException.ThrowIfNull(includeExpression.PreviousPropertyType);

var result = (IsGenericEnumerable(includeExpression.PreviousPropertyType, out var previousPropertyType)
? _thenIncludeAfterEnumerableMethodInfo
: _thenIncludeAfterReferenceMethodInfo)
.MakeGenericMethod(includeExpression.EntityType, previousPropertyType, includeExpression.PropertyType)
.Invoke(null, [query, includeExpression.LambdaExpression,]);
.MakeGenericMethod(includeExpression.EntityType, previousPropertyType, includeExpression.PropertyType)
.Invoke(null, [source, includeExpression.LambdaExpression,]);

Debug.Assert(result is not null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ public class LikeEvaluator : IEvaluator
private LikeEvaluator() { }
public static LikeEvaluator Instance = new();

public IQueryable<T> GetQuery<T>(IQueryable<T> query, Specification<T> specification) where T : class
public IQueryable<T> Evaluate<T>(IQueryable<T> source, Specification<T> specification) where T : class
{
foreach (var likeGroup in specification.LikeExpressions.GroupBy(x => x.Group))
{
query = query.Like(likeGroup);
source = source.Like(likeGroup);
}

return query;
return source;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,40 @@ public SpecificationEvaluator(IEnumerable<IEvaluator> evaluators)
Evaluators = evaluators.ToList();
}

public virtual IQueryable<TResult> GetQuery<T, TResult>(
IQueryable<T> query,
public virtual IQueryable<TResult> Evaluate<T, TResult>(
IQueryable<T> source,
Specification<T, TResult> specification,
bool ignorePaging = false) where T : class
{
ArgumentNullException.ThrowIfNull(specification);
if (specification.Selector is null && specification.SelectorMany is null) throw new SelectorNotFoundException();
if (specification.Selector is not null && specification.SelectorMany is not null) throw new ConcurrentSelectorsException();

query = GetQuery(query, (Specification<T>)specification, true);
source = Evaluate(source, (Specification<T>)specification, true);

var resultQuery = specification.Selector is not null
? query.Select(specification.Selector)
: query.SelectMany(specification.SelectorMany!);
? source.Select(specification.Selector)
: source.SelectMany(specification.SelectorMany!);

return ignorePaging
? resultQuery
: resultQuery.ApplyPaging(specification);
}

public virtual IQueryable<T> GetQuery<T>(
IQueryable<T> query,
public virtual IQueryable<T> Evaluate<T>(
IQueryable<T> source,
Specification<T> specification,
bool ignorePaging = false) where T : class
{
ArgumentNullException.ThrowIfNull(specification);

foreach (var evaluator in Evaluators)
{
query = evaluator.GetQuery(query, specification);
source = evaluator.Evaluate(source, specification);
}

return ignorePaging
? query
: query.ApplyPaging(specification);
? source
: source.ApplyPaging(specification);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static IQueryable<TSource> WithSpecification<TSource>(
where TSource : class
{
evaluator ??= SpecificationEvaluator.Default;
return evaluator.GetQuery(source, specification);
return evaluator.Evaluate(source, specification);
}

public static IQueryable<TResult> WithSpecification<TSource, TResult>(
Expand All @@ -19,7 +19,7 @@ public static IQueryable<TResult> WithSpecification<TSource, TResult>(
where TSource : class
{
evaluator ??= SpecificationEvaluator.Default;
return evaluator.GetQuery(source, specification);
return evaluator.Evaluate(source, specification);
}

public static Task<PagedResult<TSource>> ToPagedResultAsync<TSource>(
Expand All @@ -39,9 +39,9 @@ public static async Task<PagedResult<TSource>> ToPagedResultAsync<TSource>(
var count = await source.CountAsync(cancellationToken);
var pagination = new Pagination(paginationSettings, count, filter);

var query = source.ApplyPaging(pagination);
source = source.ApplyPaging(pagination);

var data = await query.ToListAsync(cancellationToken);
var data = await source.ToListAsync(cancellationToken);

return new PagedResult<TSource>(data, pagination);
}
Expand Down
44 changes: 22 additions & 22 deletions src/QuerySpecification.EntityFrameworkCore/RepositoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ protected RepositoryBase(DbContext dbContext, SpecificationEvaluator specificati
_paginationSettings = paginationSettings;
}

protected abstract IQueryable<TResult> Map<TResult>(IQueryable<T> queryable);
protected abstract IQueryable<TResult> Map<TResult>(IQueryable<T> source);

public virtual async Task<T> AddAsync(T entity, CancellationToken cancellationToken = default)
{
Expand Down Expand Up @@ -72,74 +72,74 @@ public virtual async Task<int> SaveChangesAsync(CancellationToken cancellationTo
}
public virtual async Task<T> FirstAsync(Specification<T> specification, CancellationToken cancellationToken = default)
{
var result = await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
var result = await GenerateQuery(specification).FirstOrDefaultAsync(cancellationToken);
return result ?? throw new EntityNotFoundException(typeof(T).Name);
}
public virtual async Task<TResult> FirstAsync<TResult>(Specification<T, TResult> specification, CancellationToken cancellationToken = default)
{
var result = await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
var result = await GenerateQuery(specification).FirstOrDefaultAsync(cancellationToken);
return result ?? throw new EntityNotFoundException(typeof(T).Name);
}
public virtual async Task<T?> FirstOrDefaultAsync(Specification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
return await GenerateQuery(specification).FirstOrDefaultAsync(cancellationToken);
}
public virtual async Task<TResult?> FirstOrDefaultAsync<TResult>(Specification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).FirstOrDefaultAsync(cancellationToken);
return await GenerateQuery(specification).FirstOrDefaultAsync(cancellationToken);
}
public virtual async Task<T?> SingleOrDefaultAsync(Specification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).SingleOrDefaultAsync(cancellationToken);
return await GenerateQuery(specification).SingleOrDefaultAsync(cancellationToken);
}
public virtual async Task<TResult?> SingleOrDefaultAsync<TResult>(Specification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).SingleOrDefaultAsync(cancellationToken);
return await GenerateQuery(specification).SingleOrDefaultAsync(cancellationToken);
}
public virtual async Task<List<T>> ListAsync(CancellationToken cancellationToken = default)
{
return await _dbContext.Set<T>().ToListAsync(cancellationToken);
}
public virtual async Task<List<T>> ListAsync(Specification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).ToListAsync(cancellationToken);
return await GenerateQuery(specification).ToListAsync(cancellationToken);
}
public virtual async Task<List<TResult>> ListAsync<TResult>(Specification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).ToListAsync(cancellationToken);
return await GenerateQuery(specification).ToListAsync(cancellationToken);
}
public virtual async Task<int> CountAsync(CancellationToken cancellationToken = default)
{
return await _dbContext.Set<T>().CountAsync(cancellationToken);
}
public virtual async Task<int> CountAsync(Specification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification, true).CountAsync(cancellationToken);
return await GenerateQuery(specification, true).CountAsync(cancellationToken);
}
public virtual async Task<int> CountAsync<TResult>(Specification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification, true).CountAsync(cancellationToken);
return await GenerateQuery(specification, true).CountAsync(cancellationToken);
}
public virtual async Task<bool> AnyAsync(CancellationToken cancellationToken = default)
{
return await _dbContext.Set<T>().AnyAsync(cancellationToken);
}
public virtual async Task<bool> AnyAsync(Specification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification, true).AnyAsync(cancellationToken);
return await GenerateQuery(specification, true).AnyAsync(cancellationToken);
}
public virtual async Task<bool> AnyAsync<TResult>(Specification<T, TResult> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification, true).AnyAsync(cancellationToken);
return await GenerateQuery(specification, true).AnyAsync(cancellationToken);
}

public virtual IAsyncEnumerable<T> AsAsyncEnumerable(Specification<T> specification)
{
return ApplySpecification(specification).AsAsyncEnumerable();
return GenerateQuery(specification).AsAsyncEnumerable();
}
public virtual async Task<TResult> ProjectToFirstAsync<TResult>(Specification<T> specification, CancellationToken cancellationToken = default)
{
var query = ApplySpecification(specification).AsNoTracking();
var query = GenerateQuery(specification).AsNoTracking();

var projectedQuery = Map<TResult>(query);

Expand All @@ -149,23 +149,23 @@ public virtual async Task<TResult> ProjectToFirstAsync<TResult>(Specification<T>
}
public virtual async Task<TResult?> ProjectToFirstOrDefaultAsync<TResult>(Specification<T> specification, CancellationToken cancellationToken = default)
{
var query = ApplySpecification(specification).AsNoTracking();
var query = GenerateQuery(specification).AsNoTracking();

var projectedQuery = Map<TResult>(query);

return await projectedQuery.FirstOrDefaultAsync(cancellationToken);
}
public virtual async Task<List<TResult>> ProjectToListAsync<TResult>(Specification<T> specification, CancellationToken cancellationToken = default)
{
var query = ApplySpecification(specification).AsNoTracking();
var query = GenerateQuery(specification).AsNoTracking();

var projectedQuery = Map<TResult>(query);

return await projectedQuery.ToListAsync(cancellationToken);
}
public virtual async Task<PagedResult<TResult>> ProjectToListAsync<TResult>(Specification<T> specification, PagingFilter filter, CancellationToken cancellationToken = default)
{
var query = ApplySpecification(specification, true).AsNoTracking();
var query = GenerateQuery(specification, true).AsNoTracking();
var projectedQuery = Map<TResult>(query);

var count = await projectedQuery.CountAsync(cancellationToken);
Expand All @@ -177,14 +177,14 @@ public virtual async Task<PagedResult<TResult>> ProjectToListAsync<TResult>(Spec
return new PagedResult<TResult>(data, pagination);
}

protected virtual IQueryable<T> ApplySpecification(Specification<T> specification, bool ignorePaging = false)
protected virtual IQueryable<T> GenerateQuery(Specification<T> specification, bool ignorePaging = false)
{
var query = _evaluator.GetQuery(_dbContext.Set<T>(), specification, ignorePaging);
var query = _evaluator.Evaluate(_dbContext.Set<T>(), specification, ignorePaging);
return query;
}
protected virtual IQueryable<TResult> ApplySpecification<TResult>(Specification<T, TResult> specification, bool ignorePaging = false)
protected virtual IQueryable<TResult> GenerateQuery<TResult>(Specification<T, TResult> specification, bool ignorePaging = false)
{
var query = _evaluator.GetQuery(_dbContext.Set<T>(), specification, ignorePaging);
var query = _evaluator.Evaluate(_dbContext.Set<T>(), specification, ignorePaging);
return query;
}
}
2 changes: 1 addition & 1 deletion src/QuerySpecification/Evaluators/IEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public interface IEvaluator
{
IQueryable<T> GetQuery<T>(IQueryable<T> query, Specification<T> specification) where T : class;
IQueryable<T> Evaluate<T>(IQueryable<T> source, Specification<T> specification) where T : class;
}
2 changes: 1 addition & 1 deletion src/QuerySpecification/Evaluators/IInMemoryEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public interface IInMemoryEvaluator
{
IEnumerable<T> Evaluate<T>(IEnumerable<T> query, Specification<T> specification);
IEnumerable<T> Evaluate<T>(IEnumerable<T> source, Specification<T> specification);
}
Loading

0 comments on commit bfbc523

Please sign in to comment.