Compare commits

..

No commits in common. "main" and "0.2.1" have entirely different histories.
main ... 0.2.1

11 changed files with 45 additions and 78 deletions

View File

@ -4,6 +4,7 @@ updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
target-branch: dev
schedule:
interval: "daily"
reviewers:
@ -12,6 +13,7 @@ updates:
# Maintain dependencies for nuget
- package-ecosystem: "nuget"
directory: "/"
target-branch: dev
schedule:
interval: "daily"
reviewers:

View File

@ -8,15 +8,15 @@ Workflower is a library based on .NET Standard, To handle Finite State Machines
Install the latest nuget package into your ASP.NET Core application.
```sh
dotnet add package DIT.Workflower
```
```sh
dotnet add package DIT.Workflower
```
You can also download support for Dependency Injection:
You can also download support for Dependency Injection:
```sh
dotnet add package DIT.Workflower.DependencyInjection
```
```sh
dotnet add package DIT.Workflower.DependencyInjection
```
### Workflow Builder

View File

@ -17,7 +17,7 @@ public interface IWorkflow<TState, TCommand, TContext>
/// <typeparam name="TCommand">The type of the workflow command.</typeparam>
/// <typeparam name="TContext">The type of the workflow context.</typeparam>
/// <returns>A list of transition definitions.</returns>
public List<TransitionDefinition<TState, TCommand, ContextWrapper<TContext>>> GetAllTransitionDefinitions();
public List<TransitionDefinition<TState, TCommand, TContext>> GetAllTransitionDefinitions();
/// <summary>
/// Gets a list of allowed transitions without any condition checks.

View File

@ -1,3 +1,3 @@
namespace DIT.Workflower.DependencyInjection;
public record ContextWrapper<TContext>(TContext Context, IServiceProvider ServiceProvider);
public record DIContextWrapper<TContext>(TContext Context, IServiceProvider ServiceProvider);

View File

@ -16,14 +16,14 @@
<!-- Deterministic Builds -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>
<ItemGroup >
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" Condition="'$(TargetFramework)' == 'net7.0'" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" Condition="'$(TargetFramework)' == 'net8.0'" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0" Condition="'$(TargetFramework)' == 'net7.0'" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0" Condition="'$(TargetFramework)' == 'net8.0'" />
</ItemGroup>
<ItemGroup>

View File

@ -2,10 +2,10 @@
namespace DIT.Workflower.DependencyInjection.Extensions;
public static class ServiceCollectionExtensions
public static class IServiceCollectionExtensions
{
public static ITransitionStart<TState, TCommand, ContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(
this IServiceCollection services, in int version = 1)
public static ITransitionStart<TState, TCommand, DIContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, in int version = 1)
where TState : struct
where TCommand : struct
{
@ -13,27 +13,25 @@ public static class ServiceCollectionExtensions
return AddWorkflowDefinition<TState, TCommand, TContext>(services, id, version);
}
public static ITransitionStart<TState, TCommand, ContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(
this IServiceCollection services, in string id)
public static ITransitionStart<TState, TCommand, DIContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, in string id)
where TState : struct
where TCommand : struct
{
return AddWorkflowDefinition<TState, TCommand, TContext>(services, id, version: 1);
}
public static ITransitionStart<TState, TCommand, ContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(
this IServiceCollection services, string id, int version)
public static ITransitionStart<TState, TCommand, DIContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, string id, int version)
where TState : struct
where TCommand : struct
{
var builder = WorkflowDefinitionBuilder<TState, TCommand, ContextWrapper<TContext>>.Create();
var definition = (WorkflowDefinitionBuilder<TState, TCommand, ContextWrapper<TContext>>)builder;
var builder = WorkflowDefinitionBuilder<TState, TCommand, DIContextWrapper<TContext>>.Create();
services.TryAddScoped<IWorkflowFactory<TState, TCommand, TContext>, DefaultWorkflowFactory<TState, TCommand, TContext>>();
services.TryAddSingleton<IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>, DefaultWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>>();
services.AddScoped<IWorkflow<TState, TCommand, TContext>, WorkflowDefinitionWrapper<TState, TCommand, TContext>>(sp =>
services.AddSingleton<IWorkflow<TState, TCommand, DIContextWrapper<TContext>>, WorkflowDefinitionWrapper<TState, TCommand, DIContextWrapper<TContext>>>(sp =>
{
var wrapper = new WorkflowDefinitionWrapper<TState, TCommand, TContext>(definition, sp, id, version);
var definition = (WorkflowDefinitionBuilder<TState, TCommand, DIContextWrapper<TContext>>)builder;
var wrapper = new WorkflowDefinitionWrapper<TState, TCommand, DIContextWrapper<TContext>>(definition, id, version);
return wrapper;
});

View File

@ -1,22 +1,22 @@
namespace DIT.Workflower.DependencyInjection.Extensions;
public static class ServiceProviderExtensions
public static class IServiceProviderExtensions
{
public static IWorkflowFactory<TState, TCommand, TContext> GetRequiredWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
public static IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>> GetRequiredWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
where TState : struct
where TCommand : struct
{
return sp.GetRequiredService<IWorkflowFactory<TState, TCommand, TContext>>();
return sp.GetRequiredService<IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>>();
}
public static IWorkflowFactory<TState, TCommand, TContext>? GetWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
public static IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>? GetWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
where TState : struct
where TCommand : struct
{
return sp.GetService<IWorkflowFactory<TState, TCommand, TContext>>();
return sp.GetService<IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>>();
}
public static IWorkflow<TState, TCommand, TContext> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, int version = 1)
public static IWorkflow<TState, TCommand, DIContextWrapper<TContext>> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, int version = 1)
where TState : struct
where TCommand : struct
{
@ -24,7 +24,7 @@ public static class ServiceProviderExtensions
return factory.CreateWorkflow(version);
}
public static IWorkflow<TState, TCommand, TContext> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, string id, int version = 1)
public static IWorkflow<TState, TCommand, DIContextWrapper<TContext>> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, string id, int version = 1)
where TState : struct
where TCommand : struct
{

View File

@ -1,56 +1,21 @@
namespace DIT.Workflower.DependencyInjection;
public sealed class WorkflowDefinitionWrapper<TState, TCommand, TContext> : IWorkflow<TState, TCommand, TContext>
public record WorkflowDefinitionWrapper<TState, TCommand, TContext> : WorkflowDefinition<TState, TCommand, TContext>, IWorkflow<TState, TCommand, TContext>
where TState : struct
where TCommand : struct
{
private readonly IServiceProvider _serviceProvider;
private readonly WorkflowDefinition<TState, TCommand, ContextWrapper<TContext>> _definition;
public string Id { get; }
public int Version { get; }
public List<TransitionDefinition<TState, TCommand, ContextWrapper<TContext>>> GetAllTransitionDefinitions()
public WorkflowDefinitionWrapper(WorkflowDefinitionBuilder<TState, TCommand, TContext> builder, string id, int version)
: base(builder.Transitions)
{
return _definition.GetAllTransitionDefinitions();
}
public List<Transition<TState, TCommand>> GetAllowedTransitions(TState from)
{
return _definition.GetAllowedTransitions(from);
}
public List<Transition<TState, TCommand>> GetAllowedTransitions(TContext context, TState from)
{
return _definition.GetAllowedTransitions(GetContextWrapper(context), from);
}
public IEnumerable<Transition<TState, TCommand>> GetAllowedTransitions(ListTransitionsRequest<TState, TCommand, TContext> request)
{
var wrappedRequest = new ListTransitionsRequest<TState, TCommand, ContextWrapper<TContext>>
{
From = request.From,
To = request.To,
Command = request.Command,
Context = request.Context is null ? null : GetContextWrapper(request.Context)
};
return _definition.GetAllowedTransitions(wrappedRequest);
}
public WorkflowDefinitionWrapper(WorkflowDefinitionBuilder<TState, TCommand, ContextWrapper<TContext>> builder, IServiceProvider serviceProvider, string id, int version)
{
_definition = builder.Build();
_serviceProvider = serviceProvider;
Id = id;
Version = version;
}
private ContextWrapper<TContext> GetContextWrapper(in TContext context)
=> new(context, _serviceProvider);
public static string GetDefaultId()
{
var ctxType = typeof(TContext);

View File

@ -17,7 +17,7 @@
<!-- Deterministic Builds -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>

View File

@ -1,6 +1,6 @@
namespace DIT.Workflower;
public class WorkflowDefinition<TState, TCommand, TContext>
public record WorkflowDefinition<TState, TCommand, TContext>
where TState : struct
where TCommand : struct
{
@ -41,24 +41,24 @@ public class WorkflowDefinition<TState, TCommand, TContext>
{
var query = _transitions.AsQueryable();
if (request.From is { } from)
if (request.From is TState from)
{
query = query.Where(doc => doc.From.Equals(from));
}
if (request.To is { } to)
if (request.To is TState to)
{
query = query.Where(doc => doc.To.Equals(to));
}
if (request.Command is { } command)
if (request.Command is TCommand command)
{
query = query.Where(doc => doc.Command.Equals(command));
}
if (request.Context is not null)
{
query = query.Where(doc => doc.Conditions == null || doc.Conditions.All(cond => cond(request.Context)));
query = query.Where(doc => doc.Conditions == null || !doc.Conditions.Any(cond => !cond(request.Context)));
}
return query.Select(x => x.ToTransition());

View File

@ -1,4 +1,5 @@
using DIT.Workflower.DependencyInjection.Extensions;
using DIT.Workflower.DependencyInjection.Abstractions;
using DIT.Workflower.DependencyInjection.Extensions;
using Microsoft.Extensions.DependencyInjection;
namespace DIT.Workflower.Tests.DependencyInjection;
@ -48,6 +49,7 @@ public class DependencyInjectionTests
Assert.NotNull(v1);
Assert.NotNull(v2);
Assert.Single(v1!.GetAllowedTransitions(PhoneState.Idle));
Assert.Single(v2!.GetAllowedTransitions(PhoneState.Idle));