diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs
index 15d255e73..23fed1f70 100644
--- a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs
+++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs
@@ -1,5 +1,6 @@
using Elsa.Api.Client.Models;
using Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
+using JetBrains.Annotations;
using Refit;
namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts;
@@ -7,6 +8,7 @@ namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts;
///
/// Represents a client for the workflow definitions API.
///
+[PublicAPI]
public interface IWorkflowDefinitionsApi
{
///
@@ -27,8 +29,24 @@ public interface IWorkflowDefinitionsApi
/// Whether to include the root activity of composite activities.
/// The cancellation token.
/// The workflow definition.
- [Get("/workflow-definitions/{definitionId}?versionOptions={VersionOptions}&includeCompositeRoot={includeCompositeRoot}")]
+ [Get("/workflow-definitions/{definitionId}?versionOptions={versionOptions}&includeCompositeRoot={includeCompositeRoot}")]
Task GetAsync(string definitionId, VersionOptions? versionOptions = default, bool includeCompositeRoot = false, CancellationToken cancellationToken = default);
+
+ ///
+ /// Gets the number of workflow definitions.
+ ///
+ /// The cancellation token.
+ [Get("/workflow-definitions/query/count")]
+ Task CountAsync(CancellationToken cancellationToken = default);
+
+ ///
+ /// Gets a value indicating whether a workflow definition name is unique.
+ ///
+ /// The name to check.
+ /// The cancellation token.
+ /// A response containing a value indicating whether the name is unique.
+ [Get("/workflow-definitions/validation/is-name-unique?name={name}")]
+ Task GetIsNameUniqueAsync(string name, CancellationToken cancellationToken = default);
///
/// Saves a workflow definition.
diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/CountWorkflowDefinitionsResponse.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/CountWorkflowDefinitionsResponse.cs
new file mode 100644
index 000000000..c19a98856
--- /dev/null
+++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/CountWorkflowDefinitionsResponse.cs
@@ -0,0 +1,6 @@
+namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
+
+///
+/// A response containing the number of workflow definitions.
+///
+public record CountWorkflowDefinitionsResponse(long Count);
\ No newline at end of file
diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/GetIsNameUniqueResponse.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/GetIsNameUniqueResponse.cs
new file mode 100644
index 000000000..c7f4ff548
--- /dev/null
+++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/GetIsNameUniqueResponse.cs
@@ -0,0 +1,7 @@
+namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
+
+///
+/// A response containing a value indicating whether a workflow definition name is unique.
+///
+/// true if the name is unique, otherwise false.
+public record GetIsNameUniqueResponse(bool IsUnique);
\ No newline at end of file
diff --git a/src/modules/Elsa.Common/Services/MemoryStore.cs b/src/modules/Elsa.Common/Services/MemoryStore.cs
index e261352fe..b1ebac9e5 100644
--- a/src/modules/Elsa.Common/Services/MemoryStore.cs
+++ b/src/modules/Elsa.Common/Services/MemoryStore.cs
@@ -152,4 +152,17 @@ public class MemoryStore
/// The predicate to match.
/// True if any entity matches the specified predicate, otherwise false.
public bool AnyAsync(Func predicate) => Entities.Values.Any(predicate);
+
+ ///
+ /// Returns the number of entities matching the specified predicate.
+ ///
+ /// The predicate to match.
+ /// The property to distinct by.
+ /// True if any entity matches the specified predicate, otherwise false.
+ public long CountAsync(Func predicate, Func propertySelector)
+ {
+ return Entities.Values
+ .DistinctBy(propertySelector)
+ .Count(predicate);
+ }
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Dapper/Abstractions/SqlDialectBase.cs b/src/modules/Elsa.Dapper/Abstractions/SqlDialectBase.cs
index 39c3c5462..64f96b17b 100644
--- a/src/modules/Elsa.Dapper/Abstractions/SqlDialectBase.cs
+++ b/src/modules/Elsa.Dapper/Abstractions/SqlDialectBase.cs
@@ -22,7 +22,10 @@ public abstract class SqlDialectBase : ISqlDialect
public string Delete(string table) => $"delete from {table} where 1=1";
///
- public string Count(string table) => $"select COUNT(*) from {table} where 1=1";
+ public string Count(string table) => Count("*", table);
+
+ ///
+ public string Count(string fieldExpression, string table) => $"select COUNT({fieldExpression}) from {table} where 1=1";
///
public virtual string And(string field) => $"and {field} = @{field}";
diff --git a/src/modules/Elsa.Dapper/Contracts/ISqlDialect.cs b/src/modules/Elsa.Dapper/Contracts/ISqlDialect.cs
index 94b5877e5..b7ecc5314 100644
--- a/src/modules/Elsa.Dapper/Contracts/ISqlDialect.cs
+++ b/src/modules/Elsa.Dapper/Contracts/ISqlDialect.cs
@@ -31,6 +31,13 @@ public interface ISqlDialect
///
/// The table to query.
string Count(string table);
+
+ ///
+ /// Returns a SELECT count(fieldExpression) FROM query.
+ ///
+ /// The field expression to query. Examples: "*", "distinct FieldName"
+ /// The table to query.
+ string Count(string fieldExpression, string table);
///
/// Returns an AND clause.
diff --git a/src/modules/Elsa.Dapper/Extensions/ParameterizedQueryBuilderExtensions.cs b/src/modules/Elsa.Dapper/Extensions/ParameterizedQueryBuilderExtensions.cs
index bac9afa63..bd805fb00 100644
--- a/src/modules/Elsa.Dapper/Extensions/ParameterizedQueryBuilderExtensions.cs
+++ b/src/modules/Elsa.Dapper/Extensions/ParameterizedQueryBuilderExtensions.cs
@@ -81,6 +81,18 @@ public static class ParameterizedQueryBuilderExtensions
return query;
}
+ ///
+ /// Begins a SELECT COUNT(expression) FROM query.
+ ///
+ /// The query.
+ /// The expression. Examples: "*" or "DISTINCT FieldName"
+ /// The table.
+ public static ParameterizedQuery Count(this ParameterizedQuery query, string expression, string table)
+ {
+ query.Sql.AppendLine(query.Dialect.Count(expression, table));
+ return query;
+ }
+
///
/// Appends an AND clause to the query if the value is not null.
///
diff --git a/src/modules/Elsa.Dapper/Modules/Management/Services/DapperWorkflowDefinitionStore.cs b/src/modules/Elsa.Dapper/Modules/Management/Services/DapperWorkflowDefinitionStore.cs
index 90802f584..81a1448c9 100644
--- a/src/modules/Elsa.Dapper/Modules/Management/Services/DapperWorkflowDefinitionStore.cs
+++ b/src/modules/Elsa.Dapper/Modules/Management/Services/DapperWorkflowDefinitionStore.cs
@@ -142,6 +142,14 @@ public class DapperWorkflowDefinitionStore : IWorkflowDefinitionStore
return await _store.AnyAsync(q => ApplyFilter(q, filter), cancellationToken);
}
+ ///
+ public async Task CountDistinctAsync(CancellationToken cancellationToken = default)
+ {
+ return await _store.CountAsync(
+ filter => filter.Count($"distinct {nameof(WorkflowDefinition.DefinitionId)}", TableName),
+ cancellationToken);
+ }
+
private void ApplyFilter(ParameterizedQuery query, WorkflowDefinitionFilter filter)
{
ParameterizedQueryBuilderExtensions.Equals(query
diff --git a/src/modules/Elsa.EntityFrameworkCore/Common/Store.cs b/src/modules/Elsa.EntityFrameworkCore/Common/Store.cs
index 220ce135a..bf13688f2 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Common/Store.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Common/Store.cs
@@ -305,4 +305,33 @@ public class Store where TDbContext : DbContext where TEnti
var set = dbContext.Set();
return await set.AnyAsync(predicate, cancellationToken);
}
+
+ ///
+ /// Counts the number of entities matching a predicate.
+ ///
+ /// The predicate.
+ /// The cancellation token.
+ public async Task CountAsync(Expression> predicate, CancellationToken cancellationToken = default)
+ {
+ await using var dbContext = await CreateDbContextAsync(cancellationToken);
+ var set = dbContext.Set();
+ return await set.CountAsync(predicate, cancellationToken);
+ }
+
+ ///
+ /// Counts the distinct number of entities matching a predicate.
+ ///
+ /// The predicate.
+ /// The property selector to distinct by.
+ /// The cancellation token.
+ public async Task CountAsync(Expression> predicate, Expression> propertySelector, CancellationToken cancellationToken = default)
+ {
+ await using var dbContext = await CreateDbContextAsync(cancellationToken);
+ var set = dbContext.Set();
+ return await set
+ .Where(predicate)
+ .Select(propertySelector)
+ .Distinct()
+ .CountAsync(cancellationToken);
+ }
}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionStore.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionStore.cs
index 1afd5a797..0a37bdd4d 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionStore.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionStore.cs
@@ -141,6 +141,12 @@ public class EFCoreWorkflowDefinitionStore : IWorkflowDefinitionStore
///
public async Task AnyAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToken = default) => await _store.QueryAsync(queryable => Filter(queryable, filter), cancellationToken).Any();
+ ///
+ public async Task CountDistinctAsync(CancellationToken cancellationToken = default)
+ {
+ return await _store.CountAsync(x => true, x => x.DefinitionId, cancellationToken);
+ }
+
private ValueTask SaveAsync(ManagementElsaDbContext managementElsaDbContext, WorkflowDefinition entity, CancellationToken cancellationToken)
{
var data = new WorkflowDefinitionState(entity.Options, entity.Variables, entity.Inputs, entity.Outputs, entity.Outcomes, entity.CustomProperties);
diff --git a/src/modules/Elsa.MongoDb/Common/MongoDbStore.cs b/src/modules/Elsa.MongoDb/Common/MongoDbStore.cs
index 6d88dbd74..0f882ac13 100644
--- a/src/modules/Elsa.MongoDb/Common/MongoDbStore.cs
+++ b/src/modules/Elsa.MongoDb/Common/MongoDbStore.cs
@@ -133,6 +133,12 @@ public class MongoDbStore where TDocument : class
public async Task CountAsync(Func, IMongoQueryable> query, CancellationToken cancellationToken = default) =>
await query(_collection.AsQueryable()).LongCountAsync(cancellationToken);
+ ///
+ /// Counts documents in the collection using a filter and distinct by a key selector.
+ ///
+ public async Task CountAsync(Func, IMongoQueryable> query, Expression> propertySelector, CancellationToken cancellationToken = default) =>
+ await query((IMongoQueryable)_collection.AsQueryable().DistinctBy(propertySelector)).LongCountAsync(cancellationToken);
+
///
/// Checks if any documents exist.
///
diff --git a/src/modules/Elsa.MongoDb/Modules/Management/WorkflowDefinitionStore.cs b/src/modules/Elsa.MongoDb/Modules/Management/WorkflowDefinitionStore.cs
index 7ab0c0d5f..c7196f514 100644
--- a/src/modules/Elsa.MongoDb/Modules/Management/WorkflowDefinitionStore.cs
+++ b/src/modules/Elsa.MongoDb/Modules/Management/WorkflowDefinitionStore.cs
@@ -59,11 +59,11 @@ public class MongoWorkflowDefinitionStore : IWorkflowDefinitionStore
}
///
- public async Task> FindManyAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToken = default) =>
+ public async Task> FindManyAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToken = default) =>
await _mongoDbStore.FindManyAsync(queryable => Filter(queryable, filter), cancellationToken);
///
- public async Task> FindManyAsync(WorkflowDefinitionFilter filter, WorkflowDefinitionOrder order, CancellationToken cancellationToken = default) =>
+ public async Task> FindManyAsync(WorkflowDefinitionFilter filter, WorkflowDefinitionOrder order, CancellationToken cancellationToken = default) =>
await _mongoDbStore.FindManyAsync(queryable => Order(Filter(queryable, filter), order), cancellationToken);
///
@@ -106,11 +106,11 @@ public class MongoWorkflowDefinitionStore : IWorkflowDefinitionStore
}
///
- public async Task SaveAsync(WorkflowDefinition definition, CancellationToken cancellationToken = default) =>
+ public async Task SaveAsync(WorkflowDefinition definition, CancellationToken cancellationToken = default) =>
await _mongoDbStore.SaveAsync(definition, cancellationToken);
///
- public async Task SaveManyAsync(IEnumerable definitions, CancellationToken cancellationToken = default) =>
+ public async Task SaveManyAsync(IEnumerable definitions, CancellationToken cancellationToken = default) =>
await _mongoDbStore.SaveManyAsync(definitions.Select(i => i), cancellationToken);
///
@@ -123,18 +123,26 @@ public class MongoWorkflowDefinitionStore : IWorkflowDefinitionStore
}
///
- public async Task AnyAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToken = default) =>
- await _mongoDbStore.FindManyAsync(queryable => Filter(queryable, filter), cancellationToken).Any();
+ public async Task AnyAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToken = default)
+ {
+ return await _mongoDbStore.FindManyAsync(queryable => Filter(queryable, filter), cancellationToken).Any();
+ }
- private IMongoQueryable Filter(IMongoQueryable queryable, WorkflowDefinitionFilter filter) =>
+ ///
+ public async Task CountDistinctAsync(CancellationToken cancellationToken = default)
+ {
+ return await _mongoDbStore.CountAsync(queryable => queryable, x => x.DefinitionId, cancellationToken);
+ }
+
+ private IMongoQueryable Filter(IMongoQueryable queryable, WorkflowDefinitionFilter filter) =>
(filter.Apply(queryable) as IMongoQueryable)!;
- private IMongoQueryable Order(IMongoQueryable queryable, WorkflowDefinitionOrder order) =>
+ private IMongoQueryable Order(IMongoQueryable queryable, WorkflowDefinitionOrder order) =>
(queryable.OrderBy(order) as IMongoQueryable)!;
-
- private IMongoQueryable Paginate(IMongoQueryable queryable, PageArgs pageArgs) =>
+
+ private IMongoQueryable Paginate(IMongoQueryable queryable, PageArgs pageArgs) =>
(queryable.Paginate(pageArgs) as IMongoQueryable)!;
-
- private IMongoQueryable OrderAndPaginate(IMongoQueryable queryable, WorkflowDefinitionOrder order, PageArgs pageArgs) =>
+
+ private IMongoQueryable OrderAndPaginate(IMongoQueryable queryable, WorkflowDefinitionOrder order, PageArgs pageArgs) =>
(queryable.OrderBy(order).Paginate(pageArgs) as IMongoQueryable)!;
-}
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Count/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Count/Endpoint.cs
new file mode 100644
index 000000000..238cf9c2e
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Count/Endpoint.cs
@@ -0,0 +1,39 @@
+using Elsa.Abstractions;
+using Elsa.Common.Entities;
+using Elsa.Common.Models;
+using Elsa.Workflows.Core.Contracts;
+using Elsa.Workflows.Core.Serialization.Converters;
+using Elsa.Workflows.Management.Contracts;
+using Elsa.Workflows.Management.Filters;
+using Elsa.Workflows.Management.Mappers;
+using JetBrains.Annotations;
+using Microsoft.AspNetCore.Http;
+
+namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.Count;
+
+///
+/// An endpoint for counting workflow definitions.
+///
+[PublicAPI]
+internal class Count : ElsaEndpointWithoutRequest
+{
+ private readonly IWorkflowDefinitionStore _store;
+
+ public Count(IWorkflowDefinitionStore store)
+ {
+ _store = store;
+ }
+
+ public override void Configure()
+ {
+ Get("/workflow-definitions/query/count");
+ ConfigurePermissions("read:workflow-definitions");
+ }
+
+ public override async Task HandleAsync(CancellationToken cancellationToken)
+ {
+ var count = await _store.CountDistinctAsync(cancellationToken);
+ var response = new Response(count);
+ await SendOkAsync(response, cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Count/Models.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Count/Models.cs
new file mode 100644
index 000000000..17477507f
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Count/Models.cs
@@ -0,0 +1,3 @@
+namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.Count;
+
+internal record Response(long Count);
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/IsNameUnique/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/IsNameUnique/Endpoint.cs
new file mode 100644
index 000000000..39e02f5a6
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/IsNameUnique/Endpoint.cs
@@ -0,0 +1,45 @@
+using Elsa.Abstractions;
+using Elsa.Common.Entities;
+using Elsa.Common.Models;
+using Elsa.Workflows.Core.Contracts;
+using Elsa.Workflows.Core.Serialization.Converters;
+using Elsa.Workflows.Management.Contracts;
+using Elsa.Workflows.Management.Filters;
+using Elsa.Workflows.Management.Mappers;
+using JetBrains.Annotations;
+using Microsoft.AspNetCore.Http;
+
+namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.IsNameUnique;
+
+///
+/// Checks if a workflow definition name is unique.
+///
+[PublicAPI]
+internal class IsNameUnique : ElsaEndpoint
+{
+ private readonly IWorkflowDefinitionStore _store;
+
+ public IsNameUnique(IWorkflowDefinitionStore store)
+ {
+ _store = store;
+ }
+
+ public override void Configure()
+ {
+ Get("/workflow-definitions/validation/is-name-unique");
+ ConfigurePermissions("read:workflow-definitions");
+ }
+
+ public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
+ {
+ var filter = new WorkflowDefinitionFilter
+ {
+ Name = request.Name.Trim()
+ };
+
+ var exists = await _store.AnyAsync(filter, cancellationToken);
+ var response = new Response(!exists);
+
+ await SendOkAsync(response, cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/IsNameUnique/Models.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/IsNameUnique/Models.cs
new file mode 100644
index 000000000..349c9110f
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/IsNameUnique/Models.cs
@@ -0,0 +1,8 @@
+namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.IsNameUnique;
+
+internal class Request
+{
+ public string Name { get; set; } = default!;
+}
+
+internal record Response(bool IsUnique);
diff --git a/src/modules/Elsa.Workflows.Api/Extensions/ApplicationBuilderExtensions.cs b/src/modules/Elsa.Workflows.Api/Extensions/ApplicationBuilderExtensions.cs
index a164a9a45..019cfafca 100644
--- a/src/modules/Elsa.Workflows.Api/Extensions/ApplicationBuilderExtensions.cs
+++ b/src/modules/Elsa.Workflows.Api/Extensions/ApplicationBuilderExtensions.cs
@@ -4,7 +4,13 @@ using Microsoft.AspNetCore.Builder;
// ReSharper disable once CheckNamespace
namespace Elsa.Extensions;
+///
+/// Provides extensions to .
+///
public static class ApplicationBuilderExtensions
{
+ ///
+ /// Adds middleware that handles JSON serialization errors.
+ ///
public static IApplicationBuilder UseJsonSerializationErrorHandler(this IApplicationBuilder app) => app.UseMiddleware();
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Api/Extensions/ModuleExtensions.cs b/src/modules/Elsa.Workflows.Api/Extensions/ModuleExtensions.cs
index 13171af63..b302aeb9e 100644
--- a/src/modules/Elsa.Workflows.Api/Extensions/ModuleExtensions.cs
+++ b/src/modules/Elsa.Workflows.Api/Extensions/ModuleExtensions.cs
@@ -4,8 +4,14 @@ using Elsa.Workflows.Api.Features;
// ReSharper disable once CheckNamespace
namespace Elsa.Extensions;
+///
+/// Provides extensions to .
+///
public static class ModuleExtensions
{
+ ///
+ /// Configures the workflows API feature.
+ ///
public static IModule UseWorkflowsApi(this IModule module, Action? configure = default)
{
module.Configure(configure);
diff --git a/src/modules/Elsa.Workflows.Api/Extensions/WorkflowsApiFeatureExtensions.cs b/src/modules/Elsa.Workflows.Api/Extensions/WorkflowsApiFeatureExtensions.cs
index 514f9679f..418e1f482 100644
--- a/src/modules/Elsa.Workflows.Api/Extensions/WorkflowsApiFeatureExtensions.cs
+++ b/src/modules/Elsa.Workflows.Api/Extensions/WorkflowsApiFeatureExtensions.cs
@@ -3,8 +3,14 @@ using Elsa.Workflows.Api.Features;
// ReSharper disable once CheckNamespace
namespace Elsa.Extensions;
+///
+/// Provides extensions to .
+///
public static class WorkflowsApiFeatureExtensions
{
+ ///
+ /// Adds FastEndpoint endpoints from the assembly containing .
+ ///
public static WorkflowsApiFeature AddFastEndpointsAssembly(this WorkflowsApiFeature feature)
{
feature.Module.AddFastEndpointsAssembly();
diff --git a/src/modules/Elsa.Workflows.Management/Contracts/IWorkflowDefinitionStore.cs b/src/modules/Elsa.Workflows.Management/Contracts/IWorkflowDefinitionStore.cs
index 7432c6db2..e323d4af3 100644
--- a/src/modules/Elsa.Workflows.Management/Contracts/IWorkflowDefinitionStore.cs
+++ b/src/modules/Elsa.Workflows.Management/Contracts/IWorkflowDefinitionStore.cs
@@ -141,4 +141,9 @@ public interface IWorkflowDefinitionStore
/// The cancellation token.
/// True if any workflow definition matches the specified filter.
Task AnyAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToken = default);
+
+ ///
+ /// Returns the number of logical workflow definitions.
+ ///
+ Task CountDistinctAsync(CancellationToken cancellationToken = default);
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Management/Services/MemoryWorkflowDefinitionStore.cs b/src/modules/Elsa.Workflows.Management/Services/MemoryWorkflowDefinitionStore.cs
index 166ab10e5..2c4d1ca84 100644
--- a/src/modules/Elsa.Workflows.Management/Services/MemoryWorkflowDefinitionStore.cs
+++ b/src/modules/Elsa.Workflows.Management/Services/MemoryWorkflowDefinitionStore.cs
@@ -137,7 +137,12 @@ public class MemoryWorkflowDefinitionStore : IWorkflowDefinitionStore
var exists = _store.Query(query => Filter(query, filter)).Any();
return Task.FromResult(exists);
}
-
+
+ public Task CountDistinctAsync(CancellationToken cancellationToken = default)
+ {
+ throw new NotImplementedException();
+ }
+
private IQueryable Filter(IQueryable queryable, WorkflowDefinitionFilter filter) => filter.Apply(queryable);
private string GetId(WorkflowDefinition workflowDefinition) => workflowDefinition.Id;