zeroframework/Services/DeviceCenter/ZeroFramework.DeviceCenter.Domain/Specifications/Builder/SpecificationBuilderExtensions.cs
2023-12-05 17:22:48 +08:00

170 lines
6.7 KiB
C#

using System.Linq.Expressions;
using ZeroFramework.DeviceCenter.Domain.Specifications.Exceptions;
namespace ZeroFramework.DeviceCenter.Domain.Specifications.Builder
{
public static class SpecificationBuilderExtensions
{
public static ISpecificationBuilder<T> Where<T>(
this ISpecificationBuilder<T> specificationBuilder,
Expression<Func<T, bool>> criteria)
{
((List<Expression<Func<T, bool>>>)specificationBuilder.Specification.WhereExpressions).Add(criteria);
return specificationBuilder;
}
public static IOrderedSpecificationBuilder<T> OrderBy<T>(
this ISpecificationBuilder<T> specificationBuilder,
Expression<Func<T, object?>> orderExpression)
{
((List<(Expression<Func<T, object?>> OrderExpression, OrderTypeEnum OrderType)>)specificationBuilder.Specification.OrderExpressions)
.Add((orderExpression, OrderTypeEnum.OrderBy));
var orderedSpecificationBuilder = new OrderedSpecificationBuilder<T>(specificationBuilder.Specification);
return orderedSpecificationBuilder;
}
public static IOrderedSpecificationBuilder<T> OrderByDescending<T>(
this ISpecificationBuilder<T> specificationBuilder,
Expression<Func<T, object?>> orderExpression)
{
((List<(Expression<Func<T, object?>> OrderExpression, OrderTypeEnum OrderType)>)specificationBuilder.Specification.OrderExpressions)
.Add((orderExpression, OrderTypeEnum.OrderByDescending));
var orderedSpecificationBuilder = new OrderedSpecificationBuilder<T>(specificationBuilder.Specification);
return orderedSpecificationBuilder;
}
public static IIncludableSpecificationBuilder<T, TProperty> Include<T, TProperty>(
this ISpecificationBuilder<T> specificationBuilder,
Expression<Func<T, TProperty>> includeExpression) where T : class
{
var info = new IncludeExpressionInfo(includeExpression, typeof(T), typeof(TProperty));
((List<IncludeExpressionInfo>)specificationBuilder.Specification.IncludeExpressions).Add(info);
var includeBuilder = new IncludableSpecificationBuilder<T, TProperty>(specificationBuilder.Specification);
return includeBuilder;
}
public static ISpecificationBuilder<T> Include<T>(
this ISpecificationBuilder<T> specificationBuilder,
string includeString) where T : class
{
((List<string>)specificationBuilder.Specification.IncludeStrings).Add(includeString);
return specificationBuilder;
}
public static ISpecificationBuilder<T> Search<T>(
this ISpecificationBuilder<T> specificationBuilder,
Expression<Func<T, string>> selector,
string searchTerm,
int searchGroup = 1) where T : class
{
((List<(Expression<Func<T, string>> Selector, string SearchTerm, int SearchGroup)>)specificationBuilder.Specification.SearchCriterias)
.Add((selector, searchTerm, searchGroup));
return specificationBuilder;
}
public static ISpecificationBuilder<T> Take<T>(
this ISpecificationBuilder<T> specificationBuilder,
int take)
{
if (specificationBuilder.Specification.Take != null) throw new DuplicateTakeException();
specificationBuilder.Specification.Take = take;
return specificationBuilder;
}
public static ISpecificationBuilder<T> Skip<T>(
this ISpecificationBuilder<T> specificationBuilder,
int skip)
{
if (specificationBuilder.Specification.Skip != null) throw new DuplicateSkipException();
specificationBuilder.Specification.Skip = skip;
return specificationBuilder;
}
public static ISpecificationBuilder<T> PostProcessingAction<T>(
this ISpecificationBuilder<T> specificationBuilder,
Func<IEnumerable<T>, IEnumerable<T>> predicate)
{
specificationBuilder.Specification.PostProcessingAction = predicate;
return specificationBuilder;
}
public static ISpecificationBuilder<T, TResult> Select<T, TResult>(
this ISpecificationBuilder<T, TResult> specificationBuilder,
Expression<Func<T, TResult>> selector)
{
specificationBuilder.Specification.Selector = selector;
return specificationBuilder;
}
public static ISpecificationBuilder<T, TResult> PostProcessingAction<T, TResult>(
this ISpecificationBuilder<T, TResult> specificationBuilder,
Func<IEnumerable<TResult>, IEnumerable<TResult>> predicate)
{
specificationBuilder.Specification.PostProcessingAction = predicate;
return specificationBuilder;
}
/// <summary>
/// Must be called after specifying criteria
/// </summary>
/// <param name="specificationName"></param>
/// <param name="args">Any arguments used in defining the specification</param>
public static ICacheSpecificationBuilder<T> EnableCache<T>(
this ISpecificationBuilder<T> specificationBuilder,
string specificationName, params object[] args) where T : class
{
if (string.IsNullOrEmpty(specificationName))
{
throw new ArgumentException($"Required input {specificationName} was null or empty.", specificationName);
}
specificationBuilder.Specification.CacheKey = $"{specificationName}-{string.Join("-", args)}";
specificationBuilder.Specification.CacheEnabled = true;
var cacheBuilder = new CacheSpecificationBuilder<T>(specificationBuilder.Specification);
return cacheBuilder;
}
public static ISpecificationBuilder<T> AsNoTracking<T>(
this ISpecificationBuilder<T> specificationBuilder) where T : class
{
specificationBuilder.Specification.AsNoTracking = true;
return specificationBuilder;
}
public static ISpecificationBuilder<T> AsSplitQuery<T>(
this ISpecificationBuilder<T> specificationBuilder) where T : class
{
specificationBuilder.Specification.AsSplitQuery = true;
return specificationBuilder;
}
public static ISpecificationBuilder<T> AsNoTrackingWithIdentityResolution<T>(
this ISpecificationBuilder<T> specificationBuilder) where T : class
{
specificationBuilder.Specification.AsNoTrackingWithIdentityResolution = true;
return specificationBuilder;
}
}
}