Quick Start
Get up and running with Sourcing in 5 minutes. We'll build a simple order management system with an aggregation (write side) and a projection (read side).
1. Install
zef install Sourcing
2. Define Events
Events are plain Raku classes that describe what happened:
use Sourcing;
use Sourcing::Plugin::Memory;
Sourcing::Plugin::Memory.use;
class OrderPlaced {
has UInt $.order-id;
has Str $.customer;
has Rat $.total;
}
class OrderShipped {
has UInt $.order-id;
has Str $.tracking;
}
3. Define an Aggregation
The aggregation validates commands and emits events:
aggregation Order {
has UInt $.order-id is projection-id;
has Str $.status = 'pending';
has Rat $.total = 0;
# State changes come ONLY from events
method apply(OrderPlaced $e) {
$!status = 'placed';
$!total = $e.total;
}
method apply(OrderShipped $e) {
$!status = 'shipped';
}
# Command: validates then emits
method place(Str $customer, Rat $total) is command {
die "Total must be positive" if $total <= 0;
$.order-placed: :$customer, :$total;
}
method ship(Str $tracking) is command {
die "Order not placed" if $!status ne 'placed';
$.order-shipped: :$tracking;
}
}
4. Define a Projection
The projection builds a read-optimized view:
projection OrderSummary {
has UInt $.order-id is projection-id;
has Str $.status = 'pending';
has Rat $.total = 0;
method apply(OrderPlaced $e) {
$!status = 'placed';
$!total = $e.total;
}
method apply(OrderShipped $e) {
$!status = 'shipped';
}
}
5. Use It
# Create an order
my $order = sourcing Order, :order-id(1);
$order.place: 'Alice', 99.95;
$order.^update;
say "Order status: {$order.status}"; # placed
say "Order total: {$order.total}"; # 99.95
# Ship the order
$order.ship: 'TRACK-123';
$order.^update;
say "Order status: {$order.status}"; # shipped
# Query the projection
my $summary = sourcing OrderSummary, :order-id(1);
say "Summary: Order {$summary.order-id} is {$summary.status}";
# Summary: Order 1 is shipped
What Just Happened?
sourcing Order, :order-id(1)— Created a fresh Order instance, replayed all events (none yet)$order.place: 'Alice', 99.95— Validated total > 0, emittedOrderPlacedevent$order.^update— Reset state, replayed all events from store, appliedOrderPlacedsourcing OrderSummary, :order-id(1)— Created projection, replayed events, built summary view
Next Steps
- Read the Bank Account Example for a more complete application
- Learn about Commands and automatic retry
- Explore the API Reference for detailed documentation