cdc-core 0.1.2 → 0.1.3

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +12 -4
  4. data/lib/cdc/core/change_event.rb +10 -5
  5. data/lib/cdc/core/column_change.rb +4 -4
  6. data/lib/cdc/core/composite_processor.rb +3 -3
  7. data/lib/cdc/core/event_metadata.rb +14 -9
  8. data/lib/cdc/core/event_position.rb +1 -1
  9. data/lib/cdc/core/filter.rb +8 -8
  10. data/lib/cdc/core/observer.rb +24 -19
  11. data/lib/cdc/core/ordering_key.rb +8 -3
  12. data/lib/cdc/core/ordering_policy.rb +12 -9
  13. data/lib/cdc/core/pipeline.rb +5 -5
  14. data/lib/cdc/core/processor.rb +7 -7
  15. data/lib/cdc/core/processor_chain.rb +1 -1
  16. data/lib/cdc/core/processor_result.rb +18 -14
  17. data/lib/cdc/core/router.rb +6 -6
  18. data/lib/cdc/core/source_adapter.rb +2 -2
  19. data/lib/cdc/core/transaction_envelope.rb +9 -4
  20. data/lib/cdc/core/version.rb +1 -1
  21. data/sig/cdc/core/change_event.rbs +34 -216
  22. data/sig/cdc/core/column_change.rbs +4 -43
  23. data/sig/cdc/core/composite_processor.rbs +11 -54
  24. data/sig/cdc/core/errors.rbs +1 -7
  25. data/sig/cdc/core/event_metadata.rbs +7 -39
  26. data/sig/cdc/core/event_position.rbs +12 -12
  27. data/sig/cdc/core/filter.rbs +11 -62
  28. data/sig/cdc/core/null_observer.rbs +1 -2
  29. data/sig/cdc/core/observer.rbs +11 -13
  30. data/sig/cdc/core/operation.rbs +7 -29
  31. data/sig/cdc/core/ordering_key.rbs +5 -7
  32. data/sig/cdc/core/ordering_policy.rbs +10 -15
  33. data/sig/cdc/core/ordering_scope.rbs +7 -5
  34. data/sig/cdc/core/pipeline.rbs +9 -54
  35. data/sig/cdc/core/processor.rbs +5 -56
  36. data/sig/cdc/core/processor_chain.rbs +8 -35
  37. data/sig/cdc/core/processor_result.rbs +32 -125
  38. data/sig/cdc/core/router.rbs +12 -13
  39. data/sig/cdc/core/source_adapter.rbs +2 -4
  40. data/sig/cdc/core/transaction_envelope.rbs +17 -71
  41. data/sig/cdc/core/version.rbs +1 -2
  42. data/sig/cdc/core.rbs +28 -7
  43. data/sig/cdc_core.rbs +4 -0
  44. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6b50778bfa61fb46ffb973eaa1975345cdbd6df15d4a719110dba339b63ed68
4
- data.tar.gz: e461bc281b0147d2c8fdcfc1e3c95f209076070c3585858cc97c5c90585cc6ad
3
+ metadata.gz: 9ffbf7ae1292484005aad90e904713835e5b3fc762e56e40484169c48d509156
4
+ data.tar.gz: d7edeb40f694be694535497ceb20ed663830a336d6862faae328cfafa01644d2
5
5
  SHA512:
6
- metadata.gz: 761888ea92dcd0c5f0a268bdb999016de811486fd69a3e2eaab457d1d4b21e1a79664214017961da69ec05adebcc2d99b98e2b433430a8d69e3f70e2967be8ca
7
- data.tar.gz: 27c091d4e1f0b16a1c3503cc12af85ed9311e9650f028251fbf2334d81849359b15932d92b556e4ebd11f1ef51f7b37bfdbfe630f79087ff50c450b049f3c17e
6
+ metadata.gz: b9b513c8241e683b3bc28f8d249339553bc91e8a93770384aaafc641df6617f98618c16374a5d1bdda7ab06e7609389c9e758586244a501e8dba72071eaed7c6
7
+ data.tar.gz: 39be75beb53af0cbeb3c4a5047045ff329e4510ba20c2f5ed8409f72d3e5c6f42b45873fa419da24eea23f0d5ce4e78573913731a760de4544cf4789ac1dc6ee
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.3] - 2026-06-11
4
+
5
+ ### Added
6
+
7
+ - Added generated API documentation badges and deployment-safe documentation links.
8
+
9
+ ### Fixed
10
+
11
+ - Fixed RBS validation issues and warnings across core signatures and typed metadata defaults.
12
+ - Fixed edge-case ordering policy behavior for unknown internal scopes.
13
+ - Corrected README and docs examples for current processor composition constructors.
14
+ - Improved YARD tag descriptions across core API comments.
15
+ - Polished API and architecture documentation wording, links, and Ruby snippet style.
16
+
3
17
  ## [0.1.2] - 2026-06-10
4
18
 
5
19
  - Added `CDC::Core::ProcessorChain` that feeds the successful value from one processor into the next processor
data/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # cdc-core
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/cdc-core.svg)](https://badge.fury.io/rb/cdc-core)
4
+ [![CI](https://github.com/kanutocd/cdc-core/workflows/CI/badge.svg)](https://github.com/kanutocd/cdc-core/actions)
5
+ [![Ruby Version](https://img.shields.io/badge/ruby-%3E%3D%203.4-ruby.svg)](https://www.ruby-lang.org/en/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+
9
+
3
10
  Shared Change Data Capture vocabulary for Ruby.
4
11
 
5
12
  `cdc-core` provides immutable, Ractor-safe event objects and processor contracts for building CDC systems. It intentionally does not connect to databases, parse wire protocols, decode PostgreSQL OIDs, run schedulers, or integrate with Rails.
@@ -114,11 +121,11 @@ It is the fiber-friendly runtime path.
114
121
  ## Installation
115
122
 
116
123
  ```ruby
117
- gem "cdc-core"
124
+ gem 'cdc-core'
118
125
  ```
119
126
 
120
127
  ```ruby
121
- require "cdc/core"
128
+ require 'cdc/core'
122
129
  ```
123
130
 
124
131
  ## Change Events
@@ -310,9 +317,10 @@ docs/**/*.md
310
317
 
311
318
  ```bash
312
319
  bundle exec rake
313
- bundle exec steep check
320
+ bundle exec rake rbs:validate
321
+ bundle exec yard doc
314
322
  ```
315
323
 
316
324
  ## License
317
325
 
318
- [MIT](./LICENSE.txt).
326
+ [MIT](LICENSE.txt)
@@ -9,6 +9,11 @@ module CDC
9
9
  # as operation, schema, table, before/after values, primary key, LSN, and
10
10
  # metadata.
11
11
  class ChangeEvent
12
+ EMPTY_METADATA = Ractor.make_shareable(
13
+ {} # : Hash[untyped, untyped]
14
+ .freeze
15
+ )
16
+
12
17
  # @return [Symbol] normalized CDC operation
13
18
  # @return [String] database schema name
14
19
  # @return [String] database table name
@@ -38,7 +43,7 @@ module CDC
38
43
  # @param metadata [Hash, EventMetadata] additional event metadata
39
44
  def initialize(operation:, schema:, table:, old_values: nil, new_values: nil, primary_key: nil,
40
45
  transaction_id: nil, commit_lsn: nil, sequence_number: nil, occurred_at: nil,
41
- metadata: {})
46
+ metadata: EMPTY_METADATA)
42
47
  @operation = Operation.normalize(operation)
43
48
  @schema = String(schema).freeze
44
49
  @table = String(table).freeze
@@ -64,7 +69,7 @@ module CDC
64
69
 
65
70
  # Fully qualified table name in schema.table form.
66
71
  #
67
- # @return [String]
72
+ # @return [String] fully qualified table name
68
73
  def qualified_table_name = "#{schema}.#{table}".freeze
69
74
 
70
75
  # Compute changed columns by comparing old and new values.
@@ -83,7 +88,7 @@ module CDC
83
88
 
84
89
  # Convert the event into a Ractor-shareable hash.
85
90
  #
86
- # @return [Hash{String=>Object,nil}]
91
+ # @return [Hash{String=>Object,nil}] Ractor-shareable event representation
87
92
  def to_h
88
93
  Ractor.make_shareable({
89
94
  'operation' => operation,
@@ -104,8 +109,8 @@ module CDC
104
109
 
105
110
  # Convert a hash into immutable EventMetadata storage, preserving nil.
106
111
  #
107
- # @param hash [Hash, nil]
108
- # @return [Hash, nil]
112
+ # @param hash [Hash, nil] values to normalize
113
+ # @return [Hash, nil] normalized shareable values, or nil when no values were provided
109
114
  def freeze_hash_or_nil(hash)
110
115
  return nil if hash.nil?
111
116
 
@@ -27,14 +27,14 @@ module CDC
27
27
 
28
28
  # Whether the old and new values differ.
29
29
  #
30
- # @return [Boolean]
30
+ # @return [Boolean] true when the old and new values differ
31
31
  def changed?
32
32
  old_value != new_value
33
33
  end
34
34
 
35
35
  # Convert the change into a Ractor-shareable hash.
36
36
  #
37
- # @return [Hash{String=>Object,nil}]
37
+ # @return [Hash{String=>Object,nil}] Ractor-shareable column change representation
38
38
  def to_h
39
39
  Ractor.make_shareable({ 'name' => name, 'old_value' => old_value, 'new_value' => new_value }.freeze)
40
40
  end
@@ -43,8 +43,8 @@ module CDC
43
43
 
44
44
  # Convert a value into a Ractor-shareable representation.
45
45
  #
46
- # @param value [Object, nil]
47
- # @return [Object, String, nil]
46
+ # @param value [Object, nil] value to normalize
47
+ # @return [Object, String, nil] shareable value or inspect string fallback
48
48
  def make_value_shareable(value)
49
49
  Ractor.make_shareable(value)
50
50
  rescue Ractor::Error
@@ -39,14 +39,14 @@ module CDC
39
39
 
40
40
  # Processors that declared Ractor safety.
41
41
  #
42
- # @return [Array<Processor>]
42
+ # @return [Array<Processor>] processors that declared Ractor safety
43
43
  def ractor_safe_processors
44
44
  processors.select(&:ractor_safe?).freeze
45
45
  end
46
46
 
47
47
  # Processors that should remain sequential in the core runtime.
48
48
  #
49
- # @return [Array<Processor>]
49
+ # @return [Array<Processor>] processors that should run sequentially
50
50
  def sequential_processors
51
51
  processors.reject(&:ractor_safe?).freeze
52
52
  end
@@ -57,7 +57,7 @@ module CDC
57
57
  #
58
58
  # @param result [Object] raw processor result
59
59
  # @param event [ChangeEvent] processed event
60
- # @return [ProcessorResult]
60
+ # @return [ProcessorResult] normalized processor result
61
61
  def normalize_result(result, event)
62
62
  return result if result.is_a?(ProcessorResult)
63
63
 
@@ -8,13 +8,18 @@ module CDC
8
8
  # are recursively converted into Ractor-shareable objects. Values that Ruby
9
9
  # cannot make shareable are stored as frozen #inspect strings.
10
10
  class EventMetadata
11
+ EMPTY_DATA = Ractor.make_shareable(
12
+ {} # : Hash[untyped, untyped]
13
+ .freeze
14
+ )
15
+
11
16
  # @return [Hash{String=>Object}] normalized metadata
12
17
  attr_reader :data
13
18
 
14
19
  # Build metadata from a hash-like structure.
15
20
  #
16
21
  # @param data [Hash] metadata values
17
- def initialize(data = {})
22
+ def initialize(data = EMPTY_DATA)
18
23
  @data = deep_shareable_hash(data)
19
24
  Ractor.make_shareable(self)
20
25
  end
@@ -22,7 +27,7 @@ module CDC
22
27
  # Fetch a metadata value by string or symbol key.
23
28
  #
24
29
  # @param key [String, Symbol] metadata key
25
- # @return [Object, nil]
30
+ # @return [Object, nil] metadata value for the given key
26
31
  def [](key)
27
32
  string_key = key.to_s
28
33
  return data[string_key] if data.key?(string_key)
@@ -32,7 +37,7 @@ module CDC
32
37
 
33
38
  # Return the normalized Ractor-shareable hash.
34
39
  #
35
- # @return [Hash{String=>Object}]
40
+ # @return [Hash{String=>Object}] normalized Ractor-shareable metadata
36
41
  def to_h
37
42
  data
38
43
  end
@@ -41,8 +46,8 @@ module CDC
41
46
 
42
47
  # Recursively normalize and freeze a hash.
43
48
  #
44
- # @param hash [Hash]
45
- # @return [Hash{String=>Object}]
49
+ # @param hash [Hash] metadata hash to normalize
50
+ # @return [Hash{String=>Object}] recursively normalized shareable hash
46
51
  def deep_shareable_hash(hash)
47
52
  converted = hash.each_with_object(
48
53
  {} # : Hash[String, untyped]
@@ -54,16 +59,16 @@ module CDC
54
59
 
55
60
  # Normalize metadata keys to frozen strings.
56
61
  #
57
- # @param key [Object]
58
- # @return [String]
62
+ # @param key [Object] metadata key to normalize
63
+ # @return [String] frozen string key
59
64
  def normalize_key(key)
60
65
  key.to_s.freeze
61
66
  end
62
67
 
63
68
  # Normalize a metadata value into a shareable representation.
64
69
  #
65
- # @param value [Object]
66
- # @return [Object]
70
+ # @param value [Object] metadata value to normalize
71
+ # @return [Object] Ractor-shareable value or inspect string fallback
67
72
  def normalize_value(value)
68
73
  case value
69
74
  when Hash
@@ -33,7 +33,7 @@ module CDC
33
33
 
34
34
  # Convert the position into a Ractor-shareable hash.
35
35
  #
36
- # @return [Hash{String=>Object,nil}]
36
+ # @return [Hash{String=>Object,nil}] Ractor-shareable position representation
37
37
  def to_h
38
38
  Ractor.make_shareable({
39
39
  'strategy' => strategy,
@@ -10,31 +10,31 @@ module CDC
10
10
  class Filter
11
11
  # Match every event.
12
12
  #
13
- # @return [Filter]
13
+ # @return [Filter] filter that matches every event
14
14
  def self.all = new { |_event| true }
15
15
 
16
16
  # Match events from a schema.
17
17
  #
18
18
  # @param name [#to_s] schema name
19
- # @return [Filter]
19
+ # @return [Filter] filter matching the given schema
20
20
  def self.schema(name) = new { |event| event.schema == name.to_s }
21
21
 
22
22
  # Match events from a table regardless of schema.
23
23
  #
24
24
  # @param name [#to_s] table name
25
- # @return [Filter]
25
+ # @return [Filter] filter matching the given table
26
26
  def self.table(name) = new { |event| event.table == name.to_s }
27
27
 
28
28
  # Match events from a fully qualified schema.table name.
29
29
  #
30
30
  # @param name [#to_s] qualified table name
31
- # @return [Filter]
31
+ # @return [Filter] filter matching the given qualified table name
32
32
  def self.qualified_table(name) = new { |event| event.qualified_table_name == name.to_s }
33
33
 
34
34
  # Match events by operation.
35
35
  #
36
36
  # @param operation [#to_sym] CDC operation
37
- # @return [Filter]
37
+ # @return [Filter] filter matching the given operation
38
38
  def self.operation(operation) = new { |event| event.operation == Operation.normalize(operation) }
39
39
 
40
40
  # Build a custom filter.
@@ -51,7 +51,7 @@ module CDC
51
51
  # Whether this filter matches an event.
52
52
  #
53
53
  # @param event [ChangeEvent] event to test
54
- # @return [Boolean]
54
+ # @return [Boolean] true when the predicate matches exactly
55
55
  def match?(event)
56
56
  @predicate.call(event) == true
57
57
  end
@@ -60,7 +60,7 @@ module CDC
60
60
  # Compose this filter with another filter using logical AND.
61
61
  #
62
62
  # @param other [Filter] other filter
63
- # @return [Filter]
63
+ # @return [Filter] filter that matches only when both filters match
64
64
  def &(other)
65
65
  self.class.new { |event| match?(event) && other.match?(event) }
66
66
  end
@@ -68,7 +68,7 @@ module CDC
68
68
  # Compose this filter with another filter using logical OR.
69
69
  #
70
70
  # @param other [Filter] other filter
71
- # @return [Filter]
71
+ # @return [Filter] filter that matches when either filter matches
72
72
  def |(other)
73
73
  self.class.new { |event| match?(event) || other.match?(event) }
74
74
  end
@@ -18,8 +18,8 @@ module CDC
18
18
 
19
19
  # Build a canonical metric tag set for a CDC work item or result.
20
20
  #
21
- # @param payload [ChangeEvent, TransactionEnvelope, ProcessorResult, Array]
22
- # @return [Hash{String=>Object}]
21
+ # @param payload [ChangeEvent, TransactionEnvelope, ProcessorResult, Array] payload to describe
22
+ # @return [Hash{String=>Object}] canonical metric tags for the payload
23
23
  def self.metric_tags(payload)
24
24
  tags = {} # : Hash[String, untyped]
25
25
  case payload
@@ -40,46 +40,46 @@ module CDC
40
40
 
41
41
  # Canonical metric name for the start hook.
42
42
  #
43
- # @return [String]
43
+ # @return [String] canonical dispatch-started metric name
44
44
  def self.started_metric_name = METRIC_NAMES.fetch(:dispatch_started)
45
45
 
46
46
  # Canonical metric name for the success hook.
47
47
  #
48
- # @return [String]
48
+ # @return [String] canonical dispatch-succeeded metric name
49
49
  def self.succeeded_metric_name = METRIC_NAMES.fetch(:dispatch_succeeded)
50
50
 
51
51
  # Canonical metric name for the failure hook.
52
52
  #
53
- # @return [String]
53
+ # @return [String] canonical dispatch-failed metric name
54
54
  def self.failed_metric_name = METRIC_NAMES.fetch(:dispatch_failed)
55
55
 
56
56
  # Canonical metric name for the skip hook.
57
57
  #
58
- # @return [String]
58
+ # @return [String] canonical dispatch-skipped metric name
59
59
  def self.skipped_metric_name = METRIC_NAMES.fetch(:dispatch_skipped)
60
60
 
61
61
  # Called before a work item is dispatched.
62
62
  #
63
- # @param _event [ChangeEvent, TransactionEnvelope, Array]
64
- # @return [void]
63
+ # @param _event [ChangeEvent, TransactionEnvelope, Array] work item about to be dispatched
64
+ # @return [void] no return value
65
65
  def dispatch_started(_event); end
66
66
 
67
67
  # Called after a work item is processed successfully.
68
68
  #
69
- # @param _result [ProcessorResult, Array<ProcessorResult>]
70
- # @return [void]
69
+ # @param _result [ProcessorResult, Array<ProcessorResult>] successful processor result or results
70
+ # @return [void] no return value
71
71
  def dispatch_succeeded(_result); end
72
72
 
73
73
  # Called after a work item fails.
74
74
  #
75
- # @param _result [ProcessorResult]
76
- # @return [void]
75
+ # @param _result [ProcessorResult] failed processor result
76
+ # @return [void] no return value
77
77
  def dispatch_failed(_result); end
78
78
 
79
79
  # Called when a work item is filtered or skipped.
80
80
  #
81
- # @param _result [ProcessorResult]
82
- # @return [void]
81
+ # @param _result [ProcessorResult] skipped processor result
82
+ # @return [void] no return value
83
83
  def dispatch_skipped(_result); end
84
84
 
85
85
  private_class_method def self.change_event_metric_tags(event)
@@ -102,14 +102,19 @@ module CDC
102
102
  end
103
103
 
104
104
  private_class_method def self.processor_result_metric_tags(result)
105
- {
105
+ tags = {
106
106
  'kind' => 'processor_result',
107
107
  'status' => result.status,
108
108
  'retryable' => result.retryable?
109
- }.tap do |tags|
110
- tags['processor'] = result.processor_name if result.processor_name
111
- tags['failure_reason'] = result.failure_reason if result.failure?
112
- end
109
+ } # : Hash[String, untyped]
110
+
111
+ processor_name = result.processor_name
112
+ tags['processor'] = processor_name if processor_name
113
+
114
+ failure_reason = result.failure_reason
115
+ tags['failure_reason'] = failure_reason if result.failure? && failure_reason
116
+
117
+ tags
113
118
  end
114
119
 
115
120
  private_class_method def self.batch_metric_tags(batch)
@@ -7,6 +7,11 @@ module CDC
7
7
  # OrderingKey captures the scope plus the components that define a
8
8
  # particular ordered lane. It does not choose an execution strategy.
9
9
  class OrderingKey
10
+ EMPTY_COMPONENTS = Ractor.make_shareable(
11
+ {} # : Hash[untyped, untyped]
12
+ .freeze
13
+ )
14
+
10
15
  # @return [Symbol] ordering scope
11
16
  # @return [Hash{String=>Object}] normalized key components
12
17
  attr_reader :scope, :components
@@ -15,7 +20,7 @@ module CDC
15
20
  #
16
21
  # @param scope [#to_sym] ordering scope
17
22
  # @param components [Hash] key components
18
- def initialize(scope:, components: {})
23
+ def initialize(scope:, components: EMPTY_COMPONENTS)
19
24
  @scope = OrderingScope.normalize(scope)
20
25
  @components = EventMetadata.new(components).to_h
21
26
  Ractor.make_shareable(self)
@@ -23,12 +28,12 @@ module CDC
23
28
 
24
29
  # Whether the key has no components.
25
30
  #
26
- # @return [Boolean]
31
+ # @return [Boolean] true when the key has no components
27
32
  def empty? = components.empty?
28
33
 
29
34
  # Convert the key into a Ractor-shareable hash.
30
35
  #
31
- # @return [Hash{String=>Object}]
36
+ # @return [Hash{String=>Object}] Ractor-shareable ordering key representation
32
37
  def to_h
33
38
  Ractor.make_shareable({
34
39
  'scope' => scope,
@@ -32,23 +32,26 @@ module CDC
32
32
 
33
33
  # Whether transaction boundaries should be preserved.
34
34
  #
35
- # @return [Boolean]
35
+ # @return [Boolean] true when transaction boundaries should be preserved
36
36
  def transaction_aware? = transaction_aware
37
37
 
38
38
  # Derive an ordering key for an event.
39
39
  #
40
40
  # @param event [ChangeEvent] event to classify
41
- # @return [OrderingKey, nil]
41
+ # @return [OrderingKey, nil] ordering key for the event, or nil when no key applies
42
42
  def key_for(event)
43
43
  return nil if scope == OrderingScope::NONE
44
44
 
45
- OrderingKey.new(scope: scope, components: key_components(event))
45
+ components = key_components(event)
46
+ return nil if components.nil?
47
+
48
+ OrderingKey.new(scope: scope, components: components)
46
49
  end
47
50
 
48
51
  # Derive an event position for an event.
49
52
  #
50
53
  # @param event [ChangeEvent] event to classify
51
- # @return [EventPosition]
54
+ # @return [EventPosition] position metadata for the event
52
55
  def position_for(event)
53
56
  EventPosition.new(
54
57
  strategy: position,
@@ -61,7 +64,7 @@ module CDC
61
64
 
62
65
  # Convert the policy into a Ractor-shareable hash.
63
66
  #
64
- # @return [Hash{String=>Object}]
67
+ # @return [Hash{String=>Object}] Ractor-shareable policy representation
65
68
  def to_h
66
69
  Ractor.make_shareable({
67
70
  'scope' => scope,
@@ -75,7 +78,7 @@ module CDC
75
78
  # Normalize the position strategy.
76
79
  #
77
80
  # @param position [#to_sym] position strategy
78
- # @return [Symbol]
81
+ # @return [Symbol] normalized supported position strategy
79
82
  def normalize_position(position)
80
83
  value = position.to_sym
81
84
  return value if SUPPORTED_POSITIONS.include?(value)
@@ -87,12 +90,12 @@ module CDC
87
90
 
88
91
  # Build the components for the current scope.
89
92
  #
90
- # @param event [ChangeEvent]
91
- # @return [Hash]
93
+ # @param event [ChangeEvent] event to classify
94
+ # @return [Hash, nil] key components for the current scope, or nil for an unknown internal scope
92
95
  def key_components(event)
93
96
  case scope
94
97
  when OrderingScope::GLOBAL
95
- {}
98
+ {} # : Hash[untyped, untyped]
96
99
  when OrderingScope::TRANSACTION
97
100
  { transaction_id: event.transaction_id }
98
101
  when OrderingScope::RELATION
@@ -28,7 +28,7 @@ module CDC
28
28
  # Process one event through the pipeline.
29
29
  #
30
30
  # @param event [ChangeEvent] event to process
31
- # @return [ProcessorResult]
31
+ # @return [ProcessorResult] result for the event
32
32
  def process(event)
33
33
  observer.dispatch_started(event)
34
34
  return ProcessorResult.skipped(event, metadata: { reason: 'filtered' }) unless matches?(event)
@@ -45,7 +45,7 @@ module CDC
45
45
  # Process many events in order.
46
46
  #
47
47
  # @param events [Enumerable<ChangeEvent>] events to process
48
- # @return [Array<ProcessorResult>]
48
+ # @return [Array<ProcessorResult>] results in input order
49
49
  def process_many(events)
50
50
  events.map { |event| process(event) }.freeze
51
51
  end
@@ -54,8 +54,8 @@ module CDC
54
54
 
55
55
  # Check whether every filter matches an event.
56
56
  #
57
- # @param event [ChangeEvent]
58
- # @return [Boolean]
57
+ # @param event [ChangeEvent] event to test
58
+ # @return [Boolean] true when every filter matches
59
59
  def matches?(event)
60
60
  filters.all? { |filter| filter.match?(event) }
61
61
  end
@@ -64,7 +64,7 @@ module CDC
64
64
  #
65
65
  # @param result [Object] raw processor result
66
66
  # @param event [ChangeEvent] processed event
67
- # @return [ProcessorResult]
67
+ # @return [ProcessorResult] normalized processor result
68
68
  def normalize_result(result, event)
69
69
  return result if result.is_a?(ProcessorResult)
70
70
 
@@ -10,21 +10,21 @@ module CDC
10
10
  class Processor
11
11
  # Mark this processor class as safe to execute in Ractor-aware runtimes.
12
12
  #
13
- # @return [true]
13
+ # @return [true] marker value confirming the class was marked Ractor-safe
14
14
  def self.ractor_safe!
15
15
  @ractor_safe = true
16
16
  end
17
17
 
18
18
  # Whether this processor class has declared Ractor safety.
19
19
  #
20
- # @return [Boolean]
20
+ # @return [Boolean] true when the class has declared Ractor safety
21
21
  def self.ractor_safe?
22
22
  @ractor_safe == true
23
23
  end
24
24
 
25
25
  # Whether this processor instance is Ractor-safe.
26
26
  #
27
- # @return [Boolean]
27
+ # @return [Boolean] true when the instance's class has declared Ractor safety
28
28
  def ractor_safe?
29
29
  self.class.ractor_safe?
30
30
  end
@@ -34,7 +34,7 @@ module CDC
34
34
  # Runtime layers can call this before dispatch begins. The default
35
35
  # implementation is a no-op.
36
36
  #
37
- # @return [self]
37
+ # @return [self] started processor instance
38
38
  def start
39
39
  self
40
40
  end
@@ -44,7 +44,7 @@ module CDC
44
44
  # Runtime layers can call this during shutdown. The default implementation
45
45
  # is a no-op.
46
46
  #
47
- # @return [self]
47
+ # @return [self] stopped processor instance
48
48
  def stop
49
49
  self
50
50
  end
@@ -54,7 +54,7 @@ module CDC
54
54
  # Runtime layers can call this before shutdown or checkpoints. The
55
55
  # default implementation is a no-op.
56
56
  #
57
- # @return [self]
57
+ # @return [self] flushed processor instance
58
58
  def flush
59
59
  self
60
60
  end
@@ -63,7 +63,7 @@ module CDC
63
63
  #
64
64
  # The default implementation assumes the processor is healthy.
65
65
  #
66
- # @return [Boolean]
66
+ # @return [Boolean] true when the processor can accept work
67
67
  def healthy?
68
68
  true
69
69
  end
@@ -34,7 +34,7 @@ module CDC
34
34
  # value is the final ProcessorResult produced by the chain.
35
35
  #
36
36
  # @param input [Object] initial input for the first processor
37
- # @return [ProcessorResult] final processor result or the first failed/skipped result
37
+ # @return [ProcessorResult] final processor result or the first failed or skipped result
38
38
  def process(input)
39
39
  observer.dispatch_started(input)
40
40
  current_input = input