diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters')
15 files changed, 90 insertions, 82 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 75501852ed..f836e60988 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -9,26 +9,22 @@ module ActiveRecord # records are quoted as their primary key return value.quoted_id if value.respond_to?(:quoted_id) + # FIXME: The only case we get an object other than nil or a real column + # is `SchemaStatements#add_column` with a PG array that has a non-empty default + # value. Is this really the only case? Are we missing tests for other types? + # We should have a real column object passed (or nil) here, and check for that + # instead + if column.respond_to?(:type_cast_for_database) + value = column.type_cast_for_database(value) + end + case value when String, ActiveSupport::Multibyte::Chars - value = value.to_s - return "'#{quote_string(value)}'" unless column - - case column.type - when :integer then value.to_i.to_s - when :float then value.to_f.to_s - else - "'#{quote_string(value)}'" - end - - when true, false - if column && column.type == :integer - value ? '1' : '0' - else - value ? quoted_true : quoted_false - end - # BigDecimals need to be put in a non-normalized form and quoted. + "'#{quote_string(value.to_s)}'" + when true then quoted_true + when false then quoted_false when nil then "NULL" + # BigDecimals need to be put in a non-normalized form and quoted. when BigDecimal then value.to_s('F') when Numeric, ActiveSupport::Duration then value.to_s when Date, Time then "'#{quoted_date(value)}'" @@ -47,30 +43,25 @@ module ActiveRecord return value.id end - case value - when String, ActiveSupport::Multibyte::Chars - value = value.to_s - return value unless column - - case column.type - when :integer then value.to_i - when :float then value.to_f - else - value - end + # FIXME: The only case we get an object other than nil or a real column + # is `SchemaStatements#add_column` with a PG array that has a non-empty default + # value. Is this really the only case? Are we missing tests for other types? + # We should have a real column object passed (or nil) here, and check for that + # instead + if column.respond_to?(:type_cast_for_database) + value = column.type_cast_for_database(value) + end - when true, false - if column && column.type == :integer - value ? 1 : 0 - else - value ? 't' : 'f' - end - # BigDecimals need to be put in a non-normalized form and quoted. - when nil then nil + case value + when Symbol, ActiveSupport::Multibyte::Chars + value.to_s + when true then unquoted_true + when false then unquoted_false + # BigDecimals need to be put in a non-normalized form and quoted. when BigDecimal then value.to_s('F') - when Numeric then value when Date, Time then quoted_date(value) - when Symbol then value.to_s + when *types_which_need_no_typecasting + value else to_type = column ? " to #{column.type}" : "" raise TypeError, "can't cast #{value.class}#{to_type}" @@ -109,10 +100,18 @@ module ActiveRecord "'t'" end + def unquoted_true + 't' + end + def quoted_false "'f'" end + def unquoted_false + 'f' + end + def quoted_date(value) if value.acts_like?(:time) zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal @@ -124,6 +123,12 @@ module ActiveRecord value.to_s(:db) end + + private + + def types_which_need_no_typecasting + [nil, Numeric, String] + end end end end 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 d3f8470c30..82e62786ca 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -178,17 +178,6 @@ module ActiveRecord true end - def type_cast(value, column) - case value - when TrueClass - 1 - when FalseClass - 0 - else - super - end - end - # MySQL 4 technically support transaction isolation, but it is affected by a bug # where the transaction level gets persisted for the whole session: # @@ -234,8 +223,6 @@ module ActiveRecord if value.kind_of?(String) && column && column.type == :binary s = value.unpack("H*")[0] "x'#{s}'" - elsif value.kind_of?(BigDecimal) - value.to_s("F") else super end @@ -253,10 +240,18 @@ module ActiveRecord QUOTED_TRUE end + def unquoted_true + 1 + end + def quoted_false QUOTED_FALSE end + def unquoted_false + 0 + end + # REFERENTIAL INTEGRITY ==================================== def disable_referential_integrity #:nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index 42aabd6d7f..86232f9d3f 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -18,7 +18,8 @@ module ActiveRecord alias :encoded? :coder - delegate :type, :precision, :scale, :limit, :klass, :text?, :number?, :binary?, :type_cast_for_write, to: :cast_type + delegate :type, :precision, :scale, :limit, :klass, :text?, :number?, :binary?, + :type_cast_for_write, :type_cast_for_database, to: :cast_type # Instantiates a new column in the table. # diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 4620206e1a..1f327d1f2f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -119,13 +119,13 @@ module ActiveRecord ADAPTER_NAME end - def schema_creation + def schema_creation # :nodoc: PostgreSQL::SchemaCreation.new self end # Adds `:array` option to the default set provided by the # AbstractAdapter - def prepare_column_options(column, types) + def prepare_column_options(column, types) # :nodoc: spec = super spec[:array] = 'true' if column.respond_to?(:array) && column.array spec[:default] = "\"#{column.default_function}\"" if column.default_function @@ -406,7 +406,7 @@ module ActiveRecord private - def get_oid_type(oid, fmod, column_name, sql_type = '') + def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc: if !type_map.key?(oid) load_additional_types(type_map, [oid]) end @@ -419,7 +419,7 @@ module ActiveRecord } end - def initialize_type_map(m) + def initialize_type_map(m) # :nodoc: register_class_with_limit m, 'int2', OID::Integer m.alias_type 'int4', 'int2' m.alias_type 'int8', 'int2' @@ -496,7 +496,7 @@ module ActiveRecord end # Extracts the value from a PostgreSQL column default definition. - def extract_value_from_default(default) + def extract_value_from_default(default) # :nodoc: # This is a performance optimization for Ruby 1.9.2 in development. # If the value is nil, we return nil straight away without checking # the regular expressions. If we check each regular expression, @@ -558,15 +558,15 @@ module ActiveRecord end end - def extract_default_function(default_value, default) + def extract_default_function(default_value, default) # :nodoc: default if has_default_function?(default_value, default) end - def has_default_function?(default_value, default) + def has_default_function?(default_value, default) # :nodoc: !default_value && (%r{\w+\(.*\)} === default) end - def load_additional_types(type_map, oids = nil) + def load_additional_types(type_map, oids = nil) # :nodoc: if supports_ranges? query = <<-SQL SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype @@ -760,16 +760,6 @@ module ActiveRecord end_sql end - def extract_pg_identifier_from_name(name) # :nodoc: - match_data = name.start_with?('"') ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/) - - if match_data - rest = name[match_data[0].length, name.length] - rest = rest[1, rest.length] if rest.start_with? "." - [match_data[1], (rest.length > 0 ? rest : nil)] - end - end - def extract_table_ref_from_insert_sql(sql) # :nodoc: sql[/into\s+([^\(]*).*values\s*\(/im] $1.strip if $1 diff --git a/activerecord/lib/active_record/connection_adapters/type/binary.rb b/activerecord/lib/active_record/connection_adapters/type/binary.rb index 4b2d1a66e0..60afe44de1 100644 --- a/activerecord/lib/active_record/connection_adapters/type/binary.rb +++ b/activerecord/lib/active_record/connection_adapters/type/binary.rb @@ -1,7 +1,7 @@ module ActiveRecord module ConnectionAdapters module Type - class Binary < Value # :nodoc: + class Binary < Value def type :binary end diff --git a/activerecord/lib/active_record/connection_adapters/type/boolean.rb b/activerecord/lib/active_record/connection_adapters/type/boolean.rb index 2337bdd563..0d97379189 100644 --- a/activerecord/lib/active_record/connection_adapters/type/boolean.rb +++ b/activerecord/lib/active_record/connection_adapters/type/boolean.rb @@ -1,7 +1,7 @@ module ActiveRecord module ConnectionAdapters module Type - class Boolean < Value # :nodoc: + class Boolean < Value def type :boolean end diff --git a/activerecord/lib/active_record/connection_adapters/type/date.rb b/activerecord/lib/active_record/connection_adapters/type/date.rb index 1e7205fd0b..e8becbe1f4 100644 --- a/activerecord/lib/active_record/connection_adapters/type/date.rb +++ b/activerecord/lib/active_record/connection_adapters/type/date.rb @@ -1,7 +1,7 @@ module ActiveRecord module ConnectionAdapters module Type - class Date < Value # :nodoc: + class Date < Value def type :date 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 c34f4c5a53..64f5d05301 100644 --- a/activerecord/lib/active_record/connection_adapters/type/date_time.rb +++ b/activerecord/lib/active_record/connection_adapters/type/date_time.rb @@ -1,7 +1,7 @@ module ActiveRecord module ConnectionAdapters module Type - class DateTime < Value # :nodoc: + class DateTime < Value include TimeValue def type diff --git a/activerecord/lib/active_record/connection_adapters/type/decimal.rb b/activerecord/lib/active_record/connection_adapters/type/decimal.rb index ac5af4b963..e93906ba19 100644 --- a/activerecord/lib/active_record/connection_adapters/type/decimal.rb +++ b/activerecord/lib/active_record/connection_adapters/type/decimal.rb @@ -1,7 +1,7 @@ module ActiveRecord module ConnectionAdapters module Type - class Decimal < Value # :nodoc: + class Decimal < Value include Numeric def type diff --git a/activerecord/lib/active_record/connection_adapters/type/float.rb b/activerecord/lib/active_record/connection_adapters/type/float.rb index 51cfa5d86a..f2427d2dfa 100644 --- a/activerecord/lib/active_record/connection_adapters/type/float.rb +++ b/activerecord/lib/active_record/connection_adapters/type/float.rb @@ -1,7 +1,7 @@ module ActiveRecord module ConnectionAdapters module Type - class Float < Value # :nodoc: + class Float < Value include Numeric def type @@ -12,6 +12,8 @@ module ActiveRecord ::Float end + alias type_cast_for_database type_cast + private def cast_value(value) diff --git a/activerecord/lib/active_record/connection_adapters/type/integer.rb b/activerecord/lib/active_record/connection_adapters/type/integer.rb index 8f3469434c..596f4de2a8 100644 --- a/activerecord/lib/active_record/connection_adapters/type/integer.rb +++ b/activerecord/lib/active_record/connection_adapters/type/integer.rb @@ -1,7 +1,7 @@ module ActiveRecord module ConnectionAdapters module Type - class Integer < Value # :nodoc: + class Integer < Value include Numeric def type @@ -12,6 +12,8 @@ module ActiveRecord ::Fixnum end + alias type_cast_for_database type_cast + private def cast_value(value) diff --git a/activerecord/lib/active_record/connection_adapters/type/string.rb b/activerecord/lib/active_record/connection_adapters/type/string.rb index 55f0e1ee1c..471f949e09 100644 --- a/activerecord/lib/active_record/connection_adapters/type/string.rb +++ b/activerecord/lib/active_record/connection_adapters/type/string.rb @@ -1,7 +1,7 @@ module ActiveRecord module ConnectionAdapters module Type - class String < Value # :nodoc: + class String < Value def type :string end diff --git a/activerecord/lib/active_record/connection_adapters/type/text.rb b/activerecord/lib/active_record/connection_adapters/type/text.rb index ee5842a3fc..61095ebb38 100644 --- a/activerecord/lib/active_record/connection_adapters/type/text.rb +++ b/activerecord/lib/active_record/connection_adapters/type/text.rb @@ -3,7 +3,7 @@ require 'active_record/connection_adapters/type/string' module ActiveRecord module ConnectionAdapters module Type - class Text < String # :nodoc: + class Text < String def type :text end diff --git a/activerecord/lib/active_record/connection_adapters/type/time.rb b/activerecord/lib/active_record/connection_adapters/type/time.rb index 4dd201e3fe..bc331b0fa7 100644 --- a/activerecord/lib/active_record/connection_adapters/type/time.rb +++ b/activerecord/lib/active_record/connection_adapters/type/time.rb @@ -1,7 +1,7 @@ module ActiveRecord module ConnectionAdapters module Type - class Time < Value # :nodoc: + class Time < Value include TimeValue def type diff --git a/activerecord/lib/active_record/connection_adapters/type/value.rb b/activerecord/lib/active_record/connection_adapters/type/value.rb index 54a3e9dd7a..60b443004c 100644 --- a/activerecord/lib/active_record/connection_adapters/type/value.rb +++ b/activerecord/lib/active_record/connection_adapters/type/value.rb @@ -1,9 +1,11 @@ module ActiveRecord module ConnectionAdapters module Type - class Value # :nodoc: + class Value attr_reader :precision, :scale, :limit + # Valid options are +precision+, +scale+, and +limit+. + # They are only used when dumping schema. def initialize(options = {}) options.assert_valid_keys(:precision, :scale, :limit) @precision = options[:precision] @@ -11,8 +13,13 @@ module ActiveRecord @limit = options[:limit] end + # The simplified that this object represents. Subclasses + # should override this method. def type; end + # Takes an input from the database, or from attribute setters, + # and casts it to a type appropriate for this object. This method + # should not be overriden by subclasses. Instead, override `cast_value`. def type_cast(value) cast_value(value) unless value.nil? end @@ -21,6 +28,10 @@ module ActiveRecord value end + def type_cast_for_database(value) + type_cast_for_write(value) + end + def text? false end @@ -39,7 +50,9 @@ module ActiveRecord private - def cast_value(value) + # Responsible for casting values from external sources to the appropriate + # type. Called by `type_cast` for all values except `nil`. + def cast_value(value) # :api: public value end end |