Class: PaperTrailDiff::PreparedHistoryLoader

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

Overview

Expands the explicit association tree into a request-scoped PreparedHistory.

Instance Method Summary collapse

Constructor Details

#initialize(record, root_versions:, tree:, traversal:, root_ids: [record.id], start_at: root_versions.first.created_at, end_at: nil, live_records: []) ⇒ PreparedHistoryLoader

: (untyped, root_versions: Array, tree: AssociationTree, traversal: AssociationTraversal, ?root_ids: Array, ?start_at: untyped, ?end_at: untyped, ?live_records: Array) -> void

Parameters:

  • (Object)
  • root_versions: (Array[untyped])
  • tree: (AssociationTree)
  • traversal: (AssociationTraversal)
  • root_ids: (Array[untyped]) (defaults to: [record.id])
  • start_at: (Object) (defaults to: root_versions.first.created_at)
  • end_at: (Object) (defaults to: nil)
  • live_records: (Array[untyped]) (defaults to: [])


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

def initialize( # rubocop:disable Metrics/ParameterLists
  record,
  root_versions:,
  tree:,
  traversal:,
  root_ids: [record.id],
  start_at: root_versions.first.created_at,
  end_at: nil,
  live_records: []
)
  @record = record
  @root_ids = root_ids
  @tree = tree
  @traversal = traversal
  @records = PreparedRecordIndex.new(start_at, end_at: end_at, live_records: live_records)
  @history = PreparedHistory.new(@records)
  @edges = PreparedEdgeLoader.new(@records, root_versions, start_at: start_at)
  @prepared = {} #: Hash[Array[String], Array[String]]
end

Instance Method Details

#callPreparedHistory

: () -> PreparedHistory

Returns:



29
30
31
32
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 29

def call
  load_node(@record.class, @root_ids, @tree, path: '')
  @history
end

#deferred_macro?(reflection) ⇒ Boolean

: (untyped) -> bool

Parameters:

  • (Object)

Returns:

  • (Boolean)


116
117
118
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 116

def deferred_macro?(reflection)
  reflection.options[:through] && !reflection.source_reflection.belongs_to?
end

#edge_key(owner_class, reflection) ⇒ Array[String]

: (untyped, untyped) -> Array

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Array[String])


136
137
138
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 136

def edge_key(owner_class, reflection)
  [owner_class.base_class.name.to_s, reflection.name.to_s]
end

#load_groups(groups) ⇒ void

This method returns an undefined value.

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

Parameters:

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


121
122
123
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 121

def load_groups(groups)
  groups.each_value { |group| load_records(group.fetch(:model), group.fetch(:ids)) }
end

#load_node(model_class, ids, tree, path:) ⇒ void

This method returns an undefined value.

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

Parameters:



46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 46

def load_node(model_class, ids, tree, path:)
  @traversal.reflections_for(model_class, tree, path: path).each do |reflection|
    subtree = tree.child(reflection.name)
    next unless subtree

    groups = prepare_reflection(model_class, ids, reflection)
    load_groups(groups)
    child_path = Support.association_path(path, reflection.name.to_s)
    groups.each_value do |group|
      load_node(group.fetch(:model), group.fetch(:ids), subtree, path: child_path)
    end
  end
end

#load_records(model_class, ids) ⇒ void

This method returns an undefined value.

: (untyped, Array) -> void

Parameters:

  • (Object)
  • (Array[untyped])


126
127
128
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 126

def load_records(model_class, ids)
  @records.load(model_class, ids) if versioned?(model_class)
end

#mark_prepared(owner_class, ids, reflection) ⇒ void

This method returns an undefined value.

: (untyped, Array, untyped) -> void

Parameters:

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


103
104
105
106
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 103

def mark_prepared(owner_class, ids, reflection)
  key = edge_key(owner_class, reflection)
  @prepared[key] = (@prepared.fetch(key, []) | ids.map(&:to_s))
end

#mark_unsupported(owner_class, reflection, groups) ⇒ void

This method returns an undefined value.

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

Parameters:

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


109
110
111
112
113
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 109

def mark_unsupported(owner_class, reflection, groups)
  unsupported = deferred_macro?(reflection) || reflection.foreign_key.is_a?(Array) ||
                groups.values.any? { |group| !versioned?(group.fetch(:model)) }
  @history.mark_unsupported(owner_class, reflection) if unsupported
end

#merge_groups(left, right) ⇒ Hash[String, Hash[Symbol, untyped]]

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

Parameters:

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

Returns:

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


141
142
143
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 141

def merge_groups(left, right)
  Support.merge_record_groups(left, right)
end

#prepare_edge(owner_class, owner_ids, reflection) ⇒ Hash[String, Hash[Symbol, untyped]]

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

Parameters:

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

Returns:

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


82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 82

def prepare_edge(owner_class, owner_ids, reflection)
  missing = unprepared_ids(owner_class, owner_ids, reflection)
  return @history.edge(owner_class, reflection) if missing.empty?

  load_records(owner_class, missing) if reflection.macro == :belongs_to
  groups, memberships = @edges.call(owner_class, missing, reflection)
  @history.merge_edge(owner_class, reflection, groups)
  @history.register_habtm(owner_class, reflection, memberships) if memberships
  mark_prepared(owner_class, missing, reflection)
  mark_unsupported(owner_class, reflection, groups)
  load_groups(groups)
  @history.edge(owner_class, reflection)
end

#prepare_reflection(owner_class, owner_ids, reflection) ⇒ Hash[String, Hash[Symbol, untyped]]

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

Parameters:

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

Returns:

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


61
62
63
64
65
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 61

def prepare_reflection(owner_class, owner_ids, reflection)
  return prepare_through(owner_class, owner_ids, reflection) if reflection.options[:through]

  prepare_edge(owner_class, owner_ids, reflection)
end

#prepare_through(owner_class, owner_ids, reflection) ⇒ Hash[String, Hash[Symbol, untyped]]

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

Parameters:

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

Returns:

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


68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 68

def prepare_through(owner_class, owner_ids, reflection)
  through_groups = prepare_edge(owner_class, owner_ids, reflection.through_reflection)
  targets = {} #: Hash[String, Hash[Symbol, untyped]]
  through_groups.each_value do |group|
    load_groups({ group.fetch(:model).name.to_s => group })
    source = prepare_edge(group.fetch(:model), group.fetch(:ids), reflection.source_reflection)
    targets = merge_groups(targets, source)
  end
  @history.merge_edge(owner_class, reflection, targets)
  @history.mark_unsupported(owner_class, reflection) if deferred_macro?(reflection)
  targets
end

#unprepared_ids(owner_class, ids, reflection) ⇒ Array[untyped]

: (untyped, Array, untyped) -> Array

Parameters:

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

Returns:

  • (Array[untyped])


97
98
99
100
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 97

def unprepared_ids(owner_class, ids, reflection)
  prepared = @prepared.fetch(edge_key(owner_class, reflection), [])
  ids.reject { |id| prepared.include?(id.to_s) }
end

#versioned?(model_class) ⇒ Boolean

: (untyped) -> bool

Parameters:

  • (Object)

Returns:

  • (Boolean)


131
132
133
# File 'lib/paper_trail_diff/prepared_history_loader.rb', line 131

def versioned?(model_class)
  model_class.respond_to?(:paper_trail)
end