Class: PaperTrailDiff::ActivityRootSnapshotRefresher

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

Overview

Advances scalar-only root events while retaining already reconstructed associations.

Instance Method Summary collapse

Constructor Details

#initialize(tree:, traversal:, normalizer:, record_after:, changeset:, partial_snapshotter:) ⇒ ActivityRootSnapshotRefresher

: (tree: AssociationTree, traversal: AssociationTraversal, normalizer: SnapshotNormalizer, record_after: untyped, changeset: untyped, partial_snapshotter: untyped) -> void

Parameters:



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

def initialize( # rubocop:disable Metrics/ParameterLists
  tree:,
  traversal:,
  normalizer:,
  record_after:,
  changeset:,
  partial_snapshotter:
)
  @tree = tree
  @traversal = traversal
  @normalizer = normalizer
  @record_after = record_after
  @changeset = changeset
  @partial_snapshotter = partial_snapshotter
  @unsupported_branches = {} #: Hash[String, Array[String]]
  @relationship_reflections = {} #: Hash[String, Array[untyped]]
end

Instance Method Details

#advanced_attributes(previous, version, changes) ⇒ snapshot_attributes?

: (RecordSnapshot, untyped, untyped) -> snapshot_attributes?

Parameters:

Returns:

  • (snapshot_attributes, nil)


81
82
83
84
85
86
87
88
# File 'lib/paper_trail_diff/activity_root_snapshot_refresher.rb', line 81

def advanced_attributes(previous, version, changes)
  return previous.attributes if changes.empty?

  record = @record_after.call(version)
  return unless record

  @normalizer.attributes_for(record, tree: @tree, path: '')
end

#branches_to_refresh(model_class, changes) ⇒ Array[String]

: (untyped, untyped) -> Array

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Array[String])


91
92
93
94
95
96
# File 'lib/paper_trail_diff/activity_root_snapshot_refresher.rb', line 91

def branches_to_refresh(model_class, changes)
  (unsupported_branches(model_class) + changed_relationship_branches(model_class, changes))
    .uniq
    .sort
    .freeze
end

#call(root_endpoint, context_endpoint, previous, event) ⇒ [ bool, RecordSnapshot? ]

: (untyped, untyped, RecordSnapshot?, ActivityEvent) -> [bool, RecordSnapshot?]

Parameters:

Returns:



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
# File 'lib/paper_trail_diff/activity_root_snapshot_refresher.rb', line 27

def call( # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
  root_endpoint,
  context_endpoint,
  previous,
  event
)
  return [false, nil] unless previous && event.root?

  version = event.version
  model_class = Endpoint.model_class(version)
  return [false, nil] unless same_record?(previous, version)

  changes = @changeset.call(version, model_class)
  return [false, nil] unless changes.respond_to?(:each)

  branches = branches_to_refresh(model_class, changes)
  partial = nil #: RecordSnapshot?
  unless branches.empty?
    partial = @partial_snapshotter.call(root_endpoint, context_endpoint, branches)
  end
  return [false, nil] if !branches.empty? && !partial

  attributes = advanced_attributes(previous, version, changes)
  return [false, nil] unless attributes

  incoming_associations = {} #: snapshot_associations
  incoming_associations = partial.associations if partial
  associations = previous.associations.merge(incoming_associations)
  return [true, previous] if attributes == previous.attributes &&
                             associations == previous.associations

  [
    true,
    RecordSnapshot.new(
      type: previous.type,
      id: previous.id,
      attributes: attributes,
      associations: associations
    )
  ]
end

#changed_relationship_branches(model_class, changes) ⇒ Array[String]

: (untyped, untyped) -> Array

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Array[String])


128
129
130
131
132
133
# File 'lib/paper_trail_diff/activity_root_snapshot_refresher.rb', line 128

def changed_relationship_branches(model_class, changes)
  changed = changes.each_key.map(&:to_s)
  root_relationship_reflections(model_class).filter_map do |reflection|
    reflection.name.to_s if changed.intersect?(relationship_columns(reflection))
  end
end

#direct_versioned_reflection?(reflection) ⇒ Boolean

: (untyped) -> bool

Parameters:

  • (Object)

Returns:

  • (Boolean)


111
112
113
114
115
116
117
118
119
# File 'lib/paper_trail_diff/activity_root_snapshot_refresher.rb', line 111

def direct_versioned_reflection?(reflection)
  return false if reflection.polymorphic? || reflection.options[:through]
  return false if reflection.macro == :has_and_belongs_to_many

  paper_trail = Object.const_get(:PaperTrail) #: untyped
  paper_trail.request.enabled_for_model?(reflection.klass)
rescue NameError
  false
end

#relationship_columns(reflection) ⇒ Array[String]

: (untyped) -> Array

Parameters:

  • (Object)

Returns:

  • (Array[String])


146
147
148
149
150
151
152
153
154
# File 'lib/paper_trail_diff/activity_root_snapshot_refresher.rb', line 146

def relationship_columns(reflection)
  foreign_keys = Array(reflection.foreign_key)
  # @type var foreign_keys: Array[untyped]
  columns = foreign_keys.map do |name| # rubocop:disable Style/SymbolProc
    name.to_s
  end
  columns << reflection.foreign_type.to_s if reflection.polymorphic?
  columns
end

#root_relationship_reflections(model_class) ⇒ Array[untyped]

: (untyped) -> Array

Parameters:

  • (Object)

Returns:

  • (Array[untyped])


136
137
138
139
140
141
142
143
# File 'lib/paper_trail_diff/activity_root_snapshot_refresher.rb', line 136

def root_relationship_reflections(model_class)
  key = model_class.name.to_s
  @relationship_reflections[key] ||= @traversal.reflections_for(
    model_class,
    @tree,
    path: ''
  ).select { |reflection| reflection.macro == :belongs_to }.freeze
end

#same_record?(snapshot, version) ⇒ Boolean

: (RecordSnapshot, untyped) -> bool

Parameters:

Returns:

  • (Boolean)


122
123
124
125
# File 'lib/paper_trail_diff/activity_root_snapshot_refresher.rb', line 122

def same_record?(snapshot, version)
  identity = Endpoint.identity(version)
  snapshot.type.to_s == identity.fetch(0) && snapshot.id.to_s == identity.fetch(1)
end

#unsupported_branches(model_class) ⇒ Array[String]

: (untyped) -> Array

Parameters:

  • (Object)

Returns:

  • (Array[String])


99
100
101
102
103
104
105
106
107
108
# File 'lib/paper_trail_diff/activity_root_snapshot_refresher.rb', line 99

def unsupported_branches(model_class)
  key = model_class.name.to_s
  return @unsupported_branches[key] if @unsupported_branches.key?(key)

  @unsupported_branches[key] = @traversal.selected_reflections(
    model_class
  ).filter_map do |path, reflection|
    path.split('.').first unless direct_versioned_reflection?(reflection)
  end.uniq.sort.freeze
end