Class: PaperTrailDiff::ActivityVersionCollector

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

Overview

Collects root and selected-descendant versions relevant to one root history range.

Instance Method Summary collapse

Constructor Details

#initialize(record, root_versions:, tree:, traversal:, range_start: root_versions.first, range_end: root_versions.last) ⇒ ActivityVersionCollector

: (untyped, root_versions: Array, tree: AssociationTree, traversal: AssociationTraversal, ?range_start: untyped, ?range_end: untyped) -> void

Parameters:

  • (Object)
  • root_versions: (Array[untyped])
  • tree: (AssociationTree)
  • traversal: (AssociationTraversal)
  • range_start: (Object) (defaults to: root_versions.first)
  • range_end: (Object) (defaults to: root_versions.last)


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 8

def initialize( # rubocop:disable Metrics/ParameterLists
  record,
  root_versions:,
  tree:,
  traversal:,
  range_start: root_versions.first,
  range_end: root_versions.last
)
  @record = record
  @root_versions = root_versions
  @tree = tree
  @traversal = traversal
  @range = ActivityRange.new(range_start, range_end)
  @registry = ActivityEventRegistry.new
end

Instance Method Details

#belongs_to_groups(parent_class, parent_versions, reflection) ⇒ Hash[String, untyped]

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

Parameters:

  • (Object)
  • (Array[untyped])
  • (Object)

Returns:

  • (Hash[String, untyped])


99
100
101
102
103
104
105
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 99

def belongs_to_groups(parent_class, parent_versions, reflection)
  rows = parent_class.paper_trail.version_association_class.where(
    version_id: parent_versions.map(&:id),
    foreign_key_name: reflection.foreign_key.to_s
  ).to_a
  identity_groups(rows, reflection)
end

#callArray[ActivityEvent]

: () -> Array

Returns:



25
26
27
28
29
30
31
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 25

def call
  @registry.add(@root_versions)
  collect_tree(@record.class, [@record.id], @tree, path: '', branch: nil) unless @tree.empty?
  @registry.to_a.sort_by do |event|
    Support.chronological_version_key(event.version)
  end.freeze
end

#collect_reflection(parent, reflection, subtree, path, branch) ⇒ void

This method returns an undefined value.

: (Hash[Symbol, untyped], untyped, AssociationTree, String, String) -> void

Parameters:



56
57
58
59
60
61
62
63
64
65
66
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 56

def collect_reflection(parent, reflection, subtree, path, branch)
  groups = edge_groups(parent, reflection, branch)
  groups.each_value do |group|
    @registry.add(group.fetch(:versions), branch: branch)
    next if subtree.empty?

    child_path = join_path(path, reflection.name.to_s)
    collect_tree(group.fetch(:model), group.fetch(:ids), subtree,
                 path: child_path, branch: branch)
  end
end

#collect_tree(parent_class, parent_ids, tree, path:, branch:) ⇒ void

This method returns an undefined value.

: (untyped, Array, AssociationTree, path: String, branch: String?) -> void

Parameters:

  • (Object)
  • (Array[untyped])
  • (AssociationTree)
  • path: (String)
  • branch: (String, nil)


43
44
45
46
47
48
49
50
51
52
53
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 43

def collect_tree(parent_class, parent_ids, tree, path:, branch:)
  parent = group(parent_class, parent_ids)
  @registry.add(parent.fetch(:versions), branch: branch) unless path.empty?
  @traversal.reflections_for(parent_class, tree, path: path).each do |reflection|
    subtree = tree.child(reflection.name)
    next unless subtree

    selected_branch = branch || reflection.name.to_s
    collect_reflection(parent, reflection, subtree, path, selected_branch)
  end
end

#direct_child_groups(parent_class, parent_ids, reflection) ⇒ Hash[String, untyped]

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

Parameters:

  • (Object)
  • (Array[untyped])
  • (Object)

Returns:

  • (Hash[String, untyped])


108
109
110
111
112
113
114
115
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 108

def direct_child_groups(parent_class, parent_ids, reflection)
  item_ids = ActivityChildCandidateLoader.new(
    parent_class, parent_ids, reflection, @range
  ).call
  return {} if item_ids.empty?

  { reflection.klass.name => group(reflection.klass, item_ids) }
end

#edge_groups(parent, reflection, branch) ⇒ Hash[String, untyped]

: (Hash[Symbol, untyped], untyped, String) -> Hash[String, untyped]

Parameters:

  • (Hash[Symbol, untyped])
  • (Object)
  • (String)

Returns:

  • (Hash[String, untyped])


69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 69

def edge_groups(parent, reflection, branch)
  return through_groups(parent, reflection, branch) if reflection.options[:through]

  case reflection.macro
  when :belongs_to
    belongs_to_groups(parent.fetch(:model), parent.fetch(:versions), reflection)
  when :has_one, :has_many
    direct_child_groups(parent.fetch(:model), parent.fetch(:ids), reflection)
  when :has_and_belongs_to_many
    habtm_groups(parent.fetch(:model), parent.fetch(:versions), reflection)
  else
    {}
  end
end

#group(model_class, ids) ⇒ Hash[Symbol, untyped]

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

Parameters:

  • (Object)
  • (Array[untyped])

Returns:

  • (Hash[Symbol, untyped])


143
144
145
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 143

def group(model_class, ids)
  { model: model_class, ids: ids, versions: versions_for(model_class, ids) }
end

#habtm_groups(parent_class, parent_versions, reflection) ⇒ Hash[String, untyped]

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

Parameters:

  • (Object)
  • (Array[untyped])
  • (Object)

Returns:

  • (Hash[String, untyped])


118
119
120
121
122
123
124
125
126
127
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 118

def habtm_groups(parent_class, parent_versions, reflection)
  transaction_ids = parent_versions.filter_map do |version|
    version.transaction_id if version.respond_to?(:transaction_id)
  end
  rows = parent_class.paper_trail.version_association_class.where(
    version_id: transaction_ids,
    foreign_key_name: reflection.name.to_s
  ).to_a
  identity_groups(rows, reflection)
end

#identity_groups(rows, reflection) ⇒ Hash[String, untyped]

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

Parameters:

  • (Array[untyped])
  • (Object)

Returns:

  • (Hash[String, untyped])


130
131
132
133
134
135
136
137
138
139
140
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 130

def identity_groups(rows, reflection)
  identities = rows.group_by { |row| target_class(reflection, row) }
  groups = {} #: Hash[String, untyped]
  identities.each do |model_class, class_rows|
    next unless model_class

    ids = class_rows.map(&:foreign_key_id).compact.uniq
    groups[model_class.name] = group(model_class, ids)
  end
  groups
end

#in_range?(version) ⇒ Boolean

: (untyped) -> bool

Parameters:

  • (Object)

Returns:

  • (Boolean)


184
185
186
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 184

def in_range?(version)
  @range.include?(version)
end

#join_path(parent, name) ⇒ String

: (String, String) -> String

Parameters:

  • (String)
  • (String)

Returns:

  • (String)


189
190
191
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 189

def join_path(parent, name)
  parent.empty? ? name : "#{parent}.#{name}"
end

#merge_groups!(destination, source) ⇒ void

This method returns an undefined value.

: (Hash[String, untyped], Hash[String, untyped]) -> void

Parameters:

  • (Hash[String, untyped])
  • (Hash[String, untyped])


148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 148

def merge_groups!(destination, source)
  source.each do |name, incoming|
    existing = destination[name]
    unless existing
      destination[name] = incoming
      next
    end

    ids = (existing.fetch(:ids) | incoming.fetch(:ids))
    destination[name] = group(existing.fetch(:model), ids)
  end
end

#target_class(reflection, row) ⇒ Object

: (untyped, untyped) -> untyped

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Object)


175
176
177
178
179
180
181
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 175

def target_class(reflection, row)
  return reflection.klass unless reflection.polymorphic?

  Object.const_get(row.foreign_type.to_s) unless row.foreign_type.to_s.empty?
rescue NameError
  nil
end

#through_groups(parent, reflection, branch) ⇒ Hash[String, untyped]

: (Hash[Symbol, untyped], untyped, String) -> Hash[String, untyped]

Parameters:

  • (Hash[Symbol, untyped])
  • (Object)
  • (String)

Returns:

  • (Hash[String, untyped])


85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 85

def through_groups(parent, reflection, branch)
  through = reflection.through_reflection
  intermediate = edge_groups(parent, through, branch)
  result = {} #: Hash[String, untyped]
  intermediate.each_value do |group|
    @registry.add(group.fetch(:versions), branch: branch)
    source = reflection.source_reflection
    children = edge_groups(group, source, branch)
    merge_groups!(result, children)
  end
  result
end

#versions_for(model_class, ids) ⇒ Array[untyped]

: (untyped, Array) -> Array

Parameters:

  • (Object)
  • (Array[untyped])

Returns:

  • (Array[untyped])


162
163
164
165
166
167
168
169
170
171
172
# File 'lib/paper_trail_diff/activity_version_collector.rb', line 162

def versions_for(model_class, ids)
  return [] if ids.empty?

  version_class = model_class.paper_trail.version_class
  @range.scope(
    version_class.where(
      item_type: model_class.base_class.name,
      item_id: ids
    )
  ).to_a.select { |version| in_range?(version) }
end