paper_trail_diff 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +62 -0
- data/QUICKSTART.md +302 -0
- data/README.md +258 -19
- data/lib/paper_trail_diff/activity_boundary.rb +34 -3
- data/lib/paper_trail_diff/activity_child_candidate_loader.rb +73 -0
- data/lib/paper_trail_diff/activity_event_snapshot_refresher.rb +261 -45
- data/lib/paper_trail_diff/activity_history.rb +136 -0
- data/lib/paper_trail_diff/activity_range.rb +28 -12
- data/lib/paper_trail_diff/activity_snapshot_delta.rb +64 -0
- data/lib/paper_trail_diff/activity_snapshot_sequence.rb +3 -3
- data/lib/paper_trail_diff/activity_timeline_builder.rb +54 -45
- data/lib/paper_trail_diff/activity_version_collector.rb +14 -17
- data/lib/paper_trail_diff/association_diff_traversal.rb +184 -0
- data/lib/paper_trail_diff/branch_snapshot_refresher.rb +5 -3
- data/lib/paper_trail_diff/collection_comparator.rb +155 -0
- data/lib/paper_trail_diff/collection_identity_index.rb +53 -0
- data/lib/paper_trail_diff/collection_transition.rb +25 -0
- data/lib/paper_trail_diff/comparison_batch.rb +151 -0
- data/lib/paper_trail_diff/engine.rb +5 -45
- data/lib/paper_trail_diff/errors.rb +9 -0
- data/lib/paper_trail_diff/historical_snapshot_store.rb +55 -3
- data/lib/paper_trail_diff/instrumentation.rb +30 -0
- data/lib/paper_trail_diff/live_endpoint_batch_loader.rb +133 -0
- data/lib/paper_trail_diff/live_endpoint_provider.rb +48 -0
- data/lib/paper_trail_diff/live_graph_collector.rb +52 -0
- data/lib/paper_trail_diff/paper_trail_adapter.rb +61 -34
- data/lib/paper_trail_diff/preloaded_endpoint_batch_loader.rb +48 -0
- data/lib/paper_trail_diff/prepared_edge_loader.rb +54 -17
- data/lib/paper_trail_diff/prepared_history.rb +14 -4
- data/lib/paper_trail_diff/prepared_history_loader.rb +17 -9
- data/lib/paper_trail_diff/prepared_record_index.rb +138 -10
- data/lib/paper_trail_diff/snapshot.rb +66 -3
- data/lib/paper_trail_diff/snapshot_traversal.rb +97 -0
- data/lib/paper_trail_diff/step.rb +9 -0
- data/lib/paper_trail_diff/support.rb +18 -0
- data/lib/paper_trail_diff/time_activity_timeline_builder.rb +111 -0
- data/lib/paper_trail_diff/time_range.rb +85 -0
- data/lib/paper_trail_diff/time_version_range.rb +53 -0
- data/lib/paper_trail_diff/timeline_builder.rb +13 -7
- data/lib/paper_trail_diff/timeline_range.rb +72 -0
- data/lib/paper_trail_diff/traversal.rb +80 -0
- data/lib/paper_trail_diff/traversal_emitter.rb +42 -0
- data/lib/paper_trail_diff/traversal_entry.rb +94 -0
- data/lib/paper_trail_diff/version.rb +1 -1
- data/lib/paper_trail_diff/version_association_candidate_scope.rb +73 -0
- data/lib/paper_trail_diff.rb +84 -13
- data/sig/generated/paper_trail_diff/activity_boundary.rbs +17 -2
- data/sig/generated/paper_trail_diff/activity_child_candidate_loader.rbs +40 -0
- data/sig/generated/paper_trail_diff/activity_event_snapshot_refresher.rbs +49 -8
- data/sig/generated/paper_trail_diff/activity_history.rbs +79 -0
- data/sig/generated/paper_trail_diff/activity_range.rbs +14 -5
- data/sig/generated/paper_trail_diff/activity_snapshot_delta.rbs +33 -0
- data/sig/generated/paper_trail_diff/activity_snapshot_sequence.rbs +2 -2
- data/sig/generated/paper_trail_diff/activity_timeline_builder.rbs +15 -10
- data/sig/generated/paper_trail_diff/activity_version_collector.rbs +2 -5
- data/sig/generated/paper_trail_diff/association_diff_traversal.rbs +58 -0
- data/sig/generated/paper_trail_diff/branch_snapshot_refresher.rbs +2 -2
- data/sig/generated/paper_trail_diff/collection_comparator.rbs +59 -0
- data/sig/generated/paper_trail_diff/collection_identity_index.rbs +29 -0
- data/sig/generated/paper_trail_diff/collection_transition.rbs +18 -0
- data/sig/generated/paper_trail_diff/comparison_batch.rbs +65 -0
- data/sig/generated/paper_trail_diff/engine.rbs +0 -12
- data/sig/generated/paper_trail_diff/errors.rbs +12 -0
- data/sig/generated/paper_trail_diff/historical_snapshot_store.rbs +22 -2
- data/sig/generated/paper_trail_diff/instrumentation.rbs +12 -0
- data/sig/generated/paper_trail_diff/live_endpoint_batch_loader.rbs +52 -0
- data/sig/generated/paper_trail_diff/live_endpoint_provider.rbs +23 -0
- data/sig/generated/paper_trail_diff/live_graph_collector.rbs +27 -0
- data/sig/generated/paper_trail_diff/paper_trail_adapter.rbs +21 -10
- data/sig/generated/paper_trail_diff/preloaded_endpoint_batch_loader.rbs +24 -0
- data/sig/generated/paper_trail_diff/prepared_edge_loader.rbs +22 -8
- data/sig/generated/paper_trail_diff/prepared_history.rbs +6 -0
- data/sig/generated/paper_trail_diff/prepared_history_loader.rbs +4 -2
- data/sig/generated/paper_trail_diff/prepared_record_index.rbs +61 -6
- data/sig/generated/paper_trail_diff/snapshot.rbs +37 -2
- data/sig/generated/paper_trail_diff/snapshot_traversal.rbs +29 -0
- data/sig/generated/paper_trail_diff/step.rbs +7 -0
- data/sig/generated/paper_trail_diff/support.rbs +6 -0
- data/sig/generated/paper_trail_diff/time_activity_timeline_builder.rbs +46 -0
- data/sig/generated/paper_trail_diff/time_range.rbs +41 -0
- data/sig/generated/paper_trail_diff/time_version_range.rbs +27 -0
- data/sig/generated/paper_trail_diff/timeline_builder.rbs +6 -5
- data/sig/generated/paper_trail_diff/timeline_range.rbs +41 -0
- data/sig/generated/paper_trail_diff/traversal.rbs +41 -0
- data/sig/generated/paper_trail_diff/traversal_emitter.rbs +16 -0
- data/sig/generated/paper_trail_diff/traversal_entry.rbs +52 -0
- data/sig/generated/paper_trail_diff/version_association_candidate_scope.rbs +32 -0
- data/sig/generated/paper_trail_diff.rbs +24 -8
- metadata +49 -4
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module PaperTrailDiff
|
|
5
|
+
# Shared entry construction for internal traversal collaborators.
|
|
6
|
+
class TraversalEmitter
|
|
7
|
+
#: (^(TraversalEntry) -> void) -> void
|
|
8
|
+
def initialize(receiver)
|
|
9
|
+
@receiver = receiver
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# @rbs @receiver: ^(TraversalEntry) -> void
|
|
15
|
+
|
|
16
|
+
#: (kind: Symbol, context: traversal_context, association_path: traversal_association_path, record_path: traversal_record_path, value: untyped, ?association_kind: Symbol?, ?state: traversal_state?, ?attribute: String?) -> void
|
|
17
|
+
def emit( # rubocop:disable Metrics/ParameterLists
|
|
18
|
+
kind:,
|
|
19
|
+
context:,
|
|
20
|
+
association_path:,
|
|
21
|
+
record_path:,
|
|
22
|
+
value:,
|
|
23
|
+
association_kind: nil,
|
|
24
|
+
state: nil,
|
|
25
|
+
attribute: nil
|
|
26
|
+
)
|
|
27
|
+
@receiver.call(
|
|
28
|
+
TraversalEntry.new(
|
|
29
|
+
kind: kind,
|
|
30
|
+
context: context,
|
|
31
|
+
association_path: association_path,
|
|
32
|
+
record_path: record_path,
|
|
33
|
+
association_kind: association_kind,
|
|
34
|
+
state: state,
|
|
35
|
+
attribute: attribute,
|
|
36
|
+
value: value
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
private_constant :TraversalEmitter
|
|
42
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module PaperTrailDiff
|
|
5
|
+
# One immutable location and value emitted while walking a Diff tree.
|
|
6
|
+
class TraversalEntry
|
|
7
|
+
CONTEXTS = %i[change included_state].freeze
|
|
8
|
+
STATES = %i[before after].freeze
|
|
9
|
+
private_constant :CONTEXTS, :STATES
|
|
10
|
+
|
|
11
|
+
attr_reader :kind #: Symbol
|
|
12
|
+
attr_reader :context #: traversal_context
|
|
13
|
+
attr_reader :association_path #: traversal_association_path
|
|
14
|
+
attr_reader :record_path #: traversal_record_path
|
|
15
|
+
attr_reader :association_kind #: Symbol?
|
|
16
|
+
attr_reader :state #: traversal_state?
|
|
17
|
+
attr_reader :attribute #: String?
|
|
18
|
+
attr_reader :value #: untyped
|
|
19
|
+
|
|
20
|
+
#: (kind: Symbol, context: traversal_context, ?association_path: traversal_association_path, ?record_path: traversal_record_path, ?association_kind: Symbol?, ?state: traversal_state?, ?attribute: String?, ?value: untyped) -> void
|
|
21
|
+
def initialize( # rubocop:disable Metrics/ParameterLists
|
|
22
|
+
kind:,
|
|
23
|
+
context:,
|
|
24
|
+
association_path: [],
|
|
25
|
+
record_path: [],
|
|
26
|
+
association_kind: nil,
|
|
27
|
+
state: nil,
|
|
28
|
+
attribute: nil,
|
|
29
|
+
value: nil
|
|
30
|
+
)
|
|
31
|
+
validate!(context, state)
|
|
32
|
+
@kind = kind
|
|
33
|
+
@context = context
|
|
34
|
+
@association_path = immutable_names(association_path)
|
|
35
|
+
@record_path = Support.immutable_copy(record_path)
|
|
36
|
+
@association_kind = association_kind
|
|
37
|
+
@state = state
|
|
38
|
+
@attribute = Support.immutable_copy(attribute&.to_s)
|
|
39
|
+
@value = Support.immutable_copy(value)
|
|
40
|
+
freeze
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
#: () -> bool
|
|
44
|
+
def change?
|
|
45
|
+
context == :change
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
#: () -> bool
|
|
49
|
+
def included_state?
|
|
50
|
+
context == :included_state
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
#: () -> String?
|
|
54
|
+
def association
|
|
55
|
+
association_path.last
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#: () -> RecordReference?
|
|
59
|
+
def record
|
|
60
|
+
record_path.last
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
#: () -> Hash[Symbol, untyped]
|
|
64
|
+
def to_h
|
|
65
|
+
{
|
|
66
|
+
kind: kind,
|
|
67
|
+
context: context,
|
|
68
|
+
association_path: Support.serialize(association_path),
|
|
69
|
+
record_path: Support.serialize(record_path),
|
|
70
|
+
association_kind: association_kind,
|
|
71
|
+
state: state,
|
|
72
|
+
attribute: attribute,
|
|
73
|
+
value: Support.serialize(value)
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
#: (Symbol, Symbol?) -> void
|
|
80
|
+
def validate!(candidate_context, candidate_state)
|
|
81
|
+
unless CONTEXTS.include?(candidate_context)
|
|
82
|
+
raise ArgumentError, "unsupported traversal context: #{candidate_context.inspect}"
|
|
83
|
+
end
|
|
84
|
+
return if candidate_state.nil? || STATES.include?(candidate_state)
|
|
85
|
+
|
|
86
|
+
raise ArgumentError, "unsupported traversal state: #{candidate_state.inspect}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#: (traversal_association_path) -> traversal_association_path
|
|
90
|
+
def immutable_names(names)
|
|
91
|
+
names.map { |name| Support.immutable_copy(name.to_s) }.freeze
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module PaperTrailDiff
|
|
5
|
+
# Selects association activity from a boundary forward plus the state at that boundary.
|
|
6
|
+
class VersionAssociationCandidateScope
|
|
7
|
+
#: (untyped, untyped, ?end_at: untyped) -> void
|
|
8
|
+
def initialize(version_class, start_at, end_at: nil)
|
|
9
|
+
@version_class = version_class
|
|
10
|
+
@start_at = start_at
|
|
11
|
+
@end_at = end_at
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#: (untyped) -> untyped
|
|
15
|
+
def call(relation)
|
|
16
|
+
return relation unless @start_at
|
|
17
|
+
|
|
18
|
+
relation.where(candidate_condition)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# @rbs @version_class: untyped
|
|
24
|
+
# @rbs @start_at: untyped
|
|
25
|
+
# @rbs @end_at: untyped
|
|
26
|
+
|
|
27
|
+
#: () -> String
|
|
28
|
+
def candidate_condition # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
29
|
+
connection = @version_class.connection
|
|
30
|
+
outer = connection.quote_table_name(@version_class.table_name)
|
|
31
|
+
later = connection.quote_table_name('paper_trail_diff_later_versions')
|
|
32
|
+
start_at = connection.quote(@start_at)
|
|
33
|
+
destroyed = connection.quote('destroy')
|
|
34
|
+
activity = activity_condition(outer, start_at)
|
|
35
|
+
compact_sql(<<~SQL)
|
|
36
|
+
(
|
|
37
|
+
#{activity}
|
|
38
|
+
OR (
|
|
39
|
+
#{column(outer, 'created_at')} < #{start_at}
|
|
40
|
+
AND #{column(outer, 'event')} != #{destroyed}
|
|
41
|
+
AND NOT EXISTS (
|
|
42
|
+
SELECT 1
|
|
43
|
+
FROM #{outer} #{later}
|
|
44
|
+
WHERE #{column(later, 'item_type')} = #{column(outer, 'item_type')}
|
|
45
|
+
AND #{column(later, 'item_id')} = #{column(outer, 'item_id')}
|
|
46
|
+
AND #{column(later, 'created_at')} < #{start_at}
|
|
47
|
+
AND #{column(later, 'created_at')} > #{column(outer, 'created_at')}
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
SQL
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
#: (String, String) -> String
|
|
55
|
+
def activity_condition(table, start_at)
|
|
56
|
+
condition = "#{column(table, 'created_at')} >= #{start_at}"
|
|
57
|
+
return condition unless @end_at
|
|
58
|
+
|
|
59
|
+
end_at = @version_class.connection.quote(@end_at)
|
|
60
|
+
"(#{condition} AND #{column(table, 'created_at')} <= #{end_at})"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
#: (String, String) -> String
|
|
64
|
+
def column(table, name)
|
|
65
|
+
"#{table}.#{@version_class.connection.quote_column_name(name)}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
#: (String) -> String
|
|
69
|
+
def compact_sql(sql)
|
|
70
|
+
sql.gsub(/\s+/, ' ').strip
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/paper_trail_diff.rb
CHANGED
|
@@ -5,37 +5,59 @@ require 'paper_trail'
|
|
|
5
5
|
|
|
6
6
|
require_relative 'paper_trail_diff/version'
|
|
7
7
|
require_relative 'paper_trail_diff/support'
|
|
8
|
+
require_relative 'paper_trail_diff/instrumentation'
|
|
8
9
|
require_relative 'paper_trail_diff/errors'
|
|
9
10
|
require_relative 'paper_trail_diff/configuration'
|
|
10
11
|
require_relative 'paper_trail_diff/endpoint'
|
|
11
12
|
require_relative 'paper_trail_diff/association_traversal'
|
|
12
13
|
require_relative 'paper_trail_diff/association_discovery'
|
|
13
14
|
require_relative 'paper_trail_diff/diagnostics'
|
|
15
|
+
require_relative 'paper_trail_diff/collection_identity_index'
|
|
16
|
+
require_relative 'paper_trail_diff/collection_transition'
|
|
14
17
|
require_relative 'paper_trail_diff/snapshot'
|
|
18
|
+
require_relative 'paper_trail_diff/activity_snapshot_delta'
|
|
15
19
|
require_relative 'paper_trail_diff/value_objects'
|
|
20
|
+
require_relative 'paper_trail_diff/traversal_entry'
|
|
21
|
+
require_relative 'paper_trail_diff/traversal_emitter'
|
|
22
|
+
require_relative 'paper_trail_diff/snapshot_traversal'
|
|
23
|
+
require_relative 'paper_trail_diff/association_diff_traversal'
|
|
24
|
+
require_relative 'paper_trail_diff/traversal'
|
|
25
|
+
require_relative 'paper_trail_diff/collection_comparator'
|
|
16
26
|
require_relative 'paper_trail_diff/engine'
|
|
17
27
|
require_relative 'paper_trail_diff/historical_association_reifier'
|
|
18
28
|
require_relative 'paper_trail_diff/prepared_record_index'
|
|
19
29
|
require_relative 'paper_trail_diff/prepared_history'
|
|
30
|
+
require_relative 'paper_trail_diff/version_association_candidate_scope'
|
|
20
31
|
require_relative 'paper_trail_diff/prepared_edge_loader'
|
|
21
32
|
require_relative 'paper_trail_diff/prepared_history_loader'
|
|
22
33
|
require_relative 'paper_trail_diff/prepared_association_reifier'
|
|
23
34
|
require_relative 'paper_trail_diff/live_association_reader'
|
|
35
|
+
require_relative 'paper_trail_diff/live_endpoint_batch_loader'
|
|
36
|
+
require_relative 'paper_trail_diff/preloaded_endpoint_batch_loader'
|
|
37
|
+
require_relative 'paper_trail_diff/live_endpoint_provider'
|
|
38
|
+
require_relative 'paper_trail_diff/live_graph_collector'
|
|
39
|
+
require_relative 'paper_trail_diff/comparison_batch'
|
|
24
40
|
require_relative 'paper_trail_diff/snapshot_normalizer'
|
|
25
41
|
require_relative 'paper_trail_diff/historical_snapshot_store'
|
|
26
42
|
require_relative 'paper_trail_diff/timeline_snapshot_provider'
|
|
27
43
|
require_relative 'paper_trail_diff/activity_event_snapshot_refresher'
|
|
28
44
|
require_relative 'paper_trail_diff/activity_root_snapshot_refresher'
|
|
29
45
|
require_relative 'paper_trail_diff/branch_snapshot_refresher'
|
|
30
|
-
require_relative 'paper_trail_diff/step'
|
|
31
46
|
require_relative 'paper_trail_diff/activity_boundary'
|
|
47
|
+
require_relative 'paper_trail_diff/step'
|
|
32
48
|
require_relative 'paper_trail_diff/analysis'
|
|
33
49
|
require_relative 'paper_trail_diff/version_range'
|
|
50
|
+
require_relative 'paper_trail_diff/time_range'
|
|
51
|
+
require_relative 'paper_trail_diff/time_version_range'
|
|
52
|
+
require_relative 'paper_trail_diff/timeline_range'
|
|
34
53
|
require_relative 'paper_trail_diff/timeline_builder'
|
|
35
54
|
require_relative 'paper_trail_diff/activity_range'
|
|
36
55
|
require_relative 'paper_trail_diff/activity_event'
|
|
56
|
+
require_relative 'paper_trail_diff/activity_child_candidate_loader'
|
|
37
57
|
require_relative 'paper_trail_diff/activity_version_collector'
|
|
38
58
|
require_relative 'paper_trail_diff/activity_snapshot_sequence'
|
|
59
|
+
require_relative 'paper_trail_diff/activity_history'
|
|
60
|
+
require_relative 'paper_trail_diff/time_activity_timeline_builder'
|
|
39
61
|
require_relative 'paper_trail_diff/activity_timeline_builder'
|
|
40
62
|
require_relative 'paper_trail_diff/paper_trail_adapter'
|
|
41
63
|
|
|
@@ -48,8 +70,14 @@ require_relative 'paper_trail_diff/paper_trail_adapter'
|
|
|
48
70
|
# type association_diffs = Hash[String, association_diff]
|
|
49
71
|
# type association_snapshots = Hash[String, AssociationSnapshot]
|
|
50
72
|
# type identity = Array[untyped]
|
|
73
|
+
# type comparison_input = Hash[String | Symbol, untyped]
|
|
74
|
+
# type comparison_results = Hash[identity, Diff]
|
|
51
75
|
# type ignore_option = Array[String | Symbol] | Hash[String | Symbol, untyped]
|
|
52
76
|
# type reference_key = :type | :id | "type" | "id"
|
|
77
|
+
# type traversal_context = :change | :included_state
|
|
78
|
+
# type traversal_state = :before | :after
|
|
79
|
+
# type traversal_association_path = Array[String]
|
|
80
|
+
# type traversal_record_path = Array[RecordReference]
|
|
53
81
|
# end
|
|
54
82
|
|
|
55
83
|
# Structured version comparison for PaperTrail.
|
|
@@ -64,40 +92,82 @@ module PaperTrailDiff
|
|
|
64
92
|
|
|
65
93
|
class << self
|
|
66
94
|
# Compares net state between explicit PaperTrail-version or current-record endpoints.
|
|
67
|
-
#: (untyped, untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option) -> Diff
|
|
68
|
-
def compare(
|
|
69
|
-
|
|
95
|
+
#: (untyped, untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?reload_live_endpoints: bool) -> Diff
|
|
96
|
+
def compare(
|
|
97
|
+
from_version,
|
|
98
|
+
to_version,
|
|
99
|
+
associations: [],
|
|
100
|
+
ignore: DEFAULT_IGNORED_ATTRIBUTES,
|
|
101
|
+
reload_live_endpoints: true
|
|
102
|
+
)
|
|
103
|
+
PaperTrailAdapter.new(
|
|
104
|
+
associations: associations,
|
|
105
|
+
ignore: ignore,
|
|
106
|
+
reload_live_endpoints: reload_live_endpoints
|
|
107
|
+
).compare(
|
|
70
108
|
from_version,
|
|
71
109
|
to_version
|
|
72
110
|
)
|
|
73
111
|
end
|
|
74
112
|
|
|
113
|
+
# Compares many independent endpoint pairs while batching current-record loading.
|
|
114
|
+
#: (Array[comparison_input], ?associations: Array[String | Symbol], ?ignore: ignore_option, ?reload_live_endpoints: bool) -> comparison_results
|
|
115
|
+
def compare_many(
|
|
116
|
+
comparisons,
|
|
117
|
+
associations: [],
|
|
118
|
+
ignore: DEFAULT_IGNORED_ATTRIBUTES,
|
|
119
|
+
reload_live_endpoints: true
|
|
120
|
+
)
|
|
121
|
+
PaperTrailAdapter.new(
|
|
122
|
+
associations: associations,
|
|
123
|
+
ignore: ignore,
|
|
124
|
+
reload_live_endpoints: reload_live_endpoints
|
|
125
|
+
).compare_many(comparisons)
|
|
126
|
+
end
|
|
127
|
+
|
|
75
128
|
# Compares every adjacent reconstructed state in an inclusive version range.
|
|
76
|
-
#: (untyped, from: untyped, to: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option) -> Array[Step]
|
|
77
|
-
def timeline(
|
|
129
|
+
#: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option) -> Array[Step]
|
|
130
|
+
def timeline( # rubocop:disable Metrics/ParameterLists
|
|
131
|
+
record,
|
|
132
|
+
from: nil,
|
|
133
|
+
to: nil,
|
|
134
|
+
within: nil,
|
|
135
|
+
associations: [],
|
|
136
|
+
ignore: DEFAULT_IGNORED_ATTRIBUTES
|
|
137
|
+
)
|
|
78
138
|
PaperTrailAdapter.new(associations: associations, ignore: ignore).timeline(
|
|
79
139
|
record,
|
|
80
140
|
from: from,
|
|
81
|
-
to: to
|
|
141
|
+
to: to,
|
|
142
|
+
within: within
|
|
82
143
|
)
|
|
83
144
|
end
|
|
84
145
|
|
|
85
146
|
# Compares adjacent root and selected-descendant activity boundaries.
|
|
86
|
-
#: (untyped, from: untyped, to: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option) -> Array[ActivityStep]
|
|
87
|
-
def activity_timeline(
|
|
147
|
+
#: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option) -> Array[ActivityStep]
|
|
148
|
+
def activity_timeline( # rubocop:disable Metrics/ParameterLists
|
|
149
|
+
record,
|
|
150
|
+
from: nil,
|
|
151
|
+
to: nil,
|
|
152
|
+
within: nil,
|
|
153
|
+
associations: [],
|
|
154
|
+
ignore: DEFAULT_IGNORED_ATTRIBUTES
|
|
155
|
+
)
|
|
88
156
|
PaperTrailAdapter.new(associations: associations, ignore: ignore).activity_timeline(
|
|
89
157
|
record,
|
|
90
158
|
from: from,
|
|
91
|
-
to: to
|
|
159
|
+
to: to,
|
|
160
|
+
within: within
|
|
92
161
|
)
|
|
93
162
|
end
|
|
94
163
|
|
|
95
164
|
# Builds an endpoint diff and root-checkpoint timeline while normalizing each version once.
|
|
96
|
-
#: (untyped, from: untyped, to: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool) -> Analysis
|
|
165
|
+
#: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool) -> Analysis
|
|
97
166
|
def analyze( # rubocop:disable Metrics/ParameterLists
|
|
98
167
|
record,
|
|
99
|
-
from
|
|
100
|
-
to
|
|
168
|
+
from: nil,
|
|
169
|
+
to: nil,
|
|
170
|
+
within: nil,
|
|
101
171
|
associations: [],
|
|
102
172
|
ignore: DEFAULT_IGNORED_ATTRIBUTES,
|
|
103
173
|
activity: false
|
|
@@ -106,6 +176,7 @@ module PaperTrailDiff
|
|
|
106
176
|
record,
|
|
107
177
|
from: from,
|
|
108
178
|
to: to,
|
|
179
|
+
within: within,
|
|
109
180
|
activity: activity
|
|
110
181
|
)
|
|
111
182
|
end
|
|
@@ -13,14 +13,26 @@ module PaperTrailDiff
|
|
|
13
13
|
|
|
14
14
|
attr_reader recorded_at: untyped
|
|
15
15
|
|
|
16
|
+
attr_reader event: String?
|
|
17
|
+
|
|
18
|
+
attr_reader whodunnit: untyped
|
|
19
|
+
|
|
20
|
+
attr_reader record: RecordReference
|
|
21
|
+
|
|
16
22
|
# : (untyped) -> ActivityBoundary
|
|
17
23
|
def self.from_version: (untyped) -> ActivityBoundary
|
|
18
24
|
|
|
19
25
|
# : (untyped, captured_at: untyped) -> ActivityBoundary
|
|
20
26
|
def self.current: (untyped, captured_at: untyped) -> ActivityBoundary
|
|
21
27
|
|
|
22
|
-
# : (kind: Symbol, version_id: untyped, item_type: untyped, item_id: untyped, recorded_at: untyped) -> void
|
|
23
|
-
def initialize: (kind: Symbol, version_id: untyped, item_type: untyped, item_id: untyped, recorded_at: untyped) -> void
|
|
28
|
+
# : (kind: Symbol, version_id: untyped, item_type: untyped, item_id: untyped, recorded_at: untyped, ?event: untyped, ?whodunnit: untyped) -> void
|
|
29
|
+
def initialize: (kind: Symbol, version_id: untyped, item_type: untyped, item_id: untyped, recorded_at: untyped, ?event: untyped, ?whodunnit: untyped) -> void
|
|
30
|
+
|
|
31
|
+
# : () -> bool
|
|
32
|
+
def version?: () -> bool
|
|
33
|
+
|
|
34
|
+
# : () -> bool
|
|
35
|
+
def current?: () -> bool
|
|
24
36
|
|
|
25
37
|
# : () -> Hash[Symbol, untyped]
|
|
26
38
|
def to_h: () -> Hash[Symbol, untyped]
|
|
@@ -37,6 +49,9 @@ module PaperTrailDiff
|
|
|
37
49
|
# : (from_boundary: ActivityBoundary, to_boundary: ActivityBoundary, diff: Diff) -> void
|
|
38
50
|
def initialize: (from_boundary: ActivityBoundary, to_boundary: ActivityBoundary, diff: Diff) -> void
|
|
39
51
|
|
|
52
|
+
# : () -> bool
|
|
53
|
+
def empty?: () -> bool
|
|
54
|
+
|
|
40
55
|
# : () -> Hash[Symbol, untyped]
|
|
41
56
|
def to_h: () -> Hash[Symbol, untyped]
|
|
42
57
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/activity_child_candidate_loader.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# Loads direct-child identities active at or after one activity boundary.
|
|
5
|
+
class ActivityChildCandidateLoader
|
|
6
|
+
# : (untyped, Array[untyped], untyped, ActivityRange) -> void
|
|
7
|
+
def initialize: (untyped, Array[untyped], untyped, ActivityRange) -> void
|
|
8
|
+
|
|
9
|
+
# : () -> Array[untyped]
|
|
10
|
+
def call: () -> Array[untyped]
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
@parent_class: untyped
|
|
15
|
+
|
|
16
|
+
@parent_ids: Array[untyped]
|
|
17
|
+
|
|
18
|
+
@range: ActivityRange
|
|
19
|
+
|
|
20
|
+
@reflection: untyped
|
|
21
|
+
|
|
22
|
+
# : () -> Array[untyped]
|
|
23
|
+
def historical_ids: () -> Array[untyped]
|
|
24
|
+
|
|
25
|
+
# : (untyped) -> untyped
|
|
26
|
+
def historical_relation: (untyped) -> untyped
|
|
27
|
+
|
|
28
|
+
# : (untyped) -> VersionAssociationCandidateScope
|
|
29
|
+
def candidate_scope: (untyped) -> VersionAssociationCandidateScope
|
|
30
|
+
|
|
31
|
+
# : () -> Array[untyped]
|
|
32
|
+
def current_ids: () -> Array[untyped]
|
|
33
|
+
|
|
34
|
+
# : () -> String
|
|
35
|
+
def child_item_type: () -> String
|
|
36
|
+
|
|
37
|
+
# : () -> Array[String?]
|
|
38
|
+
def parent_types: () -> Array[String?]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -6,8 +6,8 @@ module PaperTrailDiff
|
|
|
6
6
|
class ActivityEventSnapshotRefresher
|
|
7
7
|
RECORD_AFTER_HANDLERS: untyped
|
|
8
8
|
|
|
9
|
-
# : (traversal: AssociationTraversal, pool: SnapshotPool, components: untyped, ?association_reader: untyped) -> void
|
|
10
|
-
def initialize: (traversal: AssociationTraversal, pool: SnapshotPool, components: untyped, ?association_reader: untyped) -> void
|
|
9
|
+
# : (traversal: AssociationTraversal, pool: SnapshotPool, components: untyped, ?association_reader: untyped, ?record_transition: untyped) -> void
|
|
10
|
+
def initialize: (traversal: AssociationTraversal, pool: SnapshotPool, components: untyped, ?association_reader: untyped, ?record_transition: untyped) -> void
|
|
11
11
|
|
|
12
12
|
# : (untyped, untyped, RecordSnapshot, Array[String], ActivityEvent?) -> [bool, RecordSnapshot?]
|
|
13
13
|
def call: (untyped, untyped, RecordSnapshot, Array[String], ActivityEvent?) -> [ bool, RecordSnapshot? ]
|
|
@@ -20,13 +20,30 @@ module PaperTrailDiff
|
|
|
20
20
|
|
|
21
21
|
@pool: SnapshotPool
|
|
22
22
|
|
|
23
|
+
@record_transition: untyped
|
|
24
|
+
|
|
23
25
|
@traversal: AssociationTraversal
|
|
24
26
|
|
|
25
27
|
# : (Array[Array[untyped]], untyped) -> bool
|
|
26
28
|
def unsafe_through_membership_event?: (Array[Array[untyped]], untyped) -> bool
|
|
27
29
|
|
|
28
|
-
# : (
|
|
29
|
-
def
|
|
30
|
+
# : (Array[Array[untyped]], ActivitySnapshotDelta?) -> bool
|
|
31
|
+
def unsafe_nested_membership_delta?: (Array[Array[untyped]], ActivitySnapshotDelta?) -> bool
|
|
32
|
+
|
|
33
|
+
# : (untyped, untyped, RecordSnapshot, SnapshotNormalizer, Array[Array[untyped]], untyped, ActivitySnapshotDelta?) -> [bool, RecordSnapshot]
|
|
34
|
+
def collection_target_snapshot: (untyped, untyped, RecordSnapshot, SnapshotNormalizer, Array[Array[untyped]], untyped, ActivitySnapshotDelta?) -> [ bool, RecordSnapshot ]
|
|
35
|
+
|
|
36
|
+
# : (RecordSnapshot, Array[untyped], untyped, ActivitySnapshotDelta?, Array[untyped], SnapshotNormalizer, untyped, untyped) -> [untyped, RecordSnapshot?]
|
|
37
|
+
def collection_route_event_state: (RecordSnapshot, Array[untyped], untyped, ActivitySnapshotDelta?, Array[untyped], SnapshotNormalizer, untyped, untyped) -> [ untyped, RecordSnapshot? ]
|
|
38
|
+
|
|
39
|
+
# : (untyped, Array[untyped], SnapshotNormalizer, untyped, untyped) -> RecordSnapshot?
|
|
40
|
+
def normalized_collection_event_record: (untyped, Array[untyped], SnapshotNormalizer, untyped, untyped) -> RecordSnapshot?
|
|
41
|
+
|
|
42
|
+
# : (RecordSnapshot, Array[untyped], untyped, ActivitySnapshotDelta?) -> RecordSnapshot?
|
|
43
|
+
def existing_delta_record: (RecordSnapshot, Array[untyped], untyped, ActivitySnapshotDelta?) -> RecordSnapshot?
|
|
44
|
+
|
|
45
|
+
# : (RecordSnapshot, Array[untyped], ActivitySnapshotDelta) -> RecordSnapshot?
|
|
46
|
+
def nested_delta_owner: (RecordSnapshot, Array[untyped], ActivitySnapshotDelta) -> RecordSnapshot?
|
|
30
47
|
|
|
31
48
|
# : (untyped, AssociationTree, String, ?path: String) -> Array[Array[untyped]]
|
|
32
49
|
def direct_collection_routes: (untyped, AssociationTree, String, ?path: String) -> Array[Array[untyped]]
|
|
@@ -34,6 +51,18 @@ module PaperTrailDiff
|
|
|
34
51
|
# : (RecordSnapshot, Array[untyped], untyped, untyped, RecordSnapshot?, ?depth: Integer) -> [RecordSnapshot, bool]
|
|
35
52
|
def replace_collection_route: (RecordSnapshot, Array[untyped], untyped, untyped, RecordSnapshot?, ?depth: Integer) -> [ RecordSnapshot, bool ]
|
|
36
53
|
|
|
54
|
+
# : (AssociationSnapshot, untyped, untyped, untyped, RecordSnapshot, RecordSnapshot?) -> RecordSnapshot?
|
|
55
|
+
def collection_event_child: (AssociationSnapshot, untyped, untyped, untyped, RecordSnapshot, RecordSnapshot?) -> RecordSnapshot?
|
|
56
|
+
|
|
57
|
+
# : (AssociationSnapshot, Array[untyped], untyped, untyped, RecordSnapshot?, Integer) -> [Array[RecordSnapshot], RecordSnapshot?, RecordSnapshot?, bool]?
|
|
58
|
+
def replace_targeted_collection_parent: (AssociationSnapshot, Array[untyped], untyped, untyped, RecordSnapshot?, Integer) -> [ Array[RecordSnapshot], RecordSnapshot?, RecordSnapshot?, bool ]?
|
|
59
|
+
|
|
60
|
+
# : (Array[RecordSnapshot], Integer, RecordSnapshot, RecordSnapshot, bool) -> [Array[RecordSnapshot], RecordSnapshot?, RecordSnapshot?, bool]
|
|
61
|
+
def targeted_parent_replacement: (Array[RecordSnapshot], Integer, RecordSnapshot, RecordSnapshot, bool) -> [ Array[RecordSnapshot], RecordSnapshot?, RecordSnapshot?, bool ]
|
|
62
|
+
|
|
63
|
+
# : (AssociationSnapshot, untyped, untyped, untyped) -> Integer?
|
|
64
|
+
def nested_owner_position: (AssociationSnapshot, untyped, untyped, untyped) -> Integer?
|
|
65
|
+
|
|
37
66
|
# : (untyped, untyped, RecordSnapshot, AssociationTree, SnapshotNormalizer, untyped) -> [bool, RecordSnapshot?]
|
|
38
67
|
def belongs_to_target_snapshot: (untyped, untyped, RecordSnapshot, AssociationTree, SnapshotNormalizer, untyped) -> [ bool, RecordSnapshot? ]
|
|
39
68
|
|
|
@@ -77,8 +106,17 @@ module PaperTrailDiff
|
|
|
77
106
|
# : (untyped, untyped, untyped) -> untyped
|
|
78
107
|
def standard_changeset: (untyped, untyped, untyped) -> untyped
|
|
79
108
|
|
|
80
|
-
# : (untyped
|
|
81
|
-
def
|
|
109
|
+
# : (untyped) -> ActivitySnapshotDelta?
|
|
110
|
+
def activity_snapshot_delta: (untyped) -> ActivitySnapshotDelta?
|
|
111
|
+
|
|
112
|
+
# : (untyped, untyped, RecordSnapshot, ?state: Symbol) -> bool
|
|
113
|
+
def member_of_owner?: (untyped, untyped, RecordSnapshot, ?state: Symbol) -> bool
|
|
114
|
+
|
|
115
|
+
# : (untyped, untyped, state: Symbol) -> untyped
|
|
116
|
+
def event_attribute: (untyped, untyped, state: Symbol) -> untyped
|
|
117
|
+
|
|
118
|
+
# : (untyped, untyped, state: Symbol) -> untyped
|
|
119
|
+
def relationship_owner_id: (untyped, untyped, state: Symbol) -> untyped
|
|
82
120
|
|
|
83
121
|
# : (untyped, untyped, AssociationTree, String, SnapshotNormalizer, untyped, untyped) -> RecordSnapshot?
|
|
84
122
|
def normalize_event_record: (untyped, untyped, AssociationTree, String, SnapshotNormalizer, untyped, untyped) -> RecordSnapshot?
|
|
@@ -86,8 +124,11 @@ module PaperTrailDiff
|
|
|
86
124
|
# : (untyped, habtm_version: untyped) -> HistoricalAssociationReifier
|
|
87
125
|
def historical_reader: (untyped, habtm_version: untyped) -> HistoricalAssociationReifier
|
|
88
126
|
|
|
89
|
-
# : (
|
|
90
|
-
def replace_collection_record: (
|
|
127
|
+
# : (AssociationSnapshot, untyped, RecordSnapshot?) -> [Array[RecordSnapshot], RecordSnapshot?, RecordSnapshot?, bool]
|
|
128
|
+
def replace_collection_record: (AssociationSnapshot, untyped, RecordSnapshot?) -> [ Array[RecordSnapshot], RecordSnapshot?, RecordSnapshot?, bool ]
|
|
129
|
+
|
|
130
|
+
# : (Array[RecordSnapshot], Integer?, RecordSnapshot?) -> Array[RecordSnapshot]
|
|
131
|
+
def replacement_collection_records: (Array[RecordSnapshot], Integer?, RecordSnapshot?) -> Array[RecordSnapshot]
|
|
91
132
|
|
|
92
133
|
# : (untyped, RecordSnapshot?) -> String
|
|
93
134
|
def replacement_type: (untyped, RecordSnapshot?) -> String
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/activity_history.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# Immutable snapshots and steps produced by one activity-history pass.
|
|
5
|
+
class ActivityHistory
|
|
6
|
+
attr_reader steps: Array[ActivityStep]
|
|
7
|
+
|
|
8
|
+
attr_reader root_snapshots: Hash[Array[untyped], RecordSnapshot?]
|
|
9
|
+
|
|
10
|
+
attr_reader first_snapshot: RecordSnapshot?
|
|
11
|
+
|
|
12
|
+
attr_reader last_snapshot: RecordSnapshot?
|
|
13
|
+
|
|
14
|
+
# : (steps: Array[ActivityStep], root_snapshots: Hash[Array[untyped], RecordSnapshot?], first_snapshot: RecordSnapshot?, last_snapshot: RecordSnapshot?) -> void
|
|
15
|
+
def initialize: (steps: Array[ActivityStep], root_snapshots: Hash[Array[untyped], RecordSnapshot?], first_snapshot: RecordSnapshot?, last_snapshot: RecordSnapshot?) -> void
|
|
16
|
+
|
|
17
|
+
# : () -> ActivityHistory
|
|
18
|
+
def self.empty: () -> ActivityHistory
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Builds activity steps while retaining root snapshots for combined analysis.
|
|
22
|
+
class ActivityHistoryBuilder
|
|
23
|
+
# : (Array[untyped], Array[ActivityEvent], untyped, ?current: untyped, ?include_step: untyped) -> void
|
|
24
|
+
def initialize: (Array[untyped], Array[ActivityEvent], untyped, ?current: untyped, ?include_step: untyped) -> void
|
|
25
|
+
|
|
26
|
+
# : () -> ActivityHistory
|
|
27
|
+
def call: () -> ActivityHistory
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
@current: untyped
|
|
32
|
+
|
|
33
|
+
@events: Array[ActivityEvent]
|
|
34
|
+
|
|
35
|
+
@first_snapshot: RecordSnapshot?
|
|
36
|
+
|
|
37
|
+
@include_step: untyped
|
|
38
|
+
|
|
39
|
+
@previous_boundary: ActivityBoundary?
|
|
40
|
+
|
|
41
|
+
@previous_event: ActivityEvent?
|
|
42
|
+
|
|
43
|
+
@previous_snapshot: RecordSnapshot?
|
|
44
|
+
|
|
45
|
+
@root_snapshots: Hash[Array[untyped], RecordSnapshot?]
|
|
46
|
+
|
|
47
|
+
@root_versions: Array[untyped]
|
|
48
|
+
|
|
49
|
+
@selected_last_snapshot: RecordSnapshot?
|
|
50
|
+
|
|
51
|
+
@snapshotter: untyped
|
|
52
|
+
|
|
53
|
+
@steps: Array[ActivityStep]
|
|
54
|
+
|
|
55
|
+
# : () -> void
|
|
56
|
+
def reset: () -> void
|
|
57
|
+
|
|
58
|
+
# : () -> ActivitySnapshotSequence
|
|
59
|
+
def sequence: () -> ActivitySnapshotSequence
|
|
60
|
+
|
|
61
|
+
# : (ActivityEvent, RecordSnapshot?) -> void
|
|
62
|
+
def consume: (ActivityEvent, RecordSnapshot?) -> void
|
|
63
|
+
|
|
64
|
+
# : (RecordSnapshot?) -> void
|
|
65
|
+
def capture_first: (RecordSnapshot?) -> void
|
|
66
|
+
|
|
67
|
+
# : (ActivityBoundary, RecordSnapshot?) -> void
|
|
68
|
+
def append_step: (ActivityBoundary, RecordSnapshot?) -> void
|
|
69
|
+
|
|
70
|
+
# : () -> bool
|
|
71
|
+
def include_previous_step?: () -> bool
|
|
72
|
+
|
|
73
|
+
# : () -> RecordSnapshot?
|
|
74
|
+
def final_snapshot: () -> RecordSnapshot?
|
|
75
|
+
|
|
76
|
+
# : (untyped) -> Array[untyped]
|
|
77
|
+
def version_key: (untyped) -> Array[untyped]
|
|
78
|
+
end
|
|
79
|
+
end
|