diff options
author | Sean Griffin <sean@thoughtbot.com> | 2015-02-10 11:52:01 -0700 |
---|---|---|
committer | Sean Griffin <sean@thoughtbot.com> | 2015-02-10 11:55:59 -0700 |
commit | f1a0fa9e19b7e4ccaea191fc6cf0613880222ee7 (patch) | |
tree | 655c1e521e1bbe2a6c3cec8b8178bd7dc843c187 /activerecord/lib/active_record/connection_adapters | |
parent | f926c1c953df6037654732c57a6c6b23db91c9fa (diff) | |
download | rails-f1a0fa9e19b7e4ccaea191fc6cf0613880222ee7.tar.gz rails-f1a0fa9e19b7e4ccaea191fc6cf0613880222ee7.tar.bz2 rails-f1a0fa9e19b7e4ccaea191fc6cf0613880222ee7.zip |
Refactor microsecond precision to be database agnostic
The various databases don't actually need significantly different
handling for this behavior, and they can achieve it without knowing
about the type of the object.
The old implementation was returning a string, which will cause problems
such as breaking TZ aware attributes, and making it impossible for the
adapters to supply their logic for time objects.
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters')
5 files changed, 32 insertions, 46 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 55d3360070..29d85d82cb 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -127,7 +127,12 @@ module ActiveRecord end end - value.to_s(:db) + result = value.to_s(:db) + if value.respond_to?(:usec) && value.usec > 0 + "#{result}.#{sprintf("%06d", value.usec)}" + else + result + end end def prepare_binds_for_database(binds) # :nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb index 932aaf7aa7..4f6a1ec67b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb @@ -29,7 +29,7 @@ module ActiveRecord limit = column.limit || native_database_types[column.type][:limit] spec[:limit] = limit.inspect if limit - spec[:precision] = column.precision.inspect if column.precision + spec[:precision] = column.precision.inspect if column.precision && column.precision != 0 spec[:scale] = column.scale.inspect if column.scale default = schema_default(column) if column.has_default? diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 9392bcb473..ee11c0efa4 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -263,18 +263,6 @@ module ActiveRecord {} end - # QUOTING ================================================== - - # Quote date/time values for use in SQL input. Includes microseconds - # if the value is a Time responding to usec. - def quoted_date(value) #:nodoc: - if value.acts_like?(:time) && value.respond_to?(:usec) - "#{super}.#{sprintf("%06d", value.usec)}" - else - super - end - end - # Returns a bind substitution value given a bind +column+ # NOTE: The column param is currently being used by the sqlserver-adapter def substitute_at(column, _unused = 0) @@ -409,15 +397,15 @@ module ActiveRecord protected def initialize_type_map(m) # :nodoc: - register_class_with_limit m, %r(boolean)i, Type::Boolean - register_class_with_limit m, %r(char)i, Type::String - register_class_with_limit m, %r(binary)i, Type::Binary - register_class_with_limit m, %r(text)i, Type::Text - register_class_with_limit m, %r(date)i, Type::Date - register_class_with_limit m, %r(time)i, Type::Time - register_class_with_limit m, %r(datetime)i, Type::DateTime - register_class_with_limit m, %r(float)i, Type::Float - register_class_with_limit m, %r(int)i, Type::Integer + register_class_with_limit m, %r(boolean)i, Type::Boolean + register_class_with_limit m, %r(char)i, Type::String + register_class_with_limit m, %r(binary)i, Type::Binary + register_class_with_limit m, %r(text)i, Type::Text + register_class_with_precision m, %r(date)i, Type::Date + register_class_with_precision m, %r(time)i, Type::Time + register_class_with_precision m, %r(datetime)i, Type::DateTime + register_class_with_limit m, %r(float)i, Type::Float + register_class_with_limit m, %r(int)i, Type::Integer m.alias_type %r(blob)i, 'binary' m.alias_type %r(clob)i, 'text' @@ -451,6 +439,13 @@ module ActiveRecord end end + def register_class_with_precision(mapping, key, klass) # :nodoc: + mapping.register_type(key) do |*args| + precision = extract_precision(args.last) + klass.new(precision: precision) + end + end + def extract_scale(sql_type) # :nodoc: case sql_type when /\((\d+)\)/ then 0 diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index c29692d6ca..054c59ef5c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -712,11 +712,6 @@ module ActiveRecord m.alias_type %r(year)i, 'integer' m.alias_type %r(bit)i, 'binary' - m.register_type(%r(datetime)i) do |sql_type| - precision = extract_precision(sql_type) - MysqlDateTime.new(precision: precision) - end - m.register_type(%r(enum)i) do |sql_type| limit = sql_type[/^enum\((.+)\)/i, 1] .split(',').map{|enum| enum.strip.length - 2}.max @@ -734,6 +729,14 @@ module ActiveRecord end end + def extract_precision(sql_type) + if /datetime/ === sql_type + super || 0 + else + super + end + end + def fetch_type_metadata(sql_type, collation = "", extra = "") MysqlTypeMetadata.new(super(sql_type), collation: collation, extra: extra, strict: strict_mode?) end @@ -916,14 +919,6 @@ module ActiveRecord TableDefinition.new(native_database_types, name, temporary, options, as) end - class MysqlDateTime < Type::DateTime # :nodoc: - private - - def has_precision? - precision || 0 - end - end - class MysqlString < Type::String # :nodoc: def type_cast_for_database(value) case value @@ -945,7 +940,7 @@ module ActiveRecord end def type_classes_with_standard_constructor - super.merge(string: MysqlString, date_time: MysqlDateTime) + super.merge(string: MysqlString) end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb index 2fe61eeb77..b9e7894e5c 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb @@ -5,15 +5,6 @@ module ActiveRecord class DateTime < Type::DateTime # :nodoc: include Infinity - def type_cast_for_database(value) - if has_precision? && value.acts_like?(:time) && value.year <= 0 - bce_year = format("%04d", -value.year + 1) - super.sub(/^-?\d+/, bce_year) + " BC" - else - super - end - end - def cast_value(value) if value.is_a?(::String) case value |