diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 7015fadba..0fdf3de1b 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -9,8 +9,8 @@ true - - + + diff --git a/src/api/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs b/src/api/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs index 643bcb675..4b14bd2bf 100644 --- a/src/api/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs +++ b/src/api/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs @@ -3,13 +3,13 @@ namespace FSH.Framework.Core.Specifications; -public class EntitiesByBaseFilterSpec : Specification +public class EntitiesByBaseFilterSpec : Specification where T : class { public EntitiesByBaseFilterSpec(BaseFilter filter) => Query.SearchBy(filter); } -public class EntitiesByBaseFilterSpec : Specification +public class EntitiesByBaseFilterSpec : Specification where T : class { public EntitiesByBaseFilterSpec(BaseFilter filter) => Query.SearchBy(filter); diff --git a/src/api/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs b/src/api/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs index abdf49eeb..a2ff6ba52 100644 --- a/src/api/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs +++ b/src/api/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs @@ -2,14 +2,14 @@ namespace FSH.Framework.Core.Specifications; -public class EntitiesByPaginationFilterSpec : EntitiesByBaseFilterSpec +public class EntitiesByPaginationFilterSpec : EntitiesByBaseFilterSpec where T : class { public EntitiesByPaginationFilterSpec(PaginationFilter filter) : base(filter) => Query.PaginateBy(filter); } -public class EntitiesByPaginationFilterSpec : EntitiesByBaseFilterSpec +public class EntitiesByPaginationFilterSpec : EntitiesByBaseFilterSpec where T : class { public EntitiesByPaginationFilterSpec(PaginationFilter filter) : base(filter) => diff --git a/src/api/framework/Core/Specifications/SpecificationBuilderExtensions.cs b/src/api/framework/Core/Specifications/SpecificationBuilderExtensions.cs index 81b352056..177449419 100644 --- a/src/api/framework/Core/Specifications/SpecificationBuilderExtensions.cs +++ b/src/api/framework/Core/Specifications/SpecificationBuilderExtensions.cs @@ -7,10 +7,9 @@ namespace FSH.Framework.Core.Specifications; -// See https://github.com/ardalis/Specification/issues/53 public static class SpecificationBuilderExtensions { - public static ISpecificationBuilder SearchBy(this ISpecificationBuilder query, BaseFilter filter) => + public static ISpecificationBuilder SearchBy(this ISpecificationBuilder query, BaseFilter filter) where T : class => query .SearchByKeyword(filter.Keyword) .AdvancedSearch(filter.AdvancedSearch) @@ -38,20 +37,20 @@ public static ISpecificationBuilder PaginateBy(this ISpecificationBuilder< .OrderBy(filter.OrderBy); } - public static IOrderedSpecificationBuilder SearchByKeyword( + public static ISpecificationBuilder SearchByKeyword( this ISpecificationBuilder specificationBuilder, - string? keyword) => + string? keyword) where T : class => specificationBuilder.AdvancedSearch(new Search { Keyword = keyword }); - public static IOrderedSpecificationBuilder AdvancedSearch( + public static ISpecificationBuilder AdvancedSearch( this ISpecificationBuilder specificationBuilder, - Search? search) + Search? search) where T : class { if (!string.IsNullOrEmpty(search?.Keyword)) { if (search.Fields?.Any() is true) { - // search seleted fields (can contain deeper nested fields) + // search selected fields (can contain deeper nested fields) foreach (string field in search.Fields) { var paramExpr = Expression.Parameter(typeof(T)); @@ -76,7 +75,7 @@ public static IOrderedSpecificationBuilder AdvancedSearch( } } - return new OrderedSpecificationBuilder(specificationBuilder.Specification); + return specificationBuilder; } private static void AddSearchPropertyByKeyword( @@ -84,7 +83,7 @@ private static void AddSearchPropertyByKeyword( Expression propertyExpr, ParameterExpression paramExpr, string keyword, - string operatorSearch = FilterOperator.CONTAINS) + string operatorSearch = FilterOperator.CONTAINS) where T : class { if (propertyExpr is not MemberExpression memberExpr || memberExpr.Member is not PropertyInfo property) { @@ -112,13 +111,12 @@ private static void AddSearchPropertyByKeyword( var toLowerMethod = typeof(string).GetMethod("ToLower", Type.EmptyTypes); Expression callToLowerMethod = Expression.Call(selectorExpr, toLowerMethod!); - var selector = Expression.Lambda>(callToLowerMethod, paramExpr); + var selector = Expression.Lambda>(callToLowerMethod, paramExpr); - ((List>)specificationBuilder.Specification.SearchCriterias) - .Add(new SearchExpressionInfo(selector, searchTerm, 1)); + specificationBuilder.Search(selector, searchTerm, 1); } - public static IOrderedSpecificationBuilder AdvancedFilter( + public static ISpecificationBuilder AdvancedFilter( this ISpecificationBuilder specificationBuilder, Filter? filter) { @@ -126,24 +124,24 @@ public static IOrderedSpecificationBuilder AdvancedFilter( { var parameter = Expression.Parameter(typeof(T)); - Expression binaryExpresioFilter; + Expression binaryExpressionFilter; if (!string.IsNullOrEmpty(filter.Logic)) { if (filter.Filters is null) throw new CustomException("The Filters attribute is required when declaring a logic"); - binaryExpresioFilter = CreateFilterExpression(filter.Logic, filter.Filters, parameter); + binaryExpressionFilter = CreateFilterExpression(filter.Logic, filter.Filters, parameter); } else { var filterValid = GetValidFilter(filter); - binaryExpresioFilter = CreateFilterExpression(filterValid.Field!, filterValid.Operator!, filterValid.Value, parameter); + binaryExpressionFilter = CreateFilterExpression(filterValid.Field!, filterValid.Operator!, filterValid.Value, parameter); } - ((List>)specificationBuilder.Specification.WhereExpressions) - .Add(new WhereExpressionInfo(Expression.Lambda>(binaryExpresioFilter, parameter))); + var expr = Expression.Lambda>(binaryExpressionFilter, parameter); + specificationBuilder.Where(expr); } - return new OrderedSpecificationBuilder(specificationBuilder.Specification); + return specificationBuilder; } private static Expression CreateFilterExpression( @@ -155,20 +153,20 @@ private static Expression CreateFilterExpression( foreach (var filter in filters) { - Expression bExpresionFilter; + Expression bExpressionFilter; if (!string.IsNullOrEmpty(filter.Logic)) { if (filter.Filters is null) throw new CustomException("The Filters attribute is required when declaring a logic"); - bExpresionFilter = CreateFilterExpression(filter.Logic, filter.Filters, parameter); + bExpressionFilter = CreateFilterExpression(filter.Logic, filter.Filters, parameter); } else { var filterValid = GetValidFilter(filter); - bExpresionFilter = CreateFilterExpression(filterValid.Field!, filterValid.Operator!, filterValid.Value, parameter); + bExpressionFilter = CreateFilterExpression(filterValid.Field!, filterValid.Operator!, filterValid.Value, parameter); } - filterExpression = filterExpression is null ? bExpresionFilter : CombineFilter(logic, filterExpression, bExpresionFilter); + filterExpression = filterExpression is null ? bExpressionFilter : CombineFilter(logic, filterExpression, bExpressionFilter); } return filterExpression; @@ -180,9 +178,9 @@ private static Expression CreateFilterExpression( object? value, ParameterExpression parameter) { - var propertyExpresion = GetPropertyExpression(field, parameter); - var valueExpresion = GeValuetExpression(field, value, propertyExpresion.Type); - return CreateFilterExpression(propertyExpresion, valueExpresion, filterOperator); + var propertyExpression = GetPropertyExpression(field, parameter); + var valueExpression = GeValueExpression(field, value, propertyExpression.Type); + return CreateFilterExpression(propertyExpression, valueExpression, filterOperator); } private static Expression CreateFilterExpression( @@ -211,14 +209,14 @@ private static Expression CreateFilterExpression( }; } - private static Expression CombineFilter( + private static BinaryExpression CombineFilter( string filterOperator, - Expression bExpresionBase, - Expression bExpresion) => filterOperator switch + Expression bExpressionBase, + Expression bExpression) => filterOperator switch { - FilterLogic.AND => Expression.And(bExpresionBase, bExpresion), - FilterLogic.OR => Expression.Or(bExpresionBase, bExpresion), - FilterLogic.XOR => Expression.ExclusiveOr(bExpresionBase, bExpresion), + FilterLogic.AND => Expression.And(bExpressionBase, bExpression), + FilterLogic.OR => Expression.Or(bExpressionBase, bExpression), + FilterLogic.XOR => Expression.ExclusiveOr(bExpressionBase, bExpression), _ => throw new ArgumentException("FilterLogic is not valid."), }; @@ -238,7 +236,7 @@ private static MemberExpression GetPropertyExpression( private static string GetStringFromJsonElement(object value) => ((JsonElement)value).GetString()!; - private static ConstantExpression GeValuetExpression( + private static ConstantExpression GeValueExpression( string field, object? value, Type propertyType) @@ -303,10 +301,12 @@ private static Filter GetValidFilter(Filter filter) return filter; } - public static IOrderedSpecificationBuilder OrderBy( + public static ISpecificationBuilder OrderBy( this ISpecificationBuilder specificationBuilder, string[]? orderByFields) { + IOrderedSpecificationBuilder orderedBuilder = null!; + if (orderByFields is not null) { foreach (var field in ParseOrderBy(orderByFields)) @@ -323,12 +323,18 @@ public static IOrderedSpecificationBuilder OrderBy( Expression.Convert(propertyExpr, typeof(object)), paramExpr); - ((List>)specificationBuilder.Specification.OrderExpressions) - .Add(new OrderExpressionInfo(keySelector, field.Value)); + orderedBuilder = field.Value switch + { + OrderTypeEnum.OrderBy => specificationBuilder.OrderBy(keySelector), + OrderTypeEnum.OrderByDescending => specificationBuilder.OrderByDescending(keySelector), + OrderTypeEnum.ThenBy => orderedBuilder.ThenBy(keySelector), + OrderTypeEnum.ThenByDescending => orderedBuilder.ThenByDescending(keySelector), + _ => throw new CustomException("OrderTypeEnum is not valid."), + }; } } - return new OrderedSpecificationBuilder(specificationBuilder.Specification); + return specificationBuilder; } private static Dictionary ParseOrderBy(string[] orderByFields) =>