From 2e6b709d573836830f03dd8d75fe8c0ccfe8a6f4 Mon Sep 17 00:00:00 2001 From: Martin Burtscher Date: Mon, 15 Apr 2024 13:29:05 +0200 Subject: [PATCH 1/2] Extend GridSort possibilities --- ...crosoft.FluentUI.AspNetCore.Components.xml | 62 +++++++++ .../Components/DataGrid/Columns/GridSort.cs | 121 ++++++++++++++++-- tests/Core/DataGrid/GridSortTests.cs | 101 +++++++++++++++ 3 files changed, 275 insertions(+), 9 deletions(-) create mode 100644 tests/Core/DataGrid/GridSortTests.cs diff --git a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml index 1ddd434e3b..7a98727250 100644 --- a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml +++ b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml @@ -1241,6 +1241,16 @@ An expression defining how a set of instances are to be sorted. A instance representing the specified sorting rule. + + + Produces a instance that sorts according to the specified + using the specified , descending. + + The type of the expression's value. + An expression defining how a set of instances are to be sorted. + Defines how a items in a set of instances are to be compared. + A instance representing the specified sorting rule. + Updates a instance by appending a further sorting rule. @@ -1249,6 +1259,15 @@ An expression defining how a set of instances are to be sorted. A instance representing the specified sorting rule. + + + Updates a instance by appending a further sorting rule. + + The type of the expression's value. + An expression defining how a set of instances are to be sorted. + Defines how a items in a set of instances are to be compared. + A instance representing the specified sorting rule. + Updates a instance by appending a further sorting rule. @@ -1257,6 +1276,49 @@ An expression defining how a set of instances are to be sorted. A instance representing the specified sorting rule. + + + Updates a instance by appending a further sorting rule. + + The type of the expression's value. + An expression defining how a set of instances are to be sorted. + Defines how a items in a set of instances are to be compared. + A instance representing the specified sorting rule. + + + + Updates a instance by appending a further sorting rule. + + The type of the expression's value. + An expression defining how a set of instances are to be sorted. + A instance representing the specified sorting rule. + + + + Updates a instance by appending a further sorting rule. + + The type of the expression's value. + An expression defining how a set of instances are to be sorted. + Defines how a items in a set of instances are to be compared. + A instance representing the specified sorting rule. + + + + Updates a instance by appending a further sorting rule. + + The type of the expression's value. + An expression defining how a set of instances are to be sorted. + A instance representing the specified sorting rule. + + + + Updates a instance by appending a further sorting rule. + + The type of the expression's value. + An expression defining how a set of instances are to be sorted. + Defines how a items in a set of instances are to be compared. + A instance representing the specified sorting rule. + Represents a column whose cells display a single value. diff --git a/src/Core/Components/DataGrid/Columns/GridSort.cs b/src/Core/Components/DataGrid/Columns/GridSort.cs index beb0a14558..456888ef70 100644 --- a/src/Core/Components/DataGrid/Columns/GridSort.cs +++ b/src/Core/Components/DataGrid/Columns/GridSort.cs @@ -59,6 +59,18 @@ public static GridSort ByDescending(Expression> => new((queryable, asc) => asc ? queryable.OrderByDescending(expression) : queryable.OrderBy(expression), (expression, false)); + /// + /// Produces a instance that sorts according to the specified + /// using the specified , descending. + /// + /// The type of the expression's value. + /// An expression defining how a set of instances are to be sorted. + /// Defines how a items in a set of instances are to be compared. + /// A instance representing the specified sorting rule. + public static GridSort ByDescending(Expression> expression, IComparer comparer) + => new((queryable, asc) => asc ? queryable.OrderByDescending(expression, comparer) : queryable.OrderBy(expression, comparer), + (expression, false)); + /// /// Updates a instance by appending a further sorting rule. /// @@ -67,13 +79,25 @@ public static GridSort ByDescending(Expression> /// A instance representing the specified sorting rule. public GridSort ThenAscending(Expression> expression) { - _then ??= []; - _thenExpressions ??= []; - _then.Add((queryable, asc) => asc ? queryable.ThenBy(expression) : queryable.ThenByDescending(expression)); - _thenExpressions.Add((expression, true)); - _cachedPropertyListAscending = null; - _cachedPropertyListDescending = null; - return this; + return AddThenExpression( + (queryable, asc) => asc ? queryable.ThenBy(expression) : queryable.ThenByDescending(expression), + (expression, true) + ); + } + + /// + /// Updates a instance by appending a further sorting rule. + /// + /// The type of the expression's value. + /// An expression defining how a set of instances are to be sorted. + /// Defines how a items in a set of instances are to be compared. + /// A instance representing the specified sorting rule. + public GridSort ThenAscending(Expression> expression, IComparer comparer) + { + return AddThenExpression( + (queryable, asc) => asc ? queryable.ThenBy(expression, comparer) : queryable.ThenByDescending(expression, comparer), + (expression, true) + ); } /// @@ -83,13 +107,92 @@ public GridSort ThenAscending(Expression> expre /// An expression defining how a set of instances are to be sorted. /// A instance representing the specified sorting rule. public GridSort ThenDescending(Expression> expression) + { + return AddThenExpression( + (queryable, asc) => asc ? queryable.ThenByDescending(expression) : queryable.ThenBy(expression), + (expression, false)); + } + + /// + /// Updates a instance by appending a further sorting rule. + /// + /// The type of the expression's value. + /// An expression defining how a set of instances are to be sorted. + /// Defines how a items in a set of instances are to be compared. + /// A instance representing the specified sorting rule. + public GridSort ThenDescending(Expression> expression, IComparer comparer) + { + return AddThenExpression( + (queryable, asc) => asc ? queryable.ThenByDescending(expression, comparer) : queryable.ThenBy(expression, comparer), + (expression, false) + ); + } + + /// + /// Updates a instance by appending a further sorting rule. + /// + /// The type of the expression's value. + /// An expression defining how a set of instances are to be sorted. + /// A instance representing the specified sorting rule. + public GridSort ThenAlwaysAscending(Expression> expression) + { + return AddThenExpression( + (queryable, _) => queryable.ThenBy(expression), + (expression, true)); + } + + /// + /// Updates a instance by appending a further sorting rule. + /// + /// The type of the expression's value. + /// An expression defining how a set of instances are to be sorted. + /// Defines how a items in a set of instances are to be compared. + /// A instance representing the specified sorting rule. + public GridSort ThenAlwaysAscending(Expression> expression, IComparer comparer) + { + return AddThenExpression( + (queryable, _) => queryable.ThenBy(expression, comparer), + (expression, true) + ); + } + + /// + /// Updates a instance by appending a further sorting rule. + /// + /// The type of the expression's value. + /// An expression defining how a set of instances are to be sorted. + /// A instance representing the specified sorting rule. + public GridSort ThenAlwaysDescending(Expression> expression) + { + return AddThenExpression( + (queryable, _) => queryable.ThenByDescending(expression), + (expression, false)); + } + + /// + /// Updates a instance by appending a further sorting rule. + /// + /// The type of the expression's value. + /// An expression defining how a set of instances are to be sorted. + /// Defines how a items in a set of instances are to be compared. + /// A instance representing the specified sorting rule. + public GridSort ThenAlwaysDescending(Expression> expression, IComparer comparer) + { + return AddThenExpression( + (queryable, _) => queryable.ThenByDescending(expression, comparer), + (expression, false) + ); + } + + private GridSort AddThenExpression(Func, bool, IOrderedQueryable> thenSortExpression, (LambdaExpression, bool) thenExpression) { _then ??= []; _thenExpressions ??= []; - _then.Add((queryable, asc) => asc ? queryable.ThenByDescending(expression) : queryable.ThenBy(expression)); - _thenExpressions.Add((expression, false)); + _then.Add(thenSortExpression); + _thenExpressions.Add(thenExpression); _cachedPropertyListAscending = null; _cachedPropertyListDescending = null; + return this; } diff --git a/tests/Core/DataGrid/GridSortTests.cs b/tests/Core/DataGrid/GridSortTests.cs new file mode 100644 index 0000000000..e71d7f0a99 --- /dev/null +++ b/tests/Core/DataGrid/GridSortTests.cs @@ -0,0 +1,101 @@ +using FluentAssertions; +using Xunit; + +namespace Microsoft.FluentUI.AspNetCore.Components.Tests.DataGrid; + +public class GridSortTests : TestBase +{ + private static readonly GridRow[] _gridData = [ + new(2, "B"), + new(1, "A"), + new(4, "B"), + new(3, "A") + ]; + +#pragma warning disable CA1861 // Avoid constant arrays as arguments + + [Theory] + [InlineData(true, new int[] { 1, 2, 3, 4 })] + [InlineData(false, new int[] { 4, 3, 2, 1 })] + public void GridSortTests_SortBy_Number(bool ascending, IList expected) + { + var sort = GridSort.ByAscending(x => x.Number); + var ordered = sort.Apply(_gridData.AsQueryable(), ascending); + + ordered.Select(x => x.Number) + .SequenceEqual(expected) + .Should().BeTrue(); + } + + [Theory] + [InlineData(true, new int[] { 1, 3, 2, 4 })] + [InlineData(false, new int[] { 4, 2, 3, 1 })] + public void GridSortTests_SortBy_GroupThenNumberAscending(bool ascending, IList expected) + { + var sort = GridSort + .ByAscending(x => x.Group) + .ThenAscending(x => x.Number); + + var ordered = sort.Apply(_gridData.AsQueryable(), ascending); + + ordered.Select(x => x.Number) + .SequenceEqual(expected) + .Should().BeTrue(); + } + + [Theory] + [InlineData(true, new int[] { 3, 1, 4, 2 })] + [InlineData(false, new int[] { 2, 4, 1, 3 })] + public void GridSortTests_SortBy_GroupThenNumberDescending(bool ascending, IList expected) + { + var sort = GridSort + .ByAscending(x => x.Group) + .ThenDescending(x => x.Number); + + var ordered = sort.Apply(_gridData.AsQueryable(), ascending); + + ordered.Select(x => x.Number) + .SequenceEqual(expected) + .Should().BeTrue(); + } + + [Theory] + [InlineData(true, new int[] { 1, 3, 2, 4 })] + [InlineData(false, new int[] { 2, 4, 1, 3 })] + public void GridSortTests_SortBy_GroupThenNumberAlwaysAscending(bool ascending, IList expected) + { + var sort = GridSort + .ByAscending(x => x.Group) + .ThenAlwaysAscending(x => x.Number); + + var ordered = sort.Apply(_gridData.AsQueryable(), ascending); + + ordered.Select(x => x.Number) + .SequenceEqual(expected) + .Should().BeTrue(); + } + + [Theory] + [InlineData(true, new int[] { 3, 1, 4, 2 })] + [InlineData(false, new int[] { 4, 2, 3, 1 })] + public void GridSortTests_SortBy_GroupThenNumberAlwaysDescending(bool ascending, IList expected) + { + var sort = GridSort + .ByAscending(x => x.Group) + .ThenAlwaysDescending(x => x.Number); + + var ordered = sort.Apply(_gridData.AsQueryable(), ascending); + + ordered.Select(x => x.Number) + .SequenceEqual(expected) + .Should().BeTrue(); + } + +#pragma warning restore CA1861 // Avoid constant arrays as arguments + + public class GridRow(int number, string group) + { + public int Number { get; } = number; + public string Group { get; } = group; + } +} From 56e0495378be2cbe37dca1d0f484fbfde993a4f9 Mon Sep 17 00:00:00 2001 From: Martin Burtscher Date: Tue, 16 Apr 2024 18:13:02 +0200 Subject: [PATCH 2/2] Add example of new rank sort extensions --- .../Shared/Pages/DataGrid/DataGridPage.razor | 8 ++++ .../DataGrid/Examples/DataGridRankSort.razor | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 examples/Demo/Shared/Pages/DataGrid/Examples/DataGridRankSort.razor diff --git a/examples/Demo/Shared/Pages/DataGrid/DataGridPage.razor b/examples/Demo/Shared/Pages/DataGrid/DataGridPage.razor index 438cb59976..7c84366836 100644 --- a/examples/Demo/Shared/Pages/DataGrid/DataGridPage.razor +++ b/examples/Demo/Shared/Pages/DataGrid/DataGridPage.razor @@ -65,6 +65,14 @@ + + +

+ Here is an example that demonstrates the rank sort. +

+
+
+ diff --git a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridRankSort.razor b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridRankSort.razor new file mode 100644 index 0000000000..341e43f3fa --- /dev/null +++ b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridRankSort.razor @@ -0,0 +1,43 @@ + + + + + @context.Group + + + + +

Keep numbers always sorted ascending inside the group when sorting by group

+ + + + + @context.Group + + + + + + +@code { + GridSort groupRank = GridSort + .ByAscending(x => x.Group) + .ThenAscending(x => x.Number); + + GridSort groupRankNumberAlwaysAscending = GridSort + .ByAscending(x => x.Group) + .ThenAlwaysAscending(x => x.Number); + + private static readonly IQueryable _gridData = new GridRow[] { + new(2, "B"), + new(1, "A"), + new(4, "B"), + new(3, "A") + }.AsQueryable(); + + public class GridRow(int number, string group) + { + public int Number { get; } = number; + public string Group { get; } = group; + } +}