Module: Eventsimple::Event

Includes:
GlobalID::Identification
Defined in:
lib/eventsimple/event.rb

Defined Under Namespace

Modules: ClassMethods, InstanceMethods

Instance Method Summary collapse

Instance Method Details

#drives_events_for(aggregate_klass, aggregate_id:, events_namespace: nil, metadata_class: nil) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/eventsimple/event.rb', line 8

def drives_events_for(aggregate_klass, aggregate_id:, events_namespace: nil, metadata_class: nil)
  begin
    if defined?(aggregate_klass._aggregate_id) && aggregate_klass.table_exists? && table_exists?
      raise ArgumentError, "aggregate_id mismatch event:#{aggregate_id} entity:#{aggregate_klass._aggregate_id}" if aggregate_id != aggregate_klass._aggregate_id

      aggregate_column_type_in_event = aggregate_klass.column_for_attribute(aggregate_klass._aggregate_id).type if aggregate_klass.attribute_names.present?
      aggregate_column_type_in_entity = column_for_attribute(:aggregate_id).type if aggregate_klass.attribute_names.present?

      raise ArgumentError, "column type mismatch - event:#{aggregate_column_type_in_event} entity:#{aggregate_column_type_in_entity}" if aggregate_column_type_in_event != aggregate_column_type_in_entity

    end
  rescue ActiveRecord::AdapterError
    # skip checks if the database is not yet created
  end

  class_attribute :_events_namespace
  self._events_namespace = events_namespace

  class_attribute :_aggregate_klass
  self._aggregate_klass = aggregate_klass

  class_attribute :_aggregate_id
  self._aggregate_id = aggregate_id

  class_attribute :_outbox_enabled

  class_attribute :_on_invalid_transition
  self._on_invalid_transition = ->(error) { raise error }

  class_attribute :_metadata_klass
  self. = .is_a?(Class) ?  : &.to_s&.constantize

  self.inheritance_column = 'type'
  self.store_full_sti_class = false

  attribute :metadata, MetadataType.new(self)
  attr_writer :skip_dispatcher
  attr_writer :skip_apply_check

  belongs_to _aggregate_klass.model_name.element.to_sym,
    foreign_key: :aggregate_id,
    primary_key: _aggregate_id,
    class_name: _aggregate_klass.name.to_s,
    inverse_of: :events,
    autosave: false,
    validate: false

  # Override the association reader to bypass any default_scope on the aggregate model.
  # This ensures events can always find their aggregate, even if there is a default scope.
  aggregate_name = _aggregate_klass.model_name.element.to_sym
  define_method(aggregate_name) do
    assoc = association(aggregate_name)
    return assoc.target if assoc.loaded?
    return nil if self.aggregate_id.nil?

    record = _aggregate_klass.unscoped.find_by(_aggregate_id => self.aggregate_id)
    assoc.target = record
    record
  end

  default_scope { order(:created_at) }

  after_initialize :readonly!, if: :persisted?

  before_validation :extend_validation
  after_validation :perform_transition_checks, on: :create
  before_create :apply_and_persist
  after_create :dispatch
  after_create :readonly!

  include InstanceMethods
  extend ClassMethods
end