paper_trail_diff 0.5.0 → 0.6.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 +24 -0
- data/README.md +64 -1
- data/lib/paper_trail_diff/activity_root_steps.rb +9 -7
- data/lib/paper_trail_diff/activity_timeline_builder.rb +15 -8
- data/lib/paper_trail_diff/analysis.rb +19 -5
- data/lib/paper_trail_diff/analysis_batch.rb +28 -10
- data/lib/paper_trail_diff/batched_root_analyzer.rb +9 -9
- data/lib/paper_trail_diff/batched_root_versions.rb +48 -30
- data/lib/paper_trail_diff/paper_trail_adapter.rb +25 -18
- data/lib/paper_trail_diff/root_version_plan.rb +86 -0
- data/lib/paper_trail_diff/root_version_selection.rb +131 -0
- data/lib/paper_trail_diff/time_activity_timeline_builder.rb +25 -13
- data/lib/paper_trail_diff/time_version_range.rb +19 -24
- data/lib/paper_trail_diff/timeline_builder.rb +21 -18
- data/lib/paper_trail_diff/timeline_range.rb +31 -7
- data/lib/paper_trail_diff/version.rb +1 -1
- data/lib/paper_trail_diff/version_range.rb +45 -5
- data/lib/paper_trail_diff/version_scope_filter.rb +37 -0
- data/lib/paper_trail_diff.rb +24 -13
- data/sig/generated/paper_trail_diff/activity_root_steps.rbs +2 -2
- data/sig/generated/paper_trail_diff/activity_timeline_builder.rbs +6 -2
- data/sig/generated/paper_trail_diff/analysis.rbs +13 -4
- data/sig/generated/paper_trail_diff/analysis_batch.rbs +13 -6
- data/sig/generated/paper_trail_diff/batched_root_analyzer.rbs +4 -4
- data/sig/generated/paper_trail_diff/batched_root_versions.rbs +21 -14
- data/sig/generated/paper_trail_diff/paper_trail_adapter.rbs +10 -10
- data/sig/generated/paper_trail_diff/root_version_plan.rbs +56 -0
- data/sig/generated/paper_trail_diff/root_version_selection.rbs +77 -0
- data/sig/generated/paper_trail_diff/time_activity_timeline_builder.rbs +9 -4
- data/sig/generated/paper_trail_diff/time_version_range.rbs +7 -9
- data/sig/generated/paper_trail_diff/timeline_builder.rbs +6 -6
- data/sig/generated/paper_trail_diff/timeline_range.rbs +11 -2
- data/sig/generated/paper_trail_diff/version_range.rbs +17 -2
- data/sig/generated/paper_trail_diff/version_scope_filter.rbs +22 -0
- data/sig/generated/paper_trail_diff.rbs +8 -8
- metadata +10 -4
data/lib/paper_trail_diff.rb
CHANGED
|
@@ -39,6 +39,9 @@ require_relative 'paper_trail_diff/live_endpoint_provider'
|
|
|
39
39
|
require_relative 'paper_trail_diff/live_graph_collector'
|
|
40
40
|
require_relative 'paper_trail_diff/batch_boundary_resolver'
|
|
41
41
|
require_relative 'paper_trail_diff/comparison_batch'
|
|
42
|
+
require_relative 'paper_trail_diff/root_version_plan'
|
|
43
|
+
require_relative 'paper_trail_diff/version_scope_filter'
|
|
44
|
+
require_relative 'paper_trail_diff/root_version_selection'
|
|
42
45
|
require_relative 'paper_trail_diff/batched_root_versions'
|
|
43
46
|
require_relative 'paper_trail_diff/snapshot_normalizer'
|
|
44
47
|
require_relative 'paper_trail_diff/historical_snapshot_store'
|
|
@@ -142,27 +145,29 @@ module PaperTrailDiff # rubocop:disable Metrics/ModuleLength
|
|
|
142
145
|
end
|
|
143
146
|
|
|
144
147
|
# Compares every adjacent reconstructed state in an inclusive version range.
|
|
145
|
-
#: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option) -> Array[Step]
|
|
148
|
+
#: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?version_scope: untyped) -> Array[Step]
|
|
146
149
|
def timeline( # rubocop:disable Metrics/ParameterLists
|
|
147
150
|
record,
|
|
148
151
|
from: nil,
|
|
149
152
|
to: nil,
|
|
150
153
|
within: nil,
|
|
151
154
|
associations: [],
|
|
152
|
-
ignore: DEFAULT_IGNORED_ATTRIBUTES
|
|
155
|
+
ignore: DEFAULT_IGNORED_ATTRIBUTES,
|
|
156
|
+
version_scope: nil
|
|
153
157
|
)
|
|
154
158
|
PaperTrailAdapter.new(associations: associations, ignore: ignore).timeline(
|
|
155
159
|
record,
|
|
156
160
|
from: from,
|
|
157
161
|
to: to,
|
|
158
|
-
within: within
|
|
162
|
+
within: within,
|
|
163
|
+
version_scope: version_scope
|
|
159
164
|
)
|
|
160
165
|
end
|
|
161
166
|
|
|
162
167
|
# Compares adjacent root and selected-descendant activity boundaries.
|
|
163
168
|
# `reload_live_endpoints:` applies only when `to:` is a current record; the
|
|
164
169
|
# other range forms never read live state.
|
|
165
|
-
#: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?reload_live_endpoints: bool) -> Array[ActivityStep]
|
|
170
|
+
#: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?reload_live_endpoints: bool, ?version_scope: untyped) -> Array[ActivityStep]
|
|
166
171
|
def activity_timeline( # rubocop:disable Metrics/ParameterLists
|
|
167
172
|
record,
|
|
168
173
|
from: nil,
|
|
@@ -170,7 +175,8 @@ module PaperTrailDiff # rubocop:disable Metrics/ModuleLength
|
|
|
170
175
|
within: nil,
|
|
171
176
|
associations: [],
|
|
172
177
|
ignore: DEFAULT_IGNORED_ATTRIBUTES,
|
|
173
|
-
reload_live_endpoints: true
|
|
178
|
+
reload_live_endpoints: true,
|
|
179
|
+
version_scope: nil
|
|
174
180
|
)
|
|
175
181
|
PaperTrailAdapter.new(
|
|
176
182
|
associations: associations,
|
|
@@ -180,12 +186,13 @@ module PaperTrailDiff # rubocop:disable Metrics/ModuleLength
|
|
|
180
186
|
record,
|
|
181
187
|
from: from,
|
|
182
188
|
to: to,
|
|
183
|
-
within: within
|
|
189
|
+
within: within,
|
|
190
|
+
version_scope: version_scope
|
|
184
191
|
)
|
|
185
192
|
end
|
|
186
193
|
|
|
187
194
|
# Builds an endpoint diff and root-checkpoint timeline while normalizing each version once.
|
|
188
|
-
#: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool) -> Analysis
|
|
195
|
+
#: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped) -> Analysis
|
|
189
196
|
def analyze( # rubocop:disable Metrics/ParameterLists
|
|
190
197
|
record,
|
|
191
198
|
from: nil,
|
|
@@ -193,32 +200,36 @@ module PaperTrailDiff # rubocop:disable Metrics/ModuleLength
|
|
|
193
200
|
within: nil,
|
|
194
201
|
associations: [],
|
|
195
202
|
ignore: DEFAULT_IGNORED_ATTRIBUTES,
|
|
196
|
-
activity: false
|
|
203
|
+
activity: false,
|
|
204
|
+
version_scope: nil
|
|
197
205
|
)
|
|
198
206
|
PaperTrailAdapter.new(associations: associations, ignore: ignore).analyze(
|
|
199
207
|
record,
|
|
200
208
|
from: from,
|
|
201
209
|
to: to,
|
|
202
210
|
within: within,
|
|
203
|
-
activity: activity
|
|
211
|
+
activity: activity,
|
|
212
|
+
version_scope: version_scope
|
|
204
213
|
)
|
|
205
214
|
end
|
|
206
215
|
|
|
207
216
|
# Analyzes many roots over one shared time window, preparing their selected
|
|
208
217
|
# history once for the batch instead of once per record. Roots with no
|
|
209
218
|
# versions in the window return an empty `Analysis`.
|
|
210
|
-
#: (Array[untyped], ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool) -> Hash[identity, Analysis]
|
|
211
|
-
def analyze_many(
|
|
219
|
+
#: (Array[untyped], ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped) -> Hash[identity, Analysis]
|
|
220
|
+
def analyze_many( # rubocop:disable Metrics/ParameterLists
|
|
212
221
|
records,
|
|
213
222
|
within: nil,
|
|
214
223
|
associations: [],
|
|
215
224
|
ignore: DEFAULT_IGNORED_ATTRIBUTES,
|
|
216
|
-
activity: false
|
|
225
|
+
activity: false,
|
|
226
|
+
version_scope: nil
|
|
217
227
|
)
|
|
218
228
|
PaperTrailAdapter.new(associations: associations, ignore: ignore).analyze_many(
|
|
219
229
|
records,
|
|
220
230
|
within: within,
|
|
221
|
-
activity: activity
|
|
231
|
+
activity: activity,
|
|
232
|
+
version_scope: version_scope
|
|
222
233
|
)
|
|
223
234
|
end
|
|
224
235
|
|
|
@@ -4,8 +4,8 @@ module PaperTrailDiff
|
|
|
4
4
|
# Root checkpoint steps recovered from the snapshots an activity pass retained,
|
|
5
5
|
# so a combined result does not reconstruct the same boundaries twice.
|
|
6
6
|
module ActivityRootSteps
|
|
7
|
-
# : (
|
|
8
|
-
def self?.call: (
|
|
7
|
+
# : (RootVersionPlan, Hash[Array[untyped], RecordSnapshot?]) -> Array[Step]
|
|
8
|
+
def self?.call: (RootVersionPlan, Hash[Array[untyped], RecordSnapshot?]) -> Array[Step]
|
|
9
9
|
|
|
10
10
|
# : (untyped) -> Array[untyped]
|
|
11
11
|
def self?.version_key: (untyped) -> Array[untyped]
|
|
@@ -30,6 +30,10 @@ module PaperTrailDiff
|
|
|
30
30
|
# : () -> Array[ActivityStep]
|
|
31
31
|
def no_steps: () -> Array[ActivityStep]
|
|
32
32
|
|
|
33
|
+
# Every boundary in the span, filtered out or not. A filter narrows where the
|
|
34
|
+
# span starts and ends, but the sequence inside it stays complete: dropping
|
|
35
|
+
# boundaries would fold the changes they carried into a neighbouring step and
|
|
36
|
+
# credit them to whoever made that one.
|
|
33
37
|
# : () -> Array[ActivityStep]
|
|
34
38
|
def build_between_versions: () -> Array[ActivityStep]
|
|
35
39
|
|
|
@@ -67,8 +71,8 @@ module PaperTrailDiff
|
|
|
67
71
|
# Only the activity view gains the closing removal. The endpoint diff and
|
|
68
72
|
# the root timeline keep their `compare` and `timeline` semantics, under
|
|
69
73
|
# which the state at a destroy version is the state before the deletion.
|
|
70
|
-
# : (
|
|
71
|
-
def build_analysis: (
|
|
74
|
+
# : (RootVersionPlan, Array[ActivityEvent], ActivityHistory) -> Analysis
|
|
75
|
+
def build_analysis: (RootVersionPlan, Array[ActivityEvent], ActivityHistory) -> Analysis
|
|
72
76
|
|
|
73
77
|
# : () -> TimeActivityTimelineBuilder
|
|
74
78
|
def time_builder: () -> TimeActivityTimelineBuilder
|
|
@@ -9,15 +9,24 @@ module PaperTrailDiff
|
|
|
9
9
|
|
|
10
10
|
attr_reader activity_timeline: Array[ActivityStep]?
|
|
11
11
|
|
|
12
|
+
attr_reader from_snapshot: RecordSnapshot?
|
|
13
|
+
|
|
14
|
+
attr_reader to_snapshot: RecordSnapshot?
|
|
15
|
+
|
|
12
16
|
# The result for a record whose requested history contains no versions,
|
|
13
17
|
# which is an empty history rather than a failed request.
|
|
14
18
|
# : () -> Analysis
|
|
15
19
|
def self.empty: () -> Analysis
|
|
16
20
|
|
|
17
|
-
#
|
|
18
|
-
|
|
21
|
+
# The reconstructed states the diff was taken between. A report that has to
|
|
22
|
+
# render unchanged columns needs the whole final state, not only what moved.
|
|
23
|
+
# : (diff: Diff, timeline: Array[Step], ?activity_timeline: Array[ActivityStep]?, ?from_snapshot: RecordSnapshot?, ?to_snapshot: RecordSnapshot?) -> void
|
|
24
|
+
def initialize: (diff: Diff, timeline: Array[Step], ?activity_timeline: Array[ActivityStep]?, ?from_snapshot: RecordSnapshot?, ?to_snapshot: RecordSnapshot?) -> void
|
|
19
25
|
|
|
20
|
-
#
|
|
21
|
-
|
|
26
|
+
# Reconstructed endpoint states are opt-in, because they carry the whole
|
|
27
|
+
# selected graph whether or not anything changed, which dwarfs the rest of
|
|
28
|
+
# the payload for a wide graph.
|
|
29
|
+
# : (?snapshots: bool) -> Hash[Symbol, untyped]
|
|
30
|
+
def to_h: (?snapshots: bool) -> Hash[Symbol, untyped]
|
|
22
31
|
end
|
|
23
32
|
end
|
|
@@ -5,8 +5,8 @@ module PaperTrailDiff
|
|
|
5
5
|
# versions and preparing their association history once for the whole batch
|
|
6
6
|
# rather than once per root.
|
|
7
7
|
class AnalysisBatch
|
|
8
|
-
# : (Array[untyped], time_range: TimeRange?, live_loader: untyped, history_preparer: untyped, analyzer: untyped) -> void
|
|
9
|
-
def initialize: (Array[untyped], time_range: TimeRange?, live_loader: untyped, history_preparer: untyped, analyzer: untyped) -> void
|
|
8
|
+
# : (Array[untyped], time_range: TimeRange?, live_loader: untyped, history_preparer: untyped, analyzer: untyped, ?version_scope: untyped) -> void
|
|
9
|
+
def initialize: (Array[untyped], time_range: TimeRange?, live_loader: untyped, history_preparer: untyped, analyzer: untyped, ?version_scope: untyped) -> void
|
|
10
10
|
|
|
11
11
|
# : () -> Hash[identity, Analysis]
|
|
12
12
|
def call: () -> Hash[identity, Analysis]
|
|
@@ -23,6 +23,13 @@ module PaperTrailDiff
|
|
|
23
23
|
|
|
24
24
|
@time_range: TimeRange?
|
|
25
25
|
|
|
26
|
+
@version_scope: untyped
|
|
27
|
+
|
|
28
|
+
# A filter is a callable that narrows the version relation, so it is checked
|
|
29
|
+
# up front rather than failing partway through a batch.
|
|
30
|
+
# : (untyped) -> untyped
|
|
31
|
+
def validated_scope: (untyped) -> untyped
|
|
32
|
+
|
|
26
33
|
# : () -> Array[untyped]
|
|
27
34
|
def validated_records: () -> Array[untyped]
|
|
28
35
|
|
|
@@ -31,12 +38,12 @@ module PaperTrailDiff
|
|
|
31
38
|
# The roots are preloaded first, because preparation reads their current
|
|
32
39
|
# association state as a fallback and would otherwise walk it one root at a
|
|
33
40
|
# time.
|
|
34
|
-
# : (Array[untyped], Hash[Array[String],
|
|
35
|
-
def prepare: (Array[untyped], Hash[Array[String],
|
|
41
|
+
# : (Array[untyped], Hash[Array[String], RootVersionPlan]) -> void
|
|
42
|
+
def prepare: (Array[untyped], Hash[Array[String], RootVersionPlan]) -> void
|
|
36
43
|
|
|
37
44
|
# A root with no versions in range has nothing to report, which is an empty
|
|
38
45
|
# result rather than a failed request.
|
|
39
|
-
# : (untyped,
|
|
40
|
-
def analysis_for: (untyped,
|
|
46
|
+
# : (untyped, RootVersionPlan) -> Analysis
|
|
47
|
+
def analysis_for: (untyped, RootVersionPlan) -> Analysis
|
|
41
48
|
end
|
|
42
49
|
end
|
|
@@ -7,8 +7,8 @@ module PaperTrailDiff
|
|
|
7
7
|
# : (tree: AssociationTree, timeline_snapshotter: untyped, activity_snapshotter: untyped, preparer: untyped, activity: bool) -> void
|
|
8
8
|
def initialize: (tree: AssociationTree, timeline_snapshotter: untyped, activity_snapshotter: untyped, preparer: untyped, activity: bool) -> void
|
|
9
9
|
|
|
10
|
-
# : (untyped,
|
|
11
|
-
def call: (untyped,
|
|
10
|
+
# : (untyped, RootVersionPlan) -> Analysis
|
|
11
|
+
def call: (untyped, RootVersionPlan) -> Analysis
|
|
12
12
|
|
|
13
13
|
private
|
|
14
14
|
|
|
@@ -22,7 +22,7 @@ module PaperTrailDiff
|
|
|
22
22
|
|
|
23
23
|
@tree: AssociationTree
|
|
24
24
|
|
|
25
|
-
# : (untyped,
|
|
26
|
-
def activity_analysis: (untyped,
|
|
25
|
+
# : (untyped, RootVersionPlan) -> Analysis
|
|
26
|
+
def activity_analysis: (untyped, RootVersionPlan) -> Analysis
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -5,12 +5,12 @@ module PaperTrailDiff
|
|
|
5
5
|
# queries. Only the range forms that mean the same thing for every root are
|
|
6
6
|
# supported: a shared wall-clock window, or each root's own whole history.
|
|
7
7
|
class BatchedRootVersions
|
|
8
|
-
# : (Array[untyped], time_range: TimeRange?) -> void
|
|
9
|
-
def initialize: (Array[untyped], time_range: TimeRange?) -> void
|
|
8
|
+
# : (Array[untyped], time_range: TimeRange?, ?version_scope: untyped) -> void
|
|
9
|
+
def initialize: (Array[untyped], time_range: TimeRange?, ?version_scope: untyped) -> void
|
|
10
10
|
|
|
11
|
-
# Returns
|
|
12
|
-
# : () -> Hash[Array[String],
|
|
13
|
-
def call: () -> Hash[Array[String],
|
|
11
|
+
# Returns a plan per record identity.
|
|
12
|
+
# : () -> Hash[Array[String], RootVersionPlan]
|
|
13
|
+
def call: () -> Hash[Array[String], RootVersionPlan]
|
|
14
14
|
|
|
15
15
|
private
|
|
16
16
|
|
|
@@ -18,21 +18,28 @@ module PaperTrailDiff
|
|
|
18
18
|
|
|
19
19
|
@time_range: TimeRange?
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
def select_model: (untyped, Array[untyped], Hash[Array[String], Array[untyped]]) -> void
|
|
21
|
+
@version_scope: untyped
|
|
23
22
|
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
# destruction needs no later version, because none can exist.
|
|
27
|
-
# : (Array[untyped], untyped) -> Array[untyped]
|
|
28
|
-
def versions_for: (Array[untyped], untyped) -> Array[untyped]
|
|
23
|
+
# : (untyped, Array[untyped], Hash[Array[String], RootVersionPlan]) -> void
|
|
24
|
+
def select_model: (untyped, Array[untyped], Hash[Array[String], RootVersionPlan]) -> void
|
|
29
25
|
|
|
30
|
-
# : (Array[untyped]) ->
|
|
31
|
-
def
|
|
26
|
+
# : (untyped, Array[untyped]) -> [Hash[String, Array[untyped]], Set[untyped]?, Hash[String, untyped]]
|
|
27
|
+
def model_versions: (untyped, Array[untyped]) -> [ Hash[String, Array[untyped]], Set[untyped]?, Hash[String, untyped] ]
|
|
28
|
+
|
|
29
|
+
# : (Array[untyped], Set[untyped]?, untyped) -> RootVersionPlan
|
|
30
|
+
def versions_for: (Array[untyped], Set[untyped]?, untyped) -> RootVersionPlan
|
|
31
|
+
|
|
32
|
+
# One extra query names the selected mutations without discarding the
|
|
33
|
+
# unfiltered versions the successor lookup still needs.
|
|
34
|
+
# : (untyped, Array[untyped], TimeRange?) -> Set[untyped]?
|
|
35
|
+
def chosen_version_ids: (untyped, Array[untyped], TimeRange?) -> Set[untyped]?
|
|
32
36
|
|
|
33
37
|
# : (untyped, Array[untyped], TimeRange?) -> Hash[String, Array[untyped]]
|
|
34
38
|
def grouped_versions: (untyped, Array[untyped], TimeRange?) -> Hash[String, Array[untyped]]
|
|
35
39
|
|
|
40
|
+
# : (untyped, Array[untyped], TimeRange?) -> untyped
|
|
41
|
+
def range_scope: (untyped, Array[untyped], TimeRange?) -> untyped
|
|
42
|
+
|
|
36
43
|
# One row per root: the earliest version after the window, found without a
|
|
37
44
|
# window function so the query stays portable.
|
|
38
45
|
# : (untyped, Array[untyped], TimeRange) -> Hash[String, untyped]
|
|
@@ -16,18 +16,18 @@ module PaperTrailDiff
|
|
|
16
16
|
# : (Array[comparison_input]) -> comparison_results
|
|
17
17
|
def compare_many: (Array[comparison_input]) -> comparison_results
|
|
18
18
|
|
|
19
|
-
# : (untyped, from: untyped, to: untyped, within: untyped) -> Array[Step]
|
|
20
|
-
def timeline: (untyped, from: untyped, to: untyped, within: untyped) -> Array[Step]
|
|
19
|
+
# : (untyped, from: untyped, to: untyped, within: untyped, ?version_scope: untyped) -> Array[Step]
|
|
20
|
+
def timeline: (untyped, from: untyped, to: untyped, within: untyped, ?version_scope: untyped) -> Array[Step]
|
|
21
21
|
|
|
22
|
-
# : (untyped, from: untyped, to: untyped, within: untyped) -> Array[ActivityStep]
|
|
23
|
-
def activity_timeline: (untyped, from: untyped, to: untyped, within: untyped) -> Array[ActivityStep]
|
|
22
|
+
# : (untyped, from: untyped, to: untyped, within: untyped, ?version_scope: untyped) -> Array[ActivityStep]
|
|
23
|
+
def activity_timeline: (untyped, from: untyped, to: untyped, within: untyped, ?version_scope: untyped) -> Array[ActivityStep]
|
|
24
24
|
|
|
25
|
-
# : (untyped, from: untyped, to: untyped, within: untyped, ?activity: bool) -> Analysis
|
|
26
|
-
def analyze: (untyped, from: untyped, to: untyped, within: untyped, ?activity: bool) -> Analysis
|
|
25
|
+
# : (untyped, from: untyped, to: untyped, within: untyped, ?activity: bool, ?version_scope: untyped) -> Analysis
|
|
26
|
+
def analyze: (untyped, from: untyped, to: untyped, within: untyped, ?activity: bool, ?version_scope: untyped) -> Analysis
|
|
27
27
|
|
|
28
28
|
# Analyzes many roots over one shared range, preparing their history once.
|
|
29
|
-
# : (Array[untyped], within: untyped, ?activity: bool) -> Hash[identity, Analysis]
|
|
30
|
-
def analyze_many: (Array[untyped], within: untyped, ?activity: bool) -> Hash[identity, Analysis]
|
|
29
|
+
# : (Array[untyped], within: untyped, ?activity: bool, ?version_scope: untyped) -> Hash[identity, Analysis]
|
|
30
|
+
def analyze_many: (Array[untyped], within: untyped, ?activity: bool, ?version_scope: untyped) -> Hash[identity, Analysis]
|
|
31
31
|
|
|
32
32
|
private
|
|
33
33
|
|
|
@@ -65,8 +65,8 @@ module PaperTrailDiff
|
|
|
65
65
|
# : () -> ActivitySnapshotProvider
|
|
66
66
|
def build_activity_snapshotter: () -> ActivitySnapshotProvider
|
|
67
67
|
|
|
68
|
-
# : (untyped, from: untyped, to: untyped, within: untyped) -> ActivityTimelineBuilder
|
|
69
|
-
def activity_builder: (untyped, from: untyped, to: untyped, within: untyped) -> ActivityTimelineBuilder
|
|
68
|
+
# : (untyped, from: untyped, to: untyped, within: untyped, ?version_scope: untyped) -> ActivityTimelineBuilder
|
|
69
|
+
def activity_builder: (untyped, from: untyped, to: untyped, within: untyped, ?version_scope: untyped) -> ActivityTimelineBuilder
|
|
70
70
|
|
|
71
71
|
# : (untyped) -> void
|
|
72
72
|
def reject_live_habtm_activity!: (untyped) -> void
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/root_version_plan.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# Which versions a range reconstructs, and which pairs of them become steps.
|
|
5
|
+
#
|
|
6
|
+
# Without a filter those are the same thing: every selected version is a
|
|
7
|
+
# boundary and adjacent ones bound each other. A filter separates them, because
|
|
8
|
+
# each selected mutation then has to be bounded by the version that actually
|
|
9
|
+
# reveals it rather than by the next mutation that happened to be selected.
|
|
10
|
+
#
|
|
11
|
+
# A filter also separates what is *reported* from what has to be *replayed*.
|
|
12
|
+
# The activity view rebuilds state by carrying one snapshot forward across
|
|
13
|
+
# every event in order, so skipping a filtered-out version would leave that
|
|
14
|
+
# snapshot holding a state the record had already moved past. `versions` are
|
|
15
|
+
# the boundaries the steps refer to; `reconstruction_versions` are every root
|
|
16
|
+
# version the span passes through, which is what any forward replay must walk.
|
|
17
|
+
class RootVersionPlan
|
|
18
|
+
attr_reader versions: Array[untyped]
|
|
19
|
+
|
|
20
|
+
attr_reader reconstruction_versions: Array[untyped]
|
|
21
|
+
|
|
22
|
+
attr_reader steps: Array[[ untyped, untyped ]]
|
|
23
|
+
|
|
24
|
+
attr_reader context_version: untyped
|
|
25
|
+
|
|
26
|
+
# The root versions this plan reports as mutations, which excludes any
|
|
27
|
+
# version present only to reveal what the last of them produced.
|
|
28
|
+
attr_reader mutations: Array[untyped]
|
|
29
|
+
|
|
30
|
+
# Adjacent boundaries, which is what an unfiltered range reports.
|
|
31
|
+
# : (Array[untyped], ?context_version: untyped) -> RootVersionPlan
|
|
32
|
+
def self.contiguous: (Array[untyped], ?context_version: untyped) -> RootVersionPlan
|
|
33
|
+
|
|
34
|
+
# : () -> RootVersionPlan
|
|
35
|
+
def self.empty: () -> RootVersionPlan
|
|
36
|
+
|
|
37
|
+
# : (versions: Array[untyped], steps: Array[[untyped, untyped]], ?context_version: untyped, ?reconstruction_versions: Array[untyped]?, ?mutations: Array[untyped]?) -> void
|
|
38
|
+
def initialize: (versions: Array[untyped], steps: Array[[ untyped, untyped ]], ?context_version: untyped, ?reconstruction_versions: Array[untyped]?, ?mutations: Array[untyped]?) -> void
|
|
39
|
+
|
|
40
|
+
# : () -> bool
|
|
41
|
+
def empty?: () -> bool
|
|
42
|
+
|
|
43
|
+
# : (untyped) -> bool
|
|
44
|
+
def mutation?: (untyped) -> bool
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
@mutation_keys: Set[Array[untyped]]
|
|
49
|
+
|
|
50
|
+
# : () -> Array[untyped]
|
|
51
|
+
def default_mutations: () -> Array[untyped]
|
|
52
|
+
|
|
53
|
+
# : (untyped) -> Array[untyped]
|
|
54
|
+
def key: (untyped) -> Array[untyped]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/root_version_selection.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# Decides which versions a range reports, and which one reveals the last of
|
|
5
|
+
# them. A version records the state before its own event, so whatever follows
|
|
6
|
+
# the final selected mutation is the only thing that can show what it produced.
|
|
7
|
+
# That successor is reconstruction context rather than a reported mutation, so
|
|
8
|
+
# a filter must never remove it.
|
|
9
|
+
#
|
|
10
|
+
# Both the single-record and the batched selectors resolve this here, because
|
|
11
|
+
# the rule is subtle enough that two copies of it would drift apart.
|
|
12
|
+
class RootVersionSelection
|
|
13
|
+
INCOMPLETE: ::String
|
|
14
|
+
|
|
15
|
+
# : (in_range: Array[untyped], selected: Array[untyped], after_range: untyped, windowed: bool, ?context_required: bool, ?filtered: bool) -> void
|
|
16
|
+
def initialize: (in_range: Array[untyped], selected: Array[untyped], after_range: untyped, windowed: bool, ?context_required: bool, ?filtered: bool) -> void
|
|
17
|
+
|
|
18
|
+
# : () -> RootVersionPlan
|
|
19
|
+
def call: () -> RootVersionPlan
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
@after_range: untyped
|
|
24
|
+
|
|
25
|
+
@context_required: bool
|
|
26
|
+
|
|
27
|
+
@filtered: bool
|
|
28
|
+
|
|
29
|
+
@in_range: Array[untyped]
|
|
30
|
+
|
|
31
|
+
@selected: Array[untyped]
|
|
32
|
+
|
|
33
|
+
@windowed: bool
|
|
34
|
+
|
|
35
|
+
# An activity view still needs a root to reconstruct from even when no root
|
|
36
|
+
# version falls inside the window, because descendants may have moved.
|
|
37
|
+
# : () -> RootVersionPlan
|
|
38
|
+
def without_selection: () -> RootVersionPlan
|
|
39
|
+
|
|
40
|
+
# Each selected mutation is bounded by the version that reveals it, not by
|
|
41
|
+
# the next mutation that happened to be selected. Bounding by the next
|
|
42
|
+
# selection would fold anything filtered out in between into it, so the same
|
|
43
|
+
# edit would read differently depending on what followed it.
|
|
44
|
+
# : (untyped) -> RootVersionPlan
|
|
45
|
+
def filtered_plan: (untyped) -> RootVersionPlan
|
|
46
|
+
|
|
47
|
+
# Nothing can follow a destroy, so it never pairs into a step. It is still a
|
|
48
|
+
# selected mutation, and the activity view closes on the absence it leaves,
|
|
49
|
+
# so it has to stay a boundary or a filtered report loses the deletion
|
|
50
|
+
# entirely — the one event it can least afford to drop.
|
|
51
|
+
# : () -> Array[untyped]
|
|
52
|
+
def closing_versions: () -> Array[untyped]
|
|
53
|
+
|
|
54
|
+
# Everything the span passes through, filtered out or not. A replay that
|
|
55
|
+
# skipped the excluded versions would carry a stale state into the next
|
|
56
|
+
# reported step, so the two selected mutations either side of a gap would
|
|
57
|
+
# disagree about what the record looked like between them.
|
|
58
|
+
# : (Array[untyped]) -> Array[untyped]
|
|
59
|
+
def spanned: (Array[untyped]) -> Array[untyped]
|
|
60
|
+
|
|
61
|
+
# : (Array[untyped]) -> Array[untyped]
|
|
62
|
+
def chronological: (Array[untyped]) -> Array[untyped]
|
|
63
|
+
|
|
64
|
+
# : (untyped) -> untyped
|
|
65
|
+
def immediate_successor: (untyped) -> untyped
|
|
66
|
+
|
|
67
|
+
# A version left out by a filter is still the state the last selected change
|
|
68
|
+
# produced, so it is preferred over anything after the range.
|
|
69
|
+
# : () -> untyped
|
|
70
|
+
def revealing_version: () -> untyped
|
|
71
|
+
|
|
72
|
+
# A range closing on the record's own destruction needs no later version:
|
|
73
|
+
# nothing can follow it, so demanding one would reject the range forever.
|
|
74
|
+
# : () -> bool
|
|
75
|
+
def terminal_destroy?: () -> bool
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -22,8 +22,8 @@ module PaperTrailDiff
|
|
|
22
22
|
|
|
23
23
|
@tree: AssociationTree
|
|
24
24
|
|
|
25
|
-
# : () -> [ActivityHistory,
|
|
26
|
-
def history_and_versions: () -> [ ActivityHistory,
|
|
25
|
+
# : () -> [ActivityHistory, RootVersionPlan, ActivityStep?]
|
|
26
|
+
def history_and_versions: () -> [ ActivityHistory, RootVersionPlan, ActivityStep? ]
|
|
27
27
|
|
|
28
28
|
# : (Array[untyped], Array[ActivityEvent]) -> ActivityHistory
|
|
29
29
|
def build_history: (Array[untyped], Array[ActivityEvent]) -> ActivityHistory
|
|
@@ -31,8 +31,13 @@ module PaperTrailDiff
|
|
|
31
31
|
# : (ActivityHistory, ActivityStep?) -> Array[ActivityStep]
|
|
32
32
|
def activity_steps: (ActivityHistory, ActivityStep?) -> Array[ActivityStep]
|
|
33
33
|
|
|
34
|
-
#
|
|
35
|
-
|
|
34
|
+
# Root versions inside the window that the plan does not report are context
|
|
35
|
+
# rather than mutations: the version appended to reveal the last selected
|
|
36
|
+
# change, and anything a filter excluded but the replay still walks. Neither
|
|
37
|
+
# may be counted as a selected mutation. Descendant events are not filtered,
|
|
38
|
+
# so window membership is the whole test for them.
|
|
39
|
+
# : (Array[ActivityEvent], RootVersionPlan) -> Array[ActivityEvent]
|
|
40
|
+
def selected_events: (Array[ActivityEvent], RootVersionPlan) -> Array[ActivityEvent]
|
|
36
41
|
|
|
37
42
|
# The window's last selected mutation is the root's own destruction, so the
|
|
38
43
|
# timeline closes on the absence it leaves rather than on a later boundary.
|
|
@@ -3,28 +3,26 @@
|
|
|
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) -> void
|
|
7
|
-
def initialize: (untyped, time_range: TimeRange) -> void
|
|
6
|
+
# : (untyped, time_range: TimeRange, ?version_scope: untyped) -> void
|
|
7
|
+
def initialize: (untyped, time_range: TimeRange, ?version_scope: untyped) -> void
|
|
8
8
|
|
|
9
9
|
# : (?context_required: bool) -> Array[untyped]
|
|
10
10
|
def select: (?context_required: bool) -> Array[untyped]
|
|
11
11
|
|
|
12
|
+
# : (?context_required: bool) -> RootVersionPlan
|
|
13
|
+
def select_plan: (?context_required: bool) -> RootVersionPlan
|
|
14
|
+
|
|
12
15
|
private
|
|
13
16
|
|
|
14
17
|
@record: untyped
|
|
15
18
|
|
|
16
19
|
@time_range: TimeRange
|
|
17
20
|
|
|
21
|
+
@version_scope: untyped
|
|
22
|
+
|
|
18
23
|
# : () -> untyped
|
|
19
24
|
def versions_relation: () -> untyped
|
|
20
25
|
|
|
21
|
-
# A window closing on the record's own destruction needs no later version:
|
|
22
|
-
# the destroy reveals the preceding mutation and nothing can follow it, so
|
|
23
|
-
# demanding a checkpoint that can never be written would reject the range
|
|
24
|
-
# permanently.
|
|
25
|
-
# : (Array[untyped]) -> bool
|
|
26
|
-
def terminal_destroy?: (Array[untyped]) -> bool
|
|
27
|
-
|
|
28
26
|
# : (untyped) -> untyped
|
|
29
27
|
def trailing_version: (untyped) -> untyped
|
|
30
28
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module PaperTrailDiff
|
|
4
4
|
# Selects and compares a chronological slice of a record's version history.
|
|
5
5
|
class TimelineBuilder
|
|
6
|
-
# : (untyped, from: untyped, to: untyped, snapshotter: untyped, ?within: untyped, ?versions: Array[untyped]?) -> void
|
|
7
|
-
def initialize: (untyped, from: untyped, to: untyped, snapshotter: untyped, ?within: untyped, ?versions: Array[untyped]?) -> void
|
|
6
|
+
# : (untyped, from: untyped, to: untyped, snapshotter: untyped, ?within: untyped, ?versions: Array[untyped]?, ?version_scope: untyped, ?plan: RootVersionPlan?) -> void
|
|
7
|
+
def initialize: (untyped, from: untyped, to: untyped, snapshotter: untyped, ?within: untyped, ?versions: Array[untyped]?, ?version_scope: untyped, ?plan: RootVersionPlan?) -> void
|
|
8
8
|
|
|
9
9
|
# : () -> Array[Step]
|
|
10
10
|
def build: () -> Array[Step]
|
|
@@ -20,13 +20,13 @@ module PaperTrailDiff
|
|
|
20
20
|
|
|
21
21
|
@snapshotter: untyped
|
|
22
22
|
|
|
23
|
-
# : (
|
|
24
|
-
def compare_history: (
|
|
23
|
+
# : (RootVersionPlan) -> [Array[Step], RecordSnapshot?, RecordSnapshot?]
|
|
24
|
+
def compare_history: (RootVersionPlan) -> [ Array[Step], RecordSnapshot?, RecordSnapshot? ]
|
|
25
25
|
|
|
26
26
|
# : () -> [Array[Step], nil, nil]
|
|
27
27
|
def empty_history: () -> [ Array[Step], nil, nil ]
|
|
28
28
|
|
|
29
|
-
# : () ->
|
|
30
|
-
def selected_versions: () ->
|
|
29
|
+
# : () -> RootVersionPlan
|
|
30
|
+
def selected_versions: () -> RootVersionPlan
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -11,8 +11,8 @@ module PaperTrailDiff
|
|
|
11
11
|
|
|
12
12
|
attr_reader time_range: TimeRange?
|
|
13
13
|
|
|
14
|
-
# : (untyped, from: untyped, to: untyped, within: untyped, ?versions: Array[untyped]?) -> void
|
|
15
|
-
def initialize: (untyped, from: untyped, to: untyped, within: untyped, ?versions: Array[untyped]?) -> void
|
|
14
|
+
# : (untyped, from: untyped, to: untyped, within: untyped, ?versions: Array[untyped]?, ?version_scope: untyped, ?plan: RootVersionPlan?) -> void
|
|
15
|
+
def initialize: (untyped, from: untyped, to: untyped, within: untyped, ?versions: Array[untyped]?, ?version_scope: untyped, ?plan: RootVersionPlan?) -> void
|
|
16
16
|
|
|
17
17
|
# A record with no versions has no first or last boundary to resolve, which
|
|
18
18
|
# is an empty history rather than a bad request.
|
|
@@ -21,6 +21,11 @@ module PaperTrailDiff
|
|
|
21
21
|
|
|
22
22
|
# A batch may have selected these versions already, in which case reselecting
|
|
23
23
|
# them per record would undo the batching.
|
|
24
|
+
# The plan says which pairs of versions become steps, which a filter can
|
|
25
|
+
# make different from adjacent pairs of the selected versions.
|
|
26
|
+
# : (?context_required: bool) -> RootVersionPlan
|
|
27
|
+
def select_plan: (?context_required: bool) -> RootVersionPlan
|
|
28
|
+
|
|
24
29
|
# : (?context_required: bool) -> Array[untyped]
|
|
25
30
|
def select: (?context_required: bool) -> Array[untyped]
|
|
26
31
|
|
|
@@ -37,6 +42,8 @@ module PaperTrailDiff
|
|
|
37
42
|
|
|
38
43
|
@from: untyped
|
|
39
44
|
|
|
45
|
+
@plan: RootVersionPlan?
|
|
46
|
+
|
|
40
47
|
@record: untyped
|
|
41
48
|
|
|
42
49
|
@requested_from: untyped
|
|
@@ -45,6 +52,8 @@ module PaperTrailDiff
|
|
|
45
52
|
|
|
46
53
|
@to: untyped
|
|
47
54
|
|
|
55
|
+
@version_scope: untyped
|
|
56
|
+
|
|
48
57
|
@versions: Array[untyped]?
|
|
49
58
|
|
|
50
59
|
# : () -> Array[untyped]
|
|
@@ -3,8 +3,15 @@
|
|
|
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) -> void
|
|
7
|
-
def initialize: (untyped, from: untyped, to: untyped) -> void
|
|
6
|
+
# : (untyped, from: untyped, to: untyped, ?version_scope: untyped) -> void
|
|
7
|
+
def initialize: (untyped, from: untyped, to: untyped, ?version_scope: untyped) -> void
|
|
8
|
+
|
|
9
|
+
# Same selection as `select`, but keeping the step pairs a filter implies.
|
|
10
|
+
# : () -> RootVersionPlan
|
|
11
|
+
def select_plan_for_range: () -> RootVersionPlan
|
|
12
|
+
|
|
13
|
+
# : () -> untyped
|
|
14
|
+
def validated_relation: () -> untyped
|
|
8
15
|
|
|
9
16
|
# : () -> Array[untyped]
|
|
10
17
|
def select: () -> Array[untyped]
|
|
@@ -20,12 +27,20 @@ module PaperTrailDiff
|
|
|
20
27
|
|
|
21
28
|
@to: untyped
|
|
22
29
|
|
|
30
|
+
@version_scope: untyped
|
|
31
|
+
|
|
23
32
|
# : () -> untyped
|
|
24
33
|
def versions_relation: () -> untyped
|
|
25
34
|
|
|
26
35
|
# : (untyped, ?through: untyped) -> Array[untyped]
|
|
27
36
|
def select_relation: (untyped, ?through: untyped) -> Array[untyped]
|
|
28
37
|
|
|
38
|
+
# : (untyped, ?through: untyped) -> RootVersionPlan
|
|
39
|
+
def select_plan: (untyped, ?through: untyped) -> RootVersionPlan
|
|
40
|
+
|
|
41
|
+
# : (Array[untyped]) -> Array[untyped]
|
|
42
|
+
def ordered: (Array[untyped]) -> Array[untyped]
|
|
43
|
+
|
|
29
44
|
# : (untyped, untyped, boundary: Symbol) -> void
|
|
30
45
|
def validate_boundary!: (untyped, untyped, boundary: Symbol) -> void
|
|
31
46
|
|