mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
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:
parent
7e93e33c19
commit
c4ef73affd
19 changed files with 110 additions and 104 deletions
|
@ -3,7 +3,7 @@ module ActiveRecord
|
|||
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 ActiveRecord
|
|||
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 ActiveRecord
|
|||
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 ActiveRecord
|
|||
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)
|
||||
|
|
18
activerecord/lib/active_record/type/helpers/mutable.rb
Normal file
18
activerecord/lib/active_record/type/helpers/mutable.rb
Normal file
|
@ -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
|
38
activerecord/lib/active_record/type/helpers/numeric.rb
Normal file
38
activerecord/lib/active_record/type/helpers/numeric.rb
Normal file
|
@ -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
|
40
activerecord/lib/active_record/type/helpers/time_value.rb
Normal file
40
activerecord/lib/active_record/type/helpers/time_value.rb
Normal file
|
@ -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
|
Loading…
Reference in a new issue