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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +287 -0
  3. data/QUICKSTART.md +9 -6
  4. data/README.md +84 -9
  5. data/docs/architecture.md +32 -9
  6. data/docs/performance.md +106 -13
  7. data/docs/reference.md +242 -29
  8. data/docs/testing.md +34 -11
  9. data/lib/paper_trail_diff/activity_belongs_to_event_applier.rb +19 -9
  10. data/lib/paper_trail_diff/activity_collection_event_applier.rb +11 -1
  11. data/lib/paper_trail_diff/activity_collection_record_updater.rb +16 -2
  12. data/lib/paper_trail_diff/activity_event_record_resolver.rb +20 -1
  13. data/lib/paper_trail_diff/activity_event_route_finder.rb +2 -1
  14. data/lib/paper_trail_diff/activity_event_snapshot_refresher.rb +1 -1
  15. data/lib/paper_trail_diff/activity_range.rb +14 -2
  16. data/lib/paper_trail_diff/activity_relationship.rb +12 -0
  17. data/lib/paper_trail_diff/activity_root_snapshot_refresher.rb +5 -2
  18. data/lib/paper_trail_diff/activity_target_candidate_loader.rb +131 -0
  19. data/lib/paper_trail_diff/activity_timeline_builder.rb +30 -24
  20. data/lib/paper_trail_diff/activity_version_collector.rb +31 -20
  21. data/lib/paper_trail_diff/association_activity_edge.rb +236 -0
  22. data/lib/paper_trail_diff/association_activity_selection.rb +197 -0
  23. data/lib/paper_trail_diff/association_discovery.rb +8 -13
  24. data/lib/paper_trail_diff/association_traversal.rb +169 -45
  25. data/lib/paper_trail_diff/batch_safety.rb +23 -15
  26. data/lib/paper_trail_diff/batched_root_versions.rb +21 -39
  27. data/lib/paper_trail_diff/comparison_batch.rb +37 -10
  28. data/lib/paper_trail_diff/deleted_analysis_batch.rb +34 -16
  29. data/lib/paper_trail_diff/diagnostics.rb +26 -8
  30. data/lib/paper_trail_diff/direct_record_state_loader.rb +10 -1
  31. data/lib/paper_trail_diff/errors.rb +2 -1
  32. data/lib/paper_trail_diff/habtm_transaction_owners.rb +68 -0
  33. data/lib/paper_trail_diff/historical_association_reifier.rb +32 -2
  34. data/lib/paper_trail_diff/historical_snapshot_store.rb +6 -9
  35. data/lib/paper_trail_diff/live_endpoint_batch_loader.rb +35 -2
  36. data/lib/paper_trail_diff/live_graph_collector.rb +1 -1
  37. data/lib/paper_trail_diff/paper_trail_adapter.rb +22 -6
  38. data/lib/paper_trail_diff/preloaded_endpoint_batch_loader.rb +1 -1
  39. data/lib/paper_trail_diff/prepared_activity_index.rb +110 -36
  40. data/lib/paper_trail_diff/prepared_edge_loader.rb +29 -45
  41. data/lib/paper_trail_diff/prepared_history.rb +63 -54
  42. data/lib/paper_trail_diff/prepared_history_loader.rb +33 -43
  43. data/lib/paper_trail_diff/prepared_record_index.rb +26 -0
  44. data/lib/paper_trail_diff/prepared_snapshot_builder.rb +1 -1
  45. data/lib/paper_trail_diff/prepared_state_association_reader.rb +119 -29
  46. data/lib/paper_trail_diff/recorded_changes.rb +83 -0
  47. data/lib/paper_trail_diff/recorded_class.rb +53 -0
  48. data/lib/paper_trail_diff/scope_condition.rb +331 -0
  49. data/lib/paper_trail_diff/scope_ranking.rb +196 -0
  50. data/lib/paper_trail_diff/scoped_analysis_builder.rb +4 -3
  51. data/lib/paper_trail_diff/scoped_root_selection.rb +93 -43
  52. data/lib/paper_trail_diff/snapshot_normalizer.rb +10 -3
  53. data/lib/paper_trail_diff/support.rb +9 -4
  54. data/lib/paper_trail_diff/time_activity_timeline_builder.rb +0 -1
  55. data/lib/paper_trail_diff/time_range.rb +9 -12
  56. data/lib/paper_trail_diff/time_version_range.rb +5 -5
  57. data/lib/paper_trail_diff/version.rb +1 -1
  58. data/lib/paper_trail_diff/version_association_candidate_scope.rb +13 -3
  59. data/lib/paper_trail_diff/version_range.rb +8 -15
  60. data/lib/paper_trail_diff/version_scope_filter.rb +11 -3
  61. data/lib/paper_trail_diff.rb +31 -2
  62. data/sig/generated/paper_trail_diff/activity_belongs_to_event_applier.rbs +10 -2
  63. data/sig/generated/paper_trail_diff/activity_collection_event_applier.rbs +5 -0
  64. data/sig/generated/paper_trail_diff/activity_collection_record_updater.rbs +5 -0
  65. data/sig/generated/paper_trail_diff/activity_event_record_resolver.rbs +7 -0
  66. data/sig/generated/paper_trail_diff/activity_range.rbs +6 -2
  67. data/sig/generated/paper_trail_diff/activity_relationship.rbs +3 -0
  68. data/sig/generated/paper_trail_diff/activity_root_snapshot_refresher.rbs +2 -0
  69. data/sig/generated/paper_trail_diff/activity_target_candidate_loader.rbs +79 -0
  70. data/sig/generated/paper_trail_diff/activity_timeline_builder.rbs +11 -5
  71. data/sig/generated/paper_trail_diff/activity_version_collector.rbs +10 -4
  72. data/sig/generated/paper_trail_diff/association_activity_edge.rbs +148 -0
  73. data/sig/generated/paper_trail_diff/association_activity_selection.rbs +112 -0
  74. data/sig/generated/paper_trail_diff/association_discovery.rbs +3 -5
  75. data/sig/generated/paper_trail_diff/association_traversal.rbs +84 -9
  76. data/sig/generated/paper_trail_diff/batch_safety.rbs +10 -4
  77. data/sig/generated/paper_trail_diff/batched_root_versions.rbs +2 -8
  78. data/sig/generated/paper_trail_diff/comparison_batch.rbs +22 -4
  79. data/sig/generated/paper_trail_diff/deleted_analysis_batch.rbs +16 -4
  80. data/sig/generated/paper_trail_diff/diagnostics.rbs +7 -2
  81. data/sig/generated/paper_trail_diff/direct_record_state_loader.rbs +6 -0
  82. data/sig/generated/paper_trail_diff/errors.rbs +2 -1
  83. data/sig/generated/paper_trail_diff/habtm_transaction_owners.rbs +40 -0
  84. data/sig/generated/paper_trail_diff/historical_association_reifier.rbs +13 -0
  85. data/sig/generated/paper_trail_diff/historical_snapshot_store.rbs +3 -2
  86. data/sig/generated/paper_trail_diff/live_endpoint_batch_loader.rbs +17 -0
  87. data/sig/generated/paper_trail_diff/paper_trail_adapter.rbs +5 -0
  88. data/sig/generated/paper_trail_diff/prepared_activity_index.rbs +52 -10
  89. data/sig/generated/paper_trail_diff/prepared_edge_loader.rbs +4 -12
  90. data/sig/generated/paper_trail_diff/prepared_history.rbs +33 -22
  91. data/sig/generated/paper_trail_diff/prepared_history_loader.rbs +15 -13
  92. data/sig/generated/paper_trail_diff/prepared_record_index.rbs +15 -0
  93. data/sig/generated/paper_trail_diff/prepared_state_association_reader.rbs +56 -11
  94. data/sig/generated/paper_trail_diff/recorded_changes.rbs +47 -0
  95. data/sig/generated/paper_trail_diff/recorded_class.rbs +22 -0
  96. data/sig/generated/paper_trail_diff/scope_condition.rbs +185 -0
  97. data/sig/generated/paper_trail_diff/scope_ranking.rbs +117 -0
  98. data/sig/generated/paper_trail_diff/scoped_analysis_builder.rbs +2 -2
  99. data/sig/generated/paper_trail_diff/scoped_root_selection.rbs +41 -7
  100. data/sig/generated/paper_trail_diff/snapshot_normalizer.rbs +6 -0
  101. data/sig/generated/paper_trail_diff/support.rbs +5 -2
  102. data/sig/generated/paper_trail_diff/time_range.rbs +4 -0
  103. data/sig/generated/paper_trail_diff/time_version_range.rbs +4 -4
  104. data/sig/generated/paper_trail_diff/version_association_candidate_scope.rbs +7 -0
  105. data/sig/generated/paper_trail_diff/version_range.rbs +4 -2
  106. data/sig/generated/paper_trail_diff/version_scope_filter.rbs +4 -0
  107. data/sig/generated/paper_trail_diff.rbs +21 -2
  108. metadata +20 -4
@@ -12,15 +12,42 @@ module PaperTrailDiff
12
12
  # : (untyped, Array[untyped]) -> Array[untyped]
13
13
  def versions: (untyped, Array[untyped]) -> Array[untyped]
14
14
 
15
+ # Children are found by key across the whole table, so an association to
16
+ # an STI subclass finds the rows of its siblings too. Only a row that was
17
+ # of the class at some point belongs to it, and of that row only the
18
+ # versions it had the class before or after.
19
+ # : (untyped, Array[untyped]) -> Array[untyped]
20
+ def member_ids: (untyped, Array[untyped]) -> Array[untyped]
21
+
22
+ # : (untyped, Array[untyped], ActivityRange) -> Array[untyped]
23
+ def member_versions: (untyped, Array[untyped], ActivityRange) -> Array[untyped]
24
+
25
+ # The versions of a through's join rows that are on its path. Under
26
+ # `source_type:`, a row is on it only while its type column names that
27
+ # class, so only the versions it had that type before or after count. A
28
+ # version saved before the type column existed has no type to read.
29
+ # : (Hash[Symbol, untyped], untyped) -> Array[untyped]
30
+ def join_versions: (Hash[Symbol, untyped], untyped) -> Array[untyped]
31
+
15
32
  # : (untyped, Array[untyped], untyped, ActivityRange) -> Array[untyped]
16
33
  def child_ids: (untyped, Array[untyped], untyped, ActivityRange) -> Array[untyped]
17
34
 
18
- # : (untyped, Array[untyped], untyped, ?transactions: bool) -> Array[untyped]
19
- def association_rows: (untyped, Array[untyped], untyped, ?transactions: bool) -> Array[untyped]
35
+ # The `belongs_to` targets each owner pointed at in the range: at its start
36
+ # and after each change inside it, plus the live row at a current end.
37
+ # : (untyped, Array[untyped], untyped, ActivityRange) -> Array[ActivityTargetCandidateLoader::Row]
38
+ def target_rows: (untyped, Array[untyped], untyped, ActivityRange) -> Array[ActivityTargetCandidateLoader::Row]
39
+
40
+ # : (untyped, untyped) -> bool
41
+ def loaded?: (untyped, untyped) -> bool
42
+
43
+ # PT-AT records HABTM membership once per transaction, under the
44
+ # association's name, so the rows are keyed by transaction id.
45
+ # : (untyped, Array[untyped], untyped) -> Array[untyped]
46
+ def habtm_rows: (untyped, Array[untyped], untyped) -> Array[untyped]
20
47
 
21
48
  private
22
49
 
23
- @children: Hash[Array[String], untyped]
50
+ @children: Hash[untyped, untyped]
24
51
 
25
52
  @nodes: Hash[String, Array[untyped]]
26
53
 
@@ -30,7 +57,12 @@ module PaperTrailDiff
30
57
 
31
58
  @roots: Hash[Array[String], Array[untyped]]
32
59
 
33
- @rows: Hash[Array[String], Hash[String, Array[untyped]]]
60
+ @rows: Hash[untyped, Hash[String, Array[untyped]]]
61
+
62
+ @targets: Hash[untyped, untyped]
63
+
64
+ # : (untyped, Array[untyped]) -> bool
65
+ def member_class?: (untyped, Array[untyped]) -> bool
34
66
 
35
67
  # : (untyped, Array[untyped], untyped, ActivityRange) -> Array[untyped]
36
68
  def historical_ids: (untyped, Array[untyped], untyped, ActivityRange) -> Array[untyped]
@@ -41,16 +73,26 @@ module PaperTrailDiff
41
73
  # : (untyped, untyped) -> untyped
42
74
  def child_rows: (untyped, untyped) -> untyped
43
75
 
76
+ # : (Hash[String, Array[ActivityTargetCandidateLoader::Row]], Array[untyped]) -> Array[ActivityTargetCandidateLoader::Row]
77
+ def rows_for: (Hash[String, Array[ActivityTargetCandidateLoader::Row]], Array[untyped]) -> Array[ActivityTargetCandidateLoader::Row]
78
+
79
+ # : (untyped, Array[ActivityTargetCandidateLoader::Row], ActivityRange) -> Array[ActivityTargetCandidateLoader::Row]
80
+ def eligible_rows: (untyped, Array[ActivityTargetCandidateLoader::Row], ActivityRange) -> Array[ActivityTargetCandidateLoader::Row]
81
+
82
+ # : (untyped, untyped) -> untyped
83
+ def target_candidates: (untyped, untyped) -> untyped
84
+
44
85
  # Mirrors VersionAssociationCandidateScope's before-window rule. The loaded
45
86
  # series includes changes to other owners too, so an old membership cannot
46
87
  # survive a later pre-window reassignment just because that owner is absent.
47
- # : (untyped, Array[untyped], ActivityRange) -> bool
48
- def eligible_child?: (untyped, Array[untyped], ActivityRange) -> bool
88
+ # : (untyped, untyped, untyped, String?, ActivityRange) -> bool
89
+ def eligible_version?: (untyped, untyped, untyped, String?, ActivityRange) -> bool
49
90
 
50
- # : (untyped, untyped, bool) -> Hash[String, Array[untyped]]
51
- def load_association_rows: (untyped, untyped, bool) -> Hash[String, Array[untyped]]
91
+ # : (untyped, untyped) -> Hash[String, Array[untyped]]
92
+ def load_habtm_rows: (untyped, untyped) -> Hash[String, Array[untyped]]
52
93
 
53
- # : (Array[untyped], bool) -> Array[untyped]
54
- def version_ids: (Array[untyped], bool) -> Array[untyped]
94
+ # A version without a transaction id names no rows, so it can stay in.
95
+ # : (Array[untyped]) -> Array[untyped]
96
+ def transaction_ids: (Array[untyped]) -> Array[untyped]
55
97
  end
56
98
  end
@@ -3,11 +3,10 @@
3
3
  module PaperTrailDiff
4
4
  # Loads every historical identity that can participate in one association edge.
5
5
  class PreparedEdgeLoader
6
- EDGE_LOADERS: untyped
7
-
8
6
  # : (PreparedRecordIndex, Array[untyped], ?start_at: untyped) -> void
9
7
  def initialize: (PreparedRecordIndex, Array[untyped], ?start_at: untyped) -> void
10
8
 
9
+ # HABTM alone also returns each root transaction's members.
11
10
  # : (untyped, Array[untyped], untyped) -> [Hash[String, Hash[Symbol, untyped]], Hash[String, Array[untyped]]?]
12
11
  def call: (untyped, Array[untyped], untyped) -> [ Hash[String, Hash[Symbol, untyped]], Hash[String, Array[untyped]]? ]
13
12
 
@@ -19,21 +18,14 @@ module PaperTrailDiff
19
18
 
20
19
  @transaction_ids: Array[untyped]
21
20
 
22
- # : (untyped, Array[untyped], untyped) -> [Hash[String, Hash[Symbol, untyped]], nil]
23
- def belongs_to_edge: (untyped, Array[untyped], untyped) -> [ Hash[String, Hash[Symbol, untyped]], nil ]
24
-
25
- # : (untyped, Array[untyped], untyped) -> [Hash[String, Hash[Symbol, untyped]], nil]
26
- def child_edge: (untyped, Array[untyped], untyped) -> [ Hash[String, Hash[Symbol, untyped]], nil ]
27
-
28
- # : (untyped, Array[untyped], untyped) -> [Hash[String, Hash[Symbol, untyped]], Hash[String, Array[untyped]]]
29
- def habtm_edge: (untyped, Array[untyped], untyped) -> [ Hash[String, Hash[Symbol, untyped]], Hash[String, Array[untyped]] ]
30
-
31
21
  # : (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
32
22
  def belongs_to_groups: (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
33
23
 
34
24
  # : (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
35
25
  def child_groups: (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
36
26
 
27
+ # A transaction more than one owner recorded members in is left out, so
28
+ # its read falls back to HistoricalAssociationReifier, which raises.
37
29
  # : (untyped, untyped) -> [Hash[String, Hash[Symbol, untyped]], Hash[String, Array[untyped]]]
38
30
  def habtm_groups: (untyped, untyped) -> [ Hash[String, Hash[Symbol, untyped]], Hash[String, Array[untyped]] ]
39
31
 
@@ -64,7 +56,7 @@ module PaperTrailDiff
64
56
  # : (untyped, Array[untyped], ?owners: Hash[String, Array[untyped]]?) -> Hash[String, Hash[Symbol, untyped]]
65
57
  def group_for: (untyped, Array[untyped], ?owners: Hash[String, Array[untyped]]?) -> Hash[String, Hash[Symbol, untyped]]
66
58
 
67
- # Keyed rather than scanned so that a wide edge stays linear in its width.
59
+ # A set rather than a scan, so that a wide edge stays linear in its width.
68
60
  # : (Array[Array[untyped]]) -> Hash[String, Array[untyped]]
69
61
  def group_ids_by_owner: (Array[Array[untyped]]) -> Hash[String, Array[untyped]]
70
62
 
@@ -10,8 +10,9 @@ module PaperTrailDiff
10
10
  # : (PreparedRecordIndex, ?activity_index: PreparedActivityIndex?) -> void
11
11
  def initialize: (PreparedRecordIndex, ?activity_index: PreparedActivityIndex?) -> void
12
12
 
13
- # : (untyped, untyped, Hash[String, Hash[Symbol, untyped]]) -> void
14
- def merge_edge: (untyped, untyped, Hash[String, Hash[Symbol, untyped]]) -> void
13
+ # Returns every group the edge now holds.
14
+ # : (untyped, untyped, Hash[String, Hash[Symbol, untyped]]) -> Hash[String, Hash[Symbol, untyped]]
15
+ def merge_edge: (untyped, untyped, Hash[String, Hash[Symbol, untyped]]) -> Hash[String, Hash[Symbol, untyped]]
15
16
 
16
17
  # : (untyped, untyped) -> Hash[String, Hash[Symbol, untyped]]
17
18
  def edge: (untyped, untyped) -> Hash[String, Hash[Symbol, untyped]]
@@ -31,11 +32,15 @@ module PaperTrailDiff
31
32
  # : (PreparedRecordState, untyped, untyped) -> [bool, Array[PreparedRecordState]]
32
33
  def snapshot_states: (PreparedRecordState, untyped, untyped) -> [ bool, Array[PreparedRecordState] ]
33
34
 
34
- # : (untyped, untyped, untyped, habtm_boundary: untyped) -> [bool, Array[untyped]]
35
- def resolve: (untyped, untyped, untyped, habtm_boundary: untyped) -> [ bool, Array[untyped] ]
35
+ # Unranked, as a part of a has_many through is read, it returns every row
36
+ # the part's conditions admit, a record reached twice appearing twice.
37
+ # : (untyped, untyped, untyped, habtm_boundary: untyped, ?ranked: bool) -> [bool, Array[untyped]]
38
+ def resolve: (untyped, untyped, untyped, habtm_boundary: untyped, ?ranked: bool) -> [ bool, Array[untyped] ]
36
39
 
37
40
  private
38
41
 
42
+ @conditions: ScopeCondition::Cache
43
+
39
44
  @edges: Hash[Array[String], Hash[String, Hash[Symbol, untyped]]]
40
45
 
41
46
  @habtm: Hash[Array[String], Hash[String, Array[untyped]]]
@@ -46,35 +51,41 @@ module PaperTrailDiff
46
51
 
47
52
  @unsupported: Hash[Array[String], bool]
48
53
 
49
- # : (untyped, untyped) -> bool
50
- def supported?: (untyped, untyped) -> bool
54
+ # A polymorphic target's class is known only once a record names it, so
55
+ # belongs_to_records reads its scope for each record instead.
56
+ # : (untyped, untyped, bool) -> bool
57
+ def supported?: (untyped, untyped, bool) -> bool
51
58
 
52
- # : (untyped, untyped, untyped, untyped) -> Array[untyped]?
53
- def direct_records: (untyped, untyped, untyped, untyped) -> Array[untyped]?
59
+ # : (untyped, untyped, untyped, untyped, bool) -> Array[untyped]?
60
+ def direct_records: (untyped, untyped, untyped, untyped, bool) -> Array[untyped]?
54
61
 
55
- # : (untyped, untyped, untyped, untyped) -> Array[untyped]?
56
- def resolve_belongs_to: (untyped, untyped, untyped, untyped) -> Array[untyped]?
62
+ # : (untyped, untyped, untyped, untyped, bool) -> Array[untyped]?
63
+ def resolve_belongs_to: (untyped, untyped, untyped, untyped, bool) -> Array[untyped]?
57
64
 
58
- # : (untyped, untyped, untyped, untyped) -> Array[untyped]
59
- def resolve_children: (untyped, untyped, untyped, untyped) -> Array[untyped]
65
+ # : (untyped, untyped, untyped, untyped, bool) -> Array[untyped]
66
+ def resolve_children: (untyped, untyped, untyped, untyped, bool) -> Array[untyped]
60
67
 
61
- # : (untyped, untyped, untyped) -> Array[untyped]?
62
- def belongs_to_records: (untyped, untyped, untyped) -> Array[untyped]?
68
+ # : (untyped, untyped, untyped, bool) -> Array[untyped]?
69
+ def belongs_to_records: (untyped, untyped, untyped, bool) -> Array[untyped]?
63
70
 
64
- # : (untyped, untyped, untyped) -> Array[untyped]
65
- def child_records: (untyped, untyped, untyped) -> Array[untyped]
71
+ # : (untyped, untyped, untyped, bool) -> Array[untyped]
72
+ def child_records: (untyped, untyped, untyped, bool) -> Array[untyped]
66
73
 
67
74
  # : (Hash[Symbol, untyped], untyped) -> Array[untyped]
68
75
  def child_ids_for: (Hash[Symbol, untyped], untyped) -> Array[untyped]
69
76
 
70
- # : (untyped, untyped, untyped, untyped) -> Array[untyped]?
71
- def habtm_records: (untyped, untyped, untyped, untyped) -> Array[untyped]?
77
+ # : (untyped, untyped, untyped, untyped, bool) -> Array[untyped]?
78
+ def habtm_records: (untyped, untyped, untyped, untyped, bool) -> Array[untyped]?
72
79
 
73
- # : (untyped, untyped, untyped, untyped) -> Array[untyped]?
74
- def through_records: (untyped, untyped, untyped, untyped) -> Array[untyped]?
80
+ # A has_many through reads its parts unranked, as its query does. Its own
81
+ # scope applies to each row, and a ranked read then keeps a record reached
82
+ # twice as one member.
83
+ # : (untyped, untyped, untyped, untyped, bool) -> Array[untyped]?
84
+ def through_records: (untyped, untyped, untyped, untyped, bool) -> Array[untyped]?
75
85
 
76
- # : (Array[untyped], untyped, untyped, untyped) -> Array[[bool, Array[untyped]]]
77
- def resolve_sources: (Array[untyped], untyped, untyped, untyped) -> Array[[ bool, Array[untyped] ]]
86
+ # The source records of each join record, once for each join.
87
+ # : (untyped, untyped, ^(untyped, untyped) -> [bool, Array[untyped]]) -> Array[untyped]?
88
+ def through_rows: (untyped, untyped, ^(untyped, untyped) -> [ bool, Array[untyped] ]) -> Array[untyped]?
78
89
 
79
90
  # : (untyped, untyped, untyped) -> bool
80
91
  def member_of?: (untyped, untyped, untyped) -> bool
@@ -3,19 +3,22 @@
3
3
  module PaperTrailDiff
4
4
  # Expands the explicit association tree into a request-scoped PreparedHistory.
5
5
  class PreparedHistoryLoader
6
- # : (untyped, root_versions: Array[untyped], tree: AssociationTree, traversal: AssociationTraversal, ?root_ids: Array[untyped], ?start_at: untyped, ?end_at: untyped, ?live_records: Array[untyped]) -> void
7
- def initialize: (untyped, root_versions: Array[untyped], tree: AssociationTree, traversal: AssociationTraversal, ?root_ids: Array[untyped], ?start_at: untyped, ?end_at: untyped, ?live_records: Array[untyped]) -> void
6
+ # Without `end_at`, the activity range closes on the last root version.
7
+ # : (untyped, root_ids: Array[untyped], root_versions: Array[untyped], tree: AssociationTree, traversal: AssociationTraversal, start_at: untyped, end_at: untyped, live_records: Array[untyped]) -> void
8
+ def initialize: (untyped, root_ids: Array[untyped], root_versions: Array[untyped], tree: AssociationTree, traversal: AssociationTraversal, start_at: untyped, end_at: untyped, live_records: Array[untyped]) -> void
8
9
 
9
10
  # : () -> PreparedHistory
10
11
  def call: () -> PreparedHistory
11
12
 
12
13
  private
13
14
 
15
+ @activity: PreparedActivityIndex
16
+
14
17
  @edges: PreparedEdgeLoader
15
18
 
16
19
  @history: PreparedHistory
17
20
 
18
- @prepared: Hash[Array[String], Array[String]]
21
+ @prepared: Hash[untyped, Array[String]]
19
22
 
20
23
  @record: untyped
21
24
 
@@ -35,24 +38,26 @@ module PaperTrailDiff
35
38
  # : (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
36
39
  def prepare_reflection: (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
37
40
 
41
+ # Either part can itself be a through, which has no key of its own to
42
+ # read, so each part is prepared as what it is. Like an edge, it returns
43
+ # every group it holds, not only those of these owners.
38
44
  # : (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
39
45
  def prepare_through: (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
40
46
 
41
47
  # : (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
42
48
  def prepare_edge: (untyped, Array[untyped], untyped) -> Hash[String, Hash[Symbol, untyped]]
43
49
 
44
- # : (untyped, Array[untyped], untyped) -> Array[untyped]
45
- def unprepared_ids: (untyped, Array[untyped], untyped) -> Array[untyped]
50
+ # A reflection belongs to the class that declares it, so it alone names
51
+ # the edge; a subclass that inherits it reads the same records.
52
+ # : (Array[untyped], untyped) -> Array[untyped]
53
+ def unprepared_ids: (Array[untyped], untyped) -> Array[untyped]
46
54
 
47
- # : (untyped, Array[untyped], untyped) -> void
48
- def mark_prepared: (untyped, Array[untyped], untyped) -> void
55
+ # : (Array[untyped], untyped) -> void
56
+ def mark_prepared: (Array[untyped], untyped) -> void
49
57
 
50
58
  # : (untyped, untyped, Hash[String, Hash[Symbol, untyped]]) -> void
51
59
  def mark_unsupported: (untyped, untyped, Hash[String, Hash[Symbol, untyped]]) -> void
52
60
 
53
- # : (untyped) -> bool
54
- def deferred_macro?: (untyped) -> bool
55
-
56
61
  # : (Hash[String, Hash[Symbol, untyped]]) -> void
57
62
  def load_groups: (Hash[String, Hash[Symbol, untyped]]) -> void
58
63
 
@@ -62,9 +67,6 @@ module PaperTrailDiff
62
67
  # : (untyped) -> bool
63
68
  def versioned?: (untyped) -> bool
64
69
 
65
- # : (untyped, untyped) -> Array[String]
66
- def edge_key: (untyped, untyped) -> Array[String]
67
-
68
70
  # : (Hash[String, Hash[Symbol, untyped]], Hash[String, Hash[Symbol, untyped]]) -> Hash[String, Hash[Symbol, untyped]]
69
71
  def merge_groups: (Hash[String, Hash[Symbol, untyped]], Hash[String, Hash[Symbol, untyped]]) -> Hash[String, Hash[Symbol, untyped]]
70
72
  end
@@ -81,6 +81,15 @@ module PaperTrailDiff
81
81
  # : () -> Array[PreparedRecordState]
82
82
  def states: () -> Array[PreparedRecordState]
83
83
 
84
+ # The classes the record had at any point, or either side of one version.
85
+ # : (?untyped) -> Array[untyped]
86
+ def model_classes: (?untyped) -> Array[untyped]
87
+
88
+ # The states either side of one version; a create has none before it and a
89
+ # destroy none after.
90
+ # : (untyped) -> Array[PreparedRecordState]
91
+ def states_around: (untyped) -> Array[PreparedRecordState]
92
+
84
93
  # : (untyped) -> [Hash[untyped, untyped], Hash[untyped, untyped]]?
85
94
  def transition: (untyped) -> [ Hash[untyped, untyped], Hash[untyped, untyped] ]?
86
95
 
@@ -153,6 +162,12 @@ module PaperTrailDiff
153
162
  # : (untyped, untyped) -> Array[untyped]
154
163
  def versions_for_id: (untyped, untyped) -> Array[untyped]
155
164
 
165
+ # : (untyped, untyped, ?untyped) -> Array[untyped]
166
+ def model_classes: (untyped, untyped, ?untyped) -> Array[untyped]
167
+
168
+ # : (untyped, untyped, untyped) -> Array[PreparedRecordState]
169
+ def states_around: (untyped, untyped, untyped) -> Array[PreparedRecordState]
170
+
156
171
  # : (untyped, untyped) -> bool
157
172
  def loaded?: (untyped, untyped) -> bool
158
173
 
@@ -1,31 +1,76 @@
1
1
  # Generated from lib/paper_trail_diff/prepared_state_association_reader.rb with RBS::Inline
2
2
 
3
3
  module PaperTrailDiff
4
- # Reads plain direct edges without creating AR records for their members.
4
+ # Reads plain edges without creating AR records for their members: direct
5
+ # edges, polymorphic `belongs_to`, and `has_many :through` built from them.
5
6
  class PreparedStateAssociationReader
6
- # : (PreparedRecordIndex, untyped) -> void
7
- def initialize: (PreparedRecordIndex, untyped) -> void
7
+ # : (PreparedRecordIndex, untyped, ScopeCondition::Cache) -> void
8
+ def initialize: (PreparedRecordIndex, untyped, ScopeCondition::Cache) -> void
8
9
 
9
- # : (PreparedRecordState, untyped, untyped) -> [bool, Array[PreparedRecordState]]
10
- def call: (PreparedRecordState, untyped, untyped) -> [ bool, Array[PreparedRecordState] ]
10
+ # Unranked, as a part of a has_many through is read, it returns every row
11
+ # the part's conditions admit, a record reached twice appearing twice.
12
+ # : (PreparedRecordState, untyped, untyped, ?ranked: bool) -> [bool, Array[PreparedRecordState]]
13
+ def call: (PreparedRecordState, untyped, untyped, ?ranked: bool) -> [ bool, Array[PreparedRecordState] ]
11
14
 
12
15
  private
13
16
 
17
+ @conditions: ScopeCondition::Cache
18
+
14
19
  @edges: untyped
15
20
 
16
21
  @records: PreparedRecordIndex
17
22
 
18
- # : (untyped) -> bool
19
- def supported?: (untyped) -> bool
23
+ # A polymorphic target's class is known only once a record names it, so
24
+ # `target` reads its scope for each record instead.
25
+ # : (untyped, bool) -> bool
26
+ def supported?: (untyped, bool) -> bool
27
+
28
+ # : (PreparedRecordState, untyped, bool, ?untyped) -> bool
29
+ def in_scope?: (PreparedRecordState, untyped, bool, ?untyped) -> bool
30
+
31
+ # A type that names no class, or a class whose scope cannot be read as
32
+ # conditions, is left to the record path, which raises for the first and
33
+ # reads the second through its association.
34
+ # : (PreparedRecordState, untyped, untyped, bool) -> [bool, Array[PreparedRecordState]]
35
+ def target: (PreparedRecordState, untyped, untyped, bool) -> [ bool, Array[PreparedRecordState] ]
36
+
37
+ # : (PreparedRecordState, untyped) -> untyped
38
+ def target_class: (PreparedRecordState, untyped) -> untyped
39
+
40
+ # The members of each join record the owner had at the boundary, as
41
+ # PreparedHistory#through_records reads them from records. Under
42
+ # `source_type:`, only join records of that type count. A has_many
43
+ # through reads its parts unranked, as its query does.
44
+ # : (PreparedRecordState, untyped, untyped, bool) -> [bool, Array[PreparedRecordState]]
45
+ def through: (PreparedRecordState, untyped, untyped, bool) -> [ bool, Array[PreparedRecordState] ]
20
46
 
21
- # : (PreparedRecordState, untyped, untyped) -> [bool, Array[PreparedRecordState]]
22
- def children: (PreparedRecordState, untyped, untyped) -> [ bool, Array[PreparedRecordState] ]
47
+ # The through's own scope applies after its parts' scopes, to each row,
48
+ # and a ranked read then keeps a record reached twice as one member.
49
+ # : (untyped, Array[PreparedRecordState], bool) -> Array[PreparedRecordState]
50
+ def through_members: (untyped, Array[PreparedRecordState], bool) -> Array[PreparedRecordState]
51
+
52
+ # A has_one keeps the first of its records.
53
+ # : (untyped, Array[PreparedRecordState]) -> Array[PreparedRecordState]
54
+ def first_if_one: (untyped, Array[PreparedRecordState]) -> Array[PreparedRecordState]
55
+
56
+ # : (untyped, PreparedRecordState) -> bool
57
+ def typed_join?: (untyped, PreparedRecordState) -> bool
58
+
59
+ # A record reached through two join records is one member.
60
+ # : (PreparedRecordState) -> Array[untyped]
61
+ def identity: (PreparedRecordState) -> Array[untyped]
62
+
63
+ # : (PreparedRecordState, untyped, untyped, bool) -> [bool, Array[PreparedRecordState]]
64
+ def children: (PreparedRecordState, untyped, untyped, bool) -> [ bool, Array[PreparedRecordState] ]
23
65
 
24
66
  # : (untyped, PreparedRecordState) -> Array[untyped]
25
67
  def ids_for: (untyped, PreparedRecordState) -> Array[untyped]
26
68
 
27
- # : (PreparedRecordState, PreparedRecordState, untyped) -> bool
28
- def member?: (PreparedRecordState, PreparedRecordState, untyped) -> bool
69
+ # : (PreparedRecordState, PreparedRecordState, untyped, bool) -> bool
70
+ def member?: (PreparedRecordState, PreparedRecordState, untyped, bool) -> bool
71
+
72
+ # : (PreparedRecordState) -> String
73
+ def owner_id: (PreparedRecordState) -> String
29
74
 
30
75
  # : (PreparedRecordState, untyped, untyped) -> bool
31
76
  def matching_type?: (PreparedRecordState, untyped, untyped) -> bool
@@ -0,0 +1,47 @@
1
+ # Generated from lib/paper_trail_diff/recorded_changes.rb with RBS::Inline
2
+
3
+ module PaperTrailDiff
4
+ # The changes PaperTrail wrote with one version, typed by the version's model.
5
+ #
6
+ # A step's diff compares reconstructed states, so it also holds whatever was
7
+ # saved without a version before the next one was read. This is the other
8
+ # account of the same event: only what PaperTrail recorded for it. Comparing
9
+ # the two is how a caller tells an unrecorded write from the event's own edit.
10
+ #
11
+ # PaperTrail's `version.changeset` finds the model through `version.item`,
12
+ # which is a query per version and nothing at all once the record is deleted.
13
+ # The version already names its model, so neither is needed here.
14
+ class RecordedChanges
15
+ IGNORE_NAMES_REQUIRED: ::String
16
+
17
+ # : (untyped, ignore: untyped) -> Hash[String, ValueChange]?
18
+ def self.call: (untyped, ignore: untyped) -> Hash[String, ValueChange]?
19
+
20
+ # : (untyped, ignore: untyped) -> void
21
+ def initialize: (untyped, ignore: untyped) -> void
22
+
23
+ # : () -> Hash[String, ValueChange]?
24
+ def call: () -> Hash[String, ValueChange]?
25
+
26
+ private
27
+
28
+ @ignore: untyped
29
+
30
+ @version: untyped
31
+
32
+ # Validated before anything is read, so a bad option fails the same way
33
+ # whether or not this version happened to record changes. Subclasses of
34
+ # Array and String pass, as in other methods' `ignore:`; Symbol has none.
35
+ # : () -> Array[String]
36
+ def ignored_names: () -> Array[String]
37
+
38
+ # Without the column, or with it left empty for this version, nothing was
39
+ # recorded. That is not the same answer as a recorded empty changeset.
40
+ # : () -> bool
41
+ def recorded?: () -> bool
42
+
43
+ # Primary keys identify the record rather than describe it, as in a diff.
44
+ # : (untyped, Array[String]) -> Hash[String, ValueChange]
45
+ def value_changes: (untyped, Array[String]) -> Hash[String, ValueChange]
46
+ end
47
+ end
@@ -0,0 +1,22 @@
1
+ # Generated from lib/paper_trail_diff/recorded_class.rb with RBS::Inline
2
+
3
+ module PaperTrailDiff
4
+ # The class a record had at one version, which decides the associations it
5
+ # can have. Without an `item_subtype` column PaperTrail stores only the base
6
+ # class, so an STI subclass is read from the stored inheritance column: the
7
+ # state before the change, or for a create, the value it was created with.
8
+ # A version that stored neither stays on the base class.
9
+ module RecordedClass
10
+ # : (untyped) -> untyped
11
+ def self?.for: (untyped) -> untyped
12
+
13
+ # : (untyped) -> bool
14
+ def self?.sti_base?: (untyped) -> bool
15
+
16
+ # : (untyped, untyped) -> untyped
17
+ def self?.stored_type: (untyped, untyped) -> untyped
18
+
19
+ # : (StandardError) -> bool
20
+ def self?.subclass_not_found?: (StandardError) -> bool
21
+ end
22
+ end