Sourcing

Event Sourcing library for Raku with metaclasses, CQRS patterns, and declarative projections & aggregations

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

Installation

zef install Sourcing

Project Structure

ComponentPurpose
Sourcing::ProjectionRole for read-only projections
Sourcing::AggregationMarker role for write-side aggregations
Metamodel::ProjectionHOWMetaclass for projection declarations
Metamodel::AggregationHOWMetaclass for aggregation declarations
Sourcing::PluginAbstract interface for storage backends
Sourcing::Plugin::MemoryIn-memory implementation for testing
Sourcing::ProjectionStorageRegistry for automatic projection updates
Sourcing::X::OptimisticLockedException for concurrency conflicts

Next Steps