What is Sourcing?
Sourcing is a Raku (Perl 6) event sourcing library that provides a declarative approach to building projections and aggregations using metaclasses, roles, and custom traits. It implements the CQRS (Command Query Responsibility Segregation) pattern, separating the write model (aggregations) from the read model (projections).
Key Benefits
- Full audit trail — Every state change is an immutable event
- Temporal queries — Reconstruct state at any point in time
- Multiple read models — Derive different views from the same event stream
- Automatic retry — Commands retry on optimistic lock conflicts
- Declarative — Define projections and aggregations with minimal boilerplate
Quick Example
use Sourcing;
use Sourcing::Plugin::Memory;
Sourcing::Plugin::Memory.use;
class OrderPlaced { has $.order-id; has $.customer; has $.total }
class OrderShipped { has $.order-id; has $.tracking }
aggregation Order {
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' }
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;
}
}
projection OrderView {
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' }
}
my $order = sourcing Order, :order-id(1);
$order.place: 'Alice', 99.95;
$order.^update;
my $view = sourcing OrderView, :order-id(1);
say "Order {$view.order-id}: {$view.status} — \${$view.total}";
# Order 1: placed — $99.95
Core Concepts
Aggregations
The write side of CQRS. Validate commands, enforce invariants, and emit immutable events.
Projections
The read side of CQRS. Consume events to build query-optimized read models.
Commands
Methods with automatic retry, validation, and optimistic locking.
Optimistic Locking
CAS-based concurrency control with automatic retry up to 5 attempts.
Installation
zef install Sourcing
Project Structure
| Component | Purpose |
|---|---|
Sourcing::Projection | Role for read-only projections |
Sourcing::Aggregation | Marker role for write-side aggregations |
Metamodel::ProjectionHOW | Metaclass for projection declarations |
Metamodel::AggregationHOW | Metaclass for aggregation declarations |
Sourcing::Plugin | Abstract interface for storage backends |
Sourcing::Plugin::Memory | In-memory implementation for testing |
Sourcing::ProjectionStorage | Registry for automatic projection updates |
Sourcing::X::OptimisticLocked | Exception for concurrency conflicts |
Next Steps
- Read What is Event Sourcing? for the fundamentals
- Follow the Quick Start Guide to build your first projection
- Study the Bank Account Example for a complete CQRS application
- Explore the API Reference for detailed documentation