Class: RailsEventSourcing::BaseEvent

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/rails-event-sourcing/base_event.rb

Overview

This is the BaseEvent class that all Events inherit from. It takes care of serializing ‘data` and `metadata` via json It defines setters and accessors for the defined `data_attributes` After create, it calls `apply` to apply changes.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.aggregate_nameObject



73
74
75
76
77
78
# File 'lib/rails-event-sourcing/base_event.rb', line 73

def aggregate_name
  inferred_aggregate = reflect_on_all_associations(:belongs_to).first
  raise "Events must belong to an aggregate" if inferred_aggregate.nil?

  inferred_aggregate.name
end

.data_attributes(*attrs) ⇒ Object

Define attributes to be serialize in the ‘data` column. It generates setters and getters for those.

Example:

class MyEvent < RailsEventSourcing::BaseEvent

data_attributes :title, :description, :drop_id

end



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rails-event-sourcing/base_event.rb', line 88

def data_attributes(*attrs)
  @data_attributes ||= []

  attrs.map(&:to_s).each do |attr|
    @data_attributes << attr unless @data_attributes.include?(attr)

    define_method attr do
      self.data ||= {}
      self.data[attr]
    end

    define_method "#{attr}=" do |arg|
      self.data ||= {}
      self.data[attr] = arg
    end
  end

  @data_attributes
end

.event_nameObject

Underscored class name by default. ex: “post/updated” Used when sending events to the data pipeline



110
111
112
# File 'lib/rails-event-sourcing/base_event.rb', line 110

def event_name
  name.underscore
end

.events_for(aggregate) ⇒ Object



114
115
116
# File 'lib/rails-event-sourcing/base_event.rb', line 114

def events_for(aggregate)
  where(aggregate_name => aggregate)
end

.reserved_column_namesObject



118
119
120
# File 'lib/rails-event-sourcing/base_event.rb', line 118

def reserved_column_names
  %w[id created_at updated_at]
end

Instance Method Details

#aggregateObject



25
26
27
# File 'lib/rails-event-sourcing/base_event.rb', line 25

def aggregate
  public_send aggregate_name
end

#aggregate=(model) ⇒ Object



29
30
31
# File 'lib/rails-event-sourcing/base_event.rb', line 29

def aggregate=(model)
  public_send "#{aggregate_name}=", model
end

#aggregate_idObject



43
44
45
# File 'lib/rails-event-sourcing/base_event.rb', line 43

def aggregate_id
  public_send "#{aggregate_name}_id"
end

#aggregate_id=(id) ⇒ Object



33
34
35
# File 'lib/rails-event-sourcing/base_event.rb', line 33

def aggregate_id=(id)
  public_send "#{aggregate_name}_id=", id
end

#apply(aggregate) ⇒ Object

Apply the event to the aggregate passed in. Must return the aggregate.

Raises:

  • (NotImplementedError)


39
40
41
# File 'lib/rails-event-sourcing/base_event.rb', line 39

def apply(aggregate)
  raise NotImplementedError
end

#build_aggregateObject



47
48
49
# File 'lib/rails-event-sourcing/base_event.rb', line 47

def build_aggregate
  public_send "build_#{aggregate_name}"
end

#rollback!Object

Rollback an aggregate entity to a specific version

Update the aggregate with the changes up to the current event and destroys the events after



55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rails-event-sourcing/base_event.rb', line 55

def rollback!
  base_class = self.class.superclass == RailsEventSourcing::BaseEvent ? self.class : self.class.superclass
  new_attributes = aggregate.class.new.attributes
  preserve_columns = new_attributes.keys - base_class.reserved_column_names
  new_attributes.slice!(*preserve_columns)
  aggregate.assign_attributes(new_attributes)
  aggregate.transaction do
    base_class.events_for(aggregate).where('id > ?', id).destroy_all
    base_class.events_for(aggregate).reorder('id ASC').each do |event|
      event.apply(aggregate)
    end
    aggregate.save!
  end
end