Skip to content

Commit b90f412

Browse files
Merge pull request #428 from gregfullman/min-max-support
Add support for IQueryable.Min and .Max
2 parents d4449d2 + 6f82150 commit b90f412

File tree

3 files changed

+218
-0
lines changed

3 files changed

+218
-0
lines changed

src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs

+146
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,152 @@ public static long LongCount([NotNull] this IQueryable source, [NotNull] LambdaE
12941294
}
12951295
#endregion LongCount
12961296

1297+
#region Max
1298+
private static readonly MethodInfo _max = GetMethod(nameof(Queryable.Max));
1299+
1300+
/// <summary>
1301+
/// Computes the max element of a sequence.
1302+
/// </summary>
1303+
/// <param name="source">A sequence of values to calculate find the max for.</param>
1304+
/// <example>
1305+
/// <code language="cs">
1306+
/// IQueryable queryable = employees.AsQueryable();
1307+
/// var result1 = queryable.Max();
1308+
/// var result2 = queryable.Select("Roles.Max()");
1309+
/// </code>
1310+
/// </example>
1311+
/// <returns>The max element in the sequence.</returns>
1312+
[PublicAPI]
1313+
public static object Max([NotNull] this IQueryable source)
1314+
{
1315+
Check.NotNull(source, nameof(source));
1316+
1317+
return Execute(_max, source);
1318+
}
1319+
1320+
private static readonly MethodInfo _maxPredicate = GetMethod(nameof(Queryable.Max), 1);
1321+
1322+
/// <summary>
1323+
/// Computes the max element of a sequence.
1324+
/// </summary>
1325+
/// <param name="source">A sequence of values to calculate find the max for.</param>
1326+
/// <param name="config">The <see cref="ParsingConfig"/>.</param>
1327+
/// <param name="predicate">A function to test each element for a condition.</param>
1328+
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
1329+
/// <example>
1330+
/// <code language="cs">
1331+
/// IQueryable queryable = employees.AsQueryable();
1332+
/// var result = queryable.Max("Income");
1333+
/// </code>
1334+
/// </example>
1335+
/// <returns>The max element in the sequence.</returns>
1336+
[PublicAPI]
1337+
public static object Max([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
1338+
{
1339+
Check.NotNull(source, nameof(source));
1340+
Check.NotNull(config, nameof(config));
1341+
Check.NotEmpty(predicate, nameof(predicate));
1342+
1343+
bool createParameterCtor = SupportsLinqToObjects(config, source);
1344+
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(object), predicate, args);
1345+
1346+
return Execute(_maxPredicate, source, lambda);
1347+
}
1348+
1349+
/// <inheritdoc cref="Max(IQueryable, ParsingConfig, string, object[])"/>
1350+
[PublicAPI]
1351+
public static object Max([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args)
1352+
{
1353+
return Max(source, ParsingConfig.Default, predicate, args);
1354+
}
1355+
1356+
/// <summary>
1357+
/// Computes the max element of a sequence.
1358+
/// </summary>
1359+
/// <param name="source">A sequence of values to calculate find the max for.</param>
1360+
/// <param name="lambda">A Lambda Expression.</param>
1361+
/// <returns>The max element in the sequence.</returns>
1362+
[PublicAPI]
1363+
public static object Max([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
1364+
{
1365+
Check.NotNull(source, nameof(source));
1366+
return Execute(_maxPredicate, source, lambda);
1367+
}
1368+
#endregion Max
1369+
1370+
#region Min
1371+
private static readonly MethodInfo _min = GetMethod(nameof(Queryable.Min));
1372+
1373+
/// <summary>
1374+
/// Computes the min element of a sequence.
1375+
/// </summary>
1376+
/// <param name="source">A sequence of values to calculate find the min for.</param>
1377+
/// <example>
1378+
/// <code language="cs">
1379+
/// IQueryable queryable = employees.AsQueryable();
1380+
/// var result1 = queryable.Min();
1381+
/// var result2 = queryable.Select("Roles.Min()");
1382+
/// </code>
1383+
/// </example>
1384+
/// <returns>The min element in the sequence.</returns>
1385+
[PublicAPI]
1386+
public static object Min([NotNull] this IQueryable source)
1387+
{
1388+
Check.NotNull(source, nameof(source));
1389+
1390+
return Execute(_min, source);
1391+
}
1392+
1393+
private static readonly MethodInfo _minPredicate = GetMethod(nameof(Queryable.Min), 1);
1394+
1395+
/// <summary>
1396+
/// Computes the min element of a sequence.
1397+
/// </summary>
1398+
/// <param name="source">A sequence of values to calculate find the min for.</param>
1399+
/// <param name="config">The <see cref="ParsingConfig"/>.</param>
1400+
/// <param name="predicate">A function to test each element for a condition.</param>
1401+
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
1402+
/// <example>
1403+
/// <code language="cs">
1404+
/// IQueryable queryable = employees.AsQueryable();
1405+
/// var result = queryable.Min("Income");
1406+
/// </code>
1407+
/// </example>
1408+
/// <returns>The min element in the sequence.</returns>
1409+
[PublicAPI]
1410+
public static object Min([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
1411+
{
1412+
Check.NotNull(source, nameof(source));
1413+
Check.NotNull(config, nameof(config));
1414+
Check.NotEmpty(predicate, nameof(predicate));
1415+
1416+
bool createParameterCtor = SupportsLinqToObjects(config, source);
1417+
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(object), predicate, args);
1418+
1419+
return Execute(_minPredicate, source, lambda);
1420+
}
1421+
1422+
/// <inheritdoc cref="Min(IQueryable, ParsingConfig, string, object[])"/>
1423+
[PublicAPI]
1424+
public static object Min([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args)
1425+
{
1426+
return Min(source, ParsingConfig.Default, predicate, args);
1427+
}
1428+
1429+
/// <summary>
1430+
/// Computes the min element of a sequence.
1431+
/// </summary>
1432+
/// <param name="source">A sequence of values to calculate find the min for.</param>
1433+
/// <param name="lambda">A Lambda Expression.</param>
1434+
/// <returns>The min element in the sequence.</returns>
1435+
[PublicAPI]
1436+
public static object Min([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
1437+
{
1438+
Check.NotNull(source, nameof(source));
1439+
return Execute(_minPredicate, source, lambda);
1440+
}
1441+
#endregion Min
1442+
12971443
#region OfType
12981444
private static readonly MethodInfo _ofType = GetGenericMethod(nameof(Queryable.OfType));
12991445

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Linq.Dynamic.Core.Tests.Helpers.Models;
2+
using Xunit;
3+
4+
namespace System.Linq.Dynamic.Core.Tests
5+
{
6+
public partial class QueryableTests
7+
{
8+
[Fact]
9+
public void Max()
10+
{
11+
// Arrange
12+
var incomes = User.GenerateSampleModels(100).Select(u => u.Income);
13+
14+
// Act
15+
var expected = incomes.Max();
16+
var actual = incomes.AsQueryable().Max();
17+
18+
// Assert
19+
Assert.Equal(expected, actual);
20+
}
21+
22+
[Fact]
23+
public void Max_Selector()
24+
{
25+
// Arrange
26+
var users = User.GenerateSampleModels(100);
27+
28+
// Act
29+
var expected = users.Max(u => u.Income);
30+
var result = users.AsQueryable().Max("Income");
31+
32+
// Assert
33+
Assert.Equal(expected, result);
34+
}
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Linq.Dynamic.Core.Tests.Helpers.Models;
2+
using Xunit;
3+
4+
namespace System.Linq.Dynamic.Core.Tests
5+
{
6+
public partial class QueryableTests
7+
{
8+
[Fact]
9+
public void Min()
10+
{
11+
// Arrange
12+
var incomes = User.GenerateSampleModels(100).Select(u => u.Income);
13+
14+
// Act
15+
var expected = incomes.Min();
16+
var actual = incomes.AsQueryable().Min();
17+
18+
// Assert
19+
Assert.Equal(expected, actual);
20+
}
21+
22+
[Fact]
23+
public void Min_Selector()
24+
{
25+
// Arrange
26+
var users = User.GenerateSampleModels(100);
27+
28+
// Act
29+
var expected = users.Min(u => u.Income);
30+
var result = users.AsQueryable().Min("Income");
31+
32+
// Assert
33+
Assert.Equal(expected, result);
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)