Skip to content

Commit

Permalink
Merge pull request #111 from dennisdoomen/ExtendedMappingApi
Browse files Browse the repository at this point in the history
Adds global filters as well as custom handling for duplicates and misses
  • Loading branch information
dennisdoomen authored Mar 13, 2018
2 parents 8673e1d + d6d2306 commit b01ddc2
Show file tree
Hide file tree
Showing 16 changed files with 1,662 additions and 1,622 deletions.
Binary file modified .vs/LiquidProjections/v15/sqlite3/storage.ide
Binary file not shown.
6 changes: 6 additions & 0 deletions GitVersion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
branches:
(pull|pull\-requests|pr)[/-]:
mode: ContinuousDeployment
tag: pr
ignore:
sha: []
34 changes: 18 additions & 16 deletions Samples/ExampleHost/ExampleProjector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,34 @@ public ExampleProjector(IEventMapBuilder<TProjection, string, ProjectionContext>

private IEventMap<ProjectionContext> BuildMapFrom(IEventMapBuilder<TProjection, string, ProjectionContext> mapBuilder)
{
mapBuilder.HandleProjectionModificationsAs((key, context, projector, options) =>
return mapBuilder.Build(new ProjectorMap<TProjection, string, ProjectionContext>
{
TProjection projection = store.GetRepository<TProjection>().Find(key);
if (projection == null)
Create = async (key, context, projector, shouldOverride) =>
{
projection = new TProjection()
var projection = new TProjection()
{
Id = key
};

store.Add(projection);
}
await projector(projection);

return projector(projection);
});
store.Add(projection);
},
Update = async (key, context, projector, createIfMissing) =>
{
TProjection projection = store.GetRepository<TProjection>().Find(key);
await projector(projection);

mapBuilder.HandleProjectionDeletionsAs((key, context, options) =>
{
store.GetRepository<TProjection>().RemoveByKey(key);
store.Add(projection);
},
Delete = (key, context) =>
{
store.GetRepository<TProjection>().RemoveByKey(key);

return Task.FromResult(0);
return Task.FromResult(true);
},
Custom = (context, projector) => projector()
});

mapBuilder.HandleCustomActionsAs((context, projector) => projector());

return mapBuilder.Build();
}

public async Task Handle(IReadOnlyList<Transaction> transactions)
Expand Down
48 changes: 35 additions & 13 deletions Src/LiquidProjections/EventMap.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace LiquidProjections
Expand All @@ -10,8 +11,8 @@ namespace LiquidProjections
public class EventMap<TContext> : IEventMap<TContext>
{
private readonly Dictionary<Type, List<Handler>> mappings = new Dictionary<Type, List<Handler>>();

internal CustomHandler<TContext> Do { get; set; }
private readonly List<Func<object, TContext, Task<bool>>> filters =
new List<Func<object, TContext, Task<bool>>>();

internal void Add<TEvent>(Func<TEvent, TContext, Task> action)
{
Expand All @@ -23,10 +24,12 @@ internal void Add<TEvent>(Func<TEvent, TContext, Task> action)
mappings[typeof(TEvent)].Add((@event, context) => action((TEvent)@event, context));
}

/// <summary>
/// Handles <paramref name="anEvent"/> asynchronously using context <paramref name="context"/>.
/// </summary>
public async Task Handle(object anEvent, TContext context)
internal void AddFilter(Func<object, TContext, Task<bool>> filter)
{
filters.Add(filter);
}

public async Task<bool> Handle(object anEvent, TContext context)
{
if (anEvent == null)
{
Expand All @@ -38,17 +41,36 @@ public async Task Handle(object anEvent, TContext context)
throw new ArgumentNullException(nameof(context));
}

Type key = anEvent.GetType();

List<Handler> handlers;

if (mappings.TryGetValue(key, out handlers))
if (await PassesFilter(anEvent, context))
{
foreach (Handler handler in handlers)
Type key = anEvent.GetType();

if (mappings.TryGetValue(key, out var handlers))
{
await handler(anEvent, context);
foreach (Handler handler in handlers)
{
await handler(anEvent, context);
}

return true;
}
}

return false;
}

private async Task<bool> PassesFilter(object anEvent, TContext context)
{
if (filters.Count > 0)
{
bool[] results = await Task.WhenAll(filters.Select(filter => filter(anEvent, context)));

return results.All(x => x);
}
else
{
return true;
}
}

private delegate Task Handler(object @event, TContext context);
Expand Down
Loading

0 comments on commit b01ddc2

Please sign in to comment.