Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make "bigdecimal" an optional dependency #556

Merged
merged 1 commit into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ group :development, :test do
gem "rake-compiler-dock", "~> 1.0"
gem "rdoc", "~> 6.4"
gem "rspec", "~> 3.5"
# "bigdecimal" is a gem on ruby-3.4+ and it's optional for ruby-pg.
# Specs should succeed without it, but 4 examples are then excluded.
# gem "bigdecimal", "~> 3.0"
end
12 changes: 8 additions & 4 deletions lib/pg/basic_type_map_for_queries.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,22 +166,27 @@ def get_array_type(value)
@textarray_encoder
end

begin
require "bigdecimal"
has_bigdecimal = true
rescue LoadError
end

DEFAULT_TYPE_MAP = PG.make_shareable({
TrueClass => [1, 'bool', 'bool'],
FalseClass => [1, 'bool', 'bool'],
# We use text format and no type OID for numbers, because setting the OID can lead
# to unnecessary type conversions on server side.
Integer => [0, 'int8'],
Float => [0, 'float8'],
BigDecimal => [0, 'numeric'],
Time => [0, 'timestamptz'],
# We use text format and no type OID for IPAddr, because setting the OID can lead
# to unnecessary inet/cidr conversions on the server side.
IPAddr => [0, 'inet'],
Hash => [0, 'json'],
Array => :get_array_type,
BinaryData => [1, 'bytea'],
})
}.merge(has_bigdecimal ? {BigDecimal => [0, 'numeric']} : {}))
private_constant :DEFAULT_TYPE_MAP

DEFAULT_ARRAY_TYPE_MAP = PG.make_shareable({
Expand All @@ -190,9 +195,8 @@ def get_array_type(value)
Integer => [0, '_int8'],
String => [0, '_text'],
Float => [0, '_float8'],
BigDecimal => [0, '_numeric'],
Time => [0, '_timestamptz'],
IPAddr => [0, '_inet'],
})
}.merge(has_bigdecimal ? {BigDecimal => [0, '_numeric']} : {}))
private_constant :DEFAULT_ARRAY_TYPE_MAP
end
6 changes: 5 additions & 1 deletion lib/pg/basic_type_registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,11 @@ def register_default_types
alias_type 0, 'int8', 'int2'
alias_type 0, 'oid', 'int2'

register_type 0, 'numeric', PG::TextEncoder::Numeric, PG::TextDecoder::Numeric
begin
require "bigdecimal"
register_type 0, 'numeric', PG::TextEncoder::Numeric, PG::TextDecoder::Numeric
rescue LoadError
end
register_type 0, 'text', PG::TextEncoder::String, PG::TextDecoder::String
alias_type 0, 'varchar', 'text'
alias_type 0, 'char', 'text'
Expand Down
5 changes: 5 additions & 0 deletions spec/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,11 @@ def with_env_vars(**kwargs)
config.filter_run_excluding( :scheduler_address_resolve ) if RUBY_VERSION < "3.1"
config.filter_run_excluding( :ipv6 ) if Addrinfo.getaddrinfo("localhost", nil, nil, :STREAM).size < 2
config.filter_run_excluding( :ractor ) unless defined?(Ractor)
begin
require "bigdecimal"
rescue LoadError
config.filter_run_excluding( :bigdecimal )
end

### Automatically set up and tear down the database
config.before(:suite) do |*args|
Expand Down
23 changes: 17 additions & 6 deletions spec/pg/basic_type_map_for_queries_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
args = []
pr = proc { |*a| args << a }
PG::BasicTypeMapForQueries.new(@conn, registry: regi, if_undefined: pr)
expect( args.last ).to eq( ['bytea', 1] )
expect( args.first ).to eq( ["bool", 1] )
end

it "raises UndefinedEncoder for undefined types" do
Expand Down Expand Up @@ -113,12 +113,11 @@

it "should do default array-as-array param encoding" do
expect( basic_type_mapping.encode_array_as).to eq(:array)
res = @conn.exec_params( "SELECT $1,$2,$3,$4,$5,$6", [
res = @conn.exec_params( "SELECT $1,$2,$3,$4,$5", [
[1, 2, 3], # Integer -> bigint[]
[[1, 2], [3, nil]], # Integer two dimensions -> bigint[]
[1.11, 2.21], # Float -> double precision[]
['/,"'.gsub("/", "\\"), nil, 'abcäöü'], # String -> text[]
[BigDecimal("123.45")], # BigDecimal -> numeric[]
[IPAddr.new('1234::5678')], # IPAddr -> inet[]
], nil, basic_type_mapping )

Expand All @@ -127,11 +126,23 @@
'{{1,2},{3,NULL}}',
'{1.11,2.21}',
'{"//,/"",NULL,abcäöü}'.gsub("/", "\\"),
'{123.45}',
'{1234::5678}',
]] )

expect( result_typenames(res) ).to eq( ['bigint[]', 'bigint[]', 'double precision[]', 'text[]', 'numeric[]', 'inet[]'] )
expect( result_typenames(res) ).to eq( ['bigint[]', 'bigint[]', 'double precision[]', 'text[]', 'inet[]'] )
end

it "should do bigdecimal array-as-array param encoding", :bigdecimal do
expect( basic_type_mapping.encode_array_as).to eq(:array)
res = @conn.exec_params( "SELECT $1", [
[BigDecimal("123.45")], # BigDecimal -> numeric[]
], nil, basic_type_mapping )

expect( res.values ).to eq( [[
'{123.45}',
]] )

expect( result_typenames(res) ).to eq( ['numeric[]'] )
end

it "should do default array-as-array param encoding with Time objects" do
Expand Down Expand Up @@ -205,7 +216,7 @@
end
end

it "should do bigdecimal param encoding" do
it "should do bigdecimal param encoding", :bigdecimal do
large = ('123456790'*10) << '.' << ('012345679')
res = @conn.exec_params( "SELECT $1::numeric,$2::numeric",
[BigDecimal('1'), BigDecimal(large)], nil, basic_type_mapping )
Expand Down
2 changes: 1 addition & 1 deletion spec/pg/basic_type_map_for_results_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@
end
end

it "should do numeric type conversions" do
it "should do numeric type conversions", :bigdecimal do
[0].each do |format|
small = '123456790123.12'
large = ('123456790'*10) << '.' << ('012345679')
Expand Down
9 changes: 7 additions & 2 deletions spec/pg/type_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
let!(:textdec_boolean) { PG::TextDecoder::Boolean.new }
let!(:textenc_float) { PG::TextEncoder::Float.new }
let!(:textdec_float) { PG::TextDecoder::Float.new }
let!(:textenc_numeric) { PG::TextEncoder::Numeric.new }
let!(:textenc_numeric) do
begin
PG::TextEncoder::Numeric.new
rescue LoadError
end
end
let!(:textenc_string) { PG::TextEncoder::String.new }
let!(:textdec_string) { PG::TextDecoder::String.new }
let!(:textenc_timestamp) { PG::TextEncoder::TimestampWithoutTimeZone.new }
Expand Down Expand Up @@ -366,7 +371,7 @@ def textdec_timestamptz_decode_should_fail(str)
expect( textenc_float.encode(-Float::NAN) ).to eq( Float::NAN.to_s )
end

it "should encode various inputs to numeric format" do
it "should encode various inputs to numeric format", :bigdecimal do
expect( textenc_numeric.encode(0) ).to eq( "0" )
expect( textenc_numeric.encode(1) ).to eq( "1" )
expect( textenc_numeric.encode(-12345678901234567890123) ).to eq( "-12345678901234567890123" )
Expand Down
Loading