Skip to content

Commit

Permalink
feat: support int4range type
Browse files Browse the repository at this point in the history
This is an exploratory effort to support will#164

It is not ready for merging, but I wanted to to open it for discussion
and review.

Signed-off-by: Mike Fiedler <miketheman@gmail.com>
  • Loading branch information
miketheman committed Oct 9, 2019
1 parent 650b16f commit 46eacd0
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
10 changes: 10 additions & 0 deletions spec/pg/decoders/range_decoder_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "../../spec_helper"

describe PG::Decoders do
describe "int4range" do
test_decode "exclusive", "'[10,20)'::int4range", Range.new(10, 20)
test_decode "exclusive", "'(10,20]'::int4range", Range.new(11, 21)
test_decode "inclusive", "'[10,20]'::int4range", Range.new(10, 21)
test_decode "inclusive", "'[10,20)'::int4range", Range.new(10, 20)
end
end
39 changes: 39 additions & 0 deletions src/pg/decoder.cr
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,44 @@ module PG
end
end

struct RangeDecoder
include Decoder

def_oids [
3904, # int4range
]

def decode(io, bytesize, oid)
# General format is here: https://git.io/JeWQX
# Specifics for the binary representation are here: https://git.io/JeWQ1

flags = io.read_byte # first byte is flags. TODO: what do they do?

# TODO: How to use the *_bound_len to inform `read_*` to support int8range
lower_bound_len = read_i32(io) # => 4 or 8
lower_bound = read_i32(io)
upper_bound_len = read_i32(io) # => 4 or 8
upper_bound = read_i32(io)

# some debug cruft here. TODO: remove before merge
# puts "flags: #{flags.to_s}"
# puts "lbound len: #{lower_bound_len}"
# puts "lbound: #{lower_bound}"
# puts "ubound len: #{upper_bound_len}"
# puts "ubound: #{upper_bound}"

# TODO: add `exclusive` flag? Do we need to, or since the decoder
# is already receiving a discrete range type, maybe we don't?
# Ref https://www.postgresql.org/docs/10/rangetypes.html#RANGETYPES-DISCRETE
Range.new(lower_bound, upper_bound)
end

def type
# TODO: do I actually need a new PG-specific type, or can we use real Crystal Ranges?
Range
end
end

@@decoders = Hash(Int32, PG::Decoders::Decoder).new(ByteaDecoder.new)

def self.from_oid(oid)
Expand All @@ -497,6 +535,7 @@ module PG
register_decoder Float64Decoder.new
register_decoder TimeDecoder.new
register_decoder NumericDecoder.new
register_decoder RangeDecoder.new
register_decoder PointDecoder.new
register_decoder LineSegmentDecoder.new
register_decoder PathDecoder.new
Expand Down

0 comments on commit 46eacd0

Please sign in to comment.