aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/type
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/type')
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/binary.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/boolean.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/date.rb33
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/date_time.rb28
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/decimal.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/float.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/hash_lookup_type_map.rb21
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/integer.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/numeric.rb20
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/string.rb18
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/time.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/time_value.rb36
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/timestamp.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/value.rb34
14 files changed, 266 insertions, 14 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/type/binary.rb b/activerecord/lib/active_record/connection_adapters/type/binary.rb
index 168d824d3d..4b2d1a66e0 100644
--- a/activerecord/lib/active_record/connection_adapters/type/binary.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/binary.rb
@@ -5,6 +5,14 @@ module ActiveRecord
def type
:binary
end
+
+ def binary?
+ true
+ end
+
+ def klass
+ ::String
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/type/boolean.rb b/activerecord/lib/active_record/connection_adapters/type/boolean.rb
index 938d227632..2337bdd563 100644
--- a/activerecord/lib/active_record/connection_adapters/type/boolean.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/boolean.rb
@@ -5,6 +5,16 @@ module ActiveRecord
def type
:boolean
end
+
+ private
+
+ def cast_value(value)
+ if value == ''
+ nil
+ else
+ Column::TRUE_VALUES.include?(value)
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/type/date.rb b/activerecord/lib/active_record/connection_adapters/type/date.rb
index 1632f3c8f4..1e7205fd0b 100644
--- a/activerecord/lib/active_record/connection_adapters/type/date.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/date.rb
@@ -5,6 +5,39 @@ module ActiveRecord
def type
:date
end
+
+ def klass
+ ::Date
+ end
+
+ private
+
+ def cast_value(value)
+ if value.is_a?(::String)
+ return if value.empty?
+ fast_string_to_date(value) || fallback_string_to_date(value)
+ elsif value.respond_to?(:to_date)
+ value.to_date
+ else
+ value
+ end
+ end
+
+ def fast_string_to_date(string)
+ if string =~ Column::Format::ISO_DATE
+ new_date $1.to_i, $2.to_i, $3.to_i
+ end
+ end
+
+ def fallback_string_to_date(string)
+ new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday))
+ end
+
+ def new_date(year, mon, mday)
+ if year && year != 0
+ ::Date.new(year, mon, mday) rescue nil
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/type/date_time.rb b/activerecord/lib/active_record/connection_adapters/type/date_time.rb
index 1d7d3cfbbf..c34f4c5a53 100644
--- a/activerecord/lib/active_record/connection_adapters/type/date_time.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/date_time.rb
@@ -1,12 +1,34 @@
-require 'active_record/connection_adapters/type/timestamp'
-
module ActiveRecord
module ConnectionAdapters
module Type
- class DateTime < Timestamp # :nodoc:
+ class DateTime < Value # :nodoc:
+ include TimeValue
+
def type
:datetime
end
+
+ private
+
+ def cast_value(string)
+ return string unless string.is_a?(::String)
+ return if string.empty?
+
+ fast_string_to_time(string) || fallback_string_to_time(string)
+ end
+
+ # '0.123456' -> 123456
+ # '1.123456' -> 123456
+ def microseconds(time)
+ time[:sec_fraction] ? (time[:sec_fraction] * 1_000_000).to_i : 0
+ end
+
+ def fallback_string_to_time(string)
+ time_hash = ::Date._parse(string)
+ time_hash[:sec_fraction] = microseconds(time_hash)
+
+ new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset))
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/type/decimal.rb b/activerecord/lib/active_record/connection_adapters/type/decimal.rb
index 5b39ea9e2f..ac5af4b963 100644
--- a/activerecord/lib/active_record/connection_adapters/type/decimal.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/decimal.rb
@@ -2,9 +2,25 @@ module ActiveRecord
module ConnectionAdapters
module Type
class Decimal < Value # :nodoc:
+ include Numeric
+
def type
:decimal
end
+
+ def klass
+ ::BigDecimal
+ end
+
+ private
+
+ def cast_value(value)
+ if value.respond_to?(:to_d)
+ value.to_d
+ else
+ value.to_s.to_d
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/type/float.rb b/activerecord/lib/active_record/connection_adapters/type/float.rb
index 089169e7c9..51cfa5d86a 100644
--- a/activerecord/lib/active_record/connection_adapters/type/float.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/float.rb
@@ -2,9 +2,21 @@ module ActiveRecord
module ConnectionAdapters
module Type
class Float < Value # :nodoc:
+ include Numeric
+
def type
:float
end
+
+ def klass
+ ::Float
+ end
+
+ private
+
+ def cast_value(value)
+ value.to_f
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/type/hash_lookup_type_map.rb b/activerecord/lib/active_record/connection_adapters/type/hash_lookup_type_map.rb
new file mode 100644
index 0000000000..8503d3ea1b
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/type/hash_lookup_type_map.rb
@@ -0,0 +1,21 @@
+module ActiveRecord
+ module ConnectionAdapters
+ module Type
+ class HashLookupTypeMap < TypeMap # :nodoc:
+ delegate :key?, to: :@mapping
+
+ def lookup(type)
+ @mapping.fetch(type, proc { default_value }).call(type)
+ end
+
+ def fetch(type, &block)
+ @mapping.fetch(type, block).call(type)
+ end
+
+ def alias_type(type, alias_type)
+ register_type(type) { lookup(alias_type) }
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/connection_adapters/type/integer.rb b/activerecord/lib/active_record/connection_adapters/type/integer.rb
index 5510a11bd4..8f3469434c 100644
--- a/activerecord/lib/active_record/connection_adapters/type/integer.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/integer.rb
@@ -2,9 +2,25 @@ module ActiveRecord
module ConnectionAdapters
module Type
class Integer < Value # :nodoc:
+ include Numeric
+
def type
:integer
end
+
+ def klass
+ ::Fixnum
+ end
+
+ private
+
+ def cast_value(value)
+ case value
+ when true then 1
+ when false then 0
+ else value.to_i rescue nil
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/type/numeric.rb b/activerecord/lib/active_record/connection_adapters/type/numeric.rb
new file mode 100644
index 0000000000..a3379831cb
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/type/numeric.rb
@@ -0,0 +1,20 @@
+module ActiveRecord
+ module ConnectionAdapters
+ module Type
+ module Numeric # :nodoc:
+ def number?
+ true
+ end
+
+ def type_cast_for_write(value)
+ case value
+ when true then 1
+ when false then 0
+ when ::String then value.presence
+ else super
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/connection_adapters/type/string.rb b/activerecord/lib/active_record/connection_adapters/type/string.rb
index 0feb4299f5..55f0e1ee1c 100644
--- a/activerecord/lib/active_record/connection_adapters/type/string.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/string.rb
@@ -5,6 +5,24 @@ module ActiveRecord
def type
:string
end
+
+ def text?
+ true
+ end
+
+ def klass
+ ::String
+ end
+
+ private
+
+ def cast_value(value)
+ case value
+ when true then "1"
+ when false then "0"
+ else value.to_s
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/type/time.rb b/activerecord/lib/active_record/connection_adapters/type/time.rb
index a3a687a8ad..4dd201e3fe 100644
--- a/activerecord/lib/active_record/connection_adapters/type/time.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/time.rb
@@ -2,9 +2,26 @@ module ActiveRecord
module ConnectionAdapters
module Type
class Time < Value # :nodoc:
+ include TimeValue
+
def type
:time
end
+
+ private
+
+ def cast_value(value)
+ return value unless value.is_a?(::String)
+ return if value.empty?
+
+ dummy_time_value = "2000-01-01 #{value}"
+
+ fast_string_to_time(dummy_time_value) || begin
+ time_hash = ::Date._parse(dummy_time_value)
+ return if time_hash[:hour].nil?
+ new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction))
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/type/time_value.rb b/activerecord/lib/active_record/connection_adapters/type/time_value.rb
new file mode 100644
index 0000000000..e9ca4adeda
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/type/time_value.rb
@@ -0,0 +1,36 @@
+module ActiveRecord
+ module ConnectionAdapters
+ module Type
+ module TimeValue # :nodoc:
+ def klass
+ ::Time
+ 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 =~ 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
diff --git a/activerecord/lib/active_record/connection_adapters/type/timestamp.rb b/activerecord/lib/active_record/connection_adapters/type/timestamp.rb
deleted file mode 100644
index 92bf0a1954..0000000000
--- a/activerecord/lib/active_record/connection_adapters/type/timestamp.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module ActiveRecord
- module ConnectionAdapters
- module Type
- class Timestamp < Value # :nodoc:
- def type
- :timestamp
- end
- end
- end
- end
-end
diff --git a/activerecord/lib/active_record/connection_adapters/type/value.rb b/activerecord/lib/active_record/connection_adapters/type/value.rb
index f7d7b9351b..289c27f6d4 100644
--- a/activerecord/lib/active_record/connection_adapters/type/value.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/value.rb
@@ -3,6 +3,40 @@ module ActiveRecord
module Type
class Value # :nodoc:
def type; end
+
+ def extract_scale(sql_type)
+ Type.extract_scale(sql_type)
+ end
+
+ def type_cast(value)
+ cast_value(value) unless value.nil?
+ end
+
+ def type_cast_for_write(value)
+ value
+ end
+
+ def text?
+ false
+ end
+
+ def number?
+ false
+ end
+
+ def binary?
+ false
+ end
+
+ def klass
+ ::Object
+ end
+
+ private
+
+ def cast_value(value)
+ value
+ end
end
end
end