From d56b0d375ac7a0e216a20101178a0a78f3448838 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 9 Apr 2024 23:06:12 +0200 Subject: [PATCH] OrderBy --- .../NewtonsoftJsonExtensions.cs | 75 +++++++++++++++-- .../Config/SystemTextJsonParsingConfig.cs | 2 +- .../SystemTextJsonExtensions.cs | 80 ++++++++++++++++--- .../DynamicQueryableExtensions.cs | 31 ++++--- .../NewtonsoftJsonTests.cs | 18 +++++ .../SystemTextJsonTests.cs | 18 +++++ 6 files changed, 191 insertions(+), 33 deletions(-) diff --git a/src/System.Linq.Dynamic.Core.NewtonsoftJson/NewtonsoftJsonExtensions.cs b/src/System.Linq.Dynamic.Core.NewtonsoftJson/NewtonsoftJsonExtensions.cs index dca64b00..bd3c97b3 100644 --- a/src/System.Linq.Dynamic.Core.NewtonsoftJson/NewtonsoftJsonExtensions.cs +++ b/src/System.Linq.Dynamic.Core.NewtonsoftJson/NewtonsoftJsonExtensions.cs @@ -1,4 +1,5 @@ -using System.Linq.Dynamic.Core.NewtonsoftJson.Config; +using System.Collections; +using System.Linq.Dynamic.Core.NewtonsoftJson.Config; using System.Linq.Dynamic.Core.NewtonsoftJson.Extensions; using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; @@ -237,7 +238,7 @@ public static int Count(this JArray source, NewtonsoftJsonParsingConfig config, Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return queryable.Count(config, predicate, args); } @@ -343,7 +344,7 @@ public static JToken First(this JArray source, LambdaExpression lambda) Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJToken(queryable.FirstOrDefault(predicate, args)); } @@ -388,7 +389,7 @@ public static JToken Last(this JArray source, NewtonsoftJsonParsingConfig config Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJToken(queryable.Last(predicate, args)); } @@ -433,7 +434,7 @@ public static JToken Last(this JArray source, LambdaExpression lambda) Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJToken(queryable.LastOrDefault(predicate, args)); } @@ -478,7 +479,7 @@ public static JToken Max(this JArray source, NewtonsoftJsonParsingConfig config, Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJToken(queryable.Max(config, predicate, args))!; } @@ -523,7 +524,7 @@ public static JToken Min(this JArray source, NewtonsoftJsonParsingConfig config, Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJToken(queryable.Min(config, predicate, args))!; } @@ -554,6 +555,66 @@ public static JToken Min(this JArray source, LambdaExpression lambda) } #endregion Min + #region OrderBy + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// A sequence of values to order. + /// The . + /// An expression string to indicate values to order by. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static JArray OrderBy(this JArray source, NewtonsoftJsonParsingConfig config, string ordering, params object?[] args) + { + Check.NotNull(source); + Check.NotNull(source); + Check.NotNullOrEmpty(ordering); + + var queryable = ToQueryable(source, config); + return ToJArray(() => queryable.OrderBy(config, ordering, args)); + } + + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// A sequence of values to order. + /// An expression string to indicate values to order by. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static JArray OrderBy(this JArray source, string ordering, params object?[] args) + { + return OrderBy(source, NewtonsoftJsonParsingConfig.Default, ordering, args); + } + + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// A sequence of values to order. + /// The . + /// An expression string to indicate values to order by. + /// The comparer to use. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static JArray OrderBy(this JArray source, NewtonsoftJsonParsingConfig config, string ordering, IComparer comparer, params object?[] args) + { + var queryable = ToQueryable(source, config); + return ToJArray(() => queryable.OrderBy(config, ordering, comparer, args)); + } + + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// A sequence of values to order. + /// An expression string to indicate values to order by. + /// The comparer to use. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static JArray OrderBy(this JArray source, string ordering, IComparer comparer, params object?[] args) + { + return OrderBy(source, NewtonsoftJsonParsingConfig.Default, ordering, comparer, args); + } + #endregion OrderBy + #region Select /// /// Projects each element of a sequence into a new form. diff --git a/src/System.Linq.Dynamic.Core.SystemTextJson/Config/SystemTextJsonParsingConfig.cs b/src/System.Linq.Dynamic.Core.SystemTextJson/Config/SystemTextJsonParsingConfig.cs index c52c5078..17c6fcb0 100644 --- a/src/System.Linq.Dynamic.Core.SystemTextJson/Config/SystemTextJsonParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core.SystemTextJson/Config/SystemTextJsonParsingConfig.cs @@ -6,5 +6,5 @@ public class SystemTextJsonParsingConfig : ParsingConfig { public static SystemTextJsonParsingConfig Default { get; } = new(); - public DynamicJsonClassOptions? DynamicJsonClassOptions { get; set; } + // public DynamicJsonClassOptions? DynamicJsonClassOptions { get; set; } } \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core.SystemTextJson/SystemTextJsonExtensions.cs b/src/System.Linq.Dynamic.Core.SystemTextJson/SystemTextJsonExtensions.cs index e17059b2..c88b590e 100644 --- a/src/System.Linq.Dynamic.Core.SystemTextJson/SystemTextJsonExtensions.cs +++ b/src/System.Linq.Dynamic.Core.SystemTextJson/SystemTextJsonExtensions.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections; +using System.Collections.Generic; using System.Linq.Dynamic.Core.SystemTextJson.Config; using System.Linq.Dynamic.Core.SystemTextJson.Extensions; using System.Linq.Dynamic.Core.SystemTextJson.Utils; @@ -149,7 +150,7 @@ public static double Average(this JsonDocument source, SystemTextJsonParsingConf Check.NotNull(config); Check.NotEmpty(predicate); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return queryable.Average(config, predicate, args); } @@ -251,7 +252,7 @@ public static int Count(this JsonDocument source, SystemTextJsonParsingConfig co Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return queryable.Count(config, predicate, args); } @@ -411,7 +412,7 @@ public static JsonElement First(this JsonDocument source, LambdaExpression lambd Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJsonElement(queryable.FirstOrDefault(predicate, args)); } @@ -469,7 +470,7 @@ public static JsonElement Last(this JsonDocument source, SystemTextJsonParsingCo Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJsonElement(queryable.Last(predicate, args)); } @@ -527,7 +528,7 @@ public static JsonElement Last(this JsonDocument source, LambdaExpression lambda Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJsonElement(queryable.LastOrDefault(config, predicate, args)); } @@ -585,7 +586,7 @@ public static JsonElement Max(this JsonDocument source, SystemTextJsonParsingCon Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJsonElement(queryable.Max(config, predicate, args)) ?? default; } @@ -643,7 +644,7 @@ public static JsonElement Min(this JsonDocument source, SystemTextJsonParsingCon Check.NotNull(source); Check.NotNull(config); - var queryable = ToQueryable(source); + var queryable = ToQueryable(source, config); return ToJsonElement(queryable.Min(config, predicate, args)) ?? default; } @@ -674,6 +675,66 @@ public static JsonElement Min(this JsonDocument source, LambdaExpression lambda) } #endregion Min + #region OrderBy + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// A sequence of values to order. + /// The . + /// An expression string to indicate values to order by. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static JsonDocument OrderBy(this JsonDocument source, SystemTextJsonParsingConfig config, string ordering, params object?[] args) + { + Check.NotNull(source); + Check.NotNull(source); + Check.NotNullOrEmpty(ordering); + + var queryable = ToQueryable(source, config); + return ToJsonDocumentArray(() => queryable.OrderBy(config, ordering, args)); + } + + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// A sequence of values to order. + /// An expression string to indicate values to order by. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static JsonDocument OrderBy(this JsonDocument source, string ordering, params object?[] args) + { + return OrderBy(source, SystemTextJsonParsingConfig.Default, ordering, args); + } + + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// A sequence of values to order. + /// The . + /// An expression string to indicate values to order by. + /// The comparer to use. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static JsonDocument OrderBy(this JsonDocument source, SystemTextJsonParsingConfig config, string ordering, IComparer comparer, params object?[] args) + { + var queryable = ToQueryable(source, config); + return ToJsonDocumentArray(() => queryable.OrderBy(config, ordering, comparer, args)); + } + + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// A sequence of values to order. + /// An expression string to indicate values to order by. + /// The comparer to use. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static JsonDocument OrderBy(this JsonDocument source, string ordering, IComparer comparer, params object?[] args) + { + return OrderBy(source, SystemTextJsonParsingConfig.Default, ordering, comparer, args); + } + #endregion OrderBy + #region Select /// /// Projects each element of a sequence into a new form. @@ -765,6 +826,7 @@ private static JsonDocument ToJsonDocumentArray(Func func) return JsonDocumentUtils.FromObject(array); } + // ReSharper disable once UnusedParameter.Local private static IQueryable ToQueryable(JsonDocument source, SystemTextJsonParsingConfig? config = null) { var array = source.RootElement; @@ -773,7 +835,7 @@ private static IQueryable ToQueryable(JsonDocument source, SystemTextJsonParsing throw new NotSupportedException("The source is not a JSON array."); } - return JsonDocumentExtensions.ToDynamicJsonClassArray(array, config?.DynamicJsonClassOptions).AsQueryable(); + return JsonDocumentExtensions.ToDynamicJsonClassArray(array).AsQueryable(); } #endregion } \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index fc126865..47cf5dad 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -1565,11 +1565,23 @@ public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig co return InternalOrderBy(source, config, ordering, comparer, args); } + /// + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, params object?[] args) + { + return OrderBy(source, ParsingConfig.Default, ordering, args); + } + + /// + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, IComparer comparer, params object?[] args) + { + return OrderBy(source, ParsingConfig.Default, ordering, comparer, args); + } + internal static IOrderedQueryable InternalOrderBy(IQueryable source, ParsingConfig config, string ordering, object? comparer, params object?[] args) { Check.NotNull(source); Check.NotNull(config); - Check.NotEmpty(ordering, nameof(ordering)); + Check.NotEmpty(ordering); ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(source.ElementType, string.Empty, config.RenameEmptyParameterExpressionNames) }; ExpressionParser parser = new ExpressionParser(parameters, ordering, args, config); @@ -1616,19 +1628,6 @@ internal static IOrderedQueryable InternalOrderBy(IQueryable source, ParsingConf var optimized = OptimizeExpression(queryExpr); return (IOrderedQueryable)source.Provider.CreateQuery(optimized); } - - /// - public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, params object?[] args) - { - return OrderBy(source, ParsingConfig.Default, ordering, args); - } - - /// - public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, IComparer comparer, params object?[] args) - { - return OrderBy(source, ParsingConfig.Default, ordering, comparer, args); - } - #endregion OrderBy #region Page/PageResult @@ -1803,10 +1802,10 @@ public static IQueryable Select(this IQueryable source, Parsin LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(TResult), selector, args); var methodCallExpression = Expression.Call( - typeof(Queryable), + typeof(Queryable), nameof(Queryable.Select), new[] { source.ElementType, typeof(TResult) }, - source.Expression, + source.Expression, Expression.Quote(lambda) ); diff --git a/test/System.Linq.Dynamic.Core.NewtonsoftJson.Tests/NewtonsoftJsonTests.cs b/test/System.Linq.Dynamic.Core.NewtonsoftJson.Tests/NewtonsoftJsonTests.cs index 61a1c4b4..488fb5b5 100644 --- a/test/System.Linq.Dynamic.Core.NewtonsoftJson.Tests/NewtonsoftJsonTests.cs +++ b/test/System.Linq.Dynamic.Core.NewtonsoftJson.Tests/NewtonsoftJsonTests.cs @@ -164,6 +164,24 @@ public void Min() ((string?)_source.Min("Age")).Should().Be("30"); } + [Fact] + public void OrderBy() + { + // Act 1 + var result = _source.OrderBy("Age").Select("Name"); + + // Assert 1 + var array = result.Select(x => x.Value()); + array.Should().BeEquivalentTo("John", "Doe"); + + // Act 1 + var resultAsc = _source.OrderBy("Age", "Asc").Select("Name"); + + // Assert 1 + var arrayAsc = resultAsc.Select(x => x.Value()); + arrayAsc.Should().BeEquivalentTo("Doe", "John"); + } + [Fact] public void Select() { diff --git a/test/System.Linq.Dynamic.Core.SystemTextJson.Tests/SystemTextJsonTests.cs b/test/System.Linq.Dynamic.Core.SystemTextJson.Tests/SystemTextJsonTests.cs index d4cf6bd5..0d7e0b3e 100644 --- a/test/System.Linq.Dynamic.Core.SystemTextJson.Tests/SystemTextJsonTests.cs +++ b/test/System.Linq.Dynamic.Core.SystemTextJson.Tests/SystemTextJsonTests.cs @@ -176,6 +176,24 @@ public void Min() _source.Min("Age").GetRawText().Should().BeEquivalentTo("30"); } + [Fact] + public void OrderBy() + { + // Act 1 + var result = _source.OrderBy("Age").Select("Name"); + + // Assert 1 + var array = result.RootElement.EnumerateArray().Select(x => x.GetString()); + array.Should().BeEquivalentTo("John", "Doe"); + + // Act 1 + var resultAsc = _source.OrderBy("Age", "Asc").Select("Name"); + + // Assert 1 + var arrayAsc = resultAsc.RootElement.EnumerateArray().Select(x => x.GetString()); + arrayAsc.Should().BeEquivalentTo("Doe", "John"); + } + [Fact] public void Select() {