Move non-type objects into the Type::Helpers namespace

The type code is actually quite accessible, and I'm planning to
encourage people to look at the files in the `type` folder to learn more
about how it works. This will help reduce the noise from code that is
less about type casting, and more about random AR nonsense.
This commit is contained in:
Sean Griffin 2015-02-07 14:34:46 -07:00
parent 7e93e33c19
commit c4ef73affd
19 changed files with 110 additions and 104 deletions

@ -3,7 +3,7 @@ module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class Array < Type::Value # :nodoc:
include Type::Mutable
include Type::Helpers::Mutable
# Loads pg_array_parser if available. String parsing can be
# performed quicker by a native extension, which will not create

@ -3,7 +3,7 @@ module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class Hstore < Type::Value # :nodoc:
include Type::Mutable
include Type::Helpers::Mutable
def type
:hstore

@ -3,7 +3,7 @@ module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class Json < Type::Value # :nodoc:
include Type::Mutable
include Type::Helpers::Mutable
def type
:json

@ -3,7 +3,7 @@ module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class Point < Type::Value # :nodoc:
include Type::Mutable
include Type::Helpers::Mutable
def type
:point

@ -1,7 +1,4 @@
require 'active_record/type/helpers'
require 'active_record/type/mutable'
require 'active_record/type/numeric'
require 'active_record/type/time_value'
require 'active_record/type/value'
require 'active_record/type/big_integer'

@ -1,7 +1,7 @@
module ActiveRecord
module Type
class DateTime < Value # :nodoc:
include TimeValue
include Helpers::TimeValue
include Helpers::AcceptsMultiparameterTime.new(
defaults: { 4 => 0, 5 => 0 }
)

@ -1,7 +1,7 @@
module ActiveRecord
module Type
class Decimal < Value # :nodoc:
include Numeric
include Helpers::Numeric
def type
:decimal

@ -1,7 +1,7 @@
module ActiveRecord
module Type
class Float < Value # :nodoc:
include Numeric
include Helpers::Numeric
def type
:float

@ -1 +1,4 @@
require 'active_record/type/helpers/accepts_multiparameter_time'
require 'active_record/type/helpers/numeric'
require 'active_record/type/helpers/mutable'
require 'active_record/type/helpers/time_value'

@ -1,7 +1,7 @@
module ActiveRecord
module Type
module Helpers
class AcceptsMultiparameterTime < Module
class AcceptsMultiparameterTime < Module # :nodoc:
def initialize(defaults: {})
define_method(:type_cast_from_user) do |value|
if value.is_a?(Hash)

@ -0,0 +1,18 @@
module ActiveRecord
module Type
module Helpers
module Mutable # :nodoc:
def type_cast_from_user(value)
type_cast_from_database(type_cast_for_database(value))
end
# +raw_old_value+ will be the `_before_type_cast` version of the
# value (likely a string). +new_value+ will be the current, type
# cast value.
def changed_in_place?(raw_old_value, new_value)
raw_old_value != type_cast_for_database(new_value)
end
end
end
end
end

@ -0,0 +1,38 @@
module ActiveRecord
module Type
module Helpers
module Numeric # :nodoc:
def number?
true
end
def type_cast(value)
value = case value
when true then 1
when false then 0
when ::String then value.presence
else value
end
super(value)
end
def changed?(old_value, _new_value, new_value_before_type_cast) # :nodoc:
super || number_to_non_number?(old_value, new_value_before_type_cast)
end
private
def number_to_non_number?(old_value, new_value_before_type_cast)
old_value != nil && non_numeric_string?(new_value_before_type_cast)
end
def non_numeric_string?(value)
# 'wibble'.to_i will give zero, we want to make sure
# that we aren't marking int zero to string zero as
# changed.
value.to_s !~ /\A-?\d+\.?\d*\z/
end
end
end
end
end

@ -0,0 +1,40 @@
module ActiveRecord
module Type
module Helpers
module TimeValue # :nodoc:
def type_cast_for_schema(value)
"'#{value.to_s(:db)}'"
end
def user_input_in_time_zone(value)
value.in_time_zone
end
private
def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil)
# Treat 0000-00-00 00:00:00 as nil.
return if year.nil? || (year == 0 && mon == 0 && mday == 0)
if offset
time = ::Time.utc(year, mon, mday, hour, min, sec, microsec) rescue nil
return unless time
time -= offset
Base.default_timezone == :utc ? time : time.getlocal
else
::Time.public_send(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
end
end
# Doesn't handle time zones.
def fast_string_to_time(string)
if string =~ ConnectionAdapters::Column::Format::ISO_DATETIME
microsec = ($7.to_r * 1_000_000).to_i
new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
end
end
end
end
end
end

@ -1,7 +1,7 @@
module ActiveRecord
module Type
class Integer < Value # :nodoc:
include Numeric
include Helpers::Numeric
# Column storage size in bytes.
# 4 bytes means a MySQL int or Postgres integer as opposed to smallint etc.

@ -1,16 +0,0 @@
module ActiveRecord
module Type
module Mutable # :nodoc:
def type_cast_from_user(value)
type_cast_from_database(type_cast_for_database(value))
end
# +raw_old_value+ will be the `_before_type_cast` version of the
# value (likely a string). +new_value+ will be the current, type
# cast value.
def changed_in_place?(raw_old_value, new_value)
raw_old_value != type_cast_for_database(new_value)
end
end
end
end

@ -1,36 +0,0 @@
module ActiveRecord
module Type
module Numeric # :nodoc:
def number?
true
end
def type_cast(value)
value = case value
when true then 1
when false then 0
when ::String then value.presence
else value
end
super(value)
end
def changed?(old_value, _new_value, new_value_before_type_cast) # :nodoc:
super || number_to_non_number?(old_value, new_value_before_type_cast)
end
private
def number_to_non_number?(old_value, new_value_before_type_cast)
old_value != nil && non_numeric_string?(new_value_before_type_cast)
end
def non_numeric_string?(value)
# 'wibble'.to_i will give zero, we want to make sure
# that we aren't marking int zero to string zero as
# changed.
value.to_s !~ /\A-?\d+\.?\d*\z/
end
end
end
end

@ -1,7 +1,7 @@
module ActiveRecord
module Type
class Serialized < DelegateClass(Type::Value) # :nodoc:
include Mutable
include Helpers::Mutable
attr_reader :subtype, :coder

@ -1,7 +1,7 @@
module ActiveRecord
module Type
class Time < Value # :nodoc:
include TimeValue
include Helpers::TimeValue
include Helpers::AcceptsMultiparameterTime.new(
defaults: { 1 => 1970, 2 => 1, 3 => 1, 4 => 0, 5 => 0 }
)

@ -1,38 +0,0 @@
module ActiveRecord
module Type
module TimeValue # :nodoc:
def type_cast_for_schema(value)
"'#{value.to_s(:db)}'"
end
def user_input_in_time_zone(value)
value.in_time_zone
end
private
def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil)
# Treat 0000-00-00 00:00:00 as nil.
return if year.nil? || (year == 0 && mon == 0 && mday == 0)
if offset
time = ::Time.utc(year, mon, mday, hour, min, sec, microsec) rescue nil
return unless time
time -= offset
Base.default_timezone == :utc ? time : time.getlocal
else
::Time.public_send(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
end
end
# Doesn't handle time zones.
def fast_string_to_time(string)
if string =~ ConnectionAdapters::Column::Format::ISO_DATETIME
microsec = ($7.to_r * 1_000_000).to_i
new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
end
end
end
end
end