aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb6
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb68
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb19
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb26
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/float.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/integer.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/type/value.rb4
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/array_handler.rb25
10 files changed, 78 insertions, 83 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb
index 53a9c874bf..47c6f94ba7 100644
--- a/activerecord/lib/active_record/attribute_methods/serialization.rb
+++ b/activerecord/lib/active_record/attribute_methods/serialization.rb
@@ -65,6 +65,8 @@ module ActiveRecord
end
class Type # :nodoc:
+ delegate :type, :type_cast_for_database, to: :@column
+
def initialize(column)
@column = column
end
@@ -77,10 +79,6 @@ module ActiveRecord
end
end
- def type
- @column.type
- end
-
def accessor
ActiveRecord::Store::IndifferentHashAccessor
end
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index dfebb2cf56..6149ac4906 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -2,6 +2,8 @@ module ActiveRecord
module AttributeMethods
module TimeZoneConversion
class Type # :nodoc:
+ delegate :type, :type_cast_for_database, to: :@column
+
def initialize(column)
@column = column
end
@@ -10,10 +12,6 @@ module ActiveRecord
value = @column.type_cast(value)
value.acts_like?(:time) ? value.in_time_zone : value
end
-
- def type
- @column.type
- end
end
extend ActiveSupport::Concern
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 75501852ed..768d2b6d36 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,26 +43,22 @@ module ActiveRecord
return value.id
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
+
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.
+ value.to_s
+ when true then unquoted_true
+ when false then unquoted_false
when nil then nil
+ # 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)
@@ -109,10 +101,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
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..8efb288c95 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:
#
@@ -253,10 +242,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/float.rb b/activerecord/lib/active_record/connection_adapters/type/float.rb
index 51cfa5d86a..28111e9d8e 100644
--- a/activerecord/lib/active_record/connection_adapters/type/float.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/float.rb
@@ -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..8e6a509b5b 100644
--- a/activerecord/lib/active_record/connection_adapters/type/integer.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/integer.rb
@@ -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/value.rb b/activerecord/lib/active_record/connection_adapters/type/value.rb
index 54a3e9dd7a..9bbc249c2b 100644
--- a/activerecord/lib/active_record/connection_adapters/type/value.rb
+++ b/activerecord/lib/active_record/connection_adapters/type/value.rb
@@ -21,6 +21,10 @@ module ActiveRecord
value
end
+ def type_cast_for_database(value)
+ type_cast_for_write(value)
+ end
+
def text?
false
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
index 2f6c34ac08..7f937e1875 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
@@ -4,26 +4,29 @@ module ActiveRecord
def call(attribute, value)
values = value.map { |x| x.is_a?(Base) ? x.id : x }
ranges, values = values.partition { |v| v.is_a?(Range) }
+ nils, values = values.partition(&:nil?)
- values_predicate = if values.include?(nil)
- values = values.compact
-
+ values_predicate =
case values.length
- when 0
- attribute.eq(nil)
- when 1
- attribute.eq(values.first).or(attribute.eq(nil))
- else
- attribute.in(values).or(attribute.eq(nil))
+ when 0 then NullPredicate
+ when 1 then attribute.eq(values.first)
+ else attribute.in(values)
end
- else
- attribute.in(values)
+
+ unless nils.empty?
+ values_predicate = values_predicate.or(attribute.eq(nil))
end
array_predicates = ranges.map { |range| attribute.in(range) }
array_predicates << values_predicate
array_predicates.inject { |composite, predicate| composite.or(predicate) }
end
+
+ module NullPredicate
+ def self.or(other)
+ other
+ end
+ end
end
end
end