Class: PaperTrailDiff::LiveEndpointBatchLoader

Inherits:
Object
  • Object
show all
Defined in:
lib/paper_trail_diff/live_endpoint_batch_loader.rb,
sig/generated/paper_trail_diff/live_endpoint_batch_loader.rbs

Overview

Reloads current-record endpoints and their explicitly selected associations in batches.

Instance Method Summary collapse

Constructor Details

#initialize(tree:) ⇒ LiveEndpointBatchLoader

: (tree: AssociationTree) -> void

Parameters:



8
9
10
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 8

def initialize(tree:)
  @tree = tree
end

Instance Method Details

#active_record_preloaderObject

: () -> untyped

Returns:

  • (Object)


88
89
90
91
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 88

def active_record_preloader
  active_record = Object.const_get(:ActiveRecord)
  active_record.const_get(:Associations).const_get(:Preloader)
end

#batch_safe?(record, reflection) ⇒ Boolean

: (untyped, untyped) -> bool

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


94
95
96
97
98
99
100
101
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 94

def batch_safe?(record, reflection)
  scope = reflection.scope
  return false if scope && !scope.arity.zero?
  return true unless reflection.collection?

  relation = record.association(reflection.name).scope
  relation.limit_value.nil? && relation.offset_value.nil?
end

#call(records) ⇒ Hash[identity, untyped]

: (Array) -> Hash[identity, untyped]

Parameters:

  • (Array[untyped])

Returns:

  • (Hash[identity, untyped])


13
14
15
16
17
18
19
20
21
22
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 13

def call(records)
  loaded = {} #: Hash[identity, untyped]
  records.group_by(&:class).each do |model_class, grouped|
    load_group(model_class, grouped).each do |record|
      loaded[Endpoint.identity(record)] = record
    end
  end
  ensure_all_loaded!(records, loaded)
  loaded
end

#ensure_all_loaded!(records, loaded) ⇒ void

This method returns an undefined value.

: (Array, Hash[identity, untyped]) -> void

Parameters:

  • (Array[untyped])
  • (Hash[identity, untyped])


125
126
127
128
129
130
131
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 125

def ensure_all_loaded!(records, loaded)
  missing = records.map { |record| Endpoint.identity(record) }.uniq - loaded.keys
  return if missing.empty?

  message = 'current record endpoint could not be reloaded from the database'
  raise InvalidEndpointError, message
end

#load_group(model_class, records) ⇒ Array[untyped]

: (untyped, Array) -> Array

Parameters:

  • (Object)
  • (Array[untyped])

Returns:

  • (Array[untyped])


29
30
31
32
33
34
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 29

def load_group(model_class, records)
  relation = model_class.unscoped.where(model_class.primary_key => records.map(&:id).uniq)
  loaded = relation.to_a
  preload_tree(loaded, @tree)
  loaded
end

#load_individually(records, reflection) ⇒ Array[untyped]

: (Array, untyped) -> Array

Parameters:

  • (Array[untyped])
  • (Object)

Returns:

  • (Array[untyped])


104
105
106
107
108
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 104

def load_individually(records, reflection)
  unique_records(records.flat_map do |record|
    Array(record.association(reflection.name).load_target)
  end)
end

#preload_batch(records, associations) ⇒ void

This method returns an undefined value.

: (Array, Array) -> void

Parameters:

  • (Array[untyped])
  • (Array[Symbol])


78
79
80
81
82
83
84
85
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 78

def preload_batch(records, associations)
  return if associations.empty?

  active_record_preloader.new(
    records: records,
    associations: associations
  ).call
end

#preload_model_tree(model_class, records, tree) ⇒ void

This method returns an undefined value.

: (untyped, Array, AssociationTree) -> void

Parameters:



46
47
48
49
50
51
52
53
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 46

def preload_model_tree(model_class, records, tree)
  batch, individual = selected_reflections(model_class, tree).partition do |reflection, _|
    batch_safe?(records.fetch(0), reflection)
  end
  preload_batch(records, batch.map { |reflection, _| reflection.name })
  preload_subtrees(records, batch, individually: false)
  preload_subtrees(records, individual, individually: true)
end

#preload_subtrees(records, reflections, individually:) ⇒ void

This method returns an undefined value.

: (Array, Array[[untyped, AssociationTree]], individually: bool) -> void

Parameters:

  • (Array[untyped])
  • (Array[[ untyped, AssociationTree ]])
  • individually: (Boolean)


66
67
68
69
70
71
72
73
74
75
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 66

def preload_subtrees(records, reflections, individually:)
  reflections.each do |reflection, subtree|
    children = if individually
                 load_individually(records, reflection)
               else
                 targets(records, reflection)
               end
    preload_tree(children, subtree)
  end
end

#preload_tree(records, tree) ⇒ void

This method returns an undefined value.

: (Array, AssociationTree) -> void

Parameters:



37
38
39
40
41
42
43
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 37

def preload_tree(records, tree)
  return if records.empty? || tree.empty?

  records.group_by(&:class).each do |model_class, grouped_records|
    preload_model_tree(model_class, grouped_records, tree)
  end
end

#selected_reflections(model_class, tree) ⇒ Array[[ untyped, AssociationTree ]]

: (untyped, AssociationTree) -> Array[[untyped, AssociationTree]]

Parameters:

Returns:



56
57
58
59
60
61
62
63
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 56

def selected_reflections(model_class, tree)
  tree.children.map do |name, subtree|
    reflection = model_class.reflect_on_association(name)
    raise ConfigurationError, "unknown association: #{name}" unless reflection

    [reflection, subtree]
  end
end

#targets(records, reflection) ⇒ Array[untyped]

: (Array, untyped) -> Array

Parameters:

  • (Array[untyped])
  • (Object)

Returns:

  • (Array[untyped])


111
112
113
114
115
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 111

def targets(records, reflection)
  unique_records(records.flat_map do |record|
    Array(record.association(reflection.name).target)
  end)
end

#unique_records(records) ⇒ Array[untyped]

: (Array) -> Array

Parameters:

  • (Array[untyped])

Returns:

  • (Array[untyped])


118
119
120
121
122
# File 'lib/paper_trail_diff/live_endpoint_batch_loader.rb', line 118

def unique_records(records)
  records.compact.uniq do |record|
    [record.class.base_class.name.to_s, record.id.to_s]
  end
end