Skip to content

Commit

Permalink
Changed contract for ModuleExecutor (#55)
Browse files Browse the repository at this point in the history
* Changed contract for command

* Changed contract for query
  • Loading branch information
adimiko authored Nov 26, 2024
1 parent 8170ea8 commit d488c08
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 64 deletions.
6 changes: 3 additions & 3 deletions source/EasyWay.WebApi/RcpStyleExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static WebKernel MapQuery<TModule, TQuery, TReadModel>(this WebKernel web
{
webKernel.App.MapPost(typeof(TModule).Name + "/_queries/" + typeof(TQuery).Name, async ([FromBody] TQuery query, IModuleExecutor<TModule> executor, CancellationToken cancellationToken) =>
{
var queryResult = await executor.ExecuteQuery<TQuery, TReadModel>(query, cancellationToken);
var queryResult = await executor.Execute(query, cancellationToken);

return queryResult.Error switch
{
Expand All @@ -37,7 +37,7 @@ public static WebKernel MapCommand<TModule, TCommand>(this WebKernel webKernel)
{
webKernel.App.MapPost(typeof(TModule).Name + "/_commands/" + typeof(TCommand).Name, async ([FromBody] TCommand command, IModuleExecutor<TModule> executor, CancellationToken cancellationToken) =>
{
var commandResult = await executor.ExecuteCommand(command, cancellationToken);
var commandResult = await executor.Execute(command, cancellationToken);

return commandResult.Error switch
{
Expand All @@ -57,7 +57,7 @@ public static WebKernel MapCommand<TModule, TCommand, TCommandResult>(this WebKe
{
webKernel.App.MapPost(typeof(TModule).Name + "/_commands/" + typeof(TCommand).Name, async ([FromBody] TCommand command, IModuleExecutor<TModule> executor, CancellationToken cancellationToken) =>
{
var commandResult = await executor.ExecuteCommand<TCommand, TCommandResult>(command, cancellationToken);
var commandResult = await executor.Execute(command, cancellationToken);

return commandResult.Error switch
{
Expand Down
8 changes: 3 additions & 5 deletions source/EasyWay/IModuleExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
public interface IModuleExecutor<TModule>
where TModule : EasyWayModule
{
Task<CommandResult> ExecuteCommand<TCommand>(TCommand command, CancellationToken cancellationToken = default)
Task<CommandResult> Execute<TCommand>(TCommand command, CancellationToken cancellationToken = default)
where TCommand : Command<TModule>;

Task<CommandResult<TOperationResult>> ExecuteCommand<TCommand, TOperationResult>(TCommand command, CancellationToken cancellationToken = default)
where TCommand : Command<TModule, TOperationResult>
Task<CommandResult<TOperationResult>> Execute<TOperationResult>(Command<TModule, TOperationResult> command, CancellationToken cancellationToken = default)
where TOperationResult : OperationResult;

Task<QueryResult<TReadModel>> ExecuteQuery<TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken = default)
where TQuery : Query<TModule, TReadModel>
Task<QueryResult<TReadModel>> Execute<TReadModel>(Query<TModule, TReadModel> query, CancellationToken cancellationToken = default)
where TReadModel : ReadModel;
}
}
34 changes: 0 additions & 34 deletions source/EasyWay/Internals/Commands/CommandExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,39 +55,5 @@ public async Task<CommandResult> Execute<TCommand>(TCommand command, Cancellatio

return commandResult;
}

public async Task<CommandResult<TOperationResult>> Execute<TCommand, TOperationResult>(TCommand command, CancellationToken cancellationToken)
where TCommand : Command<TModule, TOperationResult>
where TOperationResult : OperationResult
{
_cancellationContextConstructor.Set(cancellationToken);

var validator = _serviceProvider.GetService<IValidator<TCommand>>();

if (validator is not null)
{
var result = validator.Validate(command);

if (!result.IsValid)
{
var errors = result.Errors
.GroupBy(x => x.PropertyName)
.ToDictionary(
g => g.Key,
g => g.Select(x => x.ErrorCode).ToArray()
);

return CommandResult<TOperationResult>.Validation(errors);
}
}

var commandResult = await _serviceProvider
.GetRequiredService<ICommandHandler<TModule, TCommand, TOperationResult>>()
.Handle(command);

await _unitOfWorkCommandHandler.Handle();

return commandResult;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using EasyWay.Internals.Contexts;
using FluentValidation;
using FluentValidation.Results;
using Microsoft.Extensions.DependencyInjection;

namespace EasyWay.Internals.Commands
{
internal sealed class CommandWithOperationResultExecutor<TModule> : ICommandWithOperationResultExecutor<TModule>
where TModule : EasyWayModule
{
private readonly IServiceProvider _serviceProvider;

private readonly ICancellationContextConstructor _cancellationContextConstructor;

private readonly IUnitOfWorkCommandHandler _unitOfWorkCommandHandler;

public CommandWithOperationResultExecutor(
IServiceProvider serviceProvider,
ICancellationContextConstructor cancellationContextConstructor,
IUnitOfWorkCommandHandler unitOfWorkCommandHandler)
{
_serviceProvider = serviceProvider;
_cancellationContextConstructor = cancellationContextConstructor;
_unitOfWorkCommandHandler = unitOfWorkCommandHandler;
}

public async Task<CommandResult<TOperationResult>> Execute<TOperationResult>(Command<TModule, TOperationResult> command, CancellationToken cancellationToken)
where TOperationResult : OperationResult
{
_cancellationContextConstructor.Set(cancellationToken);

var commandType = command.GetType();

var validatorType = typeof(IValidator<>).MakeGenericType(commandType);

var validator = _serviceProvider.GetService(validatorType);

if (validator is not null)
{
var result = (ValidationResult)validatorType
.GetMethod("Validate")
?.Invoke(validator, [command]);

if (!result.IsValid)
{
var errors = result.Errors
.GroupBy(x => x.PropertyName)
.ToDictionary(
g => g.Key,
g => g.Select(x => x.ErrorCode).ToArray()
);

return CommandResult<TOperationResult>.Validation(errors);
}
}

var commandHandlerType = typeof(ICommandHandler<,,>).MakeGenericType(typeof(TModule), commandType, typeof(TOperationResult));

var commandHandler = _serviceProvider.GetRequiredService(commandHandlerType);

var commandResult = await (Task<CommandResult<TOperationResult>>)commandHandlerType.GetMethod("Handle").Invoke(commandHandler, [command]);

await _unitOfWorkCommandHandler.Handle();

return commandResult;
}
}
}
1 change: 1 addition & 0 deletions source/EasyWay/Internals/Commands/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ internal static IServiceCollection AddCommands(
IEnumerable<Assembly> assemblies)
{
services.AddScoped(typeof(ICommandExecutor<>).MakeGenericType(moduleType), typeof(CommandExecutor<>).MakeGenericType(moduleType));
services.AddScoped(typeof(ICommandWithOperationResultExecutor<>).MakeGenericType(moduleType), typeof(CommandWithOperationResultExecutor<>).MakeGenericType(moduleType));

services.Scan(s => s.FromAssemblies(assemblies)
.AddClasses(c => c.AssignableTo(typeof(ICommandHandler<,>)))
Expand Down
4 changes: 0 additions & 4 deletions source/EasyWay/Internals/Commands/ICommandExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,5 @@ internal interface ICommandExecutor<TModule>
{
Task<CommandResult> Execute<TCommand>(TCommand command, CancellationToken cancellationToken)
where TCommand : Command<TModule>;

Task<CommandResult<TOperationResult>> Execute<TCommand, TOperationResult>(TCommand command, CancellationToken cancellationToken)
where TCommand : Command<TModule, TOperationResult>
where TOperationResult : OperationResult;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace EasyWay.Internals.Commands
{
internal interface ICommandWithOperationResultExecutor<TModule>
where TModule : EasyWayModule
{
Task<CommandResult<TOperationResult>> Execute<TOperationResult>(Command<TModule, TOperationResult> command, CancellationToken cancellationToken)
where TOperationResult : OperationResult;
}
}
14 changes: 6 additions & 8 deletions source/EasyWay/Internals/Modules/ModuleExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public ModuleExecutor(IServiceProvider serviceProvider)
_serviceProvider = serviceProvider;
}

public async Task<CommandResult> ExecuteCommand<TCommand>(TCommand command, CancellationToken cancellationToken = default)
public async Task<CommandResult> Execute<TCommand>(TCommand command, CancellationToken cancellationToken = default)
where TCommand : Command<TModule>
{
CommandResult commandResult;
Expand All @@ -31,8 +31,7 @@ public async Task<CommandResult> ExecuteCommand<TCommand>(TCommand command, Canc
return commandResult;
}

public async Task<CommandResult<TOperationResult>> ExecuteCommand<TCommand, TOperationResult>(TCommand command, CancellationToken cancellationToken = default)
where TCommand : Command<TModule, TOperationResult>
public async Task<CommandResult<TOperationResult>> Execute<TOperationResult>(Command<TModule, TOperationResult> command, CancellationToken cancellationToken = default)
where TOperationResult : OperationResult
{
CommandResult<TOperationResult> commandResult;
Expand All @@ -42,15 +41,14 @@ public async Task<CommandResult<TOperationResult>> ExecuteCommand<TCommand, TOpe
var sp = scope.ServiceProvider;

commandResult = await sp
.GetRequiredService<ICommandExecutor<TModule>>()
.Execute<TCommand, TOperationResult>(command, cancellationToken);
.GetRequiredService<ICommandWithOperationResultExecutor<TModule>>()
.Execute(command, cancellationToken);
}

return commandResult;
}

public async Task<QueryResult<TReadModel>> ExecuteQuery<TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken = default)
where TQuery : Query<TModule, TReadModel>
public async Task<QueryResult<TReadModel>> Execute<TReadModel>(Query<TModule, TReadModel> query, CancellationToken cancellationToken = default)
where TReadModel : ReadModel
{
QueryResult<TReadModel> result;
Expand All @@ -61,7 +59,7 @@ public async Task<QueryResult<TReadModel>> ExecuteQuery<TQuery, TReadModel>(TQue

result = await sp
.GetRequiredService<IQueryExecutor<TModule>>()
.Execute<TQuery, TReadModel>(query, cancellationToken);
.Execute(query, cancellationToken);
}

return result;
Expand Down
3 changes: 1 addition & 2 deletions source/EasyWay/Internals/Queries/IQueryExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
internal interface IQueryExecutor<TModule>
where TModule : EasyWayModule
{
Task<QueryResult<TReadModel>> Execute<TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken)
where TQuery : Query<TModule, TReadModel>
Task<QueryResult<TReadModel>> Execute<TReadModel>(Query<TModule, TReadModel> query, CancellationToken cancellationToken)
where TReadModel : ReadModel;
}
}
25 changes: 17 additions & 8 deletions source/EasyWay/Internals/Queries/QueryExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using EasyWay.Internals.Contexts;
using FluentValidation;
using FluentValidation.Results;
using Microsoft.Extensions.DependencyInjection;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace EasyWay.Internals.Queries
{
Expand All @@ -20,17 +20,22 @@ public QueryExecutor(
_cancellationContextConstructor = cancellationContextConstructor;
}

public async Task<QueryResult<TReadModel>> Execute<TQuery, TReadModel>(TQuery query, CancellationToken cancellationToken)
where TQuery : Query<TModule, TReadModel>
public async Task<QueryResult<TReadModel>> Execute<TReadModel>(Query<TModule, TReadModel> query, CancellationToken cancellationToken)
where TReadModel : ReadModel
{
_cancellationContextConstructor.Set(cancellationToken);

var validator = _serviceProvider.GetService<IValidator<TQuery>>();
var queryType = query.GetType();

var validatorType = typeof(IValidator<>).MakeGenericType(queryType);

var validator = _serviceProvider.GetService(validatorType);

if (validator is not null)
{
var result = validator.Validate(query);
var result = (ValidationResult)validatorType
.GetMethod("Validate")
?.Invoke(validator, [query]);

if (!result.IsValid)
{
Expand All @@ -45,9 +50,13 @@ public async Task<QueryResult<TReadModel>> Execute<TQuery, TReadModel>(TQuery qu
}
}

return await _serviceProvider
.GetRequiredService<IQueryHandler<TModule, TQuery, TReadModel>>()
.Handle(query);
var queryHandlerType = typeof(IQueryHandler<,,>).MakeGenericType(typeof(TModule), queryType, typeof(TReadModel));

var queryHandler = _serviceProvider.GetRequiredService(queryHandlerType);

var queryResult = await (Task<QueryResult<TReadModel>>) queryHandlerType.GetMethod("Handle").Invoke(queryHandler, [query]);

return queryResult;
}
}
}

0 comments on commit d488c08

Please sign in to comment.