Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add a type object to Column constructor

Part of #15134. In order to perform typecasting polymorphically, we need
to add another argument to the constructor. The order was chosen to
match the `oid_type` on `PostgreSQLColumn`.
  • Loading branch information...
commit 4bd5dffc85a4f3a660132eb85806a03fa5904e51 1 parent 7359f81
@sgrif sgrif authored
View
5 activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -3,6 +3,7 @@
require 'bigdecimal/util'
require 'active_support/core_ext/benchmark'
require 'active_record/connection_adapters/schema_cache'
+require 'active_record/connection_adapters/type'
require 'active_record/connection_adapters/abstract/schema_dumper'
require 'active_record/connection_adapters/abstract/schema_creation'
require 'monitor'
@@ -362,6 +363,10 @@ def close
protected
+ def lookup_cast_type(sql_type) # :nodoc:
+ Type::Value.new
+ end
+
def translate_exception_class(e, sql)
message = "#{e.class.name}: #{e.message}: #{sql}"
@logger.error message if @logger
View
9 activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -56,11 +56,11 @@ def schema_creation
class Column < ConnectionAdapters::Column # :nodoc:
attr_reader :collation, :strict, :extra
- def initialize(name, default, sql_type = nil, null = true, collation = nil, strict = false, extra = "")
+ def initialize(name, default, cast_type, sql_type = nil, null = true, collation = nil, strict = false, extra = "")
@strict = strict
@collation = collation
@extra = extra
- super(name, default, sql_type, null)
+ super(name, default, cast_type, sql_type, null)
end
def extract_default(default)
@@ -263,8 +263,9 @@ def each_hash(result) # :nodoc:
end
# Overridden by the adapters to instantiate their specific Column type.
- def new_column(field, default, type, null, collation, extra = "") # :nodoc:
- Column.new(field, default, type, null, collation, extra)
+ def new_column(field, default, sql_type, null, collation, extra = "") # :nodoc:
+ cast_type = lookup_cast_type(sql_type)
+ Column.new(field, default, cast_type, sql_type, null, collation, extra)
end
# Must return the Mysql error number from the exception, if the exception has an
View
4 activerecord/lib/active_record/connection_adapters/column.rb
@@ -22,12 +22,14 @@ module Format
#
# +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
+ # +cast_type+ is the object used for type casting and type information.
# +sql_type+ is used to extract the column's length, if necessary. For example +60+ in
# <tt>company_name varchar(60)</tt>.
# It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
# +null+ determines if this column allows +NULL+ values.
- def initialize(name, default, sql_type = nil, null = true)
+ def initialize(name, default, cast_type, sql_type = nil, null = true)
@name = name
+ @cast_type = cast_type
@sql_type = sql_type
@null = null
@limit = extract_limit(sql_type)
View
5 activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -69,8 +69,9 @@ def each_hash(result) # :nodoc:
end
end
- def new_column(field, default, type, null, collation, extra = "") # :nodoc:
- Column.new(field, default, type, null, collation, strict_mode?, extra)
+ def new_column(field, default, sql_type, null, collation, extra = "") # :nodoc:
+ cast_type = lookup_cast_type(sql_type)
+ Column.new(field, default, cast_type, sql_type, null, collation, strict_mode?, extra)
end
def error_number(exception)
View
5 activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -156,8 +156,9 @@ def each_hash(result) # :nodoc:
end
end
- def new_column(field, default, type, null, collation, extra = "") # :nodoc:
- Column.new(field, default, type, null, collation, strict_mode?, extra)
+ def new_column(field, default, sql_type, null, collation, extra = "") # :nodoc:
+ cast_type = lookup_cast_type(sql_type)
+ Column.new(field, default, cast_type, sql_type, null, collation, strict_mode?, extra)
end
def error_number(exception) # :nodoc:
View
4 activerecord/lib/active_record/connection_adapters/postgresql/column.rb
@@ -12,10 +12,10 @@ def initialize(name, default, oid_type, sql_type = nil, null = true)
if sql_type =~ /\[\]$/
@array = true
- super(name, default_value, sql_type[0..sql_type.length - 3], null)
+ super(name, default_value, oid_type, sql_type[0..sql_type.length - 3], null)
else
@array = false
- super(name, default_value, sql_type, null)
+ super(name, default_value, oid_type, sql_type, null)
end
@default_function = default if has_default_function?(default_value, default)
View
4 activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -394,7 +394,9 @@ def columns(table_name) #:nodoc:
field["dflt_value"] = $1.gsub('""', '"')
end
- SQLite3Column.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
+ sql_type = field['type']
+ cast_type = lookup_cast_type(sql_type)
+ SQLite3Column.new(field['name'], field['dflt_value'], cast_type, sql_type, field['notnull'].to_i == 0)
end
end
View
8 activerecord/lib/active_record/connection_adapters/type.rb
@@ -0,0 +1,8 @@
+require 'active_record/connection_adapters/type/value'
+
+module ActiveRecord
+ module ConnectionAdapters
+ module Type # :nodoc:
+ end
+ end
+end
View
8 activerecord/lib/active_record/connection_adapters/type/value.rb
@@ -0,0 +1,8 @@
+module ActiveRecord
+ module ConnectionAdapters
+ module Type
+ class Value # :nodoc:
+ end
+ end
+ end
+end
View
1  activerecord/test/active_record/connection_adapters/fake_adapter.rb
@@ -29,6 +29,7 @@ def merge_column(table_name, name, sql_type = nil, options = {})
@columns[table_name] << ActiveRecord::ConnectionAdapters::Column.new(
name.to_s,
options[:default],
+ lookup_cast_type(sql_type.to_s),
sql_type.to_s,
options[:null])
end
View
4 activerecord/test/cases/adapters/mysql/quoting_test.rb
@@ -9,13 +9,13 @@ def setup
end
def test_type_cast_true
- c = Column.new(nil, 1, 'boolean')
+ c = Column.new(nil, 1, Type::Value.new, 'boolean')
assert_equal 1, @conn.type_cast(true, nil)
assert_equal 1, @conn.type_cast(true, c)
end
def test_type_cast_false
- c = Column.new(nil, 1, 'boolean')
+ c = Column.new(nil, 1, Type::Value.new, 'boolean')
assert_equal 0, @conn.type_cast(false, nil)
assert_equal 0, @conn.type_cast(false, c)
end
View
12 activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -47,13 +47,13 @@ def test_type_cast_nil
end
def test_type_cast_true
- c = Column.new(nil, 1, 'int')
+ c = Column.new(nil, 1, Type::Value.new, 'int')
assert_equal 't', @conn.type_cast(true, nil)
assert_equal 1, @conn.type_cast(true, c)
end
def test_type_cast_false
- c = Column.new(nil, 1, 'int')
+ c = Column.new(nil, 1, Type::Value.new, 'int')
assert_equal 'f', @conn.type_cast(false, nil)
assert_equal 0, @conn.type_cast(false, c)
end
@@ -61,16 +61,16 @@ def test_type_cast_false
def test_type_cast_string
assert_equal '10', @conn.type_cast('10', nil)
- c = Column.new(nil, 1, 'int')
+ c = Column.new(nil, 1, Type::Value.new, 'int')
assert_equal 10, @conn.type_cast('10', c)
- c = Column.new(nil, 1, 'float')
+ c = Column.new(nil, 1, Type::Value.new, 'float')
assert_equal 10.1, @conn.type_cast('10.1', c)
- c = Column.new(nil, 1, 'binary')
+ c = Column.new(nil, 1, Type::Value.new, 'binary')
assert_equal '10.1', @conn.type_cast('10.1', c)
- c = Column.new(nil, 1, 'date')
+ c = Column.new(nil, 1, Type::Value.new, 'date')
assert_equal '10.1', @conn.type_cast('10.1', c)
end
View
44 activerecord/test/cases/column_definition_test.rb
@@ -12,13 +12,13 @@ def @adapter.native_database_types
end
def test_can_set_coder
- column = Column.new("title", nil, "varchar(20)")
+ column = Column.new("title", nil, Type::Value.new, "varchar(20)")
column.coder = YAML
assert_equal YAML, column.coder
end
def test_encoded?
- column = Column.new("title", nil, "varchar(20)")
+ column = Column.new("title", nil, Type::Value.new, "varchar(20)")
assert !column.encoded?
column.coder = YAML
@@ -26,7 +26,7 @@ def test_encoded?
end
def test_type_case_coded_column
- column = Column.new("title", nil, "varchar(20)")
+ column = Column.new("title", nil, Type::Value.new, "varchar(20)")
column.coder = YAML
assert_equal "hello", column.type_cast("--- hello")
end
@@ -34,7 +34,7 @@ def test_type_case_coded_column
# Avoid column definitions in create table statements like:
# `title` varchar(255) DEFAULT NULL
def test_should_not_include_default_clause_when_default_is_null
- column = Column.new("title", nil, "varchar(20)")
+ column = Column.new("title", nil, Type::Value.new, "varchar(20)")
column_def = ColumnDefinition.new(
column.name, "string",
column.limit, column.precision, column.scale, column.default, column.null)
@@ -42,7 +42,7 @@ def test_should_not_include_default_clause_when_default_is_null
end
def test_should_include_default_clause_when_default_is_present
- column = Column.new("title", "Hello", "varchar(20)")
+ column = Column.new("title", "Hello", Type::Value.new, "varchar(20)")
column_def = ColumnDefinition.new(
column.name, "string",
column.limit, column.precision, column.scale, column.default, column.null)
@@ -50,7 +50,7 @@ def test_should_include_default_clause_when_default_is_present
end
def test_should_specify_not_null_if_null_option_is_false
- column = Column.new("title", "Hello", "varchar(20)", false)
+ column = Column.new("title", "Hello", Type::Value.new, "varchar(20)", false)
column_def = ColumnDefinition.new(
column.name, "string",
column.limit, column.precision, column.scale, column.default, column.null)
@@ -59,68 +59,68 @@ def test_should_specify_not_null_if_null_option_is_false
if current_adapter?(:MysqlAdapter)
def test_should_set_default_for_mysql_binary_data_types
- binary_column = MysqlAdapter::Column.new("title", "a", "binary(1)")
+ binary_column = MysqlAdapter::Column.new("title", "a", Type::Value.new, "binary(1)")
assert_equal "a", binary_column.default
- varbinary_column = MysqlAdapter::Column.new("title", "a", "varbinary(1)")
+ varbinary_column = MysqlAdapter::Column.new("title", "a", Type::Value.new, "varbinary(1)")
assert_equal "a", varbinary_column.default
end
def test_should_not_set_default_for_blob_and_text_data_types
assert_raise ArgumentError do
- MysqlAdapter::Column.new("title", "a", "blob")
+ MysqlAdapter::Column.new("title", "a", Type::Value.new, "blob")
end
assert_raise ArgumentError do
- MysqlAdapter::Column.new("title", "Hello", "text")
+ MysqlAdapter::Column.new("title", "Hello", Type::Value.new, "text")
end
- text_column = MysqlAdapter::Column.new("title", nil, "text")
+ text_column = MysqlAdapter::Column.new("title", nil, Type::Value.new, "text")
assert_equal nil, text_column.default
- not_null_text_column = MysqlAdapter::Column.new("title", nil, "text", false)
+ not_null_text_column = MysqlAdapter::Column.new("title", nil, Type::Value.new, "text", false)
assert_equal "", not_null_text_column.default
end
def test_has_default_should_return_false_for_blob_and_text_data_types
- blob_column = MysqlAdapter::Column.new("title", nil, "blob")
+ blob_column = MysqlAdapter::Column.new("title", nil, Type::Value.new, "blob")
assert !blob_column.has_default?
- text_column = MysqlAdapter::Column.new("title", nil, "text")
+ text_column = MysqlAdapter::Column.new("title", nil, Type::Value.new, "text")
assert !text_column.has_default?
end
end
if current_adapter?(:Mysql2Adapter)
def test_should_set_default_for_mysql_binary_data_types
- binary_column = Mysql2Adapter::Column.new("title", "a", "binary(1)")
+ binary_column = Mysql2Adapter::Column.new("title", "a", Type::Value.new, "binary(1)")
assert_equal "a", binary_column.default
- varbinary_column = Mysql2Adapter::Column.new("title", "a", "varbinary(1)")
+ varbinary_column = Mysql2Adapter::Column.new("title", "a", Type::Value.new, "varbinary(1)")
assert_equal "a", varbinary_column.default
end
def test_should_not_set_default_for_blob_and_text_data_types
assert_raise ArgumentError do
- Mysql2Adapter::Column.new("title", "a", "blob")
+ Mysql2Adapter::Column.new("title", "a", Type::Value.new, "blob")
end
assert_raise ArgumentError do
- Mysql2Adapter::Column.new("title", "Hello", "text")
+ Mysql2Adapter::Column.new("title", "Hello", Type::Value.new, "text")
end
- text_column = Mysql2Adapter::Column.new("title", nil, "text")
+ text_column = Mysql2Adapter::Column.new("title", nil, Type::Value.new, "text")
assert_equal nil, text_column.default
- not_null_text_column = Mysql2Adapter::Column.new("title", nil, "text", false)
+ not_null_text_column = Mysql2Adapter::Column.new("title", nil, Type::Value.new, "text", false)
assert_equal "", not_null_text_column.default
end
def test_has_default_should_return_false_for_blob_and_text_data_types
- blob_column = Mysql2Adapter::Column.new("title", nil, "blob")
+ blob_column = Mysql2Adapter::Column.new("title", nil, Type::Value.new, "blob")
assert !blob_column.has_default?
- text_column = Mysql2Adapter::Column.new("title", nil, "text")
+ text_column = Mysql2Adapter::Column.new("title", nil, Type::Value.new, "text")
assert !text_column.has_default?
end
end
View
30 activerecord/test/cases/column_test.rb
@@ -5,7 +5,7 @@ module ActiveRecord
module ConnectionAdapters
class ColumnTest < ActiveRecord::TestCase
def test_type_cast_boolean
- column = Column.new("field", nil, "boolean")
+ column = Column.new("field", nil, Type::Value.new, "boolean")
assert column.type_cast('').nil?
assert column.type_cast(nil).nil?
@@ -36,14 +36,14 @@ def test_type_cast_boolean
end
def test_type_cast_string
- column = Column.new("field", nil, "varchar")
+ column = Column.new("field", nil, Type::Value.new, "varchar")
assert_equal "1", column.type_cast(true)
assert_equal "0", column.type_cast(false)
assert_equal "123", column.type_cast(123)
end
def test_type_cast_integer
- column = Column.new("field", nil, "integer")
+ column = Column.new("field", nil, Type::Value.new, "integer")
assert_equal 1, column.type_cast(1)
assert_equal 1, column.type_cast('1')
assert_equal 1, column.type_cast('1ignore')
@@ -56,50 +56,50 @@ def test_type_cast_integer
end
def test_type_cast_non_integer_to_integer
- column = Column.new("field", nil, "integer")
+ column = Column.new("field", nil, Type::Value.new, "integer")
assert_nil column.type_cast([1,2])
assert_nil column.type_cast({1 => 2})
assert_nil column.type_cast((1..2))
end
def test_type_cast_activerecord_to_integer
- column = Column.new("field", nil, "integer")
+ column = Column.new("field", nil, Type::Value.new, "integer")
firm = Firm.create(:name => 'Apple')
assert_nil column.type_cast(firm)
end
def test_type_cast_object_without_to_i_to_integer
- column = Column.new("field", nil, "integer")
+ column = Column.new("field", nil, Type::Value.new, "integer")
assert_nil column.type_cast(Object.new)
end
def test_type_cast_nan_and_infinity_to_integer
- column = Column.new("field", nil, "integer")
+ column = Column.new("field", nil, Type::Value.new, "integer")
assert_nil column.type_cast(Float::NAN)
assert_nil column.type_cast(1.0/0.0)
end
def test_type_cast_float
- column = Column.new("field", nil, "float")
+ column = Column.new("field", nil, Type::Value.new, "float")
assert_equal 1.0, column.type_cast("1")
end
def test_type_cast_decimal
- column = Column.new("field", nil, "decimal")
+ column = Column.new("field", nil, Type::Value.new, "decimal")
assert_equal BigDecimal.new("0"), column.type_cast(BigDecimal.new("0"))
assert_equal BigDecimal.new("123"), column.type_cast(123.0)
assert_equal BigDecimal.new("1"), column.type_cast(:"1")
end
def test_type_cast_binary
- column = Column.new("field", nil, "binary")
+ column = Column.new("field", nil, Type::Value.new, "binary")
assert_equal nil, column.type_cast(nil)
assert_equal "1", column.type_cast("1")
assert_equal 1, column.type_cast(1)
end
def test_type_cast_time
- column = Column.new("field", nil, "time")
+ column = Column.new("field", nil, Type::Value.new, "time")
assert_equal nil, column.type_cast(nil)
assert_equal nil, column.type_cast('')
assert_equal nil, column.type_cast('ABC')
@@ -109,7 +109,7 @@ def test_type_cast_time
end
def test_type_cast_datetime_and_timestamp
- [Column.new("field", nil, "datetime"), Column.new("field", nil, "timestamp")].each do |column|
+ [Column.new("field", nil, Type::Value.new, "datetime"), Column.new("field", nil, Type::Value.new, "timestamp")].each do |column|
assert_equal nil, column.type_cast(nil)
assert_equal nil, column.type_cast('')
assert_equal nil, column.type_cast(' ')
@@ -121,7 +121,7 @@ def test_type_cast_datetime_and_timestamp
end
def test_type_cast_date
- column = Column.new("field", nil, "date")
+ column = Column.new("field", nil, Type::Value.new, "date")
assert_equal nil, column.type_cast(nil)
assert_equal nil, column.type_cast('')
assert_equal nil, column.type_cast(' ')
@@ -132,7 +132,7 @@ def test_type_cast_date
end
def test_type_cast_duration_to_integer
- column = Column.new("field", nil, "integer")
+ column = Column.new("field", nil, Type::Value.new, "integer")
assert_equal 1800, column.type_cast(30.minutes)
assert_equal 7200, column.type_cast(2.hours)
end
@@ -147,7 +147,7 @@ def test_string_to_time_with_timezone
if current_adapter?(:SQLite3Adapter)
def test_binary_encoding
- column = SQLite3Column.new("field", nil, "binary")
+ column = SQLite3Column.new("field", nil, Type::Value.new, "binary")
utf8_string = "a string".encode(Encoding::UTF_8)
type_cast = column.type_cast(utf8_string)
Please sign in to comment.
Something went wrong with that request. Please try again.