paper_trail_diff 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/QUICKSTART.md +44 -2
  4. data/README.md +179 -14
  5. data/lib/paper_trail_diff/activity_child_candidate_loader.rb +73 -0
  6. data/lib/paper_trail_diff/activity_event_snapshot_refresher.rb +261 -45
  7. data/lib/paper_trail_diff/activity_history.rb +136 -0
  8. data/lib/paper_trail_diff/activity_range.rb +28 -12
  9. data/lib/paper_trail_diff/activity_snapshot_delta.rb +64 -0
  10. data/lib/paper_trail_diff/activity_snapshot_sequence.rb +3 -3
  11. data/lib/paper_trail_diff/activity_timeline_builder.rb +54 -45
  12. data/lib/paper_trail_diff/activity_version_collector.rb +14 -17
  13. data/lib/paper_trail_diff/branch_snapshot_refresher.rb +5 -3
  14. data/lib/paper_trail_diff/collection_comparator.rb +155 -0
  15. data/lib/paper_trail_diff/collection_identity_index.rb +53 -0
  16. data/lib/paper_trail_diff/collection_transition.rb +25 -0
  17. data/lib/paper_trail_diff/comparison_batch.rb +151 -0
  18. data/lib/paper_trail_diff/engine.rb +5 -45
  19. data/lib/paper_trail_diff/errors.rb +9 -0
  20. data/lib/paper_trail_diff/historical_snapshot_store.rb +55 -3
  21. data/lib/paper_trail_diff/instrumentation.rb +30 -0
  22. data/lib/paper_trail_diff/live_endpoint_batch_loader.rb +133 -0
  23. data/lib/paper_trail_diff/live_endpoint_provider.rb +48 -0
  24. data/lib/paper_trail_diff/live_graph_collector.rb +52 -0
  25. data/lib/paper_trail_diff/paper_trail_adapter.rb +61 -34
  26. data/lib/paper_trail_diff/preloaded_endpoint_batch_loader.rb +48 -0
  27. data/lib/paper_trail_diff/prepared_edge_loader.rb +54 -17
  28. data/lib/paper_trail_diff/prepared_history.rb +14 -4
  29. data/lib/paper_trail_diff/prepared_history_loader.rb +17 -9
  30. data/lib/paper_trail_diff/prepared_record_index.rb +138 -10
  31. data/lib/paper_trail_diff/snapshot.rb +66 -3
  32. data/lib/paper_trail_diff/support.rb +18 -0
  33. data/lib/paper_trail_diff/time_activity_timeline_builder.rb +111 -0
  34. data/lib/paper_trail_diff/time_range.rb +85 -0
  35. data/lib/paper_trail_diff/time_version_range.rb +53 -0
  36. data/lib/paper_trail_diff/timeline_builder.rb +13 -7
  37. data/lib/paper_trail_diff/timeline_range.rb +72 -0
  38. data/lib/paper_trail_diff/version.rb +1 -1
  39. data/lib/paper_trail_diff/version_association_candidate_scope.rb +73 -0
  40. data/lib/paper_trail_diff.rb +74 -12
  41. data/sig/generated/paper_trail_diff/activity_child_candidate_loader.rbs +40 -0
  42. data/sig/generated/paper_trail_diff/activity_event_snapshot_refresher.rbs +49 -8
  43. data/sig/generated/paper_trail_diff/activity_history.rbs +79 -0
  44. data/sig/generated/paper_trail_diff/activity_range.rbs +14 -5
  45. data/sig/generated/paper_trail_diff/activity_snapshot_delta.rbs +33 -0
  46. data/sig/generated/paper_trail_diff/activity_snapshot_sequence.rbs +2 -2
  47. data/sig/generated/paper_trail_diff/activity_timeline_builder.rbs +15 -10
  48. data/sig/generated/paper_trail_diff/activity_version_collector.rbs +2 -5
  49. data/sig/generated/paper_trail_diff/branch_snapshot_refresher.rbs +2 -2
  50. data/sig/generated/paper_trail_diff/collection_comparator.rbs +59 -0
  51. data/sig/generated/paper_trail_diff/collection_identity_index.rbs +29 -0
  52. data/sig/generated/paper_trail_diff/collection_transition.rbs +18 -0
  53. data/sig/generated/paper_trail_diff/comparison_batch.rbs +65 -0
  54. data/sig/generated/paper_trail_diff/engine.rbs +0 -12
  55. data/sig/generated/paper_trail_diff/errors.rbs +12 -0
  56. data/sig/generated/paper_trail_diff/historical_snapshot_store.rbs +22 -2
  57. data/sig/generated/paper_trail_diff/instrumentation.rbs +12 -0
  58. data/sig/generated/paper_trail_diff/live_endpoint_batch_loader.rbs +52 -0
  59. data/sig/generated/paper_trail_diff/live_endpoint_provider.rbs +23 -0
  60. data/sig/generated/paper_trail_diff/live_graph_collector.rbs +27 -0
  61. data/sig/generated/paper_trail_diff/paper_trail_adapter.rbs +21 -10
  62. data/sig/generated/paper_trail_diff/preloaded_endpoint_batch_loader.rbs +24 -0
  63. data/sig/generated/paper_trail_diff/prepared_edge_loader.rbs +22 -8
  64. data/sig/generated/paper_trail_diff/prepared_history.rbs +6 -0
  65. data/sig/generated/paper_trail_diff/prepared_history_loader.rbs +4 -2
  66. data/sig/generated/paper_trail_diff/prepared_record_index.rbs +61 -6
  67. data/sig/generated/paper_trail_diff/snapshot.rbs +37 -2
  68. data/sig/generated/paper_trail_diff/support.rbs +6 -0
  69. data/sig/generated/paper_trail_diff/time_activity_timeline_builder.rbs +46 -0
  70. data/sig/generated/paper_trail_diff/time_range.rbs +41 -0
  71. data/sig/generated/paper_trail_diff/time_version_range.rbs +27 -0
  72. data/sig/generated/paper_trail_diff/timeline_builder.rbs +6 -5
  73. data/sig/generated/paper_trail_diff/timeline_range.rbs +41 -0
  74. data/sig/generated/paper_trail_diff/version_association_candidate_scope.rbs +32 -0
  75. data/sig/generated/paper_trail_diff.rbs +16 -8
  76. metadata +38 -4
@@ -0,0 +1,18 @@
1
+ # Generated from lib/paper_trail_diff/collection_transition.rb with RBS::Inline
2
+
3
+ module PaperTrailDiff
4
+ # One collection mutation between structurally adjacent snapshots.
5
+ class CollectionTransition
6
+ attr_reader before: RecordSnapshot?
7
+
8
+ attr_reader after: RecordSnapshot?
9
+
10
+ # : (from: AssociationSnapshot, before: RecordSnapshot?, after: RecordSnapshot?) -> void
11
+ def initialize: (from: AssociationSnapshot, before: RecordSnapshot?, after: RecordSnapshot?) -> void
12
+
13
+ # : (AssociationSnapshot) -> bool
14
+ def from?: (AssociationSnapshot) -> bool
15
+
16
+ @from_object_id: Integer
17
+ end
18
+ end
@@ -0,0 +1,65 @@
1
+ # Generated from lib/paper_trail_diff/comparison_batch.rb with RBS::Inline
2
+
3
+ module PaperTrailDiff
4
+ # Validates and executes independent comparisons with shared live endpoint loading.
5
+ class ComparisonBatch
6
+ # : (Array[comparison_input], live_loader: untyped, preparer: untyped, history_preparer: untyped, historical_snapshotter: untyped, live_normalizer: untyped) -> void
7
+ def initialize: (Array[comparison_input], live_loader: untyped, preparer: untyped, history_preparer: untyped, historical_snapshotter: untyped, live_normalizer: untyped) -> void
8
+
9
+ # : () -> comparison_results
10
+ def call: () -> comparison_results
11
+
12
+ private
13
+
14
+ @comparisons: Array[comparison_input]
15
+
16
+ @historical_snapshotter: untyped
17
+
18
+ @history_preparer: untyped
19
+
20
+ @live_loader: untyped
21
+
22
+ @live_normalizer: untyped
23
+
24
+ @preparer: untyped
25
+
26
+ # : (untyped, untyped, Hash[identity, RecordSnapshot]) -> Diff
27
+ def compare: (untyped, untyped, Hash[identity, RecordSnapshot]) -> Diff
28
+
29
+ # : (untyped, Hash[identity, RecordSnapshot]) -> RecordSnapshot?
30
+ def snapshot: (untyped, Hash[identity, RecordSnapshot]) -> RecordSnapshot?
31
+
32
+ # : (Array[untyped]) -> Hash[identity, untyped]
33
+ def load_live_records: (Array[untyped]) -> Hash[identity, untyped]
34
+
35
+ # : (Hash[identity, untyped]) -> Hash[identity, RecordSnapshot]
36
+ def normalize_live_records: (Hash[identity, untyped]) -> Hash[identity, RecordSnapshot]
37
+
38
+ # : (Array[[untyped, untyped]], Hash[identity, untyped]) -> void
39
+ def prepare_historical_batches!: (Array[[ untyped, untyped ]], Hash[identity, untyped]) -> void
40
+
41
+ # : (Array[[untyped, untyped]], Hash[identity, untyped]) -> Array[untyped]
42
+ def historical_versions: (Array[[ untyped, untyped ]], Hash[identity, untyped]) -> Array[untyped]
43
+
44
+ # : () -> Array[[untyped, untyped]]
45
+ def comparison_pairs: () -> Array[[ untyped, untyped ]]
46
+
47
+ # : (untyped, Integer) -> [untyped, untyped]
48
+ def comparison_pair: (untyped, Integer) -> [ untyped, untyped ]
49
+
50
+ # : (untyped, Integer) -> void
51
+ def valid_comparison!: (untyped, Integer) -> void
52
+
53
+ # : (Hash[untyped, untyped], Symbol) -> untyped
54
+ def endpoint: (Hash[untyped, untyped], Symbol) -> untyped
55
+
56
+ # : (Array[[untyped, untyped]]) -> void
57
+ def ensure_unique_identities!: (Array[[ untyped, untyped ]]) -> void
58
+
59
+ # : (Array[[untyped, untyped]]) -> void
60
+ def prepare_endpoint_classes!: (Array[[ untyped, untyped ]]) -> void
61
+
62
+ # : (Array[[untyped, untyped]]) -> Hash[untyped, bool]
63
+ def endpoint_requirements: (Array[[ untyped, untyped ]]) -> Hash[untyped, bool]
64
+ end
65
+ end
@@ -36,18 +36,6 @@ module PaperTrailDiff
36
36
  # : (AssociationSnapshot, AssociationSnapshot) -> CollectionAssociationDiff
37
37
  private def self.compare_collection: (AssociationSnapshot, AssociationSnapshot) -> CollectionAssociationDiff
38
38
 
39
- # : (Hash[identity, RecordSnapshot], Hash[identity, RecordSnapshot]) -> Array[RecordSnapshot]
40
- private def self.records_missing_from: (Hash[identity, RecordSnapshot], Hash[identity, RecordSnapshot]) -> Array[RecordSnapshot]
41
-
42
- # : (Hash[identity, RecordSnapshot], Hash[identity, RecordSnapshot]) -> Array[RecordChange]
43
- private def self.changed_records: (Hash[identity, RecordSnapshot], Hash[identity, RecordSnapshot]) -> Array[RecordChange]
44
-
45
- # : (Array[RecordSnapshot]) -> Hash[Array[untyped], RecordSnapshot]
46
- private def self.index_records: (Array[RecordSnapshot]) -> Hash[Array[untyped], RecordSnapshot]
47
-
48
- # : (Array[Array[untyped]]) -> Array[Array[untyped]]
49
- private def self.sorted_identities: (Array[Array[untyped]]) -> Array[Array[untyped]]
50
-
51
39
  # : (RecordSnapshot?, RecordSnapshot?) -> bool
52
40
  private def self.same_identity?: (RecordSnapshot?, RecordSnapshot?) -> bool
53
41
  end
@@ -17,10 +17,22 @@ module PaperTrailDiff
17
17
  class InvalidEndpointError < Error
18
18
  end
19
19
 
20
+ # Raised when reload opt-out encounters an association that was not preloaded.
21
+ class UnloadedAssociationError < InvalidEndpointError
22
+ end
23
+
20
24
  # Raised when a timeline boundary is absent or the requested range is reversed.
21
25
  class InvalidTimelineRangeError < Error
22
26
  end
23
27
 
28
+ # Raised when `within` is not a finite, chronological range of time-like values.
29
+ class InvalidTimeRangeError < InvalidTimelineRangeError
30
+ end
31
+
32
+ # Raised when an in-range mutation has no later root boundary for reconstruction.
33
+ class IncompleteTimeRangeError < InvalidTimelineRangeError
34
+ end
35
+
24
36
  # Raised when a requested ActiveRecord association does not exist.
25
37
  class UnknownAssociationError < Error
26
38
  end
@@ -6,8 +6,12 @@ module PaperTrailDiff
6
6
  # : (tree: AssociationTree, traversal: AssociationTraversal, normalizer: SnapshotNormalizer, preparer: untyped) -> void
7
7
  def initialize: (tree: AssociationTree, traversal: AssociationTraversal, normalizer: SnapshotNormalizer, preparer: untyped) -> void
8
8
 
9
- # : (untyped, Array[untyped]) -> void
10
- def prepare: (untyped, Array[untyped]) -> void
9
+ # : (untyped, Array[untyped], ?start_at: untyped) -> void
10
+ def prepare: (untyped, Array[untyped], ?start_at: untyped) -> void
11
+
12
+ # Prepares selected history for several roots of the same model class.
13
+ # : (Array[untyped], Array[untyped]) -> void
14
+ def prepare_batch: (Array[untyped], Array[untyped]) -> void
11
15
 
12
16
  # : (untyped, untyped) -> RecordSnapshot?
13
17
  def call: (untyped, untyped) -> RecordSnapshot?
@@ -21,10 +25,17 @@ module PaperTrailDiff
21
25
  # : (untyped, habtm_version: untyped) -> untyped
22
26
  def association_reader: (untyped, habtm_version: untyped) -> untyped
23
27
 
28
+ # : (untyped) -> [Hash[untyped, untyped], Hash[untyped, untyped]]?
29
+ def record_transition: (untyped) -> [ Hash[untyped, untyped], Hash[untyped, untyped] ]?
30
+
24
31
  private
25
32
 
33
+ @live_graph_collector: LiveGraphCollector
34
+
26
35
  @normalizer: SnapshotNormalizer
27
36
 
37
+ @prepared_histories: Hash[Array[untyped], PreparedHistory]
38
+
28
39
  @prepared_history: PreparedHistory?
29
40
 
30
41
  @preparer: untyped
@@ -35,6 +46,15 @@ module PaperTrailDiff
35
46
 
36
47
  @tree: AssociationTree
37
48
 
49
+ # : (untyped) -> Array[untyped]
50
+ def context_key: (untyped) -> Array[untyped]
51
+
52
+ # : (Array[untyped], Array[untyped]) -> Hash[Symbol, untyped]
53
+ def batch_payload: (Array[untyped], Array[untyped]) -> Hash[Symbol, untyped]
54
+
55
+ # : (Array[untyped], Array[untyped]) -> void
56
+ def register_batch: (Array[untyped], Array[untyped]) -> void
57
+
38
58
  # : (untyped, untyped, tree: AssociationTree, normalizer: SnapshotNormalizer) -> RecordSnapshot?
39
59
  def snapshot_from_version: (untyped, untyped, tree: AssociationTree, normalizer: SnapshotNormalizer) -> RecordSnapshot?
40
60
 
@@ -0,0 +1,12 @@
1
+ # Generated from lib/paper_trail_diff/instrumentation.rb with RBS::Inline
2
+
3
+ module PaperTrailDiff
4
+ # Emits quiet, namespaced runtime events for application-owned diagnostics.
5
+ module Instrumentation
6
+ # : (String | Symbol, Hash[Symbol, untyped]) { () -> untyped } -> untyped
7
+ def self?.instrument: (String | Symbol, Hash[Symbol, untyped]) { () -> untyped } -> untyped
8
+
9
+ # : (association_paths: Array[String], reload_live_endpoints: bool) -> Hash[Symbol, untyped]
10
+ def self?.comparison_payload: (association_paths: Array[String], reload_live_endpoints: bool) -> Hash[Symbol, untyped]
11
+ end
12
+ end
@@ -0,0 +1,52 @@
1
+ # Generated from lib/paper_trail_diff/live_endpoint_batch_loader.rb with RBS::Inline
2
+
3
+ module PaperTrailDiff
4
+ # Reloads current-record endpoints and their explicitly selected associations in batches.
5
+ class LiveEndpointBatchLoader
6
+ # : (tree: AssociationTree) -> void
7
+ def initialize: (tree: AssociationTree) -> void
8
+
9
+ # : (Array[untyped]) -> Hash[identity, untyped]
10
+ def call: (Array[untyped]) -> Hash[identity, untyped]
11
+
12
+ private
13
+
14
+ @tree: AssociationTree
15
+
16
+ # : (untyped, Array[untyped]) -> Array[untyped]
17
+ def load_group: (untyped, Array[untyped]) -> Array[untyped]
18
+
19
+ # : (Array[untyped], AssociationTree) -> void
20
+ def preload_tree: (Array[untyped], AssociationTree) -> void
21
+
22
+ # : (untyped, Array[untyped], AssociationTree) -> void
23
+ def preload_model_tree: (untyped, Array[untyped], AssociationTree) -> void
24
+
25
+ # : (untyped, AssociationTree) -> Array[[untyped, AssociationTree]]
26
+ def selected_reflections: (untyped, AssociationTree) -> Array[[ untyped, AssociationTree ]]
27
+
28
+ # : (Array[untyped], Array[[untyped, AssociationTree]], individually: bool) -> void
29
+ def preload_subtrees: (Array[untyped], Array[[ untyped, AssociationTree ]], individually: bool) -> void
30
+
31
+ # : (Array[untyped], Array[Symbol]) -> void
32
+ def preload_batch: (Array[untyped], Array[Symbol]) -> void
33
+
34
+ # : () -> untyped
35
+ def active_record_preloader: () -> untyped
36
+
37
+ # : (untyped, untyped) -> bool
38
+ def batch_safe?: (untyped, untyped) -> bool
39
+
40
+ # : (Array[untyped], untyped) -> Array[untyped]
41
+ def load_individually: (Array[untyped], untyped) -> Array[untyped]
42
+
43
+ # : (Array[untyped], untyped) -> Array[untyped]
44
+ def targets: (Array[untyped], untyped) -> Array[untyped]
45
+
46
+ # : (Array[untyped]) -> Array[untyped]
47
+ def unique_records: (Array[untyped]) -> Array[untyped]
48
+
49
+ # : (Array[untyped], Hash[identity, untyped]) -> void
50
+ def ensure_all_loaded!: (Array[untyped], Hash[identity, untyped]) -> void
51
+ end
52
+ end
@@ -0,0 +1,23 @@
1
+ # Generated from lib/paper_trail_diff/live_endpoint_provider.rb with RBS::Inline
2
+
3
+ module PaperTrailDiff
4
+ # Selects safe reload or validated caller-owned loading for current endpoints.
5
+ class LiveEndpointProvider
6
+ attr_reader reload: bool
7
+
8
+ attr_reader comparison_payload: Hash[Symbol, untyped]
9
+
10
+ # : (tree: AssociationTree, traversal: AssociationTraversal, reload: bool) -> void
11
+ def initialize: (tree: AssociationTree, traversal: AssociationTraversal, reload: bool) -> void
12
+
13
+ # : (Array[untyped]) -> Hash[identity, untyped]
14
+ def call: (Array[untyped]) -> Hash[identity, untyped]
15
+
16
+ private
17
+
18
+ @loader: untyped
19
+
20
+ # : (Array[untyped]) -> Hash[Symbol, untyped]
21
+ def payload: (Array[untyped]) -> Hash[Symbol, untyped]
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ # Generated from lib/paper_trail_diff/live_graph_collector.rb with RBS::Inline
2
+
3
+ module PaperTrailDiff
4
+ # Flattens an already-preloaded, explicitly bounded live association graph.
5
+ class LiveGraphCollector
6
+ # : (tree: AssociationTree, traversal: AssociationTraversal) -> void
7
+ def initialize: (tree: AssociationTree, traversal: AssociationTraversal) -> void
8
+
9
+ # : (Array[untyped]) -> Array[untyped]
10
+ def call: (Array[untyped]) -> Array[untyped]
11
+
12
+ private
13
+
14
+ @traversal: AssociationTraversal
15
+
16
+ @tree: AssociationTree
17
+
18
+ # : (Array[untyped], AssociationTree, path: String, into: Hash[Array[untyped], untyped]) -> void
19
+ def collect: (Array[untyped], AssociationTree, path: String, into: Hash[Array[untyped], untyped]) -> void
20
+
21
+ # : (untyped, Array[untyped], AssociationTree, path: String, into: Hash[Array[untyped], untyped]) -> void
22
+ def collect_group: (untyped, Array[untyped], AssociationTree, path: String, into: Hash[Array[untyped], untyped]) -> void
23
+
24
+ # : (Array[untyped], untyped) -> Array[untyped]
25
+ def children_for: (Array[untyped], untyped) -> Array[untyped]
26
+ end
27
+ end
@@ -3,20 +3,24 @@
3
3
  module PaperTrailDiff
4
4
  # PaperTrail/ActiveRecord boundary that produces plain record snapshots.
5
5
  class PaperTrailAdapter
6
- # : (associations: Array[String | Symbol], ignore: ignore_option) -> void
7
- def initialize: (associations: Array[String | Symbol], ignore: ignore_option) -> void
6
+ # : (associations: Array[String | Symbol], ignore: ignore_option, ?reload_live_endpoints: bool) -> void
7
+ def initialize: (associations: Array[String | Symbol], ignore: ignore_option, ?reload_live_endpoints: bool) -> void
8
8
 
9
9
  # : (untyped, untyped) -> Diff
10
10
  def compare: (untyped, untyped) -> Diff
11
11
 
12
- # : (untyped, from: untyped, to: untyped) -> Array[Step]
13
- def timeline: (untyped, from: untyped, to: untyped) -> Array[Step]
12
+ # Compares independent pairs and returns immutable results keyed by item identity.
13
+ # : (Array[comparison_input]) -> comparison_results
14
+ def compare_many: (Array[comparison_input]) -> comparison_results
14
15
 
15
- # : (untyped, from: untyped, to: untyped) -> Array[ActivityStep]
16
- def activity_timeline: (untyped, from: untyped, to: untyped) -> Array[ActivityStep]
16
+ # : (untyped, from: untyped, to: untyped, within: untyped) -> Array[Step]
17
+ def timeline: (untyped, from: untyped, to: untyped, within: untyped) -> Array[Step]
17
18
 
18
- # : (untyped, from: untyped, to: untyped, ?activity: bool) -> Analysis
19
- def analyze: (untyped, from: untyped, to: untyped, ?activity: bool) -> Analysis
19
+ # : (untyped, from: untyped, to: untyped, within: untyped) -> Array[ActivityStep]
20
+ def activity_timeline: (untyped, from: untyped, to: untyped, within: untyped) -> Array[ActivityStep]
21
+
22
+ # : (untyped, from: untyped, to: untyped, within: untyped, ?activity: bool) -> Analysis
23
+ def analyze: (untyped, from: untyped, to: untyped, within: untyped, ?activity: bool) -> Analysis
20
24
 
21
25
  private
22
26
 
@@ -28,6 +32,10 @@ module PaperTrailDiff
28
32
 
29
33
  @ignore_policy: IgnorePolicy
30
34
 
35
+ @instrumentation_payload: Hash[Symbol, untyped]
36
+
37
+ @live_endpoints: LiveEndpointProvider
38
+
31
39
  @normalizer: SnapshotNormalizer
32
40
 
33
41
  @snapshot_pool: SnapshotPool
@@ -42,8 +50,8 @@ module PaperTrailDiff
42
50
  # : () -> ActivitySnapshotProvider
43
51
  def build_activity_snapshotter: () -> ActivitySnapshotProvider
44
52
 
45
- # : (untyped, from: untyped, to: untyped) -> ActivityTimelineBuilder
46
- def activity_builder: (untyped, from: untyped, to: untyped) -> ActivityTimelineBuilder
53
+ # : (untyped, from: untyped, to: untyped, within: untyped) -> ActivityTimelineBuilder
54
+ def activity_builder: (untyped, from: untyped, to: untyped, within: untyped) -> ActivityTimelineBuilder
47
55
 
48
56
  # : (untyped) -> void
49
57
  def reject_live_habtm_activity!: (untyped) -> void
@@ -63,6 +71,9 @@ module PaperTrailDiff
63
71
  # : (untyped) -> RecordSnapshot
64
72
  def live_snapshot: (untyped) -> RecordSnapshot
65
73
 
74
+ # : (untyped) -> RecordSnapshot
75
+ def normalize_live_snapshot: (untyped) -> RecordSnapshot
76
+
66
77
  # : (untyped, historical: bool) -> void
67
78
  def prepare_traversal!: (untyped, historical: bool) -> void
68
79
 
@@ -0,0 +1,24 @@
1
+ # Generated from lib/paper_trail_diff/preloaded_endpoint_batch_loader.rb with RBS::Inline
2
+
3
+ module PaperTrailDiff
4
+ # Validates and reuses caller-owned live records without issuing association queries.
5
+ class PreloadedEndpointBatchLoader
6
+ # : (tree: AssociationTree, traversal: AssociationTraversal) -> void
7
+ def initialize: (tree: AssociationTree, traversal: AssociationTraversal) -> void
8
+
9
+ # : (Array[untyped]) -> Hash[identity, untyped]
10
+ def call: (Array[untyped]) -> Hash[identity, untyped]
11
+
12
+ private
13
+
14
+ @traversal: AssociationTraversal
15
+
16
+ @tree: AssociationTree
17
+
18
+ # : (untyped, AssociationTree, path: String) -> void
19
+ def validate_record: (untyped, AssociationTree, path: String) -> void
20
+
21
+ # : (untyped, AssociationTree, String, untyped) -> void
22
+ def validate_association: (untyped, AssociationTree, String, untyped) -> void
23
+ end
24
+ end
@@ -5,8 +5,8 @@ module PaperTrailDiff
5
5
  class PreparedEdgeLoader
6
6
  EDGE_LOADERS: untyped
7
7
 
8
- # : (PreparedRecordIndex, Array[untyped]) -> void
9
- def initialize: (PreparedRecordIndex, Array[untyped]) -> void
8
+ # : (PreparedRecordIndex, Array[untyped], ?start_at: untyped) -> void
9
+ def initialize: (PreparedRecordIndex, Array[untyped], ?start_at: untyped) -> void
10
10
 
11
11
  # : (untyped, Array[untyped], untyped) -> [Hash[String, Hash[Symbol, untyped]], Hash[String, Array[untyped]]?]
12
12
  def call: (untyped, Array[untyped], untyped) -> [ Hash[String, Hash[Symbol, untyped]], Hash[String, Array[untyped]]? ]
@@ -15,6 +15,8 @@ module PaperTrailDiff
15
15
 
16
16
  @records: PreparedRecordIndex
17
17
 
18
+ @start_at: untyped
19
+
18
20
  @transaction_ids: Array[untyped]
19
21
 
20
22
  # : (untyped, Array[untyped], untyped) -> [Hash[String, Hash[Symbol, untyped]], nil]
@@ -41,11 +43,17 @@ module PaperTrailDiff
41
43
  # : (Array[untyped], untyped) -> Array[untyped]
42
44
  def membership_ids: (Array[untyped], untyped) -> Array[untyped]
43
45
 
44
- # : (untyped, Array[untyped], untyped, String) -> Array[untyped]
45
- def historical_child_ids: (untyped, Array[untyped], untyped, String) -> Array[untyped]
46
+ # : (untyped, Array[untyped], untyped, String) -> Hash[String, Array[untyped]]
47
+ def historical_child_ids: (untyped, Array[untyped], untyped, String) -> Hash[String, Array[untyped]]
48
+
49
+ # : (untyped, Array[untyped], untyped, String) -> untyped
50
+ def historical_child_relation: (untyped, Array[untyped], untyped, String) -> untyped
51
+
52
+ # : (untyped) -> VersionAssociationCandidateScope
53
+ def child_candidate_scope: (untyped) -> VersionAssociationCandidateScope
46
54
 
47
- # : (untyped, Array[untyped], untyped, String) -> Array[untyped]
48
- def live_child_ids: (untyped, Array[untyped], untyped, String) -> Array[untyped]
55
+ # : (untyped, Array[untyped], untyped, String) -> Hash[String, Array[untyped]]
56
+ def live_child_ids: (untyped, Array[untyped], untyped, String) -> Hash[String, Array[untyped]]
49
57
 
50
58
  # : (untyped, untyped) -> untyped
51
59
  def target_class: (untyped, untyped) -> untyped
@@ -53,8 +61,14 @@ module PaperTrailDiff
53
61
  # : (Hash[String, Hash[Symbol, untyped]], untyped, untyped) -> void
54
62
  def add_identity: (Hash[String, Hash[Symbol, untyped]], untyped, untyped) -> void
55
63
 
56
- # : (untyped, Array[untyped]) -> Hash[String, Hash[Symbol, untyped]]
57
- def group_for: (untyped, Array[untyped]) -> Hash[String, Hash[Symbol, untyped]]
64
+ # : (untyped, Array[untyped], ?owners: Hash[String, Array[untyped]]?) -> Hash[String, Hash[Symbol, untyped]]
65
+ def group_for: (untyped, Array[untyped], ?owners: Hash[String, Array[untyped]]?) -> Hash[String, Hash[Symbol, untyped]]
66
+
67
+ # : (Array[Array[untyped]]) -> Hash[String, Array[untyped]]
68
+ def group_ids_by_owner: (Array[Array[untyped]]) -> Hash[String, Array[untyped]]
69
+
70
+ # : (Hash[String, Array[untyped]], Hash[String, Array[untyped]]) -> Hash[String, Array[untyped]]
71
+ def merge_owners: (Hash[String, Array[untyped]], Hash[String, Array[untyped]]) -> Hash[String, Array[untyped]]
58
72
 
59
73
  # : (untyped) -> String?
60
74
  def scalar_foreign_key: (untyped) -> String?
@@ -20,6 +20,9 @@ module PaperTrailDiff
20
20
  # : (untyped, untyped, Hash[String, Array[untyped]]) -> void
21
21
  def register_habtm: (untyped, untyped, Hash[String, Array[untyped]]) -> void
22
22
 
23
+ # : (untyped, untyped, untyped) -> [Hash[untyped, untyped], Hash[untyped, untyped]]?
24
+ def record_transition: (untyped, untyped, untyped) -> [ Hash[untyped, untyped], Hash[untyped, untyped] ]?
25
+
23
26
  # : (untyped, untyped, untyped, habtm_boundary: untyped) -> [bool, Array[untyped]]
24
27
  def resolve: (untyped, untyped, untyped, habtm_boundary: untyped) -> [ bool, Array[untyped] ]
25
28
 
@@ -57,6 +60,9 @@ module PaperTrailDiff
57
60
  # : (untyped, untyped, untyped) -> Array[untyped]
58
61
  def child_records: (untyped, untyped, untyped) -> Array[untyped]
59
62
 
63
+ # : (Hash[Symbol, untyped], untyped) -> Array[untyped]
64
+ def child_ids_for: (Hash[Symbol, untyped], untyped) -> Array[untyped]
65
+
60
66
  # : (untyped, untyped, untyped, untyped) -> Array[untyped]?
61
67
  def habtm_records: (untyped, untyped, untyped, untyped) -> Array[untyped]?
62
68
 
@@ -3,8 +3,8 @@
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) -> void
7
- def initialize: (untyped, root_versions: Array[untyped], tree: AssociationTree, traversal: AssociationTraversal) -> void
6
+ # : (untyped, root_versions: Array[untyped], tree: AssociationTree, traversal: AssociationTraversal, ?root_ids: Array[untyped], ?start_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, ?live_records: Array[untyped]) -> void
8
8
 
9
9
  # : () -> PreparedHistory
10
10
  def call: () -> PreparedHistory
@@ -21,6 +21,8 @@ module PaperTrailDiff
21
21
 
22
22
  @records: PreparedRecordIndex
23
23
 
24
+ @root_ids: Array[untyped]
25
+
24
26
  @traversal: AssociationTraversal
25
27
 
26
28
  @tree: AssociationTree
@@ -3,23 +3,58 @@
3
3
  module PaperTrailDiff
4
4
  # Immutable scalar state from a PaperTrail version or live-record fallback.
5
5
  class PreparedRecordState
6
+ attr_reader model_class: untyped
7
+
8
+ attr_reader attributes: Hash[untyped, untyped]
9
+
6
10
  # : (untyped) -> void
7
11
  def initialize: (untyped) -> void
8
12
 
13
+ # : (untyped, Hash[untyped, untyped]) -> PreparedRecordState
14
+ def self.from_attributes: (untyped, Hash[untyped, untyped]) -> PreparedRecordState
15
+
9
16
  # : () -> untyped
10
17
  def instantiate: () -> untyped
11
18
 
12
- @attributes: Hash[untyped, untyped]
19
+ private
20
+
21
+ # : (untyped, Hash[untyped, untyped]) -> void
22
+ def initialize_attributes: (untyped, Hash[untyped, untyped]) -> void
23
+ end
24
+
25
+ # Extracts a version's scalar state without constructing a disposable AR object.
26
+ class PreparedVersionStateLoader
27
+ # : () -> void
28
+ def initialize: () -> void
29
+
30
+ # : (untyped) -> PreparedRecordState?
31
+ def call: (untyped) -> PreparedRecordState?
32
+
33
+ private
34
+
35
+ @attribute_names: Hash[untyped, Array[String]]
36
+
37
+ @serializers: Hash[untyped, untyped]
38
+
39
+ # : (Hash[untyped, untyped]) -> Hash[String, untyped]
40
+ def stringify_keys: (Hash[untyped, untyped]) -> Hash[String, untyped]
13
41
 
14
- @model_class: untyped
42
+ # : (untyped, Hash[String, untyped]) -> untyped
43
+ def reification_class: (untyped, Hash[String, untyped]) -> untyped
44
+
45
+ # : (untyped, Hash[String, untyped]) -> bool
46
+ def direct_attributes?: (untyped, Hash[String, untyped]) -> bool
47
+
48
+ # : (untyped) -> untyped
49
+ def object_attribute_serializer: (untyped) -> untyped
15
50
  end
16
51
 
17
52
  # Versions and live fallback for one model identity.
18
53
  class PreparedRecordSeries
19
54
  attr_reader versions: Array[untyped]
20
55
 
21
- # : (versions: Array[untyped], live: PreparedRecordState?) -> void
22
- def initialize: (versions: Array[untyped], live: PreparedRecordState?) -> void
56
+ # : (versions: Array[untyped], live: PreparedRecordState?, ?state_loader: PreparedVersionStateLoader) -> void
57
+ def initialize: (versions: Array[untyped], live: PreparedRecordState?, ?state_loader: PreparedVersionStateLoader) -> void
23
58
 
24
59
  # : (untyped) -> untyped
25
60
  def record_before: (untyped) -> untyped
@@ -27,12 +62,22 @@ module PaperTrailDiff
27
62
  # : () -> Array[untyped]
28
63
  def records: () -> Array[untyped]
29
64
 
65
+ # : (untyped) -> [Hash[untyped, untyped], Hash[untyped, untyped]]?
66
+ def transition: (untyped) -> [ Hash[untyped, untyped], Hash[untyped, untyped] ]?
67
+
30
68
  private
31
69
 
32
70
  @live: PreparedRecordState?
33
71
 
72
+ @state_loader: PreparedVersionStateLoader
73
+
34
74
  @states: Hash[untyped, PreparedRecordState?]
35
75
 
76
+ @version_positions: Hash[String, Integer]
77
+
78
+ # : (Integer) -> PreparedRecordState?
79
+ def state_after: (Integer) -> PreparedRecordState?
80
+
36
81
  # : (untyped, untyped) -> bool
37
82
  def eligible?: (untyped, untyped) -> bool
38
83
 
@@ -45,8 +90,8 @@ module PaperTrailDiff
45
90
 
46
91
  # Request-scoped scalar history loaded once per model identity.
47
92
  class PreparedRecordIndex
48
- # : (untyped) -> void
49
- def initialize: (untyped) -> void
93
+ # : (untyped, ?live_records: Array[untyped]) -> void
94
+ def initialize: (untyped, ?live_records: Array[untyped]) -> void
50
95
 
51
96
  # : (untyped, Array[untyped]) -> void
52
97
  def load: (untyped, Array[untyped]) -> void
@@ -54,6 +99,9 @@ module PaperTrailDiff
54
99
  # : (untyped, untyped, untyped) -> untyped
55
100
  def record_before: (untyped, untyped, untyped) -> untyped
56
101
 
102
+ # : (untyped, untyped, untyped) -> [Hash[untyped, untyped], Hash[untyped, untyped]]?
103
+ def transition: (untyped, untyped, untyped) -> [ Hash[untyped, untyped], Hash[untyped, untyped] ]?
104
+
57
105
  # : (untyped, Array[untyped]) -> Array[untyped]
58
106
  def records_for: (untyped, Array[untyped]) -> Array[untyped]
59
107
 
@@ -62,10 +110,14 @@ module PaperTrailDiff
62
110
 
63
111
  private
64
112
 
113
+ @seeded_live_records: Hash[Array[String], untyped]
114
+
65
115
  @series: Hash[Array[String], PreparedRecordSeries]
66
116
 
67
117
  @start_time: untyped
68
118
 
119
+ @state_loader: PreparedVersionStateLoader
120
+
69
121
  # : (untyped, untyped) -> Array[String]
70
122
  def identity: (untyped, untyped) -> Array[String]
71
123
 
@@ -78,6 +130,9 @@ module PaperTrailDiff
78
130
  # : (untyped, Array[untyped]) -> Array[untyped]
79
131
  def versions_for: (untyped, Array[untyped]) -> Array[untyped]
80
132
 
133
+ # : (untyped, Array[untyped]) -> Array[untyped]
134
+ def available_live_records: (untyped, Array[untyped]) -> Array[untyped]
135
+
81
136
  # : (untyped, Array[untyped]) -> Array[untyped]
82
137
  def live_records_for: (untyped, Array[untyped]) -> Array[untyped]
83
138
  end
@@ -26,6 +26,16 @@ module PaperTrailDiff
26
26
 
27
27
  SUPPORTED_KINDS: untyped
28
28
 
29
+ # Non-semantic memoization shared by structurally adjacent snapshots. The
30
+ # cached value is derived only from frozen records and is itself immutable.
31
+ class IdentityIndexCache
32
+ # : () -> void
33
+ def initialize: () -> void
34
+
35
+ # : (Array[RecordSnapshot]) -> CollectionIdentityIndex
36
+ def index: (Array[RecordSnapshot]) -> CollectionIdentityIndex
37
+ end
38
+
29
39
  # : (Symbol) -> bool
30
40
  def self.collection_kind?: (Symbol) -> bool
31
41
 
@@ -33,11 +43,36 @@ module PaperTrailDiff
33
43
 
34
44
  attr_reader records: Array[RecordSnapshot]
35
45
 
36
- # : (kind: Symbol, records: Array[RecordSnapshot]) -> void
37
- def initialize: (kind: Symbol, records: Array[RecordSnapshot]) -> void
46
+ # : (kind: Symbol, records: Array[RecordSnapshot], ?identity_index_cache: untyped, ?transition: CollectionTransition?) -> void
47
+ def initialize: (kind: Symbol, records: Array[RecordSnapshot], ?identity_index_cache: untyped, ?transition: CollectionTransition?) -> void
48
+
49
+ # Builds a structurally adjacent collection snapshot for internal activity carry-forward.
50
+ # : (Array[RecordSnapshot], before: RecordSnapshot?, after: RecordSnapshot?, membership_preserved: bool) -> AssociationSnapshot
51
+ def transition_to: (Array[RecordSnapshot], before: RecordSnapshot?, after: RecordSnapshot?, membership_preserved: bool) -> AssociationSnapshot
52
+
53
+ # : (AssociationSnapshot) -> CollectionTransition?
54
+ def transition_from: (AssociationSnapshot) -> CollectionTransition?
55
+
56
+ # : (untyped, untyped) -> Integer?
57
+ def position: (untyped, untyped) -> Integer?
58
+
59
+ # : (untyped) -> Integer?
60
+ def position_for_id: (untyped) -> Integer?
61
+
62
+ # : () -> void
63
+ def validate_unique_identities!: () -> void
38
64
 
39
65
  # : () -> Hash[Symbol, untyped]
40
66
  def to_h: () -> Hash[Symbol, untyped]
67
+
68
+ private
69
+
70
+ @identity_index_cache: untyped
71
+
72
+ @transition: CollectionTransition?
73
+
74
+ # : () -> CollectionIdentityIndex
75
+ def identity_index: () -> CollectionIdentityIndex
41
76
  end
42
77
 
43
78
  # An immutable, ActiveRecord-independent representation of a reified record.