Class: Pgoutput::Decoder::TypeRegistry

Inherits:
Object
  • Object
show all
Defined in:
lib/pgoutput/decoder/type_registry.rb

Overview

Immutable PostgreSQL OID-to-decoder registry.

The registry maps PostgreSQL type OIDs to callable decoders. It is intentionally separate from pgoutput-parser so the parser remains a pure protocol layer and the decoder owns value conversion policy.

Registry instances are immutable after construction. Decoded values are passed through Ractor.make_shareable so caller-visible values can cross Ractor boundaries safely when Ruby supports the value shape.

Constant Summary collapse

BOOL =

PostgreSQL bool OID.

16
INT8 =

PostgreSQL int8 / bigint OID.

20
INT2 =

PostgreSQL int2 / smallint OID.

21
INT4 =

PostgreSQL int4 / integer OID.

23
TEXT =

PostgreSQL text OID.

25
JSON =

PostgreSQL json OID.

114
FLOAT4 =

PostgreSQL float4 / real OID.

700
FLOAT8 =

PostgreSQL float8 / double precision OID.

701
VARCHAR =

PostgreSQL varchar OID.

1043
DATE =

PostgreSQL date OID.

1082
TIMESTAMP =

PostgreSQL timestamp without time zone OID.

1114
TIMESTAMPTZ =

PostgreSQL timestamp with time zone OID.

1184
NUMERIC =

PostgreSQL numeric OID.

1700
UUID =

PostgreSQL uuid OID.

2950
JSONB =

PostgreSQL jsonb OID.

3802

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(decoders = self.class.default_decoders) ⇒ void

Create an immutable registry.

Parameters:

  • decoders (Hash<Integer, Proc>) (defaults to: self.class.default_decoders)

    decoder table.



96
97
98
99
# File 'lib/pgoutput/decoder/type_registry.rb', line 96

def initialize(decoders = self.class.default_decoders)
  @decoders = decoders.dup.freeze
  freeze
end

Class Method Details

.defaultTypeRegistry

Return the process-local default immutable registry.

Returns:



65
66
67
# File 'lib/pgoutput/decoder/type_registry.rb', line 65

def self.default
  @default ||= new(default_decoders)
end

.default_decodersHash<Integer, Proc>

Build the default OID decoder table.

Returns:

  • (Hash<Integer, Proc>)

    default decoder table.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/pgoutput/decoder/type_registry.rb', line 72

def self.default_decoders
  {
    BOOL => ->(raw, format) { decode_bool(raw, format) },
    INT2 => ->(raw, format) { decode_int(raw, format, 2, "s>") },
    INT4 => ->(raw, format) { decode_int(raw, format, 4, "l>") },
    INT8 => ->(raw, format) { decode_int(raw, format, 8, "q>") },
    TEXT => ->(raw, _format) { raw.dup.freeze },
    VARCHAR => ->(raw, _format) { raw.dup.freeze },
    FLOAT4 => ->(raw, format) { decode_float(raw, format, 4, "g") },
    FLOAT8 => ->(raw, format) { decode_float(raw, format, 8, "G") },
    NUMERIC => ->(raw, format) { format == :text ? BigDecimal(raw) : raw.dup.freeze },
    JSON => ->(raw, format) { format == :text ? ::JSON.parse(raw) : raw.dup.freeze },
    JSONB => ->(raw, format) { decode_jsonb(raw, format) },
    UUID => ->(raw, format) { format == :text ? raw.dup.freeze : decode_uuid_binary(raw) },
    DATE => ->(raw, format) { format == :text ? Date.iso8601(raw) : raw.dup.freeze },
    TIMESTAMP => ->(raw, format) { format == :text ? Time.parse(raw) : raw.dup.freeze },
    TIMESTAMPTZ => ->(raw, format) { format == :text ? Time.parse(raw) : raw.dup.freeze }
  }.freeze
end

Instance Method Details

#decode(oid, raw, format) ⇒ Object?

Decode a raw tuple payload.

Parameters:

  • oid (Integer, nil)

    PostgreSQL type OID.

  • raw (String, nil)

    raw payload.

  • format (Symbol)

    tuple value format.

Returns:

  • (Object, nil)


107
108
109
110
111
112
113
# File 'lib/pgoutput/decoder/type_registry.rb', line 107

def decode(oid, raw, format)
  return nil if raw.nil?

  decoder = @decoders[oid]
  decoded = decoder ? decoder.call(raw, format) : raw.dup.freeze
  Ractor.make_shareable(decoded)
end

#with_decoder(oid) {|raw, format| ... } ⇒ TypeRegistry

Create a new registry with one custom decoder.

Parameters:

  • oid (Integer)

    PostgreSQL type OID.

Yield Parameters:

  • raw (String)

    raw payload.

  • format (Symbol)

    tuple value format.

Yield Returns:

  • (Object)

Returns:

Raises:

  • (ArgumentError)

    if no block is provided.



123
124
125
126
127
# File 'lib/pgoutput/decoder/type_registry.rb', line 123

def with_decoder(oid, &block)
  raise ArgumentError, "block required" unless block

  self.class.new(@decoders.merge(Integer(oid) => block))
end