Skip to content

Instantly share code, notes, and snippets.

@vollnhals
Last active July 13, 2020 13:44
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vollnhals/a7d2ce1c077ae2289056afdf7bba094a to your computer and use it in GitHub Desktop.
Save vollnhals/a7d2ce1c077ae2289056afdf7bba094a to your computer and use it in GitHub Desktop.
Implementation of interval database type in Rails 5.1
# implementation from https://github.com/rails/rails/pull/16919
# activerecord/lib/active_record/connection_adapters/postgresql/oid/interval.rb
require "active_support/duration"
module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class Interval < Type::Value # :nodoc:
def type
:interval
end
def cast_value(value)
case value
when ::ActiveSupport::Duration
value
when ::String
begin
::ActiveSupport::Duration.parse(value)
rescue ::ActiveSupport::Duration::ISO8601Parser::ParsingError
nil
end
else
super
end
end
def serialize(value)
case value
when ::ActiveSupport::Duration
value.iso8601(precision: self.precision)
when ::Numeric
# Sometimes operations on Times returns just float number of seconds so we need to handle that.
# Example: Time.current - (Time.current + 1.hour) # => -3600.000001776 (Float)
value.seconds.iso8601(precision: self.precision)
else
super
end
end
end
end
end
end
end
# activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb
module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module SchemaDefinitions
def interval(name, options = {})
column(name, :interval, options)
end
end
end
end
end
# activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
require 'active_record/connection_adapters/postgresql/schema_statements'
module SchemaStatementsWithInterval
def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **)
case type.to_s
when 'interval'
case precision
when nil; "interval"
when 0..6; "interval(#{precision})"
else raise(ActiveRecordError, "No interval type has precision of #{precision}. The allowed range of precision is from 0 to 6")
end
else
super
end
end
end
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements.send(:prepend, SchemaStatementsWithInterval)
# activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
require 'active_record/connection_adapters/postgresql_adapter'
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:interval] = { name: 'interval'}
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
alias_method :initialize_type_map_without_interval, :initialize_type_map
define_method :initialize_type_map do |m|
initialize_type_map_without_interval(m)
m.register_type 'interval' do |_, _, sql_type|
precision = extract_precision(sql_type)
::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Interval.new(precision: precision)
end
end
alias_method :configure_connection_without_interval, :configure_connection
define_method :configure_connection do
configure_connection_without_interval
execute('SET intervalstyle = iso_8601', 'SCHEMA')
end
ActiveRecord::Type.register(:interval, ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Interval, adapter: :postgresql)
end
@aronwolf90
Copy link

Hm, I could create a gem for this, until it is merget. Would this be ok for you?

@mlt
Copy link

mlt commented Sep 19, 2018

👍

@guilhermegazzinelli
Copy link

Hm, I could create a gem for this, until it is merget. Would this be ok for you?

Hi @aron, this gem was created? I'm intrested in such behavior.

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment