diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/abstract/quoting.rb')
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/quoting.rb | 132 |
1 files changed, 76 insertions, 56 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..7c1a779577 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -9,72 +9,35 @@ module ActiveRecord # records are quoted as their primary key return value.quoted_id if value.respond_to?(:quoted_id) - 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. - when nil then "NULL" - when BigDecimal then value.to_s('F') - when Numeric, ActiveSupport::Duration then value.to_s - when Date, Time then "'#{quoted_date(value)}'" - when Symbol then "'#{quote_string(value.to_s)}'" - when Class then "'#{value.to_s}'" - else - "'#{quote_string(YAML.dump(value))}'" + if column + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Passing a column to `quote` has been deprecated. It is only used + for type casting, which should be handled elsewhere. See + https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11 + for more information. + MSG + value = column.cast_type.type_cast_for_database(value) end + + _quote(value) end # Cast a +value+ to a type that the database understands. For example, # SQLite does not understand dates, so this method will convert a Date # to a String. - def type_cast(value, column) + def type_cast(value, column = nil) if value.respond_to?(:quoted_id) && value.respond_to?(:id) 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 - - 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 - when BigDecimal then value.to_s('F') - when Numeric then value - when Date, Time then quoted_date(value) - when Symbol then value.to_s - else - to_type = column ? " to #{column.type}" : "" - raise TypeError, "can't cast #{value.class}#{to_type}" + if column + value = column.cast_type.type_cast_for_database(value) end + + _type_cast(value) + rescue TypeError + to_type = column ? " to #{column.type}" : "" + raise TypeError, "can't cast #{value.class}#{to_type}" end # Quotes a string, escaping any ' (single quote) and \ (backslash) @@ -99,7 +62,7 @@ module ActiveRecord # This works for mysql and mysql2 where table.column can be used to # resolve ambiguity. # - # We override this in the sqlite and postgresql adapters to use only + # We override this in the sqlite3 and postgresql adapters to use only # the column name (as per syntax requirements). def quote_table_name_for_assignment(table, attr) quote_table_name("#{table}.#{attr}") @@ -109,10 +72,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 +95,55 @@ module ActiveRecord value.to_s(:db) end + + def prepare_binds_for_database(binds) # :nodoc: + binds.map do |column, value| + if column + column_name = column.name + value = column.cast_type.type_cast_for_database(value) + end + [column_name, value] + end + end + + private + + def types_which_need_no_typecasting + [nil, Numeric, String] + end + + def _quote(value) + case value + when String, ActiveSupport::Multibyte::Chars, Type::Binary::Data + "'#{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)}'" + when Symbol then "'#{quote_string(value.to_s)}'" + when Class then "'#{value}'" + else + "'#{quote_string(YAML.dump(value))}'" + end + end + + def _type_cast(value) + case value + when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data + 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 Date, Time then quoted_date(value) + when *types_which_need_no_typecasting + value + else raise TypeError + end + end end end end |