Type casting support is missing
It would be nice to have native ranges with support for infinity with a minimum efforts.
>> rng = ActiveRecord::Base.connection.select_one("select tstzrange('2019-01-01', 'Infinity', '[)')")['tstzrange']
=> "[\"2019-01-01 00:00:00+00\",infinity)"
>> rng.class
=> String
>> rng = ActiveRecord::Base.connection.select_all("select tstzrange('2019-01-01', 'Infinity', '[)')")
=> #<ActiveRecord::Result:0x0000000012ffde00 @columns=["tstzrange"], @rows=[["[\"2019-01-01 00:00:00+00\",infinity)"]], @hash_rows=nil, @column_types={"tstzrange"=>#<ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Range:0x0000000013936850 @subtype=#<ActiveRecord::ConnectionAdapters::PostgreSQL::OID::DateTime:0x00000000139368a0 @precision=nil, @scale=nil, @limit=nil>, @type=:tstzrange>}>
>> rng.column_types['tstzrange'].cast rng.first['tstzrange']
=> 2019-01-01 00:00:00 UTC...#<Date::Infinity:0x0000000010e19f00 @d=1>
Something along these lines could be worked into a concern or something
module ActiveRecordResultCast
extend ActiveSupport::Concern
def cast
if Rails::VERSION::MAJOR >= 5
self.map{|o| o.each{|k, v| o[k] = column_types[k].cast v}}
else
...
end
end
end
ActiveRecord::Result.send(:include, ActiveRecordResultCast)
Then
>> rng.cast
=> [{"tstzrange"=>2019-01-01 00:00:00 UTC...#<Date::Infinity:0x000000000b314600 @d=1>}]
>> rng.cast.first['tstzrange']
=> 2019-01-01 00:00:00 UTC...#<Date::Infinity:0x000000000b314600 @d=1>
I don't know whether there is a way to make it work with like select_one
without explicit #cast
call. Would be nice though…
Edit
I also have
module DatetimeInfinity
extend ActiveSupport::Concern
def infinity(options = {})
options[:negative] ? -::DateTime::Infinity.new : ::DateTime::Infinity.new
end
end
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::DateTime.send(:include, DatetimeInfinity)
Otherwise you end up with
>> rng.cast.first['tstzrange'].last.class
=> Float