diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index bd34e6be..1c72f66c 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -1294,6 +1294,152 @@ public static long LongCount([NotNull] this IQueryable source, [NotNull] LambdaE } #endregion LongCount + #region Max + private static readonly MethodInfo _max = GetMethod(nameof(Queryable.Max)); + + /// + /// Computes the max element of a sequence. + /// + /// A sequence of values to calculate find the max for. + /// + /// + /// IQueryable queryable = employees.AsQueryable(); + /// var result1 = queryable.Max(); + /// var result2 = queryable.Select("Roles.Max()"); + /// + /// + /// The max element in the sequence. + [PublicAPI] + public static object Max([NotNull] this IQueryable source) + { + Check.NotNull(source, nameof(source)); + + return Execute(_max, source); + } + + private static readonly MethodInfo _maxPredicate = GetMethod(nameof(Queryable.Max), 1); + + /// + /// Computes the max element of a sequence. + /// + /// A sequence of values to calculate find the max for. + /// The . + /// A function to test each element for a condition. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// + /// + /// IQueryable queryable = employees.AsQueryable(); + /// var result = queryable.Max("Income"); + /// + /// + /// The max element in the sequence. + [PublicAPI] + public static object Max([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + { + Check.NotNull(source, nameof(source)); + Check.NotNull(config, nameof(config)); + Check.NotEmpty(predicate, nameof(predicate)); + + bool createParameterCtor = SupportsLinqToObjects(config, source); + LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(object), predicate, args); + + return Execute(_maxPredicate, source, lambda); + } + + /// + [PublicAPI] + public static object Max([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + { + return Max(source, ParsingConfig.Default, predicate, args); + } + + /// + /// Computes the max element of a sequence. + /// + /// A sequence of values to calculate find the max for. + /// A Lambda Expression. + /// The max element in the sequence. + [PublicAPI] + public static object Max([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + { + Check.NotNull(source, nameof(source)); + return Execute(_maxPredicate, source, lambda); + } + #endregion Max + + #region Min + private static readonly MethodInfo _min = GetMethod(nameof(Queryable.Min)); + + /// + /// Computes the min element of a sequence. + /// + /// A sequence of values to calculate find the min for. + /// + /// + /// IQueryable queryable = employees.AsQueryable(); + /// var result1 = queryable.Min(); + /// var result2 = queryable.Select("Roles.Min()"); + /// + /// + /// The min element in the sequence. + [PublicAPI] + public static object Min([NotNull] this IQueryable source) + { + Check.NotNull(source, nameof(source)); + + return Execute(_min, source); + } + + private static readonly MethodInfo _minPredicate = GetMethod(nameof(Queryable.Min), 1); + + /// + /// Computes the min element of a sequence. + /// + /// A sequence of values to calculate find the min for. + /// The . + /// A function to test each element for a condition. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// + /// + /// IQueryable queryable = employees.AsQueryable(); + /// var result = queryable.Min("Income"); + /// + /// + /// The min element in the sequence. + [PublicAPI] + public static object Min([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + { + Check.NotNull(source, nameof(source)); + Check.NotNull(config, nameof(config)); + Check.NotEmpty(predicate, nameof(predicate)); + + bool createParameterCtor = SupportsLinqToObjects(config, source); + LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(object), predicate, args); + + return Execute(_minPredicate, source, lambda); + } + + /// + [PublicAPI] + public static object Min([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + { + return Min(source, ParsingConfig.Default, predicate, args); + } + + /// + /// Computes the min element of a sequence. + /// + /// A sequence of values to calculate find the min for. + /// A Lambda Expression. + /// The min element in the sequence. + [PublicAPI] + public static object Min([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + { + Check.NotNull(source, nameof(source)); + return Execute(_minPredicate, source, lambda); + } + #endregion Min + #region OfType private static readonly MethodInfo _ofType = GetGenericMethod(nameof(Queryable.OfType)); diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Max.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Max.cs new file mode 100644 index 00000000..f539a0d1 --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Max.cs @@ -0,0 +1,36 @@ +using System.Linq.Dynamic.Core.Tests.Helpers.Models; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests +{ + public partial class QueryableTests + { + [Fact] + public void Max() + { + // Arrange + var incomes = User.GenerateSampleModels(100).Select(u => u.Income); + + // Act + var expected = incomes.Max(); + var actual = incomes.AsQueryable().Max(); + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Max_Selector() + { + // Arrange + var users = User.GenerateSampleModels(100); + + // Act + var expected = users.Max(u => u.Income); + var result = users.AsQueryable().Max("Income"); + + // Assert + Assert.Equal(expected, result); + } + } +} diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Min.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Min.cs new file mode 100644 index 00000000..120d556e --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Min.cs @@ -0,0 +1,36 @@ +using System.Linq.Dynamic.Core.Tests.Helpers.Models; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests +{ + public partial class QueryableTests + { + [Fact] + public void Min() + { + // Arrange + var incomes = User.GenerateSampleModels(100).Select(u => u.Income); + + // Act + var expected = incomes.Min(); + var actual = incomes.AsQueryable().Min(); + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Min_Selector() + { + // Arrange + var users = User.GenerateSampleModels(100); + + // Act + var expected = users.Min(u => u.Income); + var result = users.AsQueryable().Min("Income"); + + // Assert + Assert.Equal(expected, result); + } + } +}