Skip to content

Commit

Permalink
Merge pull request #109 from wemogy/108-sorting-is-missing
Browse files Browse the repository at this point in the history
Introduced SortingParameters
  • Loading branch information
SebastianKuesters committed Aug 29, 2023
2 parents 23dffd0 + b516654 commit 6684f1b
Show file tree
Hide file tree
Showing 21 changed files with 4,704 additions and 4,519 deletions.
File renamed without changes.
50 changes: 50 additions & 0 deletions docs/public/docs-general/05-sorting-pagination.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Sorting & Pagination

The DatabaseRepository methods `IterateAsync` and `QueryAsync` support sorting and pagination to allow the user to retrieve a subset of the results.

## Sorting

The generic `Sorting<>` objects allows you to define a sorting on a given properties (multiple properties helps you e.g. to order first on firstname and for all entities which have the same firstname, you can define that they should be ordered by the id property). The sorting can be ascending or descending.

```csharp
var sorting = new Sorting<User>()
.OrderBy(x => x.FirstName)
.OrderByDescending(x => x.Id);

var sortedUsers = _userRepository.QueryAsync(
x => true,
sorting);
```

## Pagination

The `Pagination` objects allows you to define skip and take values to retrieve a subset of the results.

```csharp
var pagination = new Pagination()
.Skip(10)
.Take(10);

var pagedUsers = _userRepository.QueryAsync(
x => true,
pagination);
```

## Sorting & Pagination

The `IterateAsync` and `QueryAsync` methods support sorting and pagination. You can combine both to retrieve a subset of the results in a sorted order.

```csharp
var sorting = new Sorting<User>()
.OrderBy(x => x.FirstName)
.OrderByDescending(x => x.Id);

var pagination = new Pagination()
.Skip(10)
.Take(10);

var sortedPagedUsers = _userRepository.QueryAsync(
x => true,
sorting,
pagination);
```
8,364 changes: 3,913 additions & 4,451 deletions docs/public/yarn.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class Animal : EntityBase

public string PrivateNote { get; set; }

public Animal? BestFriend { get; set; }

public Animal()
: base(Guid.NewGuid().ToString())
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentAssertions;
using Wemogy.Infrastructure.Database.Core.Enums;
using Wemogy.Infrastructure.Database.Core.UnitTests.Fakes.Entities;
using Wemogy.Infrastructure.Database.Core.ValueObjects;
using Xunit;
Expand All @@ -19,7 +21,7 @@ public async Task IterateAsync_ShouldGetAnExistingItemByIdWithExpression()
var count = 0;

// Act
await MicrosoftUserRepository.IterateAsync(x => x.Id == user.Id, x =>
await MicrosoftUserRepository.IterateAsync(x => x.Id == user.Id, _ =>
{
count++;
});
Expand All @@ -38,7 +40,7 @@ public async Task IterateAsync_ShouldGetAnExistingItemByPartitionKeyWithExpressi
var count = 0;

// Act
await MicrosoftUserRepository.IterateAsync(x => x.TenantId == user.TenantId, x =>
await MicrosoftUserRepository.IterateAsync(x => x.TenantId == user.TenantId, _ =>
{
count++;
});
Expand All @@ -57,7 +59,7 @@ public async Task IterateAsync_ShouldWorkWithAsynchronousCallback()
var count = 0;

// Act
await MicrosoftUserRepository.IterateAsync(x => x.TenantId == user.TenantId, (x) =>
await MicrosoftUserRepository.IterateAsync(x => x.TenantId == user.TenantId, _ =>
{
count++;
Expand Down Expand Up @@ -88,16 +90,16 @@ public async Task IterateAsync_ShouldSupportPagination()
// Act
await MicrosoftUserRepository.IterateAsync(
x => x.TenantId == tenantId,
new PaginationParameters(0, take),
x =>
new Pagination(0, take),
_ =>
{
firstDocumentsCount++;
});

await MicrosoftUserRepository.IterateAsync(
x => x.TenantId == tenantId,
new PaginationParameters(18, take),
x =>
new Pagination(18, take),
_ =>
{
lastDocumentsCount++;
});
Expand All @@ -106,4 +108,49 @@ await MicrosoftUserRepository.IterateAsync(
firstDocumentsCount.Should().Be(take);
lastDocumentsCount.Should().Be(2);
}

[Theory]
[InlineData(SortDirection.Ascending)]
[InlineData(SortDirection.Descending)]
public async Task IterateAsync_ShouldSupportSorting(SortDirection sortDirection)
{
// Arrange
var tenantId = Guid.NewGuid().ToString();
await ResetAsync();
for (int i = 0; i < 20; i++)
{
var user = User.Faker.Generate();
user.TenantId = tenantId;
await MicrosoftUserRepository.CreateAsync(user);
}

var sortingParameters = new Sorting<User>()
.OrderBy(x => x.Firstname, sortDirection);
var callbackUsers = new List<User>();

// Act
await MicrosoftUserRepository.IterateAsync(
x => x.TenantId == tenantId,
sortingParameters,
callbackUsers.Add);

// Assert that callbackUsers are sorted by Firstname
for (int i = 0; i < callbackUsers.Count - 1; i++)
{
var current = callbackUsers[i];
var next = callbackUsers[i + 1];
var sortOrder = string.Compare(
current.Firstname,
next.Firstname,
StringComparison.Ordinal);
if (sortDirection == SortDirection.Ascending)
{
sortOrder.Should().BeLessOrEqualTo(0);
}
else
{
sortOrder.Should().BeGreaterOrEqualTo(0);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Threading.Tasks;
using FluentAssertions;
using Wemogy.Infrastructure.Database.Core.Enums;
using Wemogy.Infrastructure.Database.Core.UnitTests.Fakes.Entities;
using Wemogy.Infrastructure.Database.Core.ValueObjects;
using Xunit;
Expand Down Expand Up @@ -68,7 +70,7 @@ public async Task QueryAsync_ShouldRespectTakeCount()
public async Task QueryAsync_LambdaShouldRespectTakeCount()
{
// Arrange
var paginationParameters = new PaginationParameters(
var pagination = new Pagination(
0,
5);
await ResetAsync();
Expand All @@ -81,17 +83,17 @@ public async Task QueryAsync_LambdaShouldRespectTakeCount()
// Act
var queriedUser = await MicrosoftUserRepository.QueryAsync(
x => true,
paginationParameters);
pagination);

// Assert
queriedUser.Should().HaveCount(paginationParameters.Take);
queriedUser.Should().HaveCount(pagination.Take);
}

[Fact]
public async Task QueryAsync_LambdaShouldRespectSkipCount()
{
// Arrange
var paginationParameters = new PaginationParameters(
var pagination = new Pagination(
2,
10);
await ResetAsync();
Expand All @@ -104,9 +106,52 @@ public async Task QueryAsync_LambdaShouldRespectSkipCount()
// Act
var queriedUser = await MicrosoftUserRepository.QueryAsync(
x => true,
paginationParameters);
pagination);

// Assert
queriedUser.Should().HaveCount(users.Count - paginationParameters.Skip);
queriedUser.Should().HaveCount(users.Count - pagination.Skip);
}

[Theory]
[InlineData(SortDirection.Ascending)]
[InlineData(SortDirection.Descending)]
public async Task QueryAsync_LambdaShouldRespectSorting(SortDirection sortDirection)
{
// Arrange
var tenantId = Guid.NewGuid().ToString();
await ResetAsync();
for (int i = 0; i < 20; i++)
{
var user = User.Faker.Generate();
user.TenantId = tenantId;
await MicrosoftUserRepository.CreateAsync(user);
}

var sortingParameters = new Sorting<User>()
.OrderBy(x => x.Firstname, sortDirection);

// Act
var queriedUser = await MicrosoftUserRepository.QueryAsync(
x => true,
sortingParameters);

// Assert that queriedUser are sorted by Firstname
for (int i = 0; i < queriedUser.Count - 1; i++)
{
var current = queriedUser[i];
var next = queriedUser[i + 1];
var sortOrder = string.Compare(
current.Firstname,
next.Firstname,
StringComparison.Ordinal);
if (sortDirection == SortDirection.Ascending)
{
sortOrder.Should().BeLessOrEqualTo(0);
}
else
{
sortOrder.Should().BeGreaterOrEqualTo(0);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Linq;
using FluentAssertions;
using Wemogy.Infrastructure.Database.Core.Enums;
using Wemogy.Infrastructure.Database.Core.UnitTests.Fakes.Entities;
using Wemogy.Infrastructure.Database.Core.ValueObjects;
using Xunit;

namespace Wemogy.Infrastructure.Database.Core.UnitTests.ValueObjects;

public class SortingParametersTests
{
[Fact]
public void SortingParameters_OrderBy_HappyPath()
{
// Arrange
var sorting = new Sorting<Animal>();

// Act
sorting
.OrderBy(x => x.Firstname);
sorting
.OrderBy(x => x.BestFriend!.Firstname);

// Assert
sorting.Parameters.First().Property.Should().Be("Firstname");
sorting.Parameters.First().Direction.Should().Be(SortDirection.Ascending);
sorting.Parameters[1].Property.Should().Be("BestFriend.Firstname");
sorting.Parameters[1].Direction.Should().Be(SortDirection.Ascending);
}

[Fact]
public void SortingParameters_ApplyTo_HappyPath()
{
// Arrange
var animals = Animal.Faker.Generate(10);
var sortingParameters = new Sorting<Animal>()
.OrderBy(x => x.Firstname);

// Act
var sortedAnimals = sortingParameters
.ApplyTo(animals)
.ToList();

// Assert
sortedAnimals.Should().NotBeNull();
sortedAnimals.Should().HaveCount(10);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ Task IterateAsync(
/// </summary>
Task IterateAsync(
Expression<Func<TEntity, bool>> predicate,
PaginationParameters? paginationParameters,
Sorting<TEntity>? sorting,
Pagination? pagination,
Func<TEntity, Task> callback,
CancellationToken cancellationToken);

Expand Down
Loading

0 comments on commit 6684f1b

Please sign in to comment.