Skip to content

Commit

Permalink
feat: implement multiple sort field when list applications (#256)
Browse files Browse the repository at this point in the history
  • Loading branch information
aneojgurhem authored Feb 20, 2023
2 parents 70ea766 + 4b7af1f commit 93ab812
Show file tree
Hide file tree
Showing 22 changed files with 401 additions and 75 deletions.
18 changes: 9 additions & 9 deletions Adaptors/Memory/src/TaskTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
using ArmoniK.Core.Common;
using ArmoniK.Core.Common.Exceptions;
using ArmoniK.Core.Common.Storage;
using ArmoniK.Core.Common.Utils;

using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -345,12 +346,12 @@ public IAsyncEnumerable<string> ListTasksAsync(TaskFilter filter,
}

/// <inheritdoc />
public Task<(IEnumerable<Application> applications, int totalCount)> ListApplicationsAsync(Expression<Func<TaskData, bool>> filter,
Expression<Func<Application, object?>> orderField,
bool ascOrder,
int page,
int pageSize,
CancellationToken cancellationToken = default)
public Task<(IEnumerable<Application> applications, int totalCount)> ListApplicationsAsync(Expression<Func<TaskData, bool>> filter,
ICollection<Expression<Func<Application, object?>>> orderFields,
bool ascOrder,
int page,
int pageSize,
CancellationToken cancellationToken = default)
{
var queryable = taskId2TaskData_.AsQueryable()
.Select(pair => pair.Value)
Expand All @@ -361,9 +362,8 @@ public IAsyncEnumerable<string> ListTasksAsync(TaskFilter filter,
data.Options.ApplicationService))
.Select(group => group.Key);

var ordered = ascOrder
? queryable.OrderBy(orderField)
: queryable.OrderByDescending(orderField);
var ordered = queryable.OrderByList(orderFields,
ascOrder);

return Task.FromResult<(IEnumerable<Application> tasks, int totalCount)>((ordered.Skip(page * pageSize)
.Take(pageSize), ordered.Count()));
Expand Down
35 changes: 35 additions & 0 deletions Adaptors/MongoDB/src/IMongoQueryableExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Threading;

Expand All @@ -40,4 +43,36 @@ public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this
}
}
}

public static IOrderedMongoQueryable<T> OrderByList<T>(this IMongoQueryable<T> queryable,
ICollection<Expression<Func<T, object?>>> orderFields,
bool ascOrder = true)
{
if (ascOrder)
{
var ordered = queryable.OrderBy(orderFields.First());
if (orderFields.Count > 1)
{
foreach (var expression in orderFields.Skip(1))
{
ordered = ordered.ThenBy(expression);
}
}

return ordered;
}
else
{
var ordered = queryable.OrderByDescending(orderFields.First());
if (orderFields.Count > 1)
{
foreach (var expression in orderFields.Skip(1))
{
ordered = ordered.ThenByDescending(expression);
}
}

return ordered;
}
}
}
17 changes: 8 additions & 9 deletions Adaptors/MongoDB/src/TaskTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -446,12 +446,12 @@ public async IAsyncEnumerable<string> ListTasksAsync(TaskFilter
}

/// <inheritdoc />
public async Task<(IEnumerable<Application> applications, int totalCount)> ListApplicationsAsync(Expression<Func<TaskData, bool>> filter,
Expression<Func<Application, object?>> orderField,
bool ascOrder,
int page,
int pageSize,
CancellationToken cancellationToken = default)
public async Task<(IEnumerable<Application> applications, int totalCount)> ListApplicationsAsync(Expression<Func<TaskData, bool>> filter,
ICollection<Expression<Func<Application, object?>>> orderFields,
bool ascOrder,
int page,
int pageSize,
CancellationToken cancellationToken = default)
{
using var activity = activitySource_.StartActivity($"{nameof(ListApplicationsAsync)}");
var sessionHandle = sessionProvider_.Get();
Expand All @@ -465,9 +465,8 @@ public async IAsyncEnumerable<string> ListTasksAsync(TaskFilter
data.Options.ApplicationService))
.Select(group => group.Key);

var ordered = ascOrder
? queryable.OrderBy(orderField)
: queryable.OrderByDescending(orderField);
var ordered = queryable.OrderByList(orderFields,
ascOrder);

var taskResult = ordered.Skip(page * pageSize)
.Take(pageSize)
Expand Down
2 changes: 1 addition & 1 deletion Common/src/ArmoniK.Core.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@


<ItemGroup>
<PackageReference Include="ArmoniK.Api.Core" Version="3.4.0" />
<PackageReference Include="ArmoniK.Api.Core" Version="3.5.0-SNAPSHOT.16.822ea77" />
<PackageReference Include="Calzolari.Grpc.AspNetCore.Validation" Version="6.2.0" />
<PackageReference Include="Grpc.HealthCheck" Version="2.50.0" />
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" />
Expand Down
14 changes: 7 additions & 7 deletions Common/src/Storage/ITaskTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,20 +235,20 @@ IAsyncEnumerable<string> ListTasksAsync(TaskFilter filter,
/// List all applications extracted from task metadata matching the given filter and ordering
/// </summary>
/// <param name="filter">Filter to select tasks</param>
/// <param name="orderField">Select the field that will be used to order the tasks</param>
/// <param name="orderFields">Select the fields that will be used to order the tasks</param>
/// <param name="ascOrder">Is the order ascending</param>
/// <param name="cancellationToken">Token used to cancel the execution of the method</param>
/// <param name="page">The page of results to retrieve</param>
/// <param name="pageSize">The number of results pages</param>
/// <returns>
/// Collection of applications metadata matching the request and total number of results without paging
/// </returns>
Task<(IEnumerable<Application> applications, int totalCount)> ListApplicationsAsync(Expression<Func<TaskData, bool>> filter,
Expression<Func<Application, object?>> orderField,
bool ascOrder,
int page,
int pageSize,
CancellationToken cancellationToken = default);
Task<(IEnumerable<Application> applications, int totalCount)> ListApplicationsAsync(Expression<Func<TaskData, bool>> filter,
ICollection<Expression<Func<Application, object?>>> orderFields,
bool ascOrder,
int page,
int pageSize,
CancellationToken cancellationToken = default);

/// <summary>
/// Change the status of the task to succeeded
Expand Down
58 changes: 58 additions & 0 deletions Common/src/Utils/IQueryableExt.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// This file is part of the ArmoniK project
//
// Copyright (C) ANEO, 2021-2023. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY, without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace ArmoniK.Core.Common.Utils;

public static class IQueryableExt
{
public static IOrderedQueryable<T> OrderByList<T>(this IQueryable<T> queryable,
ICollection<Expression<Func<T, object?>>> orderFields,
bool ascOrder = true)
{
if (ascOrder)
{
var ordered = queryable.OrderBy(orderFields.First());
if (orderFields.Count > 1)
{
foreach (var expression in orderFields.Skip(1))
{
ordered = ordered.ThenBy(expression);
}
}

return ordered;
}
else
{
var ordered = queryable.OrderByDescending(orderFields.First());
if (orderFields.Count > 1)
{
foreach (var expression in orderFields.Skip(1))
{
ordered = ordered.ThenByDescending(expression);
}
}

return ordered;
}
}
}
4 changes: 2 additions & 2 deletions Common/src/gRPC/ListApplicationsRequestExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ namespace ArmoniK.Core.Common.gRPC;

public static class ListApplicationsRequestExt
{
public static Expression<Func<Application, object?>> ToApplicationField(this ListApplicationsRequest.Types.Sort sort)
public static Expression<Func<Application, object?>> ToApplicationField(this ListApplicationsRequest.Types.OrderByField field)
{
switch (sort.Field)
switch (field)
{
case ListApplicationsRequest.Types.OrderByField.Name:
return taskData => taskData.Name;
Expand Down
3 changes: 2 additions & 1 deletion Common/src/gRPC/Services/GrpcApplicationsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ public override async Task<ListApplicationsResponse> ListApplications(ListApplic
ServerCallContext context)
{
var tasks = await taskTable_.ListApplicationsAsync(request.Filter.ToApplicationFilter(),
request.Sort.ToApplicationField(),
request.Sort.Fields.Select(field => field.ToApplicationField())
.ToList(),
request.Sort.Direction == ListApplicationsRequest.Types.OrderDirection.Asc,
request.Page,
request.PageSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ public ListApplicationsRequestValidator()
.NotNull()
.NotEmpty()
.WithName($"{nameof(ListApplicationsRequest)}.{nameof(ListApplicationsRequest.Sort)}.{nameof(ListApplicationsRequest.Sort.Direction)}");
RuleFor(request => request.Sort.Field)
RuleFor(request => request.Sort.Fields)
.NotNull()
.NotEmpty()
.WithName($"{nameof(ListApplicationsRequest)}.{nameof(ListApplicationsRequest.Sort)}.{nameof(ListApplicationsRequest.Sort.Field)}");
.WithName($"{nameof(ListApplicationsRequest)}.{nameof(ListApplicationsRequest.Sort)}.{nameof(ListApplicationsRequest.Sort.Fields)}");
});
}
}
5 changes: 4 additions & 1 deletion Common/tests/Auth/AuthenticationIntegrationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,10 @@ static AuthenticationIntegrationTest()
Sort = new ListApplicationsRequest.Types.Sort
{
Direction = ListApplicationsRequest.Types.OrderDirection.Asc,
Field = ListApplicationsRequest.Types.OrderByField.Name,
Fields =
{
ListApplicationsRequest.Types.OrderByField.Name,
},
},
};

Expand Down
12 changes: 6 additions & 6 deletions Common/tests/Helpers/SimpleTaskTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,12 @@ public IAsyncEnumerable<string> ListTasksAsync(TaskFilter filter,
"")),
}, 1));

public Task<(IEnumerable<Application> applications, int totalCount)> ListApplicationsAsync(Expression<Func<TaskData, bool>> filter,
Expression<Func<Application, object?>> orderField,
bool ascOrder,
int page,
int pageSize,
CancellationToken cancellationToken = default)
public Task<(IEnumerable<Application> applications, int totalCount)> ListApplicationsAsync(Expression<Func<TaskData, bool>> filter,
ICollection<Expression<Func<Application, object?>>> orderFields,
bool ascOrder,
int page,
int pageSize,
CancellationToken cancellationToken = default)
=> Task.FromResult<(IEnumerable<Application> applications, int totalCount)>((new[]
{
new Application(TaskOptions.ApplicationName,
Expand Down
Loading

0 comments on commit 93ab812

Please sign in to comment.