Module: EventSourcery::AggregateRoot

Defined in:
lib/event_sourcery/aggregate_root.rb

Overview

EventSourcery::AggregateRoot provides a foundation for writing your own aggregate root classes. You can use it by including it in your classes, as show in the example code.

Excerpt from EventSourcery Core Concepts on Aggregates follows:

Aggregates and Command Handling

An aggregate is a cluster of domain objects that can be treated as a single unit.
Every transaction is scoped to a single aggregate. An aggregate will have one of its component objects be
the aggregate root. Any references from outside the aggregate should only go to the aggregate root.
The root can thus ensure the integrity of the aggregate as a whole.

Clients execute domain transactions against the system by issuing commands against aggregate roots. The result of these commands is new events being saved to the event store. A typical EventSourcery application will have one or more aggregate roots with multiple commands.

The following partial example is taken from the EventSourceryTodoApp. Refer a more complete example here.

Examples:

module EventSourceryTodoApp
  module Aggregates
    class Todo
      include EventSourcery::AggregateRoot

      # An event handler that updates the aggregate's state from a event
      apply TodoAdded do |event|
        @added = true
      end

      # Method on the aggregate that processes a command and emits an event as a result
      def add(payload)
        raise UnprocessableEntity, "Todo #{id.inspect} already exists" if added

        apply_event(TodoAdded,
                    aggregate_id: id,
                    body: payload,
        )
     end

      private

      attr_reader :added
    end
  end
end

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

UnknownEventError =

Raised when the aggregate doesn’t have a method to handle a given event. Consider implementing one if you get this error.

Class.new(RuntimeError)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#changesObject (readonly)

Collection of new events that are yet to be persisted

Returns:

  • Array



100
101
102
# File 'lib/event_sourcery/aggregate_root.rb', line 100

def changes
  @changes
end

#versionObject (readonly)

Current version of the aggregate. This is the same as the number of events currently loaded by the aggregate.

Returns:

  • Integer



106
107
108
# File 'lib/event_sourcery/aggregate_root.rb', line 106

def version
  @version
end

Class Method Details

.included(base) ⇒ Object



55
56
57
58
59
60
# File 'lib/event_sourcery/aggregate_root.rb', line 55

def self.included(base)
  base.extend(ClassMethods)
  base.class_eval do
    @event_handlers = Hash.new { |hash, key| hash[key] = [] }
  end
end

Instance Method Details

#clear_changesObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Clears any changes present in #changes



111
112
113
# File 'lib/event_sourcery/aggregate_root.rb', line 111

def clear_changes
  @changes.clear
end

#initialize(id, events, on_unknown_event: EventSourcery.config.on_unknown_event) ⇒ Object

Load an aggregate instance based on the given ID and events

Parameters:

  • id (String)

    ID (a UUID represented as a string) of the aggregate instance to be loaded

  • events (Array)

    Events from which the aggregate’s current state will be formed

  • on_unknown_event (Proc) (defaults to: EventSourcery.config.on_unknown_event)

    Optional. The proc to be run if an unknown event type (for which no event handler is registered using EventSourcery::AggregateRoot::ClassMethods#apply) is to be loaded.



89
90
91
92
93
94
95
# File 'lib/event_sourcery/aggregate_root.rb', line 89

def initialize(id, events, on_unknown_event: EventSourcery.config.on_unknown_event)
  @id = id.to_str
  @version = 0
  @on_unknown_event = on_unknown_event
  @changes = []
  load_history(events)
end