Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#1 - Creating a projection
// Compose a projection.
// - Tell what type of state the projection maintains (List<WizardActivity>)
var projection = Compose<List<WizardActivity>>.Projection()
.Initialize(() => new List<WizardActivity>()) // How do you want to initialize the state when you run the projection?
// When a wizard was started we want to know about it.
.When<WizardStarted>((@event, state) =>
{
var activity = new WizardActivity(@event.CorrelationId.Value, @event.TimeStamp);
if (!state.Contains(activity))
state.Add(activity);
})
// Register the endtime when a wizard was finished.
.When<WizardFinished>((@event, state) =>
{
var activity = state.SingleOrDefault(s => s.CorrelationId == @event.CorrelationId.Value);
if (activity != null)
{
activity.FinishedAt = @event.TimeStamp;
}
})
.Build();
// Using a projection
// Read 125 trace events from a file (or whereever the events are coming from)
var json = File.ReadAllText("traceevents.txt");
var traceEvents = json.Parse<IEnumerable<TraceEvent>>();
var player = new EventPlayer(new[] { projection });
player.Play(traceEvents.ToArray());
Console.WriteLine("{0} wizard activities composed.", projection.State.Count);
public static class Compose<TState> where TState : class, new()
{
public static ProjectionBuilder<TState> Projection()
{
return new ProjectionBuilder<TState>();
}
}
public class ProjectionBuilder<TState> where TState : class, new()
{
private TraceEventHandler<TState>[] _handlers;
private Func<TState> _initializer;
public ProjectionBuilder()
: this(new TraceEventHandler<TState>[0])
{
}
public ProjectionBuilder(TraceEventHandler<TState>[] handlers)
{
Guard.That(handlers).IsNotNull();
_handlers = handlers;
}
public ProjectionBuilder<TState> Initialize(Func<TState> initializer)
{
_initializer = initializer;
return this;
}
public ProjectionBuilder<TState> When<TEvent>(Action<TraceEvent, TState> handler)
where TEvent : Event
{
Guard.That(handler).IsNotNull();
var newHandler = new TraceEventHandler<TState>(typeof(TEvent), handler);
_handlers = _handlers.Concat(new[] { newHandler }).ToArray();
return this;
}
public Projection<TState> Build()
{
return new Projection<TState>(_initializer, _handlers);
}
}
public class TraceEventHandler<TState> where TState: class, new()
{
private readonly Type _event;
private readonly Action<TraceEvent, TState> _handler;
public TraceEventHandler(Type @event, Action<TraceEvent, TState> handler)
{
Guard.That(@event).IsNotNull();
Guard.That(handler).IsNotNull();
_event = @event;
_handler = handler;
}
public Type Event
{
get { return _event; }
}
public Action<TraceEvent, TState> Handler
{
get { return _handler; }
}
}
public interface IProjection
{
void Run(TraceEvent[] traceEvents);
}
public class Projection<TState> : IProjection
where TState : class, new()
{
private readonly Func<TState> _initializeState;
private readonly TraceEventHandler<TState>[] _handlers;
private TState _state;
public Projection(
Func<TState> initializeState,
TraceEventHandler<TState>[] handlers)
{
Guard.That(initializeState).IsNotNull();
Guard.That(handlers).IsNotNull();
_initializeState = initializeState;
_handlers = handlers;
}
public IReadOnlyCollection<TraceEventHandler<TState>> Handlers
{
get { return _handlers; }
}
public TState State
{
get { return _state; }
}
public void Run(TraceEvent[] traceEvents)
{
_state = _initializeState();
foreach (var traceEvent in traceEvents)
{
foreach (var handler in Handlers)
{
if (handler.Event.Name != traceEvent.EventType)
continue;
var handleIt = handler.Handler;
handleIt(traceEvent, _state);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment