pgoutput-decoder 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc6535189e67a471cc685b43e61aa084fd8e5b109cbbff682494a49a936164e6
4
- data.tar.gz: 93858268fe2519951b33561b5deec1da508f32b7d2fa00f1c364731d5c6715b7
3
+ metadata.gz: a1a32b04410b404b4eb936eac7e3cae1548830c13cdbe7a1eb5e1604fb2bdabe
4
+ data.tar.gz: b14c651c88ea56ef70b9674def89cfd774de17c1efaf9894544e6d5212061045
5
5
  SHA512:
6
- metadata.gz: 1fbac46c86f50fa10ccdb623cd301ce12b12f72bd271915d0fa567e4605f758b2961cfb466661c1e59918ef89829a8bf367d3e771bcd9d55ec31dbf3d6a2bea3
7
- data.tar.gz: 3978a4c40f0939917ca97f129130995682602cadf2254b92bee9fa1fe56608baab401112efefc756ed5dc23ce9db837c6702ca9dbb5c71e403db23a1909c5bd1
6
+ metadata.gz: aa2a36f348bab0d37668e40909acefc4b101e38a8ee990ef217848087eaaa5b3473741e33238a5fff6106e660138a946451f42ba9db25ca069ee49117cc72973
7
+ data.tar.gz: a965ef38835a5134b0ebd7f9a5eca4a54bf3786421f8365fc9110907088b797a7d2d8e86b14d2321ed37af4633df1f03ccf68b317d9209a0b43d94adc64606ee
data/CHANGELOG.md CHANGED
@@ -1,17 +1,32 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to this project will be documented in this file.
3
+ ## [Unreleased]
4
4
 
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+ ## 0.1.1 - 2026-06-17
7
6
 
8
- ## [Unreleased]
7
+ ### Fixed
9
8
 
10
- ### Added
9
+ * Curated RBS signatures shipped with the gem.
10
+ * Fixed duplicate `Pgoutput::Decoder` type declarations that caused Steep/RBS environment loading failures.
11
+ * Corrected decoder type signatures to align with actual runtime behavior.
12
+ * Improved `TypeRegistry` type annotations and value narrowing.
13
+ * Fixed Steep type-checking issues around decoder lookup, JSON decoding, UUID decoding, and numeric value decoding.
14
+ * Added missing standard library type dependencies required by Steep.
15
+ * Improved compatibility with downstream consumers using:
16
+
17
+ * `library "pgoutput-decoder"`
18
+ * `bundle exec steep check`
11
19
 
12
- - Placeholder for future development.
20
+ ### Documentation
13
21
 
14
- ---
22
+ * Refined shipped type definitions to better reflect the public API surface.
23
+
24
+ ### Internal
25
+
26
+ * No runtime behavior changes.
27
+ * No protocol decoding changes.
28
+ * No public API changes.
29
+ * This release focuses on RBS, Steep, and developer tooling correctness.
15
30
 
16
31
  ## [0.1.0] - 2026-06-01
17
32
 
@@ -32,8 +47,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
32
47
  - Added RBS signatures.
33
48
  - Added README documentation.
34
49
  - Added CI and release workflow templates.
35
-
36
- ---
37
-
38
- [Unreleased]: https://github.com/kanutocd/pgoutput-decoder/compare/v0.1.0...HEAD
39
- [0.1.0]: https://github.com/kanutocd/pgoutput-decoder/releases/tag/v0.1.0
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # pgoutput-decoder
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/pgoutput-decoder.svg)](https://badge.fury.io/rb/pgoutput-decoder)
4
+ [![CI](https://github.com/kanutocd/pgoutput-decoder/workflows/CI/badge.svg)](https://github.com/kanutocd/pgoutput-decoder/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
+
3
8
  A high-level PostgreSQL `pgoutput` logical replication value decoder for Ruby.
4
9
 
5
10
  `pgoutput-decoder` is the companion layer to [`pgoutput-parser`](https://rubygems.org/gems/pgoutput-parser). It accepts immutable protocol messages produced by `pgoutput-parser` and turns tuple payloads into application-friendly Ruby row-change events.
@@ -275,4 +280,4 @@ bundle exec steep check
275
280
 
276
281
  ## License
277
282
 
278
- MIT.
283
+ [MIT](LICENSE.txt).
@@ -19,7 +19,7 @@ module Pgoutput
19
19
  # @param tuple [Array<Pgoutput::Messages::TupleValue>]
20
20
  # @return [Hash<String, Object>]
21
21
  def build(relation, tuple)
22
- row = {}
22
+ row = {} # : Hash[String, untyped]
23
23
 
24
24
  tuple.each_with_index do |tuple_value, index|
25
25
  column = relation.columns[index]
@@ -79,7 +79,7 @@ module Pgoutput
79
79
  VARCHAR => ->(raw, _format) { raw.dup.freeze },
80
80
  FLOAT4 => ->(raw, format) { decode_float(raw, format, 4, "g") },
81
81
  FLOAT8 => ->(raw, format) { decode_float(raw, format, 8, "G") },
82
- NUMERIC => ->(raw, format) { format == :text ? BigDecimal(raw) : raw.dup.freeze },
82
+ NUMERIC => ->(raw, format) { format == :text ? Kernel.BigDecimal(raw) : raw.dup.freeze },
83
83
  JSON => ->(raw, format) { format == :text ? ::JSON.parse(raw) : raw.dup.freeze },
84
84
  JSONB => ->(raw, format) { decode_jsonb(raw, format) },
85
85
  UUID => ->(raw, format) { format == :text ? raw.dup.freeze : decode_uuid_binary(raw) },
@@ -107,7 +107,7 @@ module Pgoutput
107
107
  def decode(oid, raw, format)
108
108
  return nil if raw.nil?
109
109
 
110
- decoder = @decoders[oid]
110
+ decoder = oid ? @decoders[oid] : nil
111
111
  decoded = decoder ? decoder.call(raw, format) : raw.dup.freeze
112
112
  Ractor.make_shareable(decoded)
113
113
  end
@@ -139,14 +139,14 @@ module Pgoutput
139
139
  return raw.to_i if format == :text
140
140
  return raw.dup.freeze unless raw.bytesize == expected_length
141
141
 
142
- raw.unpack1(template)
142
+ Integer(raw.unpack1(template))
143
143
  end
144
144
 
145
145
  def decode_float(raw, format, expected_length, template)
146
146
  return Float(raw) if format == :text
147
147
  return raw.dup.freeze unless raw.bytesize == expected_length
148
148
 
149
- raw.unpack1(template)
149
+ Float(raw.unpack1(template))
150
150
  end
151
151
 
152
152
  def decode_jsonb(raw, format)
@@ -156,13 +156,13 @@ module Pgoutput
156
156
  # current on-wire format; the remaining bytes contain JSON text.
157
157
  return raw.dup.freeze unless raw.bytesize >= 2 && raw.getbyte(0) == 1
158
158
 
159
- ::JSON.parse(raw.byteslice(1..))
159
+ ::JSON.parse(raw.byteslice(1..).to_s)
160
160
  end
161
161
 
162
162
  def decode_uuid_binary(raw)
163
163
  return raw.dup.freeze unless raw.bytesize == 16
164
164
 
165
- hex = raw.unpack1("H*")
165
+ hex = raw.unpack1("H*").to_s
166
166
  "#{hex[0, 8]}-#{hex[8, 4]}-#{hex[12, 4]}-#{hex[16, 4]}-#{hex[20, 12]}".freeze
167
167
  end
168
168
  end
@@ -3,6 +3,6 @@
3
3
  module Pgoutput
4
4
  class Decoder
5
5
  # Gem version.
6
- VERSION = "0.1.0"
6
+ VERSION = "0.1.1"
7
7
  end
8
8
  end
@@ -2,6 +2,9 @@ module Pgoutput
2
2
  class Decoder
3
3
  VERSION: String
4
4
 
5
+ type parser_message = untyped
6
+ type relation = untyped
7
+ type tuple = Array[untyped]
5
8
  type event =
6
9
  Events::Begin |
7
10
  Events::Commit |
@@ -9,10 +12,31 @@ module Pgoutput
9
12
  Events::Update |
10
13
  Events::Delete
11
14
 
15
+ @type_registry: TypeRegistry
16
+ @relations: RelationCache
17
+ @row_builder: RowBuilder
18
+ @current_transaction_id: Integer?
19
+ @current_final_lsn: Integer?
20
+ @current_commit_timestamp: Integer?
21
+
12
22
  def initialize: (?type_registry: TypeRegistry) -> void
13
- def decode: (untyped message) -> event?
23
+ def decode: (parser_message message) -> event?
14
24
  def type_registry: () -> TypeRegistry
15
25
 
26
+ private
27
+
28
+ def decode_begin: (parser_message message) -> Events::Begin
29
+ def decode_commit: (parser_message message) -> Events::Commit
30
+ def decode_insert: (parser_message message) -> Events::Insert
31
+ def decode_update: (parser_message message) -> Events::Update
32
+ def decode_delete: (parser_message message) -> Events::Delete
33
+ def optional_row: (relation relation, tuple? tuple) -> Hash[String, untyped]?
34
+ def relation_for: (Integer relation_id) -> relation
35
+ def require_transaction_id: () -> Integer
36
+ def clear_transaction!: () -> nil
37
+ def parser_messages: () -> untyped
38
+ def share: [T] (T object) -> T
39
+
16
40
  class Error < StandardError
17
41
  end
18
42
 
@@ -93,27 +117,49 @@ module Pgoutput
93
117
  UUID: Integer
94
118
  JSONB: Integer
95
119
 
120
+ type decoder = ^(String raw, Symbol format) -> untyped
121
+
122
+ @decoders: Hash[Integer, decoder]
123
+
96
124
  def self.default: () -> TypeRegistry
97
- def self.default_decoders: () -> Hash[Integer, Proc]
98
- def initialize: (?Hash[Integer, Proc] decoders) -> void
125
+ def self.default_decoders: () -> Hash[Integer, decoder]
126
+ def initialize: (?Hash[Integer, decoder] decoders) -> void
99
127
  def decode: (Integer? oid, String? raw, Symbol format) -> untyped?
100
128
  def with_decoder: (Integer oid) { (String raw, Symbol format) -> untyped } -> TypeRegistry
129
+
130
+ private
131
+
132
+ def self.decode_bool: (String raw, Symbol format) -> bool
133
+ def self.decode_int: (String raw, Symbol format, Integer expected_length, String template) -> (Integer | String)
134
+ def self.decode_float: (String raw, Symbol format, Integer expected_length, String template) -> (Float | String)
135
+ def self.decode_jsonb: (String raw, Symbol format) -> untyped
136
+ def self.decode_uuid_binary: (String raw) -> String
101
137
  end
102
138
 
103
139
  class ValueDecoder
140
+ @type_registry: TypeRegistry
141
+
104
142
  def initialize: (?type_registry: TypeRegistry) -> void
105
143
  def decode: (untyped tuple_value) -> untyped?
106
144
  end
107
145
 
108
146
  class RelationCache
147
+ @relations: Hash[Integer, relation]
148
+
109
149
  def initialize: () -> void
110
- def store: (untyped relation) -> untyped
111
- def fetch: (Integer relation_id) -> untyped
150
+ def store: (relation relation) -> relation
151
+ def fetch: (Integer relation_id) -> relation
112
152
  end
113
153
 
114
154
  class RowBuilder
155
+ @value_decoder: ValueDecoder
156
+
115
157
  def initialize: (?type_registry: TypeRegistry) -> void
116
- def build: (untyped relation, Array[untyped] tuple) -> Hash[String, untyped]
158
+ def build: (relation relation, tuple tuple) -> Hash[String, untyped]
159
+
160
+ private
161
+
162
+ def normalize_oid: (untyped tuple_value, Integer oid) -> untyped
117
163
  end
118
164
  end
119
165
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgoutput-decoder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken C. Demanawa
@@ -10,117 +10,33 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: pgoutput-parser
13
+ name: bigdecimal
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '0.1'
18
+ version: '4.1'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '0.1'
26
- - !ruby/object:Gem::Dependency
27
- name: minitest
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - "~>"
31
- - !ruby/object:Gem::Version
32
- version: '5.27'
33
- type: :development
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '5.27'
40
- - !ruby/object:Gem::Dependency
41
- name: pry
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: 0.16.0
47
- type: :development
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: 0.16.0
25
+ version: '4.1'
54
26
  - !ruby/object:Gem::Dependency
55
- name: rake
56
- requirement: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '13.4'
61
- type: :development
62
- prerelease: false
63
- version_requirements: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '13.4'
68
- - !ruby/object:Gem::Dependency
69
- name: rubocop
70
- requirement: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: '1.87'
75
- type: :development
76
- prerelease: false
77
- version_requirements: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: '1.87'
82
- - !ruby/object:Gem::Dependency
83
- name: simplecov
84
- requirement: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - "~>"
87
- - !ruby/object:Gem::Version
88
- version: 0.22.0
89
- type: :development
90
- prerelease: false
91
- version_requirements: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: 0.22.0
96
- - !ruby/object:Gem::Dependency
97
- name: steep
98
- requirement: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '1.10'
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
108
- - !ruby/object:Gem::Version
109
- version: '1.10'
110
- - !ruby/object:Gem::Dependency
111
- name: yard
27
+ name: pgoutput-parser
112
28
  requirement: !ruby/object:Gem::Requirement
113
29
  requirements:
114
30
  - - "~>"
115
31
  - !ruby/object:Gem::Version
116
- version: 0.9.44
117
- type: :development
32
+ version: '0.1'
33
+ type: :runtime
118
34
  prerelease: false
119
35
  version_requirements: !ruby/object:Gem::Requirement
120
36
  requirements:
121
37
  - - "~>"
122
38
  - !ruby/object:Gem::Version
123
- version: 0.9.44
39
+ version: '0.1'
124
40
  description: Decodes pgoutput-parser protocol messages into immutable Ruby row-change
125
41
  events.
126
42
  email:
@@ -141,7 +57,6 @@ files:
141
57
  - lib/pgoutput/decoder/value_decoder.rb
142
58
  - lib/pgoutput/decoder/version.rb
143
59
  - lib/pgoutput_decoder.rb
144
- - sig/pgoutput/decoder.rbs
145
60
  - sig/pgoutput_decoder.rbs
146
61
  homepage: https://github.com/kanutocd/pgoutput-decoder
147
62
  licenses:
@@ -1,6 +0,0 @@
1
- module Pgoutput
2
- module Decoder
3
- VERSION: String
4
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
- end
6
- end