Module: Funes

Defined in:
lib/funes.rb,
lib/funes/engine.rb,
lib/funes/version.rb,
lib/funes/inspection.rb,
app/models/funes/event.rb,
lib/funes/configuration.rb,
lib/funes/unknown_event.rb,
app/models/funes/event_entry.rb,
app/jobs/funes/application_job.rb,
app/projections/funes/projection.rb,
app/models/funes/application_record.rb,
app/event_streams/funes/event_stream.rb,
app/helpers/funes/application_helper.rb,
app/mailers/funes/application_mailer.rb,
app/jobs/funes/persist_projection_job.rb,
lib/generators/funes/install_generator.rb,
lib/funes/conflicting_actual_time_error.rb,
lib/funes/event_metainformation_builder.rb,
lib/funes/invalid_event_metainformation.rb,
lib/funes/unknown_materialization_model.rb,
app/helpers/funes/projection_test_helper.rb,
lib/generators/funes/initializer_generator.rb,
app/controllers/funes/application_controller.rb,
app/serializers/funes/event_stream_serializer.rb,
lib/funes/missing_actual_time_attribute_error.rb,
lib/generators/funes/materialization_table_generator.rb

Overview

Funes is an event sourcing framework for Ruby on Rails.

Instead of updating state in place, Funes stores immutable events as the source of truth, then derives current state by replaying them through projections. This provides complete audit trails, temporal queries, and the ability to create multiple read models from the same event stream.

## Core Concepts

  • Events (Event): Immutable facts representing something that happened

  • **Event Streams** (EventStream): Append-only sequences of events for a specific entity

  • Projections (Projection): Transform events into read models (state)

## Getting Started

  1. Install the gem and run migrations: “‘bash $ bin/rails generate funes:install $ bin/rails db:migrate “`

  2. Define your events: “‘ruby class Order::Placed < Funes::Event

    attribute :total, :decimal
    attribute :customer_id, :string
    validates :total, presence: true
    

    end “‘

  3. Define a projection: “‘ruby class OrderProjection < Funes::Projection

    materialization_model OrderSnapshot
    
    interpretation_for Order::Placed do |state, event, _at|
      state.assign_attributes(total: event.total)
      state
    end
    

    end “‘

  4. Create an event stream: “‘ruby class OrderEventStream < Funes::EventStream

    add_transactional_projection OrderProjection
    

    end “‘

  5. Append events: “‘ruby stream = OrderEventStream.for(“order-123”) event = stream.append(Order::Placed.new(total: 99.99, customer_id: “cust-1”)) “`

## Three-Tier Consistency Model

Funes provides fine-grained control over projection execution:

  • **Consistency Projection**: Validates business rules before persisting events

  • **Transactional Projections**: Execute synchronously in the same database transaction

  • **Async Projections**: Execute asynchronously via ActiveJob

## Bitemporal History

Funes supports two independent temporal dimensions:

  • **Record history** (‘as_of` / `created_at`): When the system learned about an event

  • **Actual history** (‘at` / `occurred_at`): When the event actually occurred in the real world

This enables queries like “what did the system know at time T?” (‘as_of`) and “what had actually happened by time T?” (`at`), as well as full bitemporal queries combining both dimensions.

Defined Under Namespace

Modules: ApplicationHelper, Generators, Inspection, ProjectionTestHelper Classes: ApplicationController, ApplicationJob, ApplicationMailer, ApplicationRecord, Configuration, ConflictingActualTimeError, Engine, Event, EventEntry, EventMetainformation, EventMetainformationBuilder, EventStream, EventStreamSerializer, InvalidEventMetainformation, MissingActualTimeAttributeError, PersistProjectionJob, Projection, UnknownEvent, UnknownMaterializationModel

Constant Summary collapse

VERSION =
"0.2.1"

Class Method Summary collapse

Class Method Details

.configurationObject



90
91
92
# File 'lib/funes.rb', line 90

def configuration
  @configuration ||= Configuration.new
end

.configure {|configuration| ... } ⇒ Object

Yields:



94
95
96
# File 'lib/funes.rb', line 94

def configure
  yield(configuration)
end