Skip to content

Commit

Permalink
Made projection context available when determining the projection key…
Browse files Browse the repository at this point in the history
… in CrudAction (#119)
  • Loading branch information
Jubast authored and dennisdoomen committed Aug 21, 2019
1 parent d065a5d commit 0db776b
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 35 deletions.
70 changes: 60 additions & 10 deletions Src/LiquidProjections/EventMapBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,24 @@ public IEventMap<TContext> Build(ProjectorMap<TProjection, TKey, TContext> proje
private sealed class CrudAction<TEvent> : ICrudAction<TEvent, TProjection, TKey, TContext>
{
private readonly IAction<TEvent, TContext> actionBuilder;
private readonly Func<ProjectorMap<TProjection, TKey, TContext> > getProjector;
private readonly Func<ProjectorMap<TProjection, TKey, TContext>> getProjector;

public CrudAction(EventMapBuilder<TProjection, TKey, TContext> parent)
{
actionBuilder = parent.innerBuilder.Map<TEvent>();
getProjector = () => parent.projector;
}

public ICreateAction<TEvent, TProjection, TContext> AsCreateOf(Func<TEvent, TContext, TKey> getKey)
{
if (getKey == null)
{
throw new ArgumentNullException(nameof(getKey));
}

return new CreateAction(actionBuilder, getProjector, getKey);
}

public ICreateAction<TEvent, TProjection, TContext> AsCreateOf(Func<TEvent, TKey> getKey)
{
if (getKey == null)
Expand Down Expand Up @@ -218,6 +228,16 @@ public CrudAction(EventMapBuilder<TProjection, TKey, TContext> parent)
return new DeleteAction(actionBuilder, getProjector, getKey);
}

public IDeleteAction<TEvent, TKey, TContext> AsDeleteOf(Func<TEvent, TContext, TKey> getKey)
{
if (getKey == null)
{
throw new ArgumentNullException(nameof(getKey));
}

return new DeleteAction(actionBuilder, getProjector, getKey);
}

public IDeleteAction<TEvent, TKey, TContext> AsDeleteIfExistsOf(Func<TEvent, TKey> getKey)
{
return AsDeleteOf(getKey).IgnoringMisses();
Expand All @@ -230,6 +250,16 @@ public CrudAction(EventMapBuilder<TProjection, TKey, TContext> parent)
throw new ArgumentNullException(nameof(getKey));
}

return new UpdateAction(actionBuilder, getProjector, (anEvent, context) => getKey(anEvent));
}

public IUpdateAction<TEvent, TKey, TProjection, TContext> AsUpdateOf(Func<TEvent, TContext, TKey> getKey)
{
if (getKey == null)
{
throw new ArgumentNullException(nameof(getKey));
}

return new UpdateAction(actionBuilder, getProjector, getKey);
}

Expand Down Expand Up @@ -267,15 +297,27 @@ private sealed class CreateAction : ICreateAction<TEvent, TProjection, TContext>

private readonly IAction<TEvent, TContext> actionBuilder;
private readonly Func<ProjectorMap<TProjection, TKey, TContext>> projector;
private readonly Func<TEvent, TKey> getKey;
private readonly Func<TEvent, TContext, TKey> getKey;

public CreateAction(IAction<TEvent, TContext> actionBuilder,
Func<ProjectorMap<TProjection, TKey, TContext>> projector, Func<TEvent, TKey> getKey)
Func<ProjectorMap<TProjection, TKey, TContext>> projector, Func<TEvent, TContext, TKey> getKey)
{
this.actionBuilder = actionBuilder;
this.projector = projector;
this.getKey = getKey;

shouldOverwrite = (existingProjection, @event, context) =>
throw new ProjectionException(
$"Projection {typeof(TProjection)} with key {getKey(@event,context)}already exists.");
}

public CreateAction(IAction<TEvent, TContext> actionBuilder,
Func<ProjectorMap<TProjection, TKey, TContext>> projector, Func<TEvent, TKey> getKey)
{
this.actionBuilder = actionBuilder;
this.projector = projector;
this.getKey = (@event, context) =>getKey(@event);

shouldOverwrite = (existingProjection, @event, context) =>
throw new ProjectionException(
$"Projection {typeof(TProjection)} with key {getKey(@event)}already exists.");
Expand All @@ -289,7 +331,7 @@ private sealed class CreateAction : ICreateAction<TEvent, TProjection, TContext>
}

actionBuilder.As((anEvent, context) => this.projector().Create(
getKey(anEvent),
getKey(anEvent,context),
context,
projection => projector(projection, anEvent, context),
existingProjection => shouldOverwrite(existingProjection, anEvent, context)));
Expand Down Expand Up @@ -320,11 +362,11 @@ private sealed class UpdateAction : IUpdateAction<TEvent, TKey, TProjection, TCo
{
private readonly IAction<TEvent, TContext> actionBuilder;
private readonly Func<ProjectorMap<TProjection, TKey, TContext>> projector;
private readonly Func<TEvent, TKey> getKey;
private readonly Func<TEvent, TContext, TKey> getKey;
private Func<TKey, TContext, bool> handleMissesUsing;

public UpdateAction(IAction<TEvent, TContext> actionBuilder,
Func<ProjectorMap<TProjection, TKey, TContext>> projector, Func<TEvent, TKey> getKey)
Func<ProjectorMap<TProjection, TKey, TContext>> projector, Func<TEvent, TContext, TKey> getKey)
{
this.projector = projector;
this.actionBuilder = actionBuilder;
Expand All @@ -347,7 +389,7 @@ private sealed class UpdateAction : IUpdateAction<TEvent, TKey, TProjection, TCo

private async Task OnUpdate(Func<TProjection, TEvent, TContext, Task> projector, TEvent anEvent, TContext context)
{
var key = getKey(anEvent);
var key = getKey(anEvent,context);

await this.projector().Update(
key,
Expand Down Expand Up @@ -386,16 +428,24 @@ private class DeleteAction : IDeleteAction<TEvent, TKey, TContext>
private Action<TKey, TContext> handleMissing;

public DeleteAction(IAction<TEvent, TContext> actionBuilder,
Func<ProjectorMap<TProjection, TKey, TContext>> projector, Func<TEvent, TKey> getKey)
Func<ProjectorMap<TProjection, TKey, TContext>> projector, Func<TEvent, TContext, TKey> getKey)
{
actionBuilder.As((anEvent, context) => OnDelete(projector(), getKey, anEvent, context));

ThrowingIfMissing();
}

private async Task OnDelete(ProjectorMap<TProjection, TKey, TContext> projector, Func<TEvent, TKey> getKey, TEvent anEvent, TContext context)
public DeleteAction(IAction<TEvent, TContext> actionBuilder,
Func<ProjectorMap<TProjection, TKey, TContext>> projector, Func<TEvent, TKey> getKey)
{
actionBuilder.As((anEvent, context) => OnDelete(projector(), (anEvent1, context1) => getKey(anEvent1), anEvent, context));

ThrowingIfMissing();
}

private async Task OnDelete(ProjectorMap<TProjection, TKey, TContext> projector, Func<TEvent, TContext, TKey> getKey, TEvent anEvent, TContext context)
{
TKey key = getKey(anEvent);
TKey key = getKey(anEvent, context);
bool deleted = await projector.Delete(key, context);
if (!deleted)
{
Expand Down
32 changes: 31 additions & 1 deletion Src/LiquidProjections/MapBuilding/IAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ public interface ICrudAction<TEvent, TProjection, TKey, TContext> : IAction<TEve
/// </returns>
ICreateAction<TEvent, TProjection, TContext> AsCreateOf(Func<TEvent, TKey> getKey);

/// <summary>
/// Continues configuring a handler for events of type <typeparamref name="TEvent"/>.
/// Specifies that a new projection with the specified key will be created for the event handler.
/// An exception will be thrown if a projection with such key already exists.
/// </summary>
/// <param name="getKey">The delegate that determines the projection key for the event.</param>
/// <returns>
/// <see cref="ICreateAction{TEvent,TProjection,TContext}"/> that allows to continue configuring the handler.
/// </returns>
ICreateAction<TEvent, TProjection, TContext> AsCreateOf(Func<TEvent, TContext, TKey> getKey);

/// <summary>
/// Continues configuring a handler for events of type <typeparamref name="TEvent"/>.
/// Specifies that a new projection with the specified key will be created for the event handler.
Expand All @@ -76,6 +87,17 @@ public interface ICrudAction<TEvent, TProjection, TKey, TContext> : IAction<TEve
/// </returns>
IUpdateAction<TEvent, TKey, TProjection, TContext> AsUpdateOf(Func<TEvent, TKey> getKey);

/// <summary>
/// Continues configuring a handler for events of type <typeparamref name="TEvent"/>.
/// Specifies that the projection with the specified key will be updated by the event handler.
/// An exception will be thrown if a projection with such key does not exist.
/// </summary>
/// <param name="getKey">The delegate that determines the projection key for the event.</param>
/// <returns>
/// <see cref="IUpdateAction{TEvent,TKey, TProjection,TContext}"/> that allows to continue configuring the handler.
/// </returns>
IUpdateAction<TEvent, TKey, TProjection, TContext> AsUpdateOf(Func<TEvent, TContext, TKey> getKey);

/// <summary>
/// Continues configuring a handler for events of type <typeparamref name="TEvent"/>.
/// Specifies that the projection with the specified key will be updated by the event handler.
Expand All @@ -99,7 +121,7 @@ public interface ICrudAction<TEvent, TProjection, TKey, TContext> : IAction<TEve
/// that allows to continue configuring the handler.
/// </returns>
[Obsolete("Use AsCreateOf().OverwritingDuplicates() instead")]
ICreateAction<TEvent, TProjection, TContext> AsCreateOrUpdateOf(Func<TEvent, TKey> getKey);
ICreateAction<TEvent, TProjection, TContext> AsCreateOrUpdateOf(Func<TEvent, TKey> getKey);

/// <summary>
/// Finishes configuring a handler for events of type <typeparamref name="TEvent"/>.
Expand All @@ -109,6 +131,14 @@ public interface ICrudAction<TEvent, TProjection, TKey, TContext> : IAction<TEve
/// <param name="getKey">The delegate that determines the projection key for the event.</param>
IDeleteAction<TEvent, TKey, TContext> AsDeleteOf(Func<TEvent, TKey> getKey);

/// <summary>
/// Finishes configuring a handler for events of type <typeparamref name="TEvent"/>.
/// Specifies that the projection with the specified key will be deleted when handling the event.
/// An exception will be thrown if a projection with such key does not exist.
/// </summary>
/// <param name="getKey">The delegate that determines the projection key for the event.</param>
IDeleteAction<TEvent, TKey, TContext> AsDeleteOf(Func<TEvent, TContext, TKey> getKey);

/// <summary>
/// Finishes configuring a handler for events of type <typeparamref name="TEvent"/>.
/// Specifies that the projection with the specified key will be deleted when handling the event.
Expand Down

0 comments on commit 0db776b

Please sign in to comment.