Browse Source

Factory refactored.

pull/95/head
Sebastian Stehle 9 years ago
parent
commit
8448b26cb5
  1. 1
      Squidex.sln.DotSettings
  2. 81
      src/Squidex.Infrastructure/CQRS/Commands/AggregateHandler.cs
  3. 21
      src/Squidex.Infrastructure/CQRS/Commands/DefaultDomainObjectRepository.cs
  4. 2
      src/Squidex.Infrastructure/CQRS/Commands/IDomainObjectRepository.cs
  5. 11
      src/Squidex.Infrastructure/Dispatching/ActionContextDispatcher.cs
  6. 11
      src/Squidex.Infrastructure/Dispatching/ActionDispatcher.cs
  7. 11
      src/Squidex.Infrastructure/Dispatching/FuncContextDispatcher.cs
  8. 11
      src/Squidex.Infrastructure/Dispatching/FuncDispatcher.cs
  9. 22
      src/Squidex.Infrastructure/Dispatching/Helper.cs
  10. 2
      src/Squidex/Config/Domain/WriteModule.cs
  11. 2
      src/Squidex/Pipeline/CommandHandlers/ETagCommandMiddleware.cs
  12. 2
      src/Squidex/Pipeline/CommandHandlers/EnrichWithActorCommandMiddleware.cs
  13. 2
      src/Squidex/Pipeline/CommandHandlers/EnrichWithAppIdCommandMiddleware.cs
  14. 2
      src/Squidex/Pipeline/CommandHandlers/EnrichWithSchemaIdCommandMiddleware.cs
  15. 26
      tests/Squidex.Infrastructure.Tests/CQRS/Commands/AggregateHandlerTests.cs
  16. 10
      tests/Squidex.Infrastructure.Tests/CQRS/Commands/DefaultDomainObjectRepositoryTests.cs

1
Squidex.sln.DotSettings

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=CommandHandlerMiddleware_002Ecs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002A_002A_002Ejs/@EntryIndexedValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002A_002A_002Ejs/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002A_002A_002Ejs/@EntryIndexRemoved">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002A_002A_002Ejs/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002F_002A_002A_002F_002A_002Ejs/@EntryIndexedValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002F_002A_002A_002F_002A_002Ejs/@EntryIndexedValue">False</s:Boolean>

81
src/Squidex.Infrastructure/CQRS/Commands/AggregateHandler.cs

@ -10,6 +10,9 @@ using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.CQRS.Events;
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
// ReSharper disable InvertIf
namespace Squidex.Infrastructure.CQRS.Commands namespace Squidex.Infrastructure.CQRS.Commands
{ {
public sealed class AggregateHandler : IAggregateHandler public sealed class AggregateHandler : IAggregateHandler
@ -17,16 +20,6 @@ namespace Squidex.Infrastructure.CQRS.Commands
private readonly IDomainObjectRepository domainObjectRepository; private readonly IDomainObjectRepository domainObjectRepository;
private readonly IDomainObjectFactory domainObjectFactory; private readonly IDomainObjectFactory domainObjectFactory;
public IDomainObjectRepository Repository
{
get { return domainObjectRepository; }
}
public IDomainObjectFactory Factory
{
get { return domainObjectFactory; }
}
public AggregateHandler( public AggregateHandler(
IDomainObjectFactory domainObjectFactory, IDomainObjectFactory domainObjectFactory,
IDomainObjectRepository domainObjectRepository) IDomainObjectRepository domainObjectRepository)
@ -38,44 +31,58 @@ namespace Squidex.Infrastructure.CQRS.Commands
this.domainObjectRepository = domainObjectRepository; this.domainObjectRepository = domainObjectRepository;
} }
public async Task<T> CreateAsync<T>(CommandContext context, Func<T, Task> creator) where T : class, IAggregate public Task<T> CreateAsync<T>(CommandContext context, Func<T, Task> creator) where T : class, IAggregate
{ {
Guard.NotNull(creator, nameof(creator)); Guard.NotNull(creator, nameof(creator));
Guard.NotNull(context, nameof(context));
var aggregateCommand = GetCommand(context);
var aggregate = domainObjectFactory.CreateNew<T>(aggregateCommand.AggregateId);
await creator(aggregate);
await SaveAsync(aggregate); return InvokeAsync(context, creator, false);
}
if (!context.IsCompleted) public Task<T> UpdateAsync<T>(CommandContext context, Func<T, Task> updater) where T : class, IAggregate
{ {
context.Complete(new EntityCreatedResult<Guid>(aggregate.Id, aggregate.Version)); Guard.NotNull(updater, nameof(updater));
}
return aggregate; return InvokeAsync(context, updater, true);
} }
public async Task<T> UpdateAsync<T>(CommandContext context, Func<T, Task> updater) where T : class, IAggregate private async Task<T> InvokeAsync<T>(CommandContext context, Func<T, Task> handler, bool isUpdate) where T : class, IAggregate
{ {
Guard.NotNull(updater, nameof(updater));
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
var aggregateCommand = GetCommand(context); var aggregateCommand = GetCommand(context);
var aggregate = await domainObjectRepository.GetByIdAsync<T>(aggregateCommand.AggregateId, aggregateCommand.ExpectedVersion); var aggregateObject = domainObjectFactory.CreateNew<T>(aggregateCommand.AggregateId);
await updater(aggregate); if (isUpdate)
{
await domainObjectRepository.LoadAsync(aggregateObject, aggregateCommand.ExpectedVersion);
}
await handler(aggregateObject);
var events = aggregateObject.GetUncomittedEvents();
foreach (var @event in events)
{
@event.SetAggregateId(aggregateObject.Id);
}
await domainObjectRepository.SaveAsync(aggregateObject, events, Guid.NewGuid());
await SaveAsync(aggregate); aggregateObject.ClearUncommittedEvents();
if (!context.IsCompleted) if (!context.IsCompleted)
{ {
context.Complete(new EntitySavedResult(aggregate.Version)); if (isUpdate)
{
context.Complete(new EntitySavedResult(aggregateObject.Version));
}
else
{
context.Complete(EntityCreatedResult.Create(aggregateObject.Id, aggregateObject.Version));
}
} }
return aggregate; return aggregateObject;
} }
private static IAggregateCommand GetCommand(CommandContext context) private static IAggregateCommand GetCommand(CommandContext context)
@ -91,19 +98,5 @@ namespace Squidex.Infrastructure.CQRS.Commands
return command; return command;
} }
private async Task SaveAsync(IAggregate aggregate)
{
var events = aggregate.GetUncomittedEvents();
foreach (var @event in events)
{
@event.SetAggregateId(aggregate.Id);
}
await domainObjectRepository.SaveAsync(aggregate, events, Guid.NewGuid());
aggregate.ClearUncommittedEvents();
}
} }
} }

21
src/Squidex.Infrastructure/CQRS/Commands/DefaultDomainObjectRepository.cs

@ -17,40 +17,31 @@ namespace Squidex.Infrastructure.CQRS.Commands
public sealed class DefaultDomainObjectRepository : IDomainObjectRepository public sealed class DefaultDomainObjectRepository : IDomainObjectRepository
{ {
private readonly IStreamNameResolver nameResolver; private readonly IStreamNameResolver nameResolver;
private readonly IDomainObjectFactory factory;
private readonly IEventStore eventStore; private readonly IEventStore eventStore;
private readonly EventDataFormatter formatter; private readonly EventDataFormatter formatter;
public DefaultDomainObjectRepository( public DefaultDomainObjectRepository(IEventStore eventStore, IStreamNameResolver nameResolver, EventDataFormatter formatter)
IDomainObjectFactory factory,
IEventStore eventStore,
IStreamNameResolver nameResolver,
EventDataFormatter formatter)
{ {
Guard.NotNull(factory, nameof(factory));
Guard.NotNull(formatter, nameof(formatter)); Guard.NotNull(formatter, nameof(formatter));
Guard.NotNull(eventStore, nameof(eventStore)); Guard.NotNull(eventStore, nameof(eventStore));
Guard.NotNull(nameResolver, nameof(nameResolver)); Guard.NotNull(nameResolver, nameof(nameResolver));
this.factory = factory;
this.formatter = formatter; this.formatter = formatter;
this.eventStore = eventStore; this.eventStore = eventStore;
this.nameResolver = nameResolver; this.nameResolver = nameResolver;
} }
public async Task<T> GetByIdAsync<T>(Guid id, long? expectedVersion = null) where T : class, IAggregate public async Task LoadAsync(IAggregate domainObject, long? expectedVersion = null)
{ {
var streamName = nameResolver.GetStreamName(typeof(T), id); var streamName = nameResolver.GetStreamName(domainObject.GetType(), domainObject.Id);
var events = await eventStore.GetEventsAsync(streamName); var events = await eventStore.GetEventsAsync(streamName);
if (events.Count == 0) if (events.Count == 0)
{ {
throw new DomainObjectNotFoundException(id.ToString(), typeof(T)); throw new DomainObjectNotFoundException(domainObject.Id.ToString(), domainObject.GetType());
} }
var domainObject = factory.CreateNew<T>(id);
foreach (var storedEvent in events) foreach (var storedEvent in events)
{ {
var envelope = ParseKnownCommand(storedEvent); var envelope = ParseKnownCommand(storedEvent);
@ -63,10 +54,8 @@ namespace Squidex.Infrastructure.CQRS.Commands
if (expectedVersion != null && domainObject.Version != expectedVersion.Value) if (expectedVersion != null && domainObject.Version != expectedVersion.Value)
{ {
throw new DomainObjectVersionException(id.ToString(), typeof(T), domainObject.Version, expectedVersion.Value); throw new DomainObjectVersionException(domainObject.Id.ToString(), domainObject.GetType(), domainObject.Version, expectedVersion.Value);
} }
return domainObject;
} }
public async Task SaveAsync(IAggregate domainObject, ICollection<Envelope<IEvent>> events, Guid commitId) public async Task SaveAsync(IAggregate domainObject, ICollection<Envelope<IEvent>> events, Guid commitId)

2
src/Squidex.Infrastructure/CQRS/Commands/IDomainObjectRepository.cs

@ -15,7 +15,7 @@ namespace Squidex.Infrastructure.CQRS.Commands
{ {
public interface IDomainObjectRepository public interface IDomainObjectRepository
{ {
Task<T> GetByIdAsync<T>(Guid id, long? expectedVersion = null) where T : class, IAggregate; Task LoadAsync(IAggregate domainObject, long? expectedVersion = null);
Task SaveAsync(IAggregate domainObject, ICollection<Envelope<IEvent>> events, Guid commitId); Task SaveAsync(IAggregate domainObject, ICollection<Envelope<IEvent>> events, Guid commitId);
} }

11
src/Squidex.Infrastructure/Dispatching/ActionContextDispatcher.cs

@ -28,14 +28,15 @@ namespace Squidex.Infrastructure.Dispatching
BindingFlags.Public | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.NonPublic |
BindingFlags.Instance) BindingFlags.Instance)
.Where(m => Helper.HasRightName(m, methodName)) .Where(m =>
.Where(m => Helper.HasRightParameters<TIn, TContext>(m)) m.HasMatchingName(methodName) &&
.Where(m => Helper.HasRightVoidReturn(m)) m.HasMatchingParameters<TIn, TContext>() &&
m.HasMatchingReturnType(typeof(void)))
.Select(m => .Select(m =>
{ {
var inputType = m.GetParameters()[0].ParameterType; var inputType = m.GetParameters()[0].ParameterType;
var factoryMethod = var handler =
typeof(ActionContextDispatcher<TTarget, TIn, TContext>) typeof(ActionContextDispatcher<TTarget, TIn, TContext>)
.GetMethod(nameof(Factory), .GetMethod(nameof(Factory),
BindingFlags.Static | BindingFlags.Static |
@ -43,7 +44,7 @@ namespace Squidex.Infrastructure.Dispatching
.MakeGenericMethod(inputType) .MakeGenericMethod(inputType)
.Invoke(null, new object[] { m }); .Invoke(null, new object[] { m });
return (inputType, factoryMethod); return (inputType, handler);
}) })
.ToDictionary(m => m.Item1, h => (ActionContextDelegate<TIn>)h.Item2); .ToDictionary(m => m.Item1, h => (ActionContextDelegate<TIn>)h.Item2);

11
src/Squidex.Infrastructure/Dispatching/ActionDispatcher.cs

@ -28,14 +28,15 @@ namespace Squidex.Infrastructure.Dispatching
BindingFlags.Public | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.NonPublic |
BindingFlags.Instance) BindingFlags.Instance)
.Where(m => Helper.HasRightName(m, methodName)) .Where(m =>
.Where(m => Helper.HasRightParameters<TIn>(m)) m.HasMatchingName(methodName) &&
.Where(m => Helper.HasRightVoidReturn(m)) m.HasMatchingParameters<TIn>() &&
m.HasMatchingReturnType(typeof(void)))
.Select(m => .Select(m =>
{ {
var inputType = m.GetParameters()[0].ParameterType; var inputType = m.GetParameters()[0].ParameterType;
var factoryMethod = var handler =
typeof(ActionDispatcher<TTarget, TIn>) typeof(ActionDispatcher<TTarget, TIn>)
.GetMethod(nameof(Factory), .GetMethod(nameof(Factory),
BindingFlags.Static | BindingFlags.Static |
@ -43,7 +44,7 @@ namespace Squidex.Infrastructure.Dispatching
.MakeGenericMethod(inputType) .MakeGenericMethod(inputType)
.Invoke(null, new object[] { m }); .Invoke(null, new object[] { m });
return (inputType, factoryMethod); return (inputType, handler);
}) })
.ToDictionary(m => m.Item1, h => (ActionDelegate<TIn>)h.Item2); .ToDictionary(m => m.Item1, h => (ActionDelegate<TIn>)h.Item2);

11
src/Squidex.Infrastructure/Dispatching/FuncContextDispatcher.cs

@ -27,14 +27,15 @@ namespace Squidex.Infrastructure.Dispatching
BindingFlags.Public | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.NonPublic |
BindingFlags.Instance) BindingFlags.Instance)
.Where(m => Helper.HasRightName(m, methodName)) .Where(m =>
.Where(m => Helper.HasRightParameters<TIn, TContext>(m)) m.HasMatchingName(methodName) &&
.Where(m => Helper.HasRightReturnType<TOut>(m)) m.HasMatchingParameters<TIn, TContext>() &&
m.HasMatchingReturnType(typeof(TOut)))
.Select(m => .Select(m =>
{ {
var inputType = m.GetParameters()[0].ParameterType; var inputType = m.GetParameters()[0].ParameterType;
var factoryMethod = var handler =
typeof(FuncContextDispatcher<TTarget, TIn, TContext, TOut>) typeof(FuncContextDispatcher<TTarget, TIn, TContext, TOut>)
.GetMethod(nameof(Factory), .GetMethod(nameof(Factory),
BindingFlags.Static | BindingFlags.Static |
@ -42,7 +43,7 @@ namespace Squidex.Infrastructure.Dispatching
.MakeGenericMethod(inputType) .MakeGenericMethod(inputType)
.Invoke(null, new object[] { m }); .Invoke(null, new object[] { m });
return (inputType, factoryMethod); return (inputType, handler);
}) })
.ToDictionary(m => m.Item1, h => (FuncContextDelegate<TIn>)h.Item2); .ToDictionary(m => m.Item1, h => (FuncContextDelegate<TIn>)h.Item2);

11
src/Squidex.Infrastructure/Dispatching/FuncDispatcher.cs

@ -27,14 +27,15 @@ namespace Squidex.Infrastructure.Dispatching
BindingFlags.Public | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.NonPublic |
BindingFlags.Instance) BindingFlags.Instance)
.Where(m => Helper.HasRightName(m, methodName)) .Where(m =>
.Where(m => Helper.HasRightParameters<TIn>(m)) m.HasMatchingName(methodName) &&
.Where(m => Helper.HasRightReturnType<TOut>(m)) m.HasMatchingParameters<TIn>() &&
m.HasMatchingReturnType(typeof(TOut)))
.Select(m => .Select(m =>
{ {
var inputType = m.GetParameters()[0].ParameterType; var inputType = m.GetParameters()[0].ParameterType;
var factoryMethod = var handler =
typeof(FuncDispatcher<TTarget, TIn, TOut>) typeof(FuncDispatcher<TTarget, TIn, TOut>)
.GetMethod(nameof(Factory), .GetMethod(nameof(Factory),
BindingFlags.Static | BindingFlags.Static |
@ -42,7 +43,7 @@ namespace Squidex.Infrastructure.Dispatching
.MakeGenericMethod(inputType) .MakeGenericMethod(inputType)
.Invoke(null, new object[] { m }); .Invoke(null, new object[] { m });
return (inputType, factoryMethod); return (inputType, handler);
}) })
.ToDictionary(m => m.Item1, h => (FuncDelegate<TIn>)h.Item2); .ToDictionary(m => m.Item1, h => (FuncDelegate<TIn>)h.Item2);

22
src/Squidex.Infrastructure/Dispatching/Helper.cs

@ -13,34 +13,24 @@ namespace Squidex.Infrastructure.Dispatching
{ {
internal static class Helper internal static class Helper
{ {
public static bool HasRightName(MethodInfo method, string name) public static bool HasMatchingName(this MethodInfo method, string name)
{ {
return string.Equals(method.Name, name, StringComparison.OrdinalIgnoreCase); return string.Equals(method.Name, name, StringComparison.OrdinalIgnoreCase);
} }
public static bool HasRightName(MethodInfo method) public static bool HasMatchingReturnType(this MethodInfo method, Type type)
{
return string.Equals(method.Name, "On", StringComparison.OrdinalIgnoreCase);
}
public static bool HasRightReturnType<TOut>(MethodInfo method)
{
return method.ReturnType == typeof(TOut);
}
public static bool HasRightVoidReturn(MethodInfo method)
{ {
return method.ReturnType == typeof(void); return method.ReturnType == type;
} }
public static bool HasRightParameters<TIn>(MethodInfo method) public static bool HasMatchingParameters<TIn>(this MethodInfo method)
{ {
var parameters = method.GetParameters(); var parameters = method.GetParameters();
return parameters.Length == 1 && typeof(TIn).IsAssignableFrom(parameters[0].ParameterType); return parameters.Length == 1 && typeof(TIn).IsAssignableFrom(parameters[0].ParameterType);
} }
public static bool HasRightParameters<TIn, TContext>(MethodInfo method) public static bool HasMatchingParameters<TIn, TContext>(this MethodInfo method)
{ {
var parameters = method.GetParameters(); var parameters = method.GetParameters();

2
src/Squidex/Config/Domain/WriteModule.cs

@ -14,7 +14,7 @@ using Squidex.Domain.Apps.Write.Assets;
using Squidex.Domain.Apps.Write.Contents; using Squidex.Domain.Apps.Write.Contents;
using Squidex.Domain.Apps.Write.Schemas; using Squidex.Domain.Apps.Write.Schemas;
using Squidex.Infrastructure.CQRS.Commands; using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Pipeline.CommandMiddlewares; using Squidex.Pipeline.CommandHandlers;
// ReSharper disable UnusedAutoPropertyAccessor.Local // ReSharper disable UnusedAutoPropertyAccessor.Local

2
src/Squidex/Pipeline/CommandHandlers/ETagCommandMiddleware.cs

@ -13,7 +13,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Squidex.Infrastructure.CQRS.Commands; using Squidex.Infrastructure.CQRS.Commands;
namespace Squidex.Pipeline.CommandMiddlewares namespace Squidex.Pipeline.CommandHandlers
{ {
public class ETagCommandMiddleware : ICommandMiddleware public class ETagCommandMiddleware : ICommandMiddleware
{ {

2
src/Squidex/Pipeline/CommandHandlers/EnrichWithActorCommandMiddleware.cs

@ -17,7 +17,7 @@ using Squidex.Infrastructure.Security;
// ReSharper disable InvertIf // ReSharper disable InvertIf
namespace Squidex.Pipeline.CommandMiddlewares namespace Squidex.Pipeline.CommandHandlers
{ {
public class EnrichWithActorCommandMiddleware : ICommandMiddleware public class EnrichWithActorCommandMiddleware : ICommandMiddleware
{ {

2
src/Squidex/Pipeline/CommandHandlers/EnrichWithAppIdCommandMiddleware.cs

@ -15,7 +15,7 @@ using Squidex.Infrastructure.CQRS.Commands;
// ReSharper disable InvertIf // ReSharper disable InvertIf
namespace Squidex.Pipeline.CommandMiddlewares namespace Squidex.Pipeline.CommandHandlers
{ {
public sealed class EnrichWithAppIdCommandMiddleware : ICommandMiddleware public sealed class EnrichWithAppIdCommandMiddleware : ICommandMiddleware
{ {

2
src/Squidex/Pipeline/CommandHandlers/EnrichWithSchemaIdCommandMiddleware.cs

@ -18,7 +18,7 @@ using Squidex.Infrastructure.CQRS.Commands;
// ReSharper disable InvertIf // ReSharper disable InvertIf
namespace Squidex.Pipeline.CommandMiddlewares namespace Squidex.Pipeline.CommandHandlers
{ {
public sealed class EnrichWithSchemaIdCommandMiddleware : ICommandMiddleware public sealed class EnrichWithSchemaIdCommandMiddleware : ICommandMiddleware
{ {

26
tests/Squidex.Infrastructure.Tests/CQRS/Commands/AggregateHandlerTests.cs

@ -53,7 +53,6 @@ namespace Squidex.Infrastructure.CQRS.Commands
private readonly Envelope<IEvent> event1 = new Envelope<IEvent>(new MyEvent()); private readonly Envelope<IEvent> event1 = new Envelope<IEvent>(new MyEvent());
private readonly Envelope<IEvent> event2 = new Envelope<IEvent>(new MyEvent()); private readonly Envelope<IEvent> event2 = new Envelope<IEvent>(new MyEvent());
private readonly CommandContext context; private readonly CommandContext context;
private readonly MyCommand command;
private readonly AggregateHandler sut; private readonly AggregateHandler sut;
private readonly MyDomainObject domainObject; private readonly MyDomainObject domainObject;
@ -66,20 +65,7 @@ namespace Squidex.Infrastructure.CQRS.Commands
.RaiseNewEvent(event1) .RaiseNewEvent(event1)
.RaiseNewEvent(event2); .RaiseNewEvent(event2);
command = new MyCommand { AggregateId = domainObject.Id }; context = new CommandContext(new MyCommand { AggregateId = domainObject.Id });
context = new CommandContext(command);
}
[Fact]
public void Should_provide_access_to_factory()
{
Assert.Equal(factory, sut.Factory);
}
[Fact]
public void Should_provide_access_to_repository()
{
Assert.Equal(repository, sut.Repository);
} }
[Fact] [Fact]
@ -143,8 +129,8 @@ namespace Squidex.Infrastructure.CQRS.Commands
[Fact] [Fact]
public async Task Update_async_should_create_domain_object_and_save() public async Task Update_async_should_create_domain_object_and_save()
{ {
A.CallTo(() => repository.GetByIdAsync<MyDomainObject>(command.AggregateId, null)) A.CallTo(() => factory.CreateNew<MyDomainObject>(domainObject.Id))
.Returns(Task.FromResult(domainObject)); .Returns(domainObject);
A.CallTo(() => repository.SaveAsync(domainObject, A<ICollection<Envelope<IEvent>>>.Ignored, A<Guid>.Ignored)) A.CallTo(() => repository.SaveAsync(domainObject, A<ICollection<Envelope<IEvent>>>.Ignored, A<Guid>.Ignored))
.Returns(TaskHelper.Done); .Returns(TaskHelper.Done);
@ -161,14 +147,15 @@ namespace Squidex.Infrastructure.CQRS.Commands
Assert.Equal(domainObject, passedDomainObject); Assert.Equal(domainObject, passedDomainObject);
Assert.NotNull(context.Result<EntitySavedResult>()); Assert.NotNull(context.Result<EntitySavedResult>());
A.CallTo(() => repository.LoadAsync(domainObject, null)).MustHaveHappened();
A.CallTo(() => repository.SaveAsync(domainObject, A<ICollection<Envelope<IEvent>>>.Ignored, A<Guid>.Ignored)).MustHaveHappened(); A.CallTo(() => repository.SaveAsync(domainObject, A<ICollection<Envelope<IEvent>>>.Ignored, A<Guid>.Ignored)).MustHaveHappened();
} }
[Fact] [Fact]
public async Task Update_sync_should_create_domain_object_and_save() public async Task Update_sync_should_create_domain_object_and_save()
{ {
A.CallTo(() => repository.GetByIdAsync<MyDomainObject>(command.AggregateId, null)) A.CallTo(() => factory.CreateNew<MyDomainObject>(domainObject.Id))
.Returns(Task.FromResult(domainObject)); .Returns(domainObject);
A.CallTo(() => repository.SaveAsync(domainObject, A<ICollection<Envelope<IEvent>>>.Ignored, A<Guid>.Ignored)) A.CallTo(() => repository.SaveAsync(domainObject, A<ICollection<Envelope<IEvent>>>.Ignored, A<Guid>.Ignored))
.Returns(TaskHelper.Done); .Returns(TaskHelper.Done);
@ -183,6 +170,7 @@ namespace Squidex.Infrastructure.CQRS.Commands
Assert.Equal(domainObject, passedDomainObject); Assert.Equal(domainObject, passedDomainObject);
Assert.NotNull(context.Result<EntitySavedResult>()); Assert.NotNull(context.Result<EntitySavedResult>());
A.CallTo(() => repository.LoadAsync(domainObject, null)).MustHaveHappened();
A.CallTo(() => repository.SaveAsync(domainObject, A<ICollection<Envelope<IEvent>>>.Ignored, A<Guid>.Ignored)).MustHaveHappened(); A.CallTo(() => repository.SaveAsync(domainObject, A<ICollection<Envelope<IEvent>>>.Ignored, A<Guid>.Ignored)).MustHaveHappened();
} }
} }

10
tests/Squidex.Infrastructure.Tests/CQRS/Commands/DefaultDomainObjectRepositoryTests.cs

@ -40,7 +40,7 @@ namespace Squidex.Infrastructure.CQRS.Commands
A.CallTo(() => factory.CreateNew<MyDomainObject>(aggregateId)) A.CallTo(() => factory.CreateNew<MyDomainObject>(aggregateId))
.Returns(domainObject); .Returns(domainObject);
sut = new DefaultDomainObjectRepository(factory, eventStore, streamNameResolver, eventDataFormatter); sut = new DefaultDomainObjectRepository(eventStore, streamNameResolver, eventDataFormatter);
} }
public sealed class MyEvent : IEvent public sealed class MyEvent : IEvent
@ -77,7 +77,7 @@ namespace Squidex.Infrastructure.CQRS.Commands
A.CallTo(() => eventStore.GetEventsAsync(streamName)) A.CallTo(() => eventStore.GetEventsAsync(streamName))
.Returns(Task.FromResult<IReadOnlyList<StoredEvent>>(new List<StoredEvent>())); .Returns(Task.FromResult<IReadOnlyList<StoredEvent>>(new List<StoredEvent>()));
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.GetByIdAsync<MyDomainObject>(aggregateId)); await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.LoadAsync(domainObject, -1));
} }
[Fact] [Fact]
@ -103,9 +103,9 @@ namespace Squidex.Infrastructure.CQRS.Commands
A.CallTo(() => eventDataFormatter.Parse(eventData2)) A.CallTo(() => eventDataFormatter.Parse(eventData2))
.Returns(new Envelope<IEvent>(event2)); .Returns(new Envelope<IEvent>(event2));
var result = await sut.GetByIdAsync<MyDomainObject>(aggregateId); await sut.LoadAsync(domainObject);
Assert.Equal(result.AppliedEvents, new[] { event1, event2 }); Assert.Equal(domainObject.AppliedEvents, new[] { event1, event2 });
} }
[Fact] [Fact]
@ -131,7 +131,7 @@ namespace Squidex.Infrastructure.CQRS.Commands
A.CallTo(() => eventDataFormatter.Parse(eventData2)) A.CallTo(() => eventDataFormatter.Parse(eventData2))
.Returns(new Envelope<IEvent>(event2)); .Returns(new Envelope<IEvent>(event2));
await Assert.ThrowsAsync<DomainObjectVersionException>(() => sut.GetByIdAsync<MyDomainObject>(aggregateId, 200)); await Assert.ThrowsAsync<DomainObjectVersionException>(() => sut.LoadAsync(domainObject, 200));
} }
[Fact] [Fact]

Loading…
Cancel
Save