paper_trail_diff 0.9.0 → 0.11.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +94 -0
  3. data/README.md +181 -0
  4. data/lib/paper_trail_diff/activity_boundary.rb +20 -4
  5. data/lib/paper_trail_diff/activity_grouping.rb +26 -0
  6. data/lib/paper_trail_diff/activity_timeline_builder.rb +13 -6
  7. data/lib/paper_trail_diff/activity_transaction_grouper.rb +83 -0
  8. data/lib/paper_trail_diff/diagnostics.rb +4 -2
  9. data/lib/paper_trail_diff/errors.rb +8 -0
  10. data/lib/paper_trail_diff/nested_comparator.rb +108 -0
  11. data/lib/paper_trail_diff/paper_trail_adapter.rb +31 -12
  12. data/lib/paper_trail_diff/prepared_history_loader.rb +1 -1
  13. data/lib/paper_trail_diff/scoped_analysis.rb +31 -0
  14. data/lib/paper_trail_diff/scoped_root_selection.rb +148 -0
  15. data/lib/paper_trail_diff/support.rb +13 -0
  16. data/lib/paper_trail_diff/time_activity_timeline_builder.rb +13 -8
  17. data/lib/paper_trail_diff/traversal_preparer.rb +25 -0
  18. data/lib/paper_trail_diff/version.rb +1 -1
  19. data/lib/paper_trail_diff.rb +101 -12
  20. data/sig/generated/paper_trail_diff/activity_boundary.rbs +13 -2
  21. data/sig/generated/paper_trail_diff/activity_grouping.rbs +19 -0
  22. data/sig/generated/paper_trail_diff/activity_timeline_builder.rbs +4 -2
  23. data/sig/generated/paper_trail_diff/activity_transaction_grouper.rbs +54 -0
  24. data/sig/generated/paper_trail_diff/errors.rbs +10 -0
  25. data/sig/generated/paper_trail_diff/nested_comparator.rbs +68 -0
  26. data/sig/generated/paper_trail_diff/paper_trail_adapter.rbs +15 -8
  27. data/sig/generated/paper_trail_diff/scoped_analysis.rbs +25 -0
  28. data/sig/generated/paper_trail_diff/scoped_root_selection.rbs +93 -0
  29. data/sig/generated/paper_trail_diff/support.rbs +11 -0
  30. data/sig/generated/paper_trail_diff/time_activity_timeline_builder.rbs +4 -2
  31. data/sig/generated/paper_trail_diff/traversal_preparer.rbs +10 -0
  32. data/sig/generated/paper_trail_diff.rbs +58 -4
  33. metadata +14 -4
@@ -27,14 +27,47 @@ module PaperTrailDiff
27
27
  def self.activity_timeline: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?reload_live_endpoints: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool) -> Array[ActivityStep]
28
28
 
29
29
  # Builds an endpoint diff and root-checkpoint timeline while normalizing each version once.
30
- # : (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool) -> Analysis
31
- def self.analyze: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool) -> Analysis
30
+ # : (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool, ?group: Symbol?) -> Analysis
31
+ def self.analyze: (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool, ?group: Symbol?) -> Analysis
32
32
 
33
33
  # Analyzes many roots over one shared time window, preparing their selected
34
34
  # history once for the batch instead of once per record. Roots with no
35
35
  # versions in the window return an empty `Analysis`.
36
- # : (Array[untyped], ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?) -> Hash[identity, Analysis]
37
- def self.analyze_many: (Array[untyped], ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?) -> Hash[identity, Analysis]
36
+ #
37
+ # Pass `records` to analyze a list you assembled, which returns a Hash keyed
38
+ # by identity. Pass `scope:` with a `limit:` to have the roots selected for
39
+ # you from a relation, which returns a `ScopedAnalysis` -- the same Hash,
40
+ # plus the roots the relation could not reach. See `analyze_scope` for why
41
+ # that second collection exists.
42
+ # : (?Array[untyped]?, ?scope: untyped, ?limit: Integer?, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?) -> (Hash[identity, Analysis] | ScopedAnalysis)
43
+ def self.analyze_many: (?Array[untyped]?, ?scope: untyped, ?limit: Integer?, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?) -> (Hash[identity, Analysis] | ScopedAnalysis)
44
+
45
+ # Analyzes every root the relation reaches whose history moved inside the
46
+ # window, selecting them in a fixed number of queries rather than making the
47
+ # caller rediscover them.
48
+ #
49
+ # `limit:` is required and exceeding it raises. Selection moves into the gem
50
+ # here, so the bound on how much work a page can ask for has to move with
51
+ # it, and a truncated audit report is worse than a refused one.
52
+ #
53
+ # Returns a `ScopedAnalysis`, which destructures:
54
+ #
55
+ # analyses, unreachable = PaperTrailDiff.analyze_scope(
56
+ # Article.where(status: 'published'), within: july, limit: 500
57
+ # )
58
+ #
59
+ # `unreachable` names roots that changed in the window but have no live row
60
+ # left. A relation's conditions are evaluated against the live table, so a
61
+ # destroyed root cannot be tested against them at all -- its history is
62
+ # intact and the state it held at destruction may well have matched. Those
63
+ # roots are reported rather than dropped so that a page auditing deletions
64
+ # is told where to look instead of quietly coming up short.
65
+ #
66
+ # Note also that a relation selects on current state, not on state during
67
+ # the window: `where(status: 'published')` means published *now*, which is a
68
+ # different set from what was published while the window was open.
69
+ # : (untyped, limit: Integer?, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?) -> ScopedAnalysis
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?) -> ScopedAnalysis
38
71
 
39
72
  # Returns the association macros this release can normalize.
40
73
  # : () -> Array[Symbol]
@@ -47,6 +80,27 @@ module PaperTrailDiff
47
80
  # Reports known reconstruction hazards without mutating application state.
48
81
  # : (untyped, untyped, ?associations: Array[String | Symbol]) -> DiagnosticReport
49
82
  def self.diagnose: (untyped, untyped, ?associations: Array[String | Symbol]) -> DiagnosticReport
83
+
84
+ # Looks inside an attribute the database stores whole, such as a JSON or
85
+ # jsonb column, and reports which keys changed.
86
+ #
87
+ # change = diff.attributes.fetch('config')
88
+ # PaperTrailDiff.nested_changes(change)
89
+ # # => { ['theme'] => <from "dark" to "light">,
90
+ # # ['limits', 'max'] => <from 10 to 20> }
91
+ #
92
+ # Accepts the `ValueChange` an attribute diff already produced, or a bare
93
+ # pair. Returns an empty hash when the pair is not two readable structures,
94
+ # which is the honest answer: a column that held text on one side and JSON
95
+ # on the other changed wholesale, and the caller still has that change.
96
+ #
97
+ # Paths are arrays because a JSON key may contain a dot. Arrays are reported
98
+ # whole rather than by index, since their elements carry no identity and a
99
+ # list that merely shifted would otherwise look changed throughout. A key
100
+ # that was absent reads as `NestedComparator::ABSENT` rather than nil, which
101
+ # JSON uses for a present null.
102
+ # : (untyped, ?untyped) -> Hash[Array[String], ValueChange]
103
+ def self.nested_changes: (untyped, ?untyped) -> Hash[Array[String], ValueChange]
50
104
  end
51
105
 
52
106
  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.9.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Williams
@@ -55,6 +55,7 @@ files:
55
55
  - lib/paper_trail_diff/activity_event_record_resolver.rb
56
56
  - lib/paper_trail_diff/activity_event_route_finder.rb
57
57
  - lib/paper_trail_diff/activity_event_snapshot_refresher.rb
58
+ - lib/paper_trail_diff/activity_grouping.rb
58
59
  - lib/paper_trail_diff/activity_history.rb
59
60
  - lib/paper_trail_diff/activity_range.rb
60
61
  - lib/paper_trail_diff/activity_relationship.rb
@@ -63,6 +64,7 @@ files:
63
64
  - lib/paper_trail_diff/activity_snapshot_delta.rb
64
65
  - lib/paper_trail_diff/activity_snapshot_sequence.rb
65
66
  - lib/paper_trail_diff/activity_timeline_builder.rb
67
+ - lib/paper_trail_diff/activity_transaction_grouper.rb
66
68
  - lib/paper_trail_diff/activity_version_collector.rb
67
69
  - lib/paper_trail_diff/analysis.rb
68
70
  - lib/paper_trail_diff/analysis_batch.rb
@@ -89,6 +91,7 @@ files:
89
91
  - lib/paper_trail_diff/live_endpoint_batch_loader.rb
90
92
  - lib/paper_trail_diff/live_endpoint_provider.rb
91
93
  - lib/paper_trail_diff/live_graph_collector.rb
94
+ - lib/paper_trail_diff/nested_comparator.rb
92
95
  - lib/paper_trail_diff/paper_trail_adapter.rb
93
96
  - lib/paper_trail_diff/preloaded_endpoint_batch_loader.rb
94
97
  - lib/paper_trail_diff/prepared_association_reifier.rb
@@ -98,6 +101,8 @@ files:
98
101
  - lib/paper_trail_diff/prepared_record_index.rb
99
102
  - lib/paper_trail_diff/root_version_plan.rb
100
103
  - lib/paper_trail_diff/root_version_selection.rb
104
+ - lib/paper_trail_diff/scoped_analysis.rb
105
+ - lib/paper_trail_diff/scoped_root_selection.rb
101
106
  - lib/paper_trail_diff/snapshot.rb
102
107
  - lib/paper_trail_diff/snapshot_normalizer.rb
103
108
  - lib/paper_trail_diff/snapshot_traversal.rb
@@ -132,6 +137,7 @@ files:
132
137
  - sig/generated/paper_trail_diff/activity_event_record_resolver.rbs
133
138
  - sig/generated/paper_trail_diff/activity_event_route_finder.rbs
134
139
  - sig/generated/paper_trail_diff/activity_event_snapshot_refresher.rbs
140
+ - sig/generated/paper_trail_diff/activity_grouping.rbs
135
141
  - sig/generated/paper_trail_diff/activity_history.rbs
136
142
  - sig/generated/paper_trail_diff/activity_range.rbs
137
143
  - sig/generated/paper_trail_diff/activity_relationship.rbs
@@ -140,6 +146,7 @@ files:
140
146
  - sig/generated/paper_trail_diff/activity_snapshot_delta.rbs
141
147
  - sig/generated/paper_trail_diff/activity_snapshot_sequence.rbs
142
148
  - sig/generated/paper_trail_diff/activity_timeline_builder.rbs
149
+ - sig/generated/paper_trail_diff/activity_transaction_grouper.rbs
143
150
  - sig/generated/paper_trail_diff/activity_version_collector.rbs
144
151
  - sig/generated/paper_trail_diff/analysis.rbs
145
152
  - sig/generated/paper_trail_diff/analysis_batch.rbs
@@ -166,6 +173,7 @@ files:
166
173
  - sig/generated/paper_trail_diff/live_endpoint_batch_loader.rbs
167
174
  - sig/generated/paper_trail_diff/live_endpoint_provider.rbs
168
175
  - sig/generated/paper_trail_diff/live_graph_collector.rbs
176
+ - sig/generated/paper_trail_diff/nested_comparator.rbs
169
177
  - sig/generated/paper_trail_diff/paper_trail_adapter.rbs
170
178
  - sig/generated/paper_trail_diff/preloaded_endpoint_batch_loader.rbs
171
179
  - sig/generated/paper_trail_diff/prepared_association_reifier.rbs
@@ -175,6 +183,8 @@ files:
175
183
  - sig/generated/paper_trail_diff/prepared_record_index.rbs
176
184
  - sig/generated/paper_trail_diff/root_version_plan.rbs
177
185
  - sig/generated/paper_trail_diff/root_version_selection.rbs
186
+ - sig/generated/paper_trail_diff/scoped_analysis.rbs
187
+ - sig/generated/paper_trail_diff/scoped_root_selection.rbs
178
188
  - sig/generated/paper_trail_diff/snapshot.rbs
179
189
  - sig/generated/paper_trail_diff/snapshot_normalizer.rbs
180
190
  - sig/generated/paper_trail_diff/snapshot_traversal.rbs
@@ -202,11 +212,11 @@ licenses:
202
212
  metadata:
203
213
  allowed_push_host: https://rubygems.org
204
214
  bug_tracker_uri: https://github.com/aheathwilliams/paper_trail_diff/issues
205
- changelog_uri: https://github.com/aheathwilliams/paper_trail_diff/blob/v0.9.0/CHANGELOG.md
206
- documentation_uri: https://github.com/aheathwilliams/paper_trail_diff/blob/v0.9.0/README.md
215
+ changelog_uri: https://github.com/aheathwilliams/paper_trail_diff/blob/v0.11.0/CHANGELOG.md
216
+ documentation_uri: https://github.com/aheathwilliams/paper_trail_diff/blob/v0.11.0/README.md
207
217
  homepage_uri: https://github.com/aheathwilliams/paper_trail_diff
208
218
  rubygems_mfa_required: 'true'
209
- source_code_uri: https://github.com/aheathwilliams/paper_trail_diff/tree/v0.9.0
219
+ source_code_uri: https://github.com/aheathwilliams/paper_trail_diff/tree/v0.11.0
210
220
  rdoc_options: []
211
221
  require_paths:
212
222
  - lib