Skip to content

Instantly share code, notes, and snippets.

@jnthn
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jnthn/da27ded3fbf06df7c54a to your computer and use it in GitHub Desktop.
Save jnthn/da27ded3fbf06df7c54a to your computer and use it in GitHub Desktop.
class Domain { ... }
class Aggregate {
has $.id;
trusts Domain;
method !apply-events($id, @events) {
$!id = $id;
self.apply($_) for @events;
}
proto method apply($) {*}
}
role EventStore {
method load($type, $id) { ... }
method store($type, $id, @new-events, $base-version) { ... }
}
class X::EventStore::Conflict is Exception {
}
class Domain {
has EventStore $.event-store = die "Must supply an event store";
has $.attempts = 2;
method process(Aggregate $type, $id, &call) {
my $attempts-remaining = $.attempts;
while $attempts-remaining-- > 0 {
my $agg = $type.new();
my @events = $.event-store.load($type, $id);
$agg!Aggregate::apply-events($id, @events);
my @new-events = call($agg);
$.event-store.store($type, $id, @new-events, @events.elems);
return;
CATCH { when X::EventStore::Conflict { $attempts-remaining++; } }
}
}
}
use Evject;
use Monitor;
monitor InMemoryEventStore does EventStore {
has %!streams;
method load($type, $id) {
my @copy = @(%!streams{aggregate-key($type, $id)} // ());
return @copy;
}
method store($type, $id, @new-events, $base-version) {
my $key = aggregate-key($type, $id);
my @current := (%!streams{$key} //= @[]);
if @current.elems != $base-version {
X::EventStore::Conflict.throw;
}
push @current, @new-events;
}
sub aggregate-key($type, $id) {
$type.^name ~ $id
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment