Skip to main content

Module projection

Module projection 

Source
Expand description

§Projection Module

Three-trait architecture for building read models from event streams:

  • Projector — stateless event handler (the “machine”). Contains the pure logic for transforming events into read model writes.
  • Projection — composed read model unit (the “output”). Ties a projector to its storage backend.
  • ReadModelStore — persistence layer for projections. Backend-agnostic storage (defined in read_model_store module).

§Design Principles

  • Separation of concerns: Handler logic (projector) is separate from storage (read model store) and orchestration (projection engine)
  • Stateless projectors: Projectors take &self, not &mut self. All mutable state lives in the ReadModelStore via interior mutability.
  • Rebuildable: Projections can be rebuilt from scratch by replaying events
  • Idempotent: Handling the same event multiple times should be safe
  • Composable: One projector per read model concern; swap backends freely

§Example

use arc_core::projection::{Projector, Projection, ProjectionUnit, ProjectionEngine};
use arc_core::read_model_store::{ReadModelStore, InMemoryReadModelStore};
use arc_core::event::Event;
use std::sync::Arc;

struct UserListProjector;

#[async_trait]
impl Projector for UserListProjector {
    fn name(&self) -> &str { "UserList" }

    fn handles(&self) -> Vec<String> {
        vec!["UserCreated".to_string(), "ProfileUpdated".to_string()]
    }

    async fn apply(&self, event: &Event, store: &dyn ReadModelStore) -> ProjectionResult<()> {
        match event.event_type.as_str() {
            "UserCreated" => {
                store.upsert(Upsert::new("users_view", &event.aggregate_id, event.payload.clone())).await
                    .map_err(|e| ProjectionError::handle_failed("UserList", &event.event_type, &event.event_id.to_string(), e.to_string()))?;
            }
            _ => {}
        }
        Ok(())
    }
}

// Compose: projector + store = projection
let store = Arc::new(InMemoryReadModelStore::new());
let projection = ProjectionUnit::new(Box::new(UserListProjector), store, "users_view");

// Register with engine
let mut engine = ProjectionEngine::new(event_store);
engine.register(Box::new(projection));
engine.process(&event).await?;

Structs§

ProjectionEngine
Engine for managing multiple projections.
ProjectionEngineHandler
Adapter that lets a ProjectionEngine subscribe to an EventBus. Wraps the engine in an EventHandler that routes every relevant event through ProjectionEngine::process. The engine stays accessible from outside (e.g. for rebuild_all) via the same Arc.
ProjectionUnit
Standard composition of a Projector and a ReadModelStore.

Enums§

ProjectionError
Errors that can occur during projection operations.

Traits§

Projection
A projection is the composed unit of a projector + its read model store.
Projector
A projector contains the pure event-handling logic for building a read model.

Type Aliases§

ProjectionResult
Result type for projection operations.