crystal-lang / crystal-mysql

MySQL connector for Crystal
MIT License
107 stars 36 forks source link

Inconsistent return value types #67

Closed Blacksmoke16 closed 5 years ago

Blacksmoke16 commented 5 years ago

The data type of the return value seems to be dependent on the context it the value originates from. For example:

# Where value1 is `INT` column
db.scalar("select value1 from datapoints limit 1").as(Int32) # => Correct Int32

# Where value2 is `BIGINT` column
db.scalar("select value2 from datapoints limit 1").as(Int64) # => Correct Int64

db.scalar("select 100 - 75").as(Int32) # => Error, cannot cast Int64 to Int32

db.scalar("select sum(value1) from datapoints").as(Int64) # => Error, cannot cast Float64 to Int64

Shouldn't select 100 - 75 be returned as an Int32 and the last query be an Int64 in this case since the sum is greater than the max of Int32 and are all integers.

It seems it will return an Int64 on any select that involves math as an Int64. However i'm not sure this is by design or unintentional...

This makes it harder to work with aggregations, since the return type is going to be different than the Postgres shard would return.

bcardiff commented 5 years ago

The type returned of each value is determined by the database engine. At least that is true in this driver.

There is no built in conversion from the returned type to an expected type.

Something like the following might help to unify the result to an Int64 when needed. The driver could always define new custom types. Without new concepts like which types are numerics, the solution will always depend on know supported types by each driver.

value = db.sacalar(query)
value64 = 
  case value
    when Int64
      value
    when Int32
      value.to_i64
    when ...
      ... expr : Int64 ...
    else
      raise "Unsupported numeric scalar type"
    end
Blacksmoke16 commented 5 years ago

Gotcha, thanks for the tips.