Class: PaperTrailDiff::ActivityCollectionEventApplier

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

Overview

Applies a safe collection event across every selected route for its record type.

Instance Method Summary collapse

Constructor Details

#initialize(record_resolver:, record_normalizer:, route_updater:, relationship:) ⇒ ActivityCollectionEventApplier

: (record_resolver: ActivityEventRecordResolver, record_normalizer: ActivityEventRecordNormalizer, route_updater: ActivityCollectionRouteUpdater, relationship: ActivityRelationship) -> void

Parameters:



8
9
10
11
12
13
# File 'lib/paper_trail_diff/activity_collection_event_applier.rb', line 8

def initialize(record_resolver:, record_normalizer:, route_updater:, relationship:)
  @record_resolver = record_resolver
  @record_normalizer = record_normalizer
  @route_updater = route_updater
  @relationship = relationship
end

Instance Method Details

#apply_route(snapshot, route, version, delta, fallback_record, normalizer, endpoints) ⇒ RecordSnapshot

: (RecordSnapshot, Array, untyped, ActivitySnapshotDelta?, Array, SnapshotNormalizer, Array) -> RecordSnapshot

Parameters:

Returns:



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/paper_trail_diff/activity_collection_event_applier.rb', line 49

def apply_route( # rubocop:disable Metrics/ParameterLists
  snapshot, route, version, delta, fallback_record, normalizer, endpoints
)
  record, replacement = route_event_state(
    snapshot, route, version, delta, fallback_record, normalizer, endpoints
  )
  change = ActivityCollectionRouteChange.new(
    route: route,
    version: version,
    record: record,
    replacement: replacement
  )
  @route_updater.call(snapshot, change).fetch(0)
end

#call(root_endpoint, context_endpoint, previous, normalizer, routes, version, delta) ⇒ [ bool, RecordSnapshot ]

: (untyped, untyped, RecordSnapshot, SnapshotNormalizer, Array[Array[untyped]], untyped, ActivitySnapshotDelta?) -> [bool, RecordSnapshot]

Parameters:

Returns:



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/paper_trail_diff/activity_collection_event_applier.rb', line 22

def call( # rubocop:disable Metrics/ParameterLists
  root_endpoint,
  context_endpoint,
  previous,
  normalizer,
  routes,
  version,
  delta
)
  fallback_record = [] #: Array[untyped]
  endpoints = [root_endpoint, context_endpoint]
  snapshot = routes.reduce(previous) do |current, route|
    apply_route(
      current, route, version, delta, fallback_record, normalizer, endpoints
    )
  end
  [true, snapshot]
end

#existing_delta_record(snapshot, route, version, delta) ⇒ RecordSnapshot?

: (RecordSnapshot, Array, untyped, ActivitySnapshotDelta?) -> RecordSnapshot?

Parameters:

Returns:



113
114
115
116
117
118
119
120
121
122
# File 'lib/paper_trail_diff/activity_collection_event_applier.rb', line 113

def existing_delta_record(snapshot, route, version, delta)
  return unless delta && route.length.between?(1, 2)

  owner = route.length == 1 ? snapshot : nested_delta_owner(snapshot, route, delta)
  return unless owner

  association = owner.associations.fetch(route.last.fetch(0))
  position = association.position_for_id(version.item_id)
  association.records.fetch(position) if position
end

#nested_delta_owner(snapshot, route, delta) ⇒ RecordSnapshot?

: (RecordSnapshot, Array, ActivitySnapshotDelta) -> RecordSnapshot?

Parameters:

Returns:



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/paper_trail_diff/activity_collection_event_applier.rb', line 125

def nested_delta_owner(snapshot, route, delta)
  parent_name = route.first.fetch(0)
  reflection = route.last.fetch(1)
  association = snapshot.associations.fetch(parent_name)
  owner_id = @relationship.owner_id(delta, reflection, state: :before)
  position = association.position_for_id(owner_id)
  return unless position

  owner = association.records.fetch(position)
  owner if @relationship.member_of_owner?(delta, reflection, owner, state: :before)
end

#normalized_event_record(record, route, normalizer, endpoints) ⇒ RecordSnapshot?

: (untyped, Array, SnapshotNormalizer, Array) -> RecordSnapshot?

Parameters:

Returns:



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

def normalized_event_record(record, route, normalizer, endpoints)
  _name, reflection, subtree, path = route.last
  @record_normalizer.call(
    record,
    reflection: reflection,
    subtree: subtree,
    path: path,
    normalizer: normalizer,
    root_endpoint: endpoints.fetch(0),
    context_endpoint: endpoints.fetch(1)
  )
end

#route_event_state(snapshot, route, version, delta, fallback_record, normalizer, endpoints) ⇒ [ untyped, RecordSnapshot? ]

: (RecordSnapshot, Array, untyped, ActivitySnapshotDelta?, Array, SnapshotNormalizer, Array) -> [untyped, RecordSnapshot?]

Parameters:

Returns:



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

def route_event_state( # rubocop:disable Metrics/ParameterLists
  snapshot, route, version, delta, fallback_record, normalizer, endpoints
)
  existing = existing_delta_record(snapshot, route, version, delta) if delta
  return [delta, delta.apply(existing)] if delta && existing

  fallback_record << @record_resolver.record_after(version) if fallback_record.empty?
  record = fallback_record.first
  return [record, nil] unless record

  [record, normalized_event_record(record, route, normalizer, endpoints)]
end

#safe?(routes, version, delta) ⇒ Boolean

: (Array[Array[untyped]], untyped, ActivitySnapshotDelta?) -> bool

Parameters:

Returns:

  • (Boolean)


16
17
18
19
# File 'lib/paper_trail_diff/activity_collection_event_applier.rb', line 16

def safe?(routes, version, delta)
  !unsafe_through_membership_event?(routes, version) &&
    !unsafe_nested_membership_delta?(routes, delta)
end

#unsafe_nested_membership_delta?(routes, delta) ⇒ Boolean

: (Array[Array[untyped]], ActivitySnapshotDelta?) -> bool

Parameters:

Returns:

  • (Boolean)


76
77
78
79
80
81
82
# File 'lib/paper_trail_diff/activity_collection_event_applier.rb', line 76

def unsafe_nested_membership_delta?(routes, delta)
  return false unless delta

  routes.any? do |route|
    route.length > 1 && delta.relationship_changed?(route.last.fetch(1))
  end
end

#unsafe_through_membership_event?(routes, version) ⇒ Boolean

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

Parameters:

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

Returns:

  • (Boolean)


65
66
67
68
69
70
71
72
73
# File 'lib/paper_trail_diff/activity_collection_event_applier.rb', line 65

def unsafe_through_membership_event?(routes, version)
  return false if version.event.to_s == 'update'

  routes.any? do |route|
    route.first(route.length - 1).any? do |entry|
      entry.fetch(1).options[:through]
    end
  end
end