paper_trail_diff 0.13.1 → 0.14.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 +287 -0
- data/QUICKSTART.md +9 -6
- data/README.md +84 -9
- data/docs/architecture.md +32 -9
- data/docs/performance.md +106 -13
- data/docs/reference.md +242 -29
- data/docs/testing.md +34 -11
- data/lib/paper_trail_diff/activity_belongs_to_event_applier.rb +19 -9
- data/lib/paper_trail_diff/activity_collection_event_applier.rb +11 -1
- data/lib/paper_trail_diff/activity_collection_record_updater.rb +16 -2
- data/lib/paper_trail_diff/activity_event_record_resolver.rb +20 -1
- data/lib/paper_trail_diff/activity_event_route_finder.rb +2 -1
- data/lib/paper_trail_diff/activity_event_snapshot_refresher.rb +1 -1
- data/lib/paper_trail_diff/activity_range.rb +14 -2
- data/lib/paper_trail_diff/activity_relationship.rb +12 -0
- data/lib/paper_trail_diff/activity_root_snapshot_refresher.rb +5 -2
- data/lib/paper_trail_diff/activity_target_candidate_loader.rb +131 -0
- data/lib/paper_trail_diff/activity_timeline_builder.rb +30 -24
- data/lib/paper_trail_diff/activity_version_collector.rb +31 -20
- data/lib/paper_trail_diff/association_activity_edge.rb +236 -0
- data/lib/paper_trail_diff/association_activity_selection.rb +197 -0
- data/lib/paper_trail_diff/association_discovery.rb +8 -13
- data/lib/paper_trail_diff/association_traversal.rb +169 -45
- data/lib/paper_trail_diff/batch_safety.rb +23 -15
- data/lib/paper_trail_diff/batched_root_versions.rb +21 -39
- data/lib/paper_trail_diff/comparison_batch.rb +37 -10
- data/lib/paper_trail_diff/deleted_analysis_batch.rb +34 -16
- data/lib/paper_trail_diff/diagnostics.rb +26 -8
- data/lib/paper_trail_diff/direct_record_state_loader.rb +10 -1
- data/lib/paper_trail_diff/errors.rb +2 -1
- data/lib/paper_trail_diff/habtm_transaction_owners.rb +68 -0
- data/lib/paper_trail_diff/historical_association_reifier.rb +32 -2
- data/lib/paper_trail_diff/historical_snapshot_store.rb +6 -9
- data/lib/paper_trail_diff/live_endpoint_batch_loader.rb +35 -2
- data/lib/paper_trail_diff/live_graph_collector.rb +1 -1
- data/lib/paper_trail_diff/paper_trail_adapter.rb +22 -6
- data/lib/paper_trail_diff/preloaded_endpoint_batch_loader.rb +1 -1
- data/lib/paper_trail_diff/prepared_activity_index.rb +110 -36
- data/lib/paper_trail_diff/prepared_edge_loader.rb +29 -45
- data/lib/paper_trail_diff/prepared_history.rb +63 -54
- data/lib/paper_trail_diff/prepared_history_loader.rb +33 -43
- data/lib/paper_trail_diff/prepared_record_index.rb +26 -0
- data/lib/paper_trail_diff/prepared_snapshot_builder.rb +1 -1
- data/lib/paper_trail_diff/prepared_state_association_reader.rb +119 -29
- data/lib/paper_trail_diff/recorded_changes.rb +83 -0
- data/lib/paper_trail_diff/recorded_class.rb +53 -0
- data/lib/paper_trail_diff/scope_condition.rb +331 -0
- data/lib/paper_trail_diff/scope_ranking.rb +196 -0
- data/lib/paper_trail_diff/scoped_analysis_builder.rb +4 -3
- data/lib/paper_trail_diff/scoped_root_selection.rb +93 -43
- data/lib/paper_trail_diff/snapshot_normalizer.rb +10 -3
- data/lib/paper_trail_diff/support.rb +9 -4
- data/lib/paper_trail_diff/time_activity_timeline_builder.rb +0 -1
- data/lib/paper_trail_diff/time_range.rb +9 -12
- data/lib/paper_trail_diff/time_version_range.rb +5 -5
- data/lib/paper_trail_diff/version.rb +1 -1
- data/lib/paper_trail_diff/version_association_candidate_scope.rb +13 -3
- data/lib/paper_trail_diff/version_range.rb +8 -15
- data/lib/paper_trail_diff/version_scope_filter.rb +11 -3
- data/lib/paper_trail_diff.rb +31 -2
- data/sig/generated/paper_trail_diff/activity_belongs_to_event_applier.rbs +10 -2
- data/sig/generated/paper_trail_diff/activity_collection_event_applier.rbs +5 -0
- data/sig/generated/paper_trail_diff/activity_collection_record_updater.rbs +5 -0
- data/sig/generated/paper_trail_diff/activity_event_record_resolver.rbs +7 -0
- data/sig/generated/paper_trail_diff/activity_range.rbs +6 -2
- data/sig/generated/paper_trail_diff/activity_relationship.rbs +3 -0
- data/sig/generated/paper_trail_diff/activity_root_snapshot_refresher.rbs +2 -0
- data/sig/generated/paper_trail_diff/activity_target_candidate_loader.rbs +79 -0
- data/sig/generated/paper_trail_diff/activity_timeline_builder.rbs +11 -5
- data/sig/generated/paper_trail_diff/activity_version_collector.rbs +10 -4
- data/sig/generated/paper_trail_diff/association_activity_edge.rbs +148 -0
- data/sig/generated/paper_trail_diff/association_activity_selection.rbs +112 -0
- data/sig/generated/paper_trail_diff/association_discovery.rbs +3 -5
- data/sig/generated/paper_trail_diff/association_traversal.rbs +84 -9
- data/sig/generated/paper_trail_diff/batch_safety.rbs +10 -4
- data/sig/generated/paper_trail_diff/batched_root_versions.rbs +2 -8
- data/sig/generated/paper_trail_diff/comparison_batch.rbs +22 -4
- data/sig/generated/paper_trail_diff/deleted_analysis_batch.rbs +16 -4
- data/sig/generated/paper_trail_diff/diagnostics.rbs +7 -2
- data/sig/generated/paper_trail_diff/direct_record_state_loader.rbs +6 -0
- data/sig/generated/paper_trail_diff/errors.rbs +2 -1
- data/sig/generated/paper_trail_diff/habtm_transaction_owners.rbs +40 -0
- data/sig/generated/paper_trail_diff/historical_association_reifier.rbs +13 -0
- data/sig/generated/paper_trail_diff/historical_snapshot_store.rbs +3 -2
- data/sig/generated/paper_trail_diff/live_endpoint_batch_loader.rbs +17 -0
- data/sig/generated/paper_trail_diff/paper_trail_adapter.rbs +5 -0
- data/sig/generated/paper_trail_diff/prepared_activity_index.rbs +52 -10
- data/sig/generated/paper_trail_diff/prepared_edge_loader.rbs +4 -12
- data/sig/generated/paper_trail_diff/prepared_history.rbs +33 -22
- data/sig/generated/paper_trail_diff/prepared_history_loader.rbs +15 -13
- data/sig/generated/paper_trail_diff/prepared_record_index.rbs +15 -0
- data/sig/generated/paper_trail_diff/prepared_state_association_reader.rbs +56 -11
- data/sig/generated/paper_trail_diff/recorded_changes.rbs +47 -0
- data/sig/generated/paper_trail_diff/recorded_class.rbs +22 -0
- data/sig/generated/paper_trail_diff/scope_condition.rbs +185 -0
- data/sig/generated/paper_trail_diff/scope_ranking.rbs +117 -0
- data/sig/generated/paper_trail_diff/scoped_analysis_builder.rbs +2 -2
- data/sig/generated/paper_trail_diff/scoped_root_selection.rbs +41 -7
- data/sig/generated/paper_trail_diff/snapshot_normalizer.rbs +6 -0
- data/sig/generated/paper_trail_diff/support.rbs +5 -2
- data/sig/generated/paper_trail_diff/time_range.rbs +4 -0
- data/sig/generated/paper_trail_diff/time_version_range.rbs +4 -4
- data/sig/generated/paper_trail_diff/version_association_candidate_scope.rbs +7 -0
- data/sig/generated/paper_trail_diff/version_range.rbs +4 -2
- data/sig/generated/paper_trail_diff/version_scope_filter.rbs +4 -0
- data/sig/generated/paper_trail_diff.rbs +21 -2
- metadata +20 -4
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/scope_condition.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# An association scope, or its target's default scope, read as conditions
|
|
5
|
+
# on stored attributes, so membership at a boundary can be decided from each
|
|
6
|
+
# record's state there rather than by a query. A limit, offset or has_one
|
|
7
|
+
# order then ranks the records that meet the conditions (ScopeRanking). It
|
|
8
|
+
# reads the relation the scope builds once and never runs application code
|
|
9
|
+
# per record. A scope it cannot read exactly builds no condition, and the
|
|
10
|
+
# caller keeps its slower path.
|
|
11
|
+
class ScopeCondition
|
|
12
|
+
# Relation parts that leave membership to the where clause and the
|
|
13
|
+
# ranking alone.
|
|
14
|
+
RELATION_VALUES: untyped
|
|
15
|
+
|
|
16
|
+
# Types whose stored values compare in Ruby as the database compares them,
|
|
17
|
+
# named rather than referenced so that loading needs no Active Model.
|
|
18
|
+
VALUE_TYPES: untyped
|
|
19
|
+
|
|
20
|
+
TEXT_TYPE: ::String
|
|
21
|
+
|
|
22
|
+
ENUM_TYPE: ::String
|
|
23
|
+
|
|
24
|
+
BIND_PARAM: ::String
|
|
25
|
+
|
|
26
|
+
ATTRIBUTE: ::String
|
|
27
|
+
|
|
28
|
+
# Adapters that compare strings exactly by default. MySQL and SQL Server
|
|
29
|
+
# ignore case and trailing spaces by default, which Ruby cannot follow.
|
|
30
|
+
EXACT_TEXT_ADAPTERS: untyped
|
|
31
|
+
|
|
32
|
+
# Raised while reading a node that has no exact plain-Ruby reading.
|
|
33
|
+
class Unreadable < StandardError
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Whether the reflection filters its target beyond its keys at all.
|
|
37
|
+
# : (untyped) -> bool
|
|
38
|
+
def self.scoped?: (untyped) -> bool
|
|
39
|
+
|
|
40
|
+
# A through also filters by the scopes of each reflection it passes.
|
|
41
|
+
# : (untyped) -> bool
|
|
42
|
+
def self.scoped_path?: (untyped) -> bool
|
|
43
|
+
|
|
44
|
+
# Returns nil when the scope cannot be read as plain conditions and an
|
|
45
|
+
# exact ranking. A part of a has_many through is read unranked: the
|
|
46
|
+
# through's query keeps only its conditions.
|
|
47
|
+
# : (untyped, ?untyped, ?ranked: bool) -> ScopeCondition?
|
|
48
|
+
def self.build: (untyped, ?untyped, ?ranked: bool) -> ScopeCondition?
|
|
49
|
+
|
|
50
|
+
# nil when the relation picks its members by conditions alone.
|
|
51
|
+
# : (untyped, untyped, untyped) -> ScopeRanking?
|
|
52
|
+
def self.ranking: (untyped, untyped, untyped) -> ScopeRanking?
|
|
53
|
+
|
|
54
|
+
# A has_one through orders its rows by its own order and then its parts',
|
|
55
|
+
# and takes the first, so one that passes a ranked part is not read. A
|
|
56
|
+
# has_many through keeps only its parts' conditions.
|
|
57
|
+
# : (untyped) -> bool
|
|
58
|
+
def self.ranked_through?: (untyped) -> bool
|
|
59
|
+
|
|
60
|
+
# Whether any part of a through, at any depth, has a limit, an offset or
|
|
61
|
+
# a has_one order.
|
|
62
|
+
# : (untyped) -> bool
|
|
63
|
+
def self.ranked_parts?: (untyped) -> bool
|
|
64
|
+
|
|
65
|
+
# A polymorphic part's class, and so its scope, is known only per record.
|
|
66
|
+
# : (untyped) -> bool
|
|
67
|
+
def self.ranked_part?: (untyped) -> bool
|
|
68
|
+
|
|
69
|
+
# A scope that takes the owner differs per record, so it is never read.
|
|
70
|
+
# : (untyped, untyped) -> untyped
|
|
71
|
+
def self.scoped_relation: (untyped, untyped) -> untyped
|
|
72
|
+
|
|
73
|
+
# Some parts, such as the having clause `or` sets, may be present but
|
|
74
|
+
# empty.
|
|
75
|
+
# : (untyped) -> bool
|
|
76
|
+
def self.plain_relation?: (untyped) -> bool
|
|
77
|
+
|
|
78
|
+
# : (untyped, Array[untyped], ?ScopeRanking?) -> void
|
|
79
|
+
def initialize: (untyped, Array[untyped], ?ScopeRanking?) -> void
|
|
80
|
+
|
|
81
|
+
# : (Hash[String, untyped]) -> bool
|
|
82
|
+
def matches?: (Hash[String, untyped]) -> bool
|
|
83
|
+
|
|
84
|
+
# The members among records that are each the owner's by key: those that
|
|
85
|
+
# meet the conditions, then ranked.
|
|
86
|
+
# : (Array[untyped]) -> Array[untyped]
|
|
87
|
+
def members: (Array[untyped]) -> Array[untyped]
|
|
88
|
+
|
|
89
|
+
# Records that meet the conditions, as ranked; unchanged without a
|
|
90
|
+
# ranking.
|
|
91
|
+
# : (Array[untyped]) -> Array[untyped]
|
|
92
|
+
def rank: (Array[untyped]) -> Array[untyped]
|
|
93
|
+
|
|
94
|
+
# SQL compares NULL with nothing, so only an IS NULL test, an equality
|
|
95
|
+
# with nil, matches it.
|
|
96
|
+
COMPARISONS: untyped
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
@model_class: untyped
|
|
101
|
+
|
|
102
|
+
@predicate: Array[untyped]
|
|
103
|
+
|
|
104
|
+
@ranking: ScopeRanking?
|
|
105
|
+
|
|
106
|
+
# : (Array[untyped], Hash[String, untyped]) -> bool
|
|
107
|
+
def evaluate: (Array[untyped], Hash[String, untyped]) -> bool
|
|
108
|
+
|
|
109
|
+
# The form the database holds, as the scope's own values were cast.
|
|
110
|
+
# : (String, Hash[String, untyped]) -> untyped
|
|
111
|
+
def stored: (String, Hash[String, untyped]) -> untyped
|
|
112
|
+
|
|
113
|
+
# Builds each reflection's condition once per target class.
|
|
114
|
+
class Cache
|
|
115
|
+
# : () -> void
|
|
116
|
+
def initialize: () -> void
|
|
117
|
+
|
|
118
|
+
# nil when the scope cannot be read from stored attributes.
|
|
119
|
+
# : (untyped, ?untyped, ?ranked: bool) -> ScopeCondition?
|
|
120
|
+
def call: (untyped, ?untyped, ?ranked: bool) -> ScopeCondition?
|
|
121
|
+
|
|
122
|
+
# The records the reflection's scope admits, as it ranks them. Its
|
|
123
|
+
# condition must exist.
|
|
124
|
+
# : (untyped, Array[untyped], ?untyped, ranked: bool) -> Array[untyped]
|
|
125
|
+
def select: (untyped, Array[untyped], ?untyped, ranked: bool) -> Array[untyped]
|
|
126
|
+
|
|
127
|
+
@conditions: Hash[Array[untyped], ScopeCondition?]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Compiles a where clause into nested arrays of plain comparisons.
|
|
131
|
+
class Reader
|
|
132
|
+
# : (untyped) -> void
|
|
133
|
+
def initialize: (untyped) -> void
|
|
134
|
+
|
|
135
|
+
# : (untyped) -> Array[untyped]
|
|
136
|
+
def call: (untyped) -> Array[untyped]
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
@model_class: untyped
|
|
141
|
+
|
|
142
|
+
# An Or is binary before Rails 7.2 and n-ary from it.
|
|
143
|
+
# : (untyped) -> Array[untyped]
|
|
144
|
+
def either: (untyped) -> Array[untyped]
|
|
145
|
+
|
|
146
|
+
# : (untyped) -> Array[untyped]
|
|
147
|
+
def comparison: (untyped) -> Array[untyped]
|
|
148
|
+
|
|
149
|
+
# : (Symbol, untyped) -> Array[untyped]
|
|
150
|
+
def binary: (Symbol, untyped) -> Array[untyped]
|
|
151
|
+
|
|
152
|
+
# : (untyped) -> Array[untyped]
|
|
153
|
+
def homogeneous_in: (untyped) -> Array[untyped]
|
|
154
|
+
|
|
155
|
+
# Active Record writes an empty NOT IN as a condition that is always
|
|
156
|
+
# true, and a NOT IN list holding NULL matches no row.
|
|
157
|
+
# : (Symbol, untyped, Array[untyped]) -> Array[untyped]
|
|
158
|
+
def list: (Symbol, untyped, Array[untyped]) -> Array[untyped]
|
|
159
|
+
|
|
160
|
+
# Ruby comparison stands in for SQL only on the record's own column of
|
|
161
|
+
# a type both compare alike.
|
|
162
|
+
# : (untyped) -> String
|
|
163
|
+
def column: (untyped) -> String
|
|
164
|
+
|
|
165
|
+
# : (String) -> bool
|
|
166
|
+
def comparable?: (String) -> bool
|
|
167
|
+
|
|
168
|
+
# An enum compares the values it stores, which its subtype describes. A
|
|
169
|
+
# wrapper such as a serialized or encrypted type is none of these.
|
|
170
|
+
# : (untyped) -> untyped
|
|
171
|
+
def value_type: (untyped) -> untyped
|
|
172
|
+
|
|
173
|
+
# A list that is not plain values, such as a subquery, is unreadable.
|
|
174
|
+
# : (untyped) -> Array[untyped]
|
|
175
|
+
def values: (untyped) -> Array[untyped]
|
|
176
|
+
|
|
177
|
+
# A value out of the column's range makes Active Record write a
|
|
178
|
+
# constant condition instead, so it is left unread. Active Record
|
|
179
|
+
# writes IS NULL for a value that is nil before casting, but `= NULL`,
|
|
180
|
+
# which matches nothing, for one that only casts to nil.
|
|
181
|
+
# : (untyped) -> untyped
|
|
182
|
+
def value: (untyped) -> untyped
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/scope_ranking.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# The order, offset and limit by which a scope picks its members from the
|
|
5
|
+
# records that meet its conditions, as the database would rank them. It is
|
|
6
|
+
# read only when the order is total and every key compares in Ruby as SQL
|
|
7
|
+
# compares it; otherwise build returns nil and the caller keeps its slower
|
|
8
|
+
# path.
|
|
9
|
+
class ScopeRanking
|
|
10
|
+
DIRECTIONS: untyped
|
|
11
|
+
|
|
12
|
+
ATTRIBUTE: ::String
|
|
13
|
+
|
|
14
|
+
ENUM_TYPE: ::String
|
|
15
|
+
|
|
16
|
+
# Integers, booleans and dates sort alike everywhere. Strings follow a
|
|
17
|
+
# collation, so they are not read.
|
|
18
|
+
ORDER_TYPES: untyped
|
|
19
|
+
|
|
20
|
+
# Times sort alike only at the precision both the column and history
|
|
21
|
+
# keep. A time of day is not read: in memory it keeps the date it was
|
|
22
|
+
# given, which the database drops.
|
|
23
|
+
DATETIME_TYPE: ::String
|
|
24
|
+
|
|
25
|
+
# Where each adapter sorts NULL in an ascending order by default; a
|
|
26
|
+
# descending order reverses it. Another adapter's ranking is not read.
|
|
27
|
+
NULLS_LAST: untyped
|
|
28
|
+
|
|
29
|
+
# Places in a sort key, of which only the order counts: a value between a
|
|
30
|
+
# NULL sorted first and one sorted last, and false before true. Every
|
|
31
|
+
# value is a number, so that a descending key can negate it.
|
|
32
|
+
NULL_PLACE: untyped
|
|
33
|
+
|
|
34
|
+
VALUE_PLACE: ::Integer
|
|
35
|
+
|
|
36
|
+
BOOLEAN_VALUE: untyped
|
|
37
|
+
|
|
38
|
+
# Whether the relation picks members by rank rather than by condition
|
|
39
|
+
# alone. A has_one takes the first record its order names.
|
|
40
|
+
# : (untyped, untyped) -> bool
|
|
41
|
+
def self.ranks?: (untyped, untyped) -> bool
|
|
42
|
+
|
|
43
|
+
# A has_many, through or not, or a direct has_one is ranked per owner as
|
|
44
|
+
# its own query ranks it. A has_many through ranks the rows its join
|
|
45
|
+
# yields, a record reached twice counting twice, by its own order first.
|
|
46
|
+
# Returns nil when the ranking cannot be read exactly.
|
|
47
|
+
# : (untyped, untyped, untyped) -> ScopeRanking?
|
|
48
|
+
def self.build: (untyped, untyped, untyped) -> ScopeRanking?
|
|
49
|
+
|
|
50
|
+
# : (untyped) -> bool
|
|
51
|
+
def self.own?: (untyped) -> bool
|
|
52
|
+
|
|
53
|
+
# Active Record casts a limit to an integer but keeps an offset as given,
|
|
54
|
+
# which may be a String or SQL.
|
|
55
|
+
# : (untyped) -> bool
|
|
56
|
+
def self.plain_offset?: (untyped) -> bool
|
|
57
|
+
|
|
58
|
+
# The order's keys up to the primary key, which makes it total. Keys
|
|
59
|
+
# after it never decide anything.
|
|
60
|
+
# : (Array[untyped], untyped) -> Array[[String, bool]]?
|
|
61
|
+
def self.keys: (Array[untyped], untyped) -> Array[[ String, bool ]]?
|
|
62
|
+
|
|
63
|
+
# The record's own column, sorted plainly in one direction.
|
|
64
|
+
# : (untyped, untyped) -> String?
|
|
65
|
+
def self.column: (untyped, untyped) -> String?
|
|
66
|
+
|
|
67
|
+
# : (untyped, String) -> bool
|
|
68
|
+
def self.orderable?: (untyped, String) -> bool
|
|
69
|
+
|
|
70
|
+
# Active Record truncates a time to its column's precision before writing
|
|
71
|
+
# it, so history holds the stored value when it keeps that many digits.
|
|
72
|
+
# Times the type stores in UTC sort as the instants they name; local
|
|
73
|
+
# times repeat an hour when clocks go back.
|
|
74
|
+
# : (untyped, untyped) -> bool
|
|
75
|
+
def self.exact_time?: (untyped, untyped) -> bool
|
|
76
|
+
|
|
77
|
+
# : (untyped, Array[[String, bool]], bool, Integer?, Integer?) -> void
|
|
78
|
+
def initialize: (untyped, Array[[ String, bool ]], bool, Integer?, Integer?) -> void
|
|
79
|
+
|
|
80
|
+
# The members among records that met the scope's conditions, in order.
|
|
81
|
+
# : (Array[untyped]) -> Array[untyped]
|
|
82
|
+
def call: (Array[untyped]) -> Array[untyped]
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
@keys: Array[[ String, bool ]]
|
|
87
|
+
|
|
88
|
+
@limit: Integer?
|
|
89
|
+
|
|
90
|
+
@model_class: untyped
|
|
91
|
+
|
|
92
|
+
@nulls_last: bool
|
|
93
|
+
|
|
94
|
+
@offset: Integer?
|
|
95
|
+
|
|
96
|
+
# Keys compare in turn, and the primary key always decides. A descending
|
|
97
|
+
# key negates its places, which also moves NULL to the other end, as each
|
|
98
|
+
# adapter does by default.
|
|
99
|
+
# : (Hash[String, untyped]) -> Array[Array[Numeric]]
|
|
100
|
+
def sort_key: (Hash[String, untyped]) -> Array[Array[Numeric]]
|
|
101
|
+
|
|
102
|
+
# NULL holds the adapter's place alone, so it never compares as a value.
|
|
103
|
+
# A version saved before its column existed holds NULL there too.
|
|
104
|
+
# : (untyped) -> Array[Numeric]
|
|
105
|
+
def place: (untyped) -> Array[Numeric]
|
|
106
|
+
|
|
107
|
+
# A time as its seconds, exactly, and a date as its day number.
|
|
108
|
+
# : (untyped) -> Numeric
|
|
109
|
+
def number: (untyped) -> Numeric
|
|
110
|
+
|
|
111
|
+
# The value the database sorts by, as the key's type casts it. An enum
|
|
112
|
+
# sorts by the integer it stores; other types are compared cast, since an
|
|
113
|
+
# adapter may serialize a time or date as a wrapper, as SQL Server does.
|
|
114
|
+
# : (String, Hash[String, untyped]) -> untyped
|
|
115
|
+
def stored: (String, Hash[String, untyped]) -> untyped
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module PaperTrailDiff
|
|
4
4
|
# Selects both populations and checks their shared ceiling before analysis.
|
|
5
5
|
class ScopedAnalysisBuilder
|
|
6
|
-
# : (untyped, limit: Integer?, within: untyped, historical_filter: untyped, max_filter_versions: Integer, include_deleted: bool, analyzer: untyped, deleted_analyzer: untyped) -> void
|
|
7
|
-
def initialize: (untyped, limit: Integer?, within: untyped, historical_filter: untyped, max_filter_versions: Integer, include_deleted: bool, analyzer: untyped, deleted_analyzer: untyped) -> void
|
|
6
|
+
# : (untyped, limit: Integer?, within: untyped, historical_filter: untyped, max_filter_versions: Integer, include_deleted: bool, analyzer: untyped, deleted_analyzer: untyped, ?activity_tree: AssociationTree?) -> void
|
|
7
|
+
def initialize: (untyped, limit: Integer?, within: untyped, historical_filter: untyped, max_filter_versions: Integer, include_deleted: bool, analyzer: untyped, deleted_analyzer: untyped, ?activity_tree: AssociationTree?) -> void
|
|
8
8
|
|
|
9
9
|
# : () -> ScopedAnalysis
|
|
10
10
|
def call: () -> ScopedAnalysis
|
|
@@ -38,8 +38,11 @@ module PaperTrailDiff
|
|
|
38
38
|
def initialize: (records: Array[untyped], unreachable: Array[Array[String]]) -> void
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
#
|
|
42
|
-
|
|
41
|
+
# `activity_tree` names the association paths whose changes also select a
|
|
42
|
+
# root, as an activity analysis reports them. Without one, only a root's
|
|
43
|
+
# own versions select it.
|
|
44
|
+
# : (untyped, time_range: TimeRange?, limit: Integer, ?historical_filter: untyped, ?max_filter_versions: Integer, ?activity_tree: AssociationTree?) -> void
|
|
45
|
+
def initialize: (untyped, time_range: TimeRange?, limit: Integer, ?historical_filter: untyped, ?max_filter_versions: Integer, ?activity_tree: AssociationTree?) -> void
|
|
43
46
|
|
|
44
47
|
# : () -> Result
|
|
45
48
|
def call: () -> Result
|
|
@@ -50,6 +53,8 @@ module PaperTrailDiff
|
|
|
50
53
|
|
|
51
54
|
@limit: Integer
|
|
52
55
|
|
|
56
|
+
@related: AssociationActivitySelection?
|
|
57
|
+
|
|
53
58
|
@scope: untyped
|
|
54
59
|
|
|
55
60
|
@time_range: TimeRange?
|
|
@@ -59,14 +64,28 @@ module PaperTrailDiff
|
|
|
59
64
|
# in the window -- not to the relation or `limit:` -- so a report on one
|
|
60
65
|
# record could read every id in a busy table. A subquery keeps the work
|
|
61
66
|
# bounded by what the relation and the deletions actually contain.
|
|
62
|
-
# : () -> Result
|
|
63
|
-
def database_selection: () -> Result
|
|
67
|
+
# : (Array[AssociationActivitySelection::Query]) -> Result
|
|
68
|
+
def database_selection: (Array[AssociationActivitySelection::Query]) -> Result
|
|
69
|
+
|
|
70
|
+
# Comparing in SQL needs every subquery's column to share the key's type.
|
|
71
|
+
# : (Array[AssociationActivitySelection::source]) -> Array[AssociationActivitySelection::Query]?
|
|
72
|
+
def subqueries: (Array[AssociationActivitySelection::source]) -> Array[AssociationActivitySelection::Query]?
|
|
73
|
+
|
|
74
|
+
# : (Array[String]) -> Result
|
|
75
|
+
def plucked_selection: (Array[String]) -> Result
|
|
64
76
|
|
|
65
77
|
# Comparing the two columns in SQL needs them to share a type: PostgreSQL
|
|
66
|
-
# rejects an integer key against a string item_id outright.
|
|
78
|
+
# rejects an integer key against a string item_id outright. A composite
|
|
79
|
+
# key names no single attribute, so it has no type and never matches.
|
|
67
80
|
# : () -> bool
|
|
68
81
|
def comparable_keys?: () -> bool
|
|
69
82
|
|
|
83
|
+
# : () -> Symbol?
|
|
84
|
+
def key_type: () -> Symbol?
|
|
85
|
+
|
|
86
|
+
# : (Array[AssociationActivitySelection::Query]) -> Array[String]
|
|
87
|
+
def related_missing_ids: (Array[AssociationActivitySelection::Query]) -> Array[String]
|
|
88
|
+
|
|
70
89
|
# Changed in the window but without a row, found with an anti-join instead
|
|
71
90
|
# of comparing two plucked lists.
|
|
72
91
|
# : () -> Array[String]
|
|
@@ -81,6 +100,10 @@ module PaperTrailDiff
|
|
|
81
100
|
# : (untyped) -> untyped
|
|
82
101
|
def normalize_scope: (untyped) -> untyped
|
|
83
102
|
|
|
103
|
+
# : () -> void
|
|
104
|
+
def reject_unversioned!: () -> void
|
|
105
|
+
|
|
106
|
+
# No Integer subclass has instances, so this is `is_a?` by another name.
|
|
84
107
|
# : (Integer) -> Integer
|
|
85
108
|
def validate_limit: (Integer) -> Integer
|
|
86
109
|
|
|
@@ -98,8 +121,13 @@ module PaperTrailDiff
|
|
|
98
121
|
# Deduplicate records rather than adding SQL DISTINCT: an otherwise valid
|
|
99
122
|
# relation may order by joined columns or select a PostgreSQL json column.
|
|
100
123
|
# Read bounded pages until the relation ends or too many unique roots appear.
|
|
101
|
-
#
|
|
102
|
-
|
|
124
|
+
# Each candidate source is an id list or a subquery; a record matching any
|
|
125
|
+
# of them is selected.
|
|
126
|
+
# : (Array[untyped]) -> Array[untyped]
|
|
127
|
+
def selected_records: (Array[untyped]) -> Array[untyped]
|
|
128
|
+
|
|
129
|
+
# : (Array[untyped]) -> untyped
|
|
130
|
+
def candidate_relation: (Array[untyped]) -> untyped
|
|
103
131
|
|
|
104
132
|
# : (untyped, Integer) -> Array[untyped]
|
|
105
133
|
def record_page: (untyped, Integer) -> Array[untyped]
|
|
@@ -121,6 +149,12 @@ module PaperTrailDiff
|
|
|
121
149
|
# : () -> String
|
|
122
150
|
def item_type: () -> String
|
|
123
151
|
|
|
152
|
+
# A relation delegates class methods to its model, so every mutation here,
|
|
153
|
+
# which drops `.model`, answers the same.
|
|
154
|
+
# mutant:disable
|
|
155
|
+
# : () -> untyped
|
|
156
|
+
def model: () -> untyped
|
|
157
|
+
|
|
124
158
|
# : () -> untyped
|
|
125
159
|
def base_class: () -> untyped
|
|
126
160
|
|
|
@@ -98,6 +98,12 @@ module PaperTrailDiff
|
|
|
98
98
|
# : (untyped, untyped, AssociationTree, String, untyped) -> AssociationSnapshot
|
|
99
99
|
def association_snapshot: (untyped, untyped, AssociationTree, String, untyped) -> AssociationSnapshot
|
|
100
100
|
|
|
101
|
+
# A reified history can hold a member PaperTrail could not rebuild. A
|
|
102
|
+
# through loads a record once per join that reaches it; it is one member,
|
|
103
|
+
# as Active Record compares records by class and id.
|
|
104
|
+
# : (untyped, untyped) -> Array[untyped]
|
|
105
|
+
def members: (untyped, untyped) -> Array[untyped]
|
|
106
|
+
|
|
101
107
|
# : (Array[untyped], AssociationTree, String, untyped) -> Array[RecordSnapshot]
|
|
102
108
|
def normalize_children: (Array[untyped], AssociationTree, String, untyped) -> Array[RecordSnapshot]
|
|
103
109
|
|
|
@@ -15,6 +15,9 @@ module PaperTrailDiff
|
|
|
15
15
|
# : (untyped) -> Array[untyped]
|
|
16
16
|
def self?.chronological_version_key: (untyped) -> Array[untyped]
|
|
17
17
|
|
|
18
|
+
# : (untyped, untyped) -> Array[untyped]
|
|
19
|
+
def self?.version_key: (untyped, untyped) -> Array[untyped]
|
|
20
|
+
|
|
18
21
|
# Ordering falls back to the id whenever timestamps tie, which recovers the
|
|
19
22
|
# real order only while ids increase with insertion. An autoincrement id
|
|
20
23
|
# does; a UUID does not, so a tie between UUID-keyed versions is genuinely
|
|
@@ -59,8 +62,8 @@ module PaperTrailDiff
|
|
|
59
62
|
# : (untyped, untyped) -> Integer
|
|
60
63
|
def self?.compare_versions: (untyped, untyped) -> Integer
|
|
61
64
|
|
|
62
|
-
# : (String, String) -> String
|
|
63
|
-
def self?.association_path: (String, String) -> String
|
|
65
|
+
# : (String, String | Symbol) -> String
|
|
66
|
+
def self?.association_path: (String, String | Symbol) -> String
|
|
64
67
|
|
|
65
68
|
# : (Hash[String, Hash[Symbol, untyped]], Hash[String, Hash[Symbol, untyped]]) -> Hash[String, Hash[Symbol, untyped]]
|
|
66
69
|
def self?.merge_record_groups: (Hash[String, Hash[Symbol, untyped]], Hash[String, Hash[Symbol, untyped]]) -> Hash[String, Hash[Symbol, untyped]]
|
|
@@ -41,6 +41,10 @@ module PaperTrailDiff
|
|
|
41
41
|
# : (untyped, boundary: Symbol) -> Time
|
|
42
42
|
def coerce_time: (untyped, boundary: Symbol) -> Time
|
|
43
43
|
|
|
44
|
+
# Active Support 8.0 and older warn, once per process, that `to_time` will
|
|
45
|
+
# change on a zoned time, so read zoned values without it. Every branch
|
|
46
|
+
# gives the same instant, so no spec (and no mutation) can tell them apart.
|
|
47
|
+
# mutant:disable
|
|
44
48
|
# : (untyped) -> Time
|
|
45
49
|
def time_value: (untyped) -> Time
|
|
46
50
|
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
module PaperTrailDiff
|
|
4
4
|
# Selects in-range root versions plus one later reconstruction boundary.
|
|
5
5
|
class TimeVersionRange
|
|
6
|
-
# : (untyped, time_range: TimeRange,
|
|
7
|
-
def initialize: (untyped, time_range: TimeRange,
|
|
6
|
+
# : (untyped, time_range: TimeRange, version_scope: untyped, live_endpoint: untyped) -> void
|
|
7
|
+
def initialize: (untyped, time_range: TimeRange, version_scope: untyped, live_endpoint: untyped) -> void
|
|
8
8
|
|
|
9
|
-
# : (
|
|
10
|
-
def select_plan: (
|
|
9
|
+
# : (context_required: bool) -> RootVersionPlan
|
|
10
|
+
def select_plan: (context_required: bool) -> RootVersionPlan
|
|
11
11
|
|
|
12
12
|
private
|
|
13
13
|
|
|
@@ -36,6 +36,13 @@ module PaperTrailDiff
|
|
|
36
36
|
# : (Hash[Symbol, String], String, untyped) -> String
|
|
37
37
|
def activity_condition: (Hash[Symbol, String], String, untyped) -> String
|
|
38
38
|
|
|
39
|
+
# A time quoted on its own takes the adapter's default precision, which on
|
|
40
|
+
# SQL Server is `datetime` and rounds to 1/300 second. Serializing through
|
|
41
|
+
# the column's type quotes it as a bound value would be, at the precision
|
|
42
|
+
# `created_at` is stored with.
|
|
43
|
+
# : (untyped, untyped) -> String
|
|
44
|
+
def quote_time: (untyped, untyped) -> String
|
|
45
|
+
|
|
39
46
|
# : (untyped, String, String) -> String
|
|
40
47
|
def column: (untyped, String, String) -> String
|
|
41
48
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module PaperTrailDiff
|
|
4
4
|
# Selects an inclusive, chronological range from a record's root versions.
|
|
5
5
|
class VersionRange
|
|
6
|
-
# : (untyped, from: untyped, to: untyped,
|
|
7
|
-
def initialize: (untyped, from: untyped, to: untyped,
|
|
6
|
+
# : (untyped, from: untyped, to: untyped, version_scope: untyped) -> void
|
|
7
|
+
def initialize: (untyped, from: untyped, to: untyped, version_scope: untyped) -> void
|
|
8
8
|
|
|
9
9
|
# Keep both reconstruction boundaries and the step pairs a filter implies.
|
|
10
10
|
# : () -> RootVersionPlan
|
|
@@ -35,6 +35,8 @@ module PaperTrailDiff
|
|
|
35
35
|
# : (untyped, untyped, boundary: Symbol) -> void
|
|
36
36
|
def validate_boundary!: (untyped, untyped, boundary: Symbol) -> void
|
|
37
37
|
|
|
38
|
+
# The relation holds only this record's versions, so finding the id there
|
|
39
|
+
# also settles which record the version belongs to.
|
|
38
40
|
# : (untyped, untyped) -> bool
|
|
39
41
|
def valid_boundary?: (untyped, untyped) -> bool
|
|
40
42
|
end
|
|
@@ -12,6 +12,10 @@ module PaperTrailDiff
|
|
|
12
12
|
# : (untyped, Array[untyped]) -> Array[untyped]
|
|
13
13
|
def call: (untyped, Array[untyped]) -> Array[untyped]
|
|
14
14
|
|
|
15
|
+
# The ids of the versions the scope keeps, or nil when there is no scope.
|
|
16
|
+
# : (untyped) -> Set[untyped]?
|
|
17
|
+
def chosen_ids: (untyped) -> Set[untyped]?
|
|
18
|
+
|
|
15
19
|
private
|
|
16
20
|
|
|
17
21
|
@scope: untyped
|
|
@@ -41,7 +41,9 @@ module PaperTrailDiff
|
|
|
41
41
|
def self.analyze_many: (Array[untyped], ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool, ?group: Symbol?, ?allow_expensive: bool) -> Hash[identity, Analysis]
|
|
42
42
|
|
|
43
43
|
# Analyzes every root the relation reaches whose history moved inside the
|
|
44
|
-
# window.
|
|
44
|
+
# window. With `activity: true`, a change to a record on one of the
|
|
45
|
+
# requested association paths also counts, because the activity timeline
|
|
46
|
+
# reports it. Joined duplicates are read in bounded pages and analyzed once.
|
|
45
47
|
#
|
|
46
48
|
# `limit:` is required and exceeding it raises. Selection moves into the gem
|
|
47
49
|
# here. The relation's own limit/offset select the live page; this separate
|
|
@@ -67,7 +69,8 @@ module PaperTrailDiff
|
|
|
67
69
|
# : (untyped, limit: Integer?, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool, ?group: Symbol?, ?historical_filter: untyped, ?max_filter_versions: Integer, ?include_deleted: bool, ?allow_expensive: bool) -> ScopedAnalysis
|
|
68
70
|
def self.analyze_scope: (untyped, limit: Integer?, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool, ?group: Symbol?, ?historical_filter: untyped, ?max_filter_versions: Integer, ?include_deleted: bool, ?allow_expensive: bool) -> ScopedAnalysis
|
|
69
71
|
|
|
70
|
-
# Recent root and selected-child activity through the current saved state
|
|
72
|
+
# Recent root and selected-child activity through the current saved state,
|
|
73
|
+
# for every root that changed or whose requested associations did.
|
|
71
74
|
# Historical windows remain explicit on analyze_scope; this entry point is
|
|
72
75
|
# deliberately named for a report through now rather than an as-of query.
|
|
73
76
|
# : (untyped, since: untyped, limit: Integer, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?snapshots: bool, ?group: Symbol?, ?include_deleted: bool, ?historical_filter: untyped, ?max_filter_versions: Integer, ?allow_expensive: bool) -> ScopedAnalysis
|
|
@@ -105,6 +108,22 @@ module PaperTrailDiff
|
|
|
105
108
|
# JSON uses for a present null.
|
|
106
109
|
# : (untyped, ?untyped) -> nested_changes
|
|
107
110
|
def self.nested_changes: (untyped, ?untyped) -> nested_changes
|
|
111
|
+
|
|
112
|
+
# Reads what PaperTrail recorded with one version: its `object_changes`,
|
|
113
|
+
# typed by the version's model, as `{ "title" => <from "Draft" to "Published"> }`.
|
|
114
|
+
#
|
|
115
|
+
# versions = PaperTrail::Version.where(id: steps.map { _1.source_boundary.version_id })
|
|
116
|
+
# versions.to_h { [_1.id, PaperTrailDiff.recorded_changes(_1)] }
|
|
117
|
+
#
|
|
118
|
+
# A step's diff compares the states before and after an event, so it also
|
|
119
|
+
# includes anything saved without a version in between; this does not.
|
|
120
|
+
# Returns nil when nothing was recorded (no `object_changes` column, or no
|
|
121
|
+
# value for this version), which differs from a recorded empty hash. Unlike
|
|
122
|
+
# PaperTrail's `version.changeset`, it never loads the record, so it costs no
|
|
123
|
+
# query per version and still types a deleted record's changes. `ignore:`
|
|
124
|
+
# takes attribute names, as an array, and defaults to `updated_at`.
|
|
125
|
+
# : (untyped, ?ignore: Array[String | Symbol]) -> Hash[String, ValueChange]?
|
|
126
|
+
def self.recorded_changes: (untyped, ?ignore: Array[String | Symbol]) -> Hash[String, ValueChange]?
|
|
108
127
|
end
|
|
109
128
|
|
|
110
129
|
module PaperTrailDiff
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: paper_trail_diff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.14.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Williams
|
|
@@ -67,11 +67,14 @@ files:
|
|
|
67
67
|
- lib/paper_trail_diff/activity_root_steps.rb
|
|
68
68
|
- lib/paper_trail_diff/activity_snapshot_delta.rb
|
|
69
69
|
- lib/paper_trail_diff/activity_snapshot_sequence.rb
|
|
70
|
+
- lib/paper_trail_diff/activity_target_candidate_loader.rb
|
|
70
71
|
- lib/paper_trail_diff/activity_timeline_builder.rb
|
|
71
72
|
- lib/paper_trail_diff/activity_transaction_grouper.rb
|
|
72
73
|
- lib/paper_trail_diff/activity_version_collector.rb
|
|
73
74
|
- lib/paper_trail_diff/analysis.rb
|
|
74
75
|
- lib/paper_trail_diff/analysis_batch.rb
|
|
76
|
+
- lib/paper_trail_diff/association_activity_edge.rb
|
|
77
|
+
- lib/paper_trail_diff/association_activity_selection.rb
|
|
75
78
|
- lib/paper_trail_diff/association_diff_traversal.rb
|
|
76
79
|
- lib/paper_trail_diff/association_discovery.rb
|
|
77
80
|
- lib/paper_trail_diff/association_traversal.rb
|
|
@@ -91,6 +94,7 @@ files:
|
|
|
91
94
|
- lib/paper_trail_diff/endpoint.rb
|
|
92
95
|
- lib/paper_trail_diff/engine.rb
|
|
93
96
|
- lib/paper_trail_diff/errors.rb
|
|
97
|
+
- lib/paper_trail_diff/habtm_transaction_owners.rb
|
|
94
98
|
- lib/paper_trail_diff/historical_association_reifier.rb
|
|
95
99
|
- lib/paper_trail_diff/historical_filter.rb
|
|
96
100
|
- lib/paper_trail_diff/historical_snapshot_store.rb
|
|
@@ -110,8 +114,12 @@ files:
|
|
|
110
114
|
- lib/paper_trail_diff/prepared_record_index.rb
|
|
111
115
|
- lib/paper_trail_diff/prepared_snapshot_builder.rb
|
|
112
116
|
- lib/paper_trail_diff/prepared_state_association_reader.rb
|
|
117
|
+
- lib/paper_trail_diff/recorded_changes.rb
|
|
118
|
+
- lib/paper_trail_diff/recorded_class.rb
|
|
113
119
|
- lib/paper_trail_diff/root_version_plan.rb
|
|
114
120
|
- lib/paper_trail_diff/root_version_selection.rb
|
|
121
|
+
- lib/paper_trail_diff/scope_condition.rb
|
|
122
|
+
- lib/paper_trail_diff/scope_ranking.rb
|
|
115
123
|
- lib/paper_trail_diff/scoped_analysis.rb
|
|
116
124
|
- lib/paper_trail_diff/scoped_analysis_builder.rb
|
|
117
125
|
- lib/paper_trail_diff/scoped_root_selection.rb
|
|
@@ -160,11 +168,14 @@ files:
|
|
|
160
168
|
- sig/generated/paper_trail_diff/activity_root_steps.rbs
|
|
161
169
|
- sig/generated/paper_trail_diff/activity_snapshot_delta.rbs
|
|
162
170
|
- sig/generated/paper_trail_diff/activity_snapshot_sequence.rbs
|
|
171
|
+
- sig/generated/paper_trail_diff/activity_target_candidate_loader.rbs
|
|
163
172
|
- sig/generated/paper_trail_diff/activity_timeline_builder.rbs
|
|
164
173
|
- sig/generated/paper_trail_diff/activity_transaction_grouper.rbs
|
|
165
174
|
- sig/generated/paper_trail_diff/activity_version_collector.rbs
|
|
166
175
|
- sig/generated/paper_trail_diff/analysis.rbs
|
|
167
176
|
- sig/generated/paper_trail_diff/analysis_batch.rbs
|
|
177
|
+
- sig/generated/paper_trail_diff/association_activity_edge.rbs
|
|
178
|
+
- sig/generated/paper_trail_diff/association_activity_selection.rbs
|
|
168
179
|
- sig/generated/paper_trail_diff/association_diff_traversal.rbs
|
|
169
180
|
- sig/generated/paper_trail_diff/association_discovery.rbs
|
|
170
181
|
- sig/generated/paper_trail_diff/association_traversal.rbs
|
|
@@ -184,6 +195,7 @@ files:
|
|
|
184
195
|
- sig/generated/paper_trail_diff/endpoint.rbs
|
|
185
196
|
- sig/generated/paper_trail_diff/engine.rbs
|
|
186
197
|
- sig/generated/paper_trail_diff/errors.rbs
|
|
198
|
+
- sig/generated/paper_trail_diff/habtm_transaction_owners.rbs
|
|
187
199
|
- sig/generated/paper_trail_diff/historical_association_reifier.rbs
|
|
188
200
|
- sig/generated/paper_trail_diff/historical_filter.rbs
|
|
189
201
|
- sig/generated/paper_trail_diff/historical_snapshot_store.rbs
|
|
@@ -203,8 +215,12 @@ files:
|
|
|
203
215
|
- sig/generated/paper_trail_diff/prepared_record_index.rbs
|
|
204
216
|
- sig/generated/paper_trail_diff/prepared_snapshot_builder.rbs
|
|
205
217
|
- sig/generated/paper_trail_diff/prepared_state_association_reader.rbs
|
|
218
|
+
- sig/generated/paper_trail_diff/recorded_changes.rbs
|
|
219
|
+
- sig/generated/paper_trail_diff/recorded_class.rbs
|
|
206
220
|
- sig/generated/paper_trail_diff/root_version_plan.rbs
|
|
207
221
|
- sig/generated/paper_trail_diff/root_version_selection.rbs
|
|
222
|
+
- sig/generated/paper_trail_diff/scope_condition.rbs
|
|
223
|
+
- sig/generated/paper_trail_diff/scope_ranking.rbs
|
|
208
224
|
- sig/generated/paper_trail_diff/scoped_analysis.rbs
|
|
209
225
|
- sig/generated/paper_trail_diff/scoped_analysis_builder.rbs
|
|
210
226
|
- sig/generated/paper_trail_diff/scoped_root_selection.rbs
|
|
@@ -238,11 +254,11 @@ licenses:
|
|
|
238
254
|
metadata:
|
|
239
255
|
allowed_push_host: https://rubygems.org
|
|
240
256
|
bug_tracker_uri: https://github.com/aheathwilliams/paper_trail_diff/issues
|
|
241
|
-
changelog_uri: https://github.com/aheathwilliams/paper_trail_diff/blob/v0.
|
|
242
|
-
documentation_uri: https://github.com/aheathwilliams/paper_trail_diff/blob/v0.
|
|
257
|
+
changelog_uri: https://github.com/aheathwilliams/paper_trail_diff/blob/v0.14.0/CHANGELOG.md
|
|
258
|
+
documentation_uri: https://github.com/aheathwilliams/paper_trail_diff/blob/v0.14.0/README.md
|
|
243
259
|
homepage_uri: https://github.com/aheathwilliams/paper_trail_diff
|
|
244
260
|
rubygems_mfa_required: 'true'
|
|
245
|
-
source_code_uri: https://github.com/aheathwilliams/paper_trail_diff/tree/v0.
|
|
261
|
+
source_code_uri: https://github.com/aheathwilliams/paper_trail_diff/tree/v0.14.0
|
|
246
262
|
rdoc_options: []
|
|
247
263
|
require_paths:
|
|
248
264
|
- lib
|