提交 9664661f 编写于 作者: R Rafael Mendonça França

Merge pull request #15592 from sgrif/sg-type-cast-from-database

Rename `type_cast` to `type_cast_from_database`
......@@ -57,7 +57,7 @@ def ids_reader
def ids_writer(ids)
pk_column = reflection.primary_key_column
ids = Array(ids).reject { |id| id.blank? }
ids.map! { |i| pk_column.type_cast(i) }
ids.map! { |i| pk_column.type_cast_from_user(i) }
replace(klass.find(ids).index_by { |r| r.id }.values_at(*ids))
end
......
......@@ -144,7 +144,7 @@ def instantiate(result_set, aliases)
column_aliases = aliases.column_aliases join_root
result_set.each { |row_hash|
primary_id = type_caster.type_cast row_hash[primary_key]
primary_id = type_caster.type_cast_from_database row_hash[primary_key]
parent = parents[primary_id] ||= join_root.instantiate(row_hash, column_aliases)
construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
}
......
......@@ -123,9 +123,9 @@ def read_attribute(attr_name)
}
if self.class.cache_attribute?(name)
@attributes[name] = column.type_cast(value)
@attributes[name] = column.type_cast_from_database(value)
else
column.type_cast value
column.type_cast_from_database value
end
}
end
......
......@@ -2,7 +2,7 @@ module ActiveRecord
module AttributeMethods
module TimeZoneConversion
class Type < SimpleDelegator # :nodoc:
def type_cast(value)
def type_cast_from_database(value)
convert_time_to_time_zone(super)
end
......
......@@ -17,7 +17,7 @@ module Format
delegate :type, :precision, :scale, :limit, :klass, :accessor,
:text?, :number?, :binary?, :serialized?, :changed?,
:type_cast, :type_cast_from_user, :type_cast_for_database,
:type_cast_from_user, :type_cast_from_database, :type_cast_for_database,
:type_cast_for_schema,
to: :cast_type
......@@ -52,7 +52,7 @@ def human_name
end
def default
@default ||= type_cast(@original_default)
@default ||= type_cast_from_database(@original_default)
end
def with_type(type)
......
......@@ -108,7 +108,7 @@ def type_cast_array(oid, value)
if ::Array === value
value.map {|item| type_cast_array(oid, item)}
else
oid.type_cast value
oid.type_cast_from_database value
end
end
end
......
......@@ -8,15 +8,15 @@ def type
end
def type_cast_from_user(value)
type_cast(type_cast_for_database(value))
type_cast_from_database(type_cast_for_database(value))
end
def type_cast_for_database(value)
ConnectionAdapters::PostgreSQLColumn.hstore_to_string(value)
def type_cast_from_database(value)
ConnectionAdapters::PostgreSQLColumn.string_to_hstore(value)
end
def cast_value(value)
ConnectionAdapters::PostgreSQLColumn.string_to_hstore value
def type_cast_for_database(value)
ConnectionAdapters::PostgreSQLColumn.hstore_to_string(value)
end
def accessor
......
......@@ -8,15 +8,15 @@ def type
end
def type_cast_from_user(value)
type_cast(type_cast_for_database(value))
type_cast_from_database(type_cast_for_database(value))
end
def type_cast_for_database(value)
ConnectionAdapters::PostgreSQLColumn.json_to_string(value)
def type_cast_from_database(value)
ConnectionAdapters::PostgreSQLColumn.string_to_json(value)
end
def cast_value(value)
ConnectionAdapters::PostgreSQLColumn.string_to_json value
def type_cast_for_database(value)
ConnectionAdapters::PostgreSQLColumn.json_to_string(value)
end
def accessor
......
......@@ -29,7 +29,7 @@ def type_cast_for_schema(value)
end
def type_cast_single(value)
infinity?(value) ? value : @subtype.type_cast(value)
infinity?(value) ? value : @subtype.type_cast_from_database(value)
end
def cast_value(value)
......
......@@ -348,14 +348,14 @@ def extension_enabled?(name)
if supports_extensions?
res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled",
'SCHEMA'
res.column_types['enabled'].type_cast res.rows.first.first
res.column_types['enabled'].type_cast_from_database res.rows.first.first
end
end
def extensions
if supports_extensions?
res = exec_query "SELECT extname from pg_extension", "SCHEMA"
res.rows.map { |r| res.column_types['extname'].type_cast r.first }
res.rows.map { |r| res.column_types['extname'].type_cast_from_database r.first }
else
super
end
......
......@@ -516,7 +516,7 @@ def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
# Determines if a hash contains a truthy _destroy key.
def has_destroy_flag?(hash)
Type::Boolean.new.type_cast(hash['_destroy'])
Type::Boolean.new.type_cast_from_user(hash['_destroy'])
end
# Determines if a new record should be rejected by checking
......
......@@ -179,7 +179,7 @@ def pluck(*column_names)
result = result.map do |attributes|
values = attributes.values
columns.zip(values).map { |column, value| column.type_cast value }
columns.zip(values).map { |column, value| column.type_cast_from_database value }
end
columns.one? ? result.map!(&:first) : result
end
......@@ -379,7 +379,7 @@ def type_cast_calculated_value(value, column, operation = nil)
end
def type_cast_using_column(value, column)
column ? column.type_cast(value) : value
column ? column.type_cast_from_database(value) : value
end
# TODO: refactor to allow non-string `select_values` (eg. Arel nodes).
......
......@@ -9,7 +9,7 @@ def initialize(subtype, coder)
super(subtype)
end
def type_cast(value)
def type_cast_from_database(value)
if is_default_value?(value)
value
else
......@@ -18,7 +18,7 @@ def type_cast(value)
end
def type_cast_from_user(value)
type_cast(type_cast_for_database(value))
type_cast_from_database(type_cast_for_database(value))
end
def type_cast_for_database(value)
......
......@@ -16,11 +16,8 @@ def initialize(options = {})
# must 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?
def type_cast_from_database(value)
type_cast(value)
end
def type_cast_from_user(value)
......@@ -64,6 +61,12 @@ def changed?(old_value, new_value, _new_value_before_type_cast) # :nodoc:
end
private
# 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) # :api: public
cast_value(value) unless value.nil?
end
# Responsible for casting values from external sources to the appropriate
# type. Called by `type_cast` for all values except `nil`.
......
......@@ -105,7 +105,7 @@ def test_tinyint_integer_typecasting
result = @conn.exec_query('SELECT status FROM ex')
assert_equal 2, result.column_types['status'].type_cast(result.last['status'])
assert_equal 2, result.column_types['status'].type_cast_from_database(result.last['status'])
end
end
......
......@@ -90,9 +90,9 @@ def test_change_column_default_with_array
end
def test_type_cast_array
assert_equal(['1', '2', '3'], @column.type_cast('{1,2,3}'))
assert_equal([], @column.type_cast('{}'))
assert_equal([nil], @column.type_cast('{NULL}'))
assert_equal(['1', '2', '3'], @column.type_cast_from_database('{1,2,3}'))
assert_equal([], @column.type_cast_from_database('{}'))
assert_equal([nil], @column.type_cast_from_database('{NULL}'))
end
def test_type_cast_integers
......
......@@ -33,16 +33,16 @@ def test_type_cast_binary_converts_the_encoding
data = "\u001F\x8B"
assert_equal('UTF-8', data.encoding.name)
assert_equal('ASCII-8BIT', @column.type_cast(data).encoding.name)
assert_equal('ASCII-8BIT', @column.type_cast_from_database(data).encoding.name)
end
def test_type_cast_binary_value
data = "\u001F\x8B".force_encoding("BINARY")
assert_equal(data, @column.type_cast(data))
assert_equal(data, @column.type_cast_from_database(data))
end
def test_type_case_nil
assert_equal(nil, @column.type_cast(nil))
assert_equal(nil, @column.type_cast_from_database(nil))
end
def test_read_value
......
......@@ -121,7 +121,7 @@ def test_statement_key_is_logged
name = @subscriber.payloads.last[:statement_name]
assert name
res = @connection.exec_query("EXPLAIN (FORMAT JSON) EXECUTE #{name}(#{bindval})")
plan = res.column_types['QUERY PLAN'].type_cast res.rows.first.first
plan = res.column_types['QUERY PLAN'].type_cast_from_database res.rows.first.first
assert_operator plan.length, :>, 0
end
......
......@@ -118,11 +118,11 @@ def test_type_cast_hstore
data = "\"1\"=>\"2\""
hash = @column.class.string_to_hstore data
assert_equal({'1' => '2'}, hash)
assert_equal({'1' => '2'}, @column.type_cast(data))
assert_equal({'1' => '2'}, @column.type_cast_from_database(data))
assert_equal({}, @column.type_cast(""))
assert_equal({'key'=>nil}, @column.type_cast('key => NULL'))
assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast(%q(c=>"}", "\"a\""=>"b \"a b")))
assert_equal({}, @column.type_cast_from_database(""))
assert_equal({'key'=>nil}, @column.type_cast_from_database('key => NULL'))
assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast_from_database(%q(c=>"}", "\"a\""=>"b \"a b")))
end
def test_with_store_accessors
......@@ -180,31 +180,31 @@ def test_gen4
end
def test_parse1
assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @column.type_cast('a=>null,b=>NuLl,c=>"NuLl",null=>c'))
assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @column.type_cast_from_database('a=>null,b=>NuLl,c=>"NuLl",null=>c'))
end
def test_parse2
assert_equal({" " => " "}, @column.type_cast("\\ =>\\ "))
assert_equal({" " => " "}, @column.type_cast_from_database("\\ =>\\ "))
end
def test_parse3
assert_equal({"=" => ">"}, @column.type_cast("==>>"))
assert_equal({"=" => ">"}, @column.type_cast_from_database("==>>"))
end
def test_parse4
assert_equal({"=a"=>"q=w"}, @column.type_cast('\=a=>q=w'))
assert_equal({"=a"=>"q=w"}, @column.type_cast_from_database('\=a=>q=w'))
end
def test_parse5
assert_equal({"=a"=>"q=w"}, @column.type_cast('"=a"=>q\=w'))
assert_equal({"=a"=>"q=w"}, @column.type_cast_from_database('"=a"=>q\=w'))
end
def test_parse6
assert_equal({"\"a"=>"q>w"}, @column.type_cast('"\"a"=>q>w'))
assert_equal({"\"a"=>"q>w"}, @column.type_cast_from_database('"\"a"=>q>w'))
end
def test_parse7
assert_equal({"\"a"=>"q\"w"}, @column.type_cast('\"a=>q"w'))
assert_equal({"\"a"=>"q\"w"}, @column.type_cast_from_database('\"a=>q"w'))
end
def test_rewrite
......
......@@ -80,11 +80,11 @@ def test_type_cast_json
data = "{\"a_key\":\"a_value\"}"
hash = column.class.string_to_json data
assert_equal({'a_key' => 'a_value'}, hash)
assert_equal({'a_key' => 'a_value'}, column.type_cast(data))
assert_equal({'a_key' => 'a_value'}, column.type_cast_from_database(data))
assert_equal({}, column.type_cast("{}"))
assert_equal({'key'=>nil}, column.type_cast('{"key": null}'))
assert_equal({'c'=>'}','"a"'=>'b "a b'}, column.type_cast(%q({"c":"}", "\"a\"":"b \"a b"})))
assert_equal({}, column.type_cast_from_database("{}"))
assert_equal({'key'=>nil}, column.type_cast_from_database('{"key": null}'))
assert_equal({'c'=>'}','"a"'=>'b "a b'}, column.type_cast_from_database(%q({"c":"}", "\"a\"":"b \"a b"})))
end
def test_rewrite
......
......@@ -49,10 +49,10 @@ def test_money_values
def test_money_type_cast
column = PostgresqlMoney.columns_hash['wealth']
assert_equal(12345678.12, column.type_cast("$12,345,678.12"))
assert_equal(12345678.12, column.type_cast("$12.345.678,12"))
assert_equal(-1.15, column.type_cast("-$1.15"))
assert_equal(-2.25, column.type_cast("($2.25)"))
assert_equal(12345678.12, column.type_cast_from_user("$12,345,678.12"))
assert_equal(12345678.12, column.type_cast_from_user("$12.345.678,12"))
assert_equal(-1.15, column.type_cast_from_user("-$1.15"))
assert_equal(-2.25, column.type_cast_from_user("($2.25)"))
end
def test_schema_dumping
......
......@@ -12,11 +12,11 @@ def initialize(delegate, decoration = "decorated!")
super(delegate)
end
def type_cast(value)
def type_cast_from_user(value)
"#{super} #{@decoration}"
end
alias type_cast_from_user type_cast
alias type_cast_from_database type_cast_from_user
end
setup do
......
......@@ -1489,7 +1489,7 @@ def test_column_types_typecast
attrs.delete 'id'
typecast = Class.new {
def type_cast value
def type_cast_from_database value
"t.lo"
end
}
......
......@@ -85,7 +85,7 @@ def test_decimal_without_scale
cast_type = @connection.type_map.lookup(type)
assert_equal :decimal, cast_type.type
assert_equal 2, cast_type.type_cast(2.1)
assert_equal 2, cast_type.type_cast_from_user(2.1)
end
end
......
......@@ -95,7 +95,7 @@ def test_non_existent_columns_are_identity_types
column = @first.column_for_attribute("attribute_that_doesnt_exist")
object = Object.new
assert_equal object, column.type_cast(object)
assert_equal object, column.type_cast_from_database(object)
assert_equal object, column.type_cast_from_user(object)
assert_equal object, column.type_cast_for_database(object)
end
......
......@@ -6,141 +6,141 @@ module ConnectionAdapters
class TypesTest < ActiveRecord::TestCase
def test_type_cast_boolean
type = Type::Boolean.new
assert type.type_cast('').nil?
assert type.type_cast(nil).nil?
assert type.type_cast(true)
assert type.type_cast(1)
assert type.type_cast('1')
assert type.type_cast('t')
assert type.type_cast('T')
assert type.type_cast('true')
assert type.type_cast('TRUE')
assert type.type_cast('on')
assert type.type_cast('ON')
assert type.type_cast_from_user('').nil?
assert type.type_cast_from_user(nil).nil?
assert type.type_cast_from_user(true)
assert type.type_cast_from_user(1)
assert type.type_cast_from_user('1')
assert type.type_cast_from_user('t')
assert type.type_cast_from_user('T')
assert type.type_cast_from_user('true')
assert type.type_cast_from_user('TRUE')
assert type.type_cast_from_user('on')
assert type.type_cast_from_user('ON')
# explicitly check for false vs nil
assert_equal false, type.type_cast(false)
assert_equal false, type.type_cast(0)
assert_equal false, type.type_cast('0')
assert_equal false, type.type_cast('f')
assert_equal false, type.type_cast('F')
assert_equal false, type.type_cast('false')
assert_equal false, type.type_cast('FALSE')
assert_equal false, type.type_cast('off')
assert_equal false, type.type_cast('OFF')
assert_equal false, type.type_cast(' ')
assert_equal false, type.type_cast("\u3000\r\n")
assert_equal false, type.type_cast("\u0000")
assert_equal false, type.type_cast('SOMETHING RANDOM')
assert_equal false, type.type_cast_from_user(false)
assert_equal false, type.type_cast_from_user(0)
assert_equal false, type.type_cast_from_user('0')
assert_equal false, type.type_cast_from_user('f')
assert_equal false, type.type_cast_from_user('F')
assert_equal false, type.type_cast_from_user('false')
assert_equal false, type.type_cast_from_user('FALSE')
assert_equal false, type.type_cast_from_user('off')
assert_equal false, type.type_cast_from_user('OFF')
assert_equal false, type.type_cast_from_user(' ')
assert_equal false, type.type_cast_from_user("\u3000\r\n")
assert_equal false, type.type_cast_from_user("\u0000")
assert_equal false, type.type_cast_from_user('SOMETHING RANDOM')
end
def test_type_cast_string
type = Type::String.new
assert_equal "1", type.type_cast(true)
assert_equal "0", type.type_cast(false)
assert_equal "123", type.type_cast(123)
assert_equal "1", type.type_cast_from_user(true)
assert_equal "0", type.type_cast_from_user(false)
assert_equal "123", type.type_cast_from_user(123)
end
def test_type_cast_integer
type = Type::Integer.new
assert_equal 1, type.type_cast(1)
assert_equal 1, type.type_cast('1')
assert_equal 1, type.type_cast('1ignore')
assert_equal 0, type.type_cast('bad1')
assert_equal 0, type.type_cast('bad')
assert_equal 1, type.type_cast(1.7)
assert_equal 0, type.type_cast(false)
assert_equal 1, type.type_cast(true)
assert_nil type.type_cast(nil)
assert_equal 1, type.type_cast_from_user(1)
assert_equal 1, type.type_cast_from_user('1')
assert_equal 1, type.type_cast_from_user('1ignore')
assert_equal 0, type.type_cast_from_user('bad1')
assert_equal 0, type.type_cast_from_user('bad')
assert_equal 1, type.type_cast_from_user(1.7)
assert_equal 0, type.type_cast_from_user(false)
assert_equal 1, type.type_cast_from_user(true)
assert_nil type.type_cast_from_user(nil)
end
def test_type_cast_non_integer_to_integer
type = Type::Integer.new
assert_nil type.type_cast([1,2])
assert_nil type.type_cast({1 => 2})
assert_nil type.type_cast((1..2))
assert_nil type.type_cast_from_user([1,2])
assert_nil type.type_cast_from_user({1 => 2})
assert_nil type.type_cast_from_user((1..2))
end
def test_type_cast_activerecord_to_integer
type = Type::Integer.new
firm = Firm.create(:name => 'Apple')
assert_nil type.type_cast(firm)
assert_nil type.type_cast_from_user(firm)
end
def test_type_cast_object_without_to_i_to_integer
type = Type::Integer.new
assert_nil type.type_cast(Object.new)
assert_nil type.type_cast_from_user(Object.new)
end
def test_type_cast_nan_and_infinity_to_integer
type = Type::Integer.new
assert_nil type.type_cast(Float::NAN)
assert_nil type.type_cast(1.0/0.0)
assert_nil type.type_cast_from_user(Float::NAN)
assert_nil type.type_cast_from_user(1.0/0.0)
end
def test_type_cast_float
type = Type::Float.new
assert_equal 1.0, type.type_cast("1")
assert_equal 1.0, type.type_cast_from_user("1")
end
def test_type_cast_decimal
type = Type::Decimal.new
assert_equal BigDecimal.new("0"), type.type_cast(BigDecimal.new("0"))
assert_equal BigDecimal.new("123"), type.type_cast(123.0)
assert_equal BigDecimal.new("1"), type.type_cast(:"1")
assert_equal BigDecimal.new("0"), type.type_cast_from_user(BigDecimal.new("0"))
assert_equal BigDecimal.new("123"), type.type_cast_from_user(123.0)
assert_equal BigDecimal.new("1"), type.type_cast_from_user(:"1")
end
def test_type_cast_binary
type = Type::Binary.new
assert_equal nil, type.type_cast(nil)
assert_equal "1", type.type_cast("1")
assert_equal 1, type.type_cast(1)
assert_equal nil, type.type_cast_from_user(nil)
assert_equal "1", type.type_cast_from_user("1")
assert_equal 1, type.type_cast_from_user(1)
end
def test_type_cast_time
type = Type::Time.new
assert_equal nil, type.type_cast(nil)
assert_equal nil, type.type_cast('')
assert_equal nil, type.type_cast('ABC')
assert_equal nil, type.type_cast_from_user(nil)
assert_equal nil, type.type_cast_from_user('')
assert_equal nil, type.type_cast_from_user('ABC')
time_string = Time.now.utc.strftime("%T")
assert_equal time_string, type.type_cast(time_string).strftime("%T")
assert_equal time_string, type.type_cast_from_user(time_string).strftime("%T")
end
def test_type_cast_datetime_and_timestamp
type = Type::DateTime.new
assert_equal nil, type.type_cast(nil)
assert_equal nil, type.type_cast('')
assert_equal nil, type.type_cast(' ')
assert_equal nil, type.type_cast('ABC')
assert_equal nil, type.type_cast_from_user(nil)
assert_equal nil, type.type_cast_from_user('')
assert_equal nil, type.type_cast_from_user(' ')
assert_equal nil, type.type_cast_from_user('ABC')
datetime_string = Time.now.utc.strftime("%FT%T")
assert_equal datetime_string, type.type_cast(datetime_string).strftime("%FT%T")
assert_equal datetime_string, type.type_cast_from_user(datetime_string).strftime("%FT%T")
end
def test_type_cast_date
type = Type::Date.new
assert_equal nil, type.type_cast(nil)
assert_equal nil, type.type_cast('')
assert_equal nil, type.type_cast(' ')
assert_equal nil, type.type_cast('ABC')
assert_equal nil, type.type_cast_from_user(nil)
assert_equal nil, type.type_cast_from_user('')
assert_equal nil, type.type_cast_from_user(' ')
assert_equal nil, type.type_cast_from_user('ABC')
date_string = Time.now.utc.strftime("%F")
assert_equal date_string, type.type_cast(date_string).strftime("%F")
assert_equal date_string, type.type_cast_from_user(date_string).strftime("%F")
end
def test_type_cast_duration_to_integer
type = Type::Integer.new
assert_equal 1800, type.type_cast(30.minutes)
assert_equal 7200, type.type_cast(2.hours)
assert_equal 1800, type.type_cast_from_user(30.minutes)
assert_equal 7200, type.type_cast_from_user(2.hours)
end
def test_string_to_time_with_timezone
[:utc, :local].each do |zone|
with_timezone_config default: zone do
type = Type::DateTime.new
assert_equal Time.utc(2013, 9, 4, 0, 0, 0), type.type_cast("Wed, 04 Sep 2013 03:00:00 EAT")
assert_equal Time.utc(2013, 9, 4, 0, 0, 0), type.type_cast_from_user("Wed, 04 Sep 2013 03:00:00 EAT")
end
end
end
......@@ -149,7 +149,7 @@ def test_string_to_time_with_timezone
def test_binary_encoding
type = SQLite3Binary.new
utf8_string = "a string".encode(Encoding::UTF_8)
type_cast = type.type_cast(utf8_string)
type_cast = type.type_cast_from_user(utf8_string)
assert_equal Encoding::ASCII_8BIT, type_cast.encoding
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册