Class: Yes::Core::ReadModel::Builder

Inherits:
Object
  • Object
show all
Includes:
OpenTelemetry::Trackable
Defined in:
lib/yes/core/read_model/builder.rb

Overview

Base class for read model builders that distribute events to proper event handlers and manage read model lifecycle including rebuilding.

Constant Summary collapse

EventValidationErrorsPresent =
Class.new(Error)
InvalidReadModelBuilderClass =
Class.new(Error)
MissingReadModelId =
Class.new(Error)
RebuildError =
Class.new(Error)
READ_MODEL_CLASS_REGEXP =
/(?<context>\w+)::ReadModels::(?<version>V\d+)?(::)?(?<aggregate>\w+)/

Instance Method Summary collapse

Constructor Details

#initializeBuilder

Returns a new instance of Builder.



94
95
96
# File 'lib/yes/core/read_model/builder.rb', line 94

def initialize
  self.read_model_class = default_read_model_class
end

Instance Method Details

#aggregate_id_keyString

Returns:

  • (String)


90
91
92
# File 'lib/yes/core/read_model/builder.rb', line 90

def aggregate_id_key
  "#{underscore(read_model_class_name_match[:aggregate].to_s)}_id"
end

#call(event, read_model: nil) ⇒ void

This method returns an undefined value.

Based on event type class it distributes event to a proper event handler

Parameters:

  • event (Yes::Core::Event)
  • read_model (ActiveRecord::Base) (defaults to: nil)

    AR object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/yes/core/read_model/builder.rb', line 30

def call(event, read_model: nil)
  read_model ||= read_model(event)

  otl_record_data(read_model, event)

  handler = handler_class(event)&.new(read_model)
  return unless handler

  locale = event.data['locale']&.to_sym || I18n.default_locale
  return unless correct_locale?(locale)

  I18n.with_locale(locale) do
    next handler.call(event) unless self.class.otl_tracer

    OpenTelemetry::OtlSpan.new(otl_data: otl_data(handler), otl_tracer: self.class.otl_tracer).otl_span do
      handler.call(event)
    end
  ensure
    otl_record_processed(read_model, event, handler)
  end
end

#rebuild(id:, eventstore: PgEventstore.client) ⇒ ActiveRecord::Base?

Parameters:

  • id (String)

    id of the read model to rebuild

  • eventstore (PgEventstore::Client) (defaults to: PgEventstore.client)

    eventstore client

Returns:

  • (ActiveRecord::Base, nil)

Raises:



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/yes/core/read_model/builder.rb', line 70

def rebuild(id:, eventstore: PgEventstore.client)
  # delete is intentional to avoid any callbacks
  read_model_class.delete(id) if read_model_class.exists?(id)
  context = read_model_class_name_match[:context]
  stream_name = read_model_class_name_match[:aggregate]
  enum = eventstore.read_paginated(
    PgEventstore::Stream.new(context:, stream_name:, stream_id: id), options: { resolve_link_tos: true }
  )
  read_model = read_model_class.find_or_create_by(id:)

  enum.each do |events|
    events.each do |event|
      # pass in read model for efficiency
      call(event, read_model:)
    end
  end
  read_model
end

#rebuild_many(eventstore: PgEventstore.client, ids: read_model_class.pluck(:id)) ⇒ Object

Parameters:

  • eventstore (PgEventstore::Client) (defaults to: PgEventstore.client)

    eventstore client

  • ids (Array<String>) (defaults to: read_model_class.pluck(:id))

    ids to rebuild



59
60
61
62
63
64
# File 'lib/yes/core/read_model/builder.rb', line 59

def rebuild_many(
  eventstore: PgEventstore.client,
  ids: read_model_class.pluck(:id)
)
  ids.each { |id| rebuild(eventstore:, id:) }
end