Unable to return BigDecimal in resultsets

Hello all,

Can someone please help me understand why trying to return a BigDecimal in the named tuple resultset seems to fail (with can’t infer block type error) but returning a nilable BigDecimal works just fine? Please see the example code and the error message below:

require "db"
require "pg"
require "big"
require "big/number"
require "big/json"

db = DB.open("postgres://foo:bar@localhost:5432/quux")
db.query_one "select 1::numeric as n", as: {n: BigDecimal} #fails to compile with BigDecimal
db.query_one "select 1::numeric as n", as: {n: BigDecimal?} #compiles ok with BigDecimal?

and the error message:

In src/main.cr:878:4

 878 | db.query_one "select 1::numeric as n", as: {n: BigDecimal}
          ^--------
Error: instantiating 'DB::Database#query_one(String, as: NamedTuple(n: BigDecimal.class))'


In lib/db/src/db/query_methods.cr:112:7

 112 | query_one(query, *args_, args: args) do |rs|
       ^--------
Error: can't infer block return type, try to cast the block body with `as`. See: https://crystal-lang.org/reference/syntax_and_semantics/as.html#usage-for-when-the-compiler-cant-infer-the-type-of-a-block

Thanks!

Two things:

  • Make sure you’re using the master branch for the pg shard since this PR has not yet had a tagged release
    • It will compile without that PR but you’ll get a In PG::ResultSet#read the column n returned a PG::Numeric but a (BigDecimal | Nil) was expected. (DB::ColumnTypeMismatchError) exception at runtime
  • Make sure you load the pg/pg_ext/big_decimal extension
require "db"
require "pg"
require "big"
require "big/number"
require "big/json"
require "pg/pg_ext/big_decimal"

db = DB.open("postgres:///")
pp db.query_one "select 1::numeric as n", as: {n: BigDecimal}
# {n: 1.0}
pp db.query_one "select 1::numeric as n", as: {n: BigDecimal?}
# {n: 1.0}
1 Like

@jgaskins Awesome, that worked, thank you!

To anyone wondering how to modify your shard.yml to point to a branch (in this case master):

dependencies:
  pg:
    github: will/crystal-pg
    branch: master

Might be a bit safer to pin to a specific commit than master itself.

dependencies:
  pg:
    github: will/crystal-pg
    commit: cafe112f2847f366262460ee999e74f9c7e8b31c

Then if there’s ever a breaking change or something you wouldn’t have to worry about it inadvertently making its way into your project when doing a shards update.

2 Likes