From 4d9ef959d4fa4c7a270ad1b8fd94931980b49e25 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Mon, 10 Jul 2023 16:10:00 +0200 Subject: [PATCH] Add paging support for skip + take format --- .../Contracts/IWorkflowInstancesApi.cs | 6 +- src/modules/Elsa.Common/Models/PageArgs.cs | 55 ++++++++++++++++--- .../Elsa.Elasticsearch/Common/ElasticStore.cs | 2 +- .../Management/WorkflowInstanceStore.cs | 2 +- .../Runtime/WorkflowExecutionLogStore.cs | 4 +- .../Elsa.EntityFrameworkCore/Common/Store.cs | 1 - .../Endpoints/Labels/List/Models.cs | 2 +- .../WorkflowDefinitions/List/Endpoint.cs | 2 +- .../Journal/List/Endpoint.cs | 2 +- .../WorkflowInstances/Journal/List/Models.cs | 10 ++++ .../WorkflowInstances/List/Endpoint.cs | 2 +- 11 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowInstances/Contracts/IWorkflowInstancesApi.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowInstances/Contracts/IWorkflowInstancesApi.cs index 88476b99e..49e49daab 100644 --- a/src/clients/Elsa.Api.Client/Resources/WorkflowInstances/Contracts/IWorkflowInstancesApi.cs +++ b/src/clients/Elsa.Api.Client/Resources/WorkflowInstances/Contracts/IWorkflowInstancesApi.cs @@ -28,11 +28,11 @@ public interface IWorkflowInstancesApi /// Returns a workflow instance. /// /// The ID of the workflow instance for which to return the journal. - /// The page number. - /// The page size. + /// The number of records to skip. + /// The number of records to return. /// The cancellation token. [Get("/workflow-instances/{workflowInstanceId}/journal")] - Task> GetJournalAsync(string workflowInstanceId, int? page = default, int? pageSize = default, CancellationToken cancellationToken = default); + Task> GetJournalAsync(string workflowInstanceId, int? skip = default, int? take = default, CancellationToken cancellationToken = default); /// /// Deletes a workflow instance. diff --git a/src/modules/Elsa.Common/Models/PageArgs.cs b/src/modules/Elsa.Common/Models/PageArgs.cs index fb678f14d..60cce764e 100644 --- a/src/modules/Elsa.Common/Models/PageArgs.cs +++ b/src/modules/Elsa.Common/Models/PageArgs.cs @@ -3,23 +3,64 @@ namespace Elsa.Common.Models; /// /// Represents pagination arguments. /// -/// The zero-based page number. -/// The number of items per page. -public record PageArgs(int? Page, int? PageSize) +public record PageArgs { + /// + /// Creates pagination arguments from a page number and page size. + /// + /// The zero-based page number. + /// The number of items per page. + public static PageArgs FromPage(int? page, int? pageSize) => new() { Offset = page * pageSize, Limit = pageSize }; + + /// + /// Creates pagination arguments from an offset and limit. + /// + /// The number of items to skip. + /// The number of items to take. + public static PageArgs FromRange(int? offset, int? limit) => new() { Offset = offset, Limit = limit }; + + /// + /// Creates pagination arguments from page and page size or offset and limit. + /// + /// The zero-based page number. + /// The number of items per page. + /// The number of items to skip. + /// The number of items to take. + /// Thrown when neither page and pageSize nor offset and limit are specified. + public static PageArgs From(int? page, int? pageSize, int? offset, int? limit) + { + if(page != null && pageSize != null) + return FromPage(page, pageSize); + + if(offset != null && limit != null) + return FromRange(offset, limit); + + throw new ArgumentException("Either page and pageSize or offset and limit must be specified."); + } + /// /// Gets the offset of the page. /// - public int? Offset => Page * PageSize; + public int? Offset { get; set; } /// - /// Gets the limit of the page. + /// Gets or sets the limit of the page. /// - public int? Limit => PageSize; + public int? Limit { get; set; } + + /// + /// Gets the zero-based page number. + /// + public int? Page => Offset.HasValue && Limit.HasValue ? Offset / Limit : null; + + /// + /// Gets the number of items per page. + /// + public int? PageSize => Limit; /// /// Returns pagination arguments for the next page. /// /// The arguments for the next page. - public PageArgs Next() => this with { Page = Page + 1 }; + public PageArgs Next() => this with { Offset = Page + 1 }; } \ No newline at end of file diff --git a/src/modules/Elsa.Elasticsearch/Common/ElasticStore.cs b/src/modules/Elsa.Elasticsearch/Common/ElasticStore.cs index d8ece6cf1..7dc95aef8 100644 --- a/src/modules/Elsa.Elasticsearch/Common/ElasticStore.cs +++ b/src/modules/Elsa.Elasticsearch/Common/ElasticStore.cs @@ -30,7 +30,7 @@ public class ElasticStore where T : class /// public async Task> SearchAsync(Action> search, CancellationToken cancellationToken = default) { - var page = new PageArgs(0, 1000); + var page = PageArgs.FromPage(0, 1000); var collectedItems = new List(); while(true) diff --git a/src/modules/Elsa.Elasticsearch/Modules/Management/WorkflowInstanceStore.cs b/src/modules/Elsa.Elasticsearch/Modules/Management/WorkflowInstanceStore.cs index aecf45c1e..538cd13c9 100644 --- a/src/modules/Elsa.Elasticsearch/Modules/Management/WorkflowInstanceStore.cs +++ b/src/modules/Elsa.Elasticsearch/Modules/Management/WorkflowInstanceStore.cs @@ -29,7 +29,7 @@ public class ElasticWorkflowInstanceStore : IWorkflowInstanceStore /// public async Task FindAsync(WorkflowInstanceFilter filter, CancellationToken cancellationToken = default) { - var result = await _store.SearchAsync(d => Filter(d, filter), new PageArgs(0, 1), cancellationToken); + var result = await _store.SearchAsync(d => Filter(d, filter), PageArgs.FromRange(0, 1), cancellationToken); return result.Items.FirstOrDefault(); } diff --git a/src/modules/Elsa.Elasticsearch/Modules/Runtime/WorkflowExecutionLogStore.cs b/src/modules/Elsa.Elasticsearch/Modules/Runtime/WorkflowExecutionLogStore.cs index fe568a6d6..de7d3b9cd 100644 --- a/src/modules/Elsa.Elasticsearch/Modules/Runtime/WorkflowExecutionLogStore.cs +++ b/src/modules/Elsa.Elasticsearch/Modules/Runtime/WorkflowExecutionLogStore.cs @@ -40,14 +40,14 @@ public class ElasticWorkflowExecutionLogStore : IWorkflowExecutionLogStore /// public async Task FindAsync(WorkflowExecutionLogRecordFilter filter, CancellationToken cancellationToken = default) { - var result = await _store.SearchAsync(d => Filter(d, filter), new PageArgs(0, 1), cancellationToken); + var result = await _store.SearchAsync(d => Filter(d, filter), PageArgs.FromRange(0, 1), cancellationToken); return result.Items.FirstOrDefault(); } /// public async Task FindAsync(WorkflowExecutionLogRecordFilter filter, WorkflowExecutionLogRecordOrder order, CancellationToken cancellationToken = default) { - var result = await _store.SearchAsync(d => Sort(Filter(d, filter), order), new PageArgs(0, 1), cancellationToken); + var result = await _store.SearchAsync(d => Sort(Filter(d, filter), order), PageArgs.FromRange(0, 1), cancellationToken); return result.Items.FirstOrDefault(); } diff --git a/src/modules/Elsa.EntityFrameworkCore/Common/Store.cs b/src/modules/Elsa.EntityFrameworkCore/Common/Store.cs index bf13688f2..66bd7effb 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Common/Store.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Common/Store.cs @@ -274,7 +274,6 @@ public class Store where TDbContext : DbContext where TEnti var set = dbContext.Set(); var queryable = query(set.AsQueryable()); - queryable = query(queryable); var entities = await queryable.ToListAsync(cancellationToken); if (onLoading != null) diff --git a/src/modules/Elsa.Labels/Endpoints/Labels/List/Models.cs b/src/modules/Elsa.Labels/Endpoints/Labels/List/Models.cs index fe8f04a27..db96f5d51 100644 --- a/src/modules/Elsa.Labels/Endpoints/Labels/List/Models.cs +++ b/src/modules/Elsa.Labels/Endpoints/Labels/List/Models.cs @@ -8,7 +8,7 @@ public class Request public int? Page { get; set; } public int? PageSize { get; set; } - public PageArgs ToPageArgs() => new(Page, PageSize); + public PageArgs ToPageArgs() => PageArgs.FromPage(Page, PageSize); } public class Response diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/List/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/List/Endpoint.cs index 23f28f691..cb5dae8ab 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/List/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/List/Endpoint.cs @@ -27,7 +27,7 @@ internal class List : ElsaEndpoint public override async Task ExecuteAsync(Request request, CancellationToken cancellationToken) { - var pageArgs = new PageArgs(request.Page, request.PageSize); + var pageArgs = PageArgs.FromPage(request.Page, request.PageSize); var filter = CreateFilter(request); var summaries = await FindAsync(request, filter, pageArgs, cancellationToken); diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Journal/List/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Journal/List/Endpoint.cs index 089a7d3e0..401802f2a 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Journal/List/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Journal/List/Endpoint.cs @@ -30,7 +30,7 @@ internal class Get : ElsaEndpoint /// public override async Task ExecuteAsync(Request request, CancellationToken cancellationToken) { - var pageArgs = new PageArgs(request.Page, request.PageSize); + var pageArgs = PageArgs.From(request.Page, request.PageSize, request.Skip, request.Take); var filter = new WorkflowExecutionLogRecordFilter { WorkflowInstanceId = request.WorkflowInstanceId }; var order = new WorkflowExecutionLogRecordOrder(x => x.Sequence, OrderDirection.Ascending); var pageOfRecords = await _store.FindManyAsync(filter, pageArgs, order, cancellationToken); diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Journal/List/Models.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Journal/List/Models.cs index fc9450f67..99c140835 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Journal/List/Models.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Journal/List/Models.cs @@ -23,6 +23,16 @@ internal class Request /// The size of the page to get. /// public int? PageSize { get; set; } + + /// + /// The number of records to skip. + /// + public int? Skip { get; set; } + + /// + /// The number of records to take. + /// + public int? Take { get; set; } } internal class Response diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/List/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/List/Endpoint.cs index 549f77332..843917651 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/List/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/List/Endpoint.cs @@ -28,7 +28,7 @@ internal class List : ElsaEndpoint public override async Task ExecuteAsync(Request request, CancellationToken cancellationToken) { - var pageArgs = new PageArgs(request.Page, request.PageSize); + var pageArgs = PageArgs.FromPage(request.Page, request.PageSize); var filter = new WorkflowInstanceFilter {