2014-05-23 18:24:52 +00:00
|
|
|
require 'cases/helper'
|
|
|
|
|
|
|
|
class OverloadedType < ActiveRecord::Base
|
2015-02-06 18:05:38 +00:00
|
|
|
attribute :overloaded_float, :integer
|
|
|
|
attribute :overloaded_string_with_limit, :string, limit: 50
|
|
|
|
attribute :non_existent_decimal, :decimal
|
|
|
|
attribute :string_with_default, :string, default: 'the overloaded default'
|
2014-05-23 18:24:52 +00:00
|
|
|
end
|
|
|
|
|
2014-05-28 17:11:57 +00:00
|
|
|
class ChildOfOverloadedType < OverloadedType
|
|
|
|
end
|
|
|
|
|
|
|
|
class GrandchildOfOverloadedType < ChildOfOverloadedType
|
2015-02-06 18:05:38 +00:00
|
|
|
attribute :overloaded_float, :float
|
2014-05-28 17:11:57 +00:00
|
|
|
end
|
|
|
|
|
2014-05-23 18:24:52 +00:00
|
|
|
class UnoverloadedType < ActiveRecord::Base
|
|
|
|
self.table_name = 'overloaded_types'
|
|
|
|
end
|
|
|
|
|
|
|
|
module ActiveRecord
|
|
|
|
class CustomPropertiesTest < ActiveRecord::TestCase
|
2014-10-31 22:06:14 +00:00
|
|
|
test "overloading types" do
|
2014-05-23 18:24:52 +00:00
|
|
|
data = OverloadedType.new
|
|
|
|
|
|
|
|
data.overloaded_float = "1.1"
|
|
|
|
data.unoverloaded_float = "1.1"
|
|
|
|
|
|
|
|
assert_equal 1, data.overloaded_float
|
|
|
|
assert_equal 1.1, data.unoverloaded_float
|
|
|
|
end
|
|
|
|
|
2014-10-31 22:06:14 +00:00
|
|
|
test "overloaded properties save" do
|
2014-05-23 18:24:52 +00:00
|
|
|
data = OverloadedType.new
|
|
|
|
|
|
|
|
data.overloaded_float = "2.2"
|
|
|
|
data.save!
|
|
|
|
data.reload
|
|
|
|
|
|
|
|
assert_equal 2, data.overloaded_float
|
2014-05-29 13:55:44 +00:00
|
|
|
assert_kind_of Fixnum, OverloadedType.last.overloaded_float
|
2014-05-23 18:24:52 +00:00
|
|
|
assert_equal 2.0, UnoverloadedType.last.overloaded_float
|
2014-05-29 13:55:44 +00:00
|
|
|
assert_kind_of Float, UnoverloadedType.last.overloaded_float
|
2014-05-23 18:24:52 +00:00
|
|
|
end
|
|
|
|
|
2014-10-31 22:06:14 +00:00
|
|
|
test "properties assigned in constructor" do
|
2014-05-23 18:24:52 +00:00
|
|
|
data = OverloadedType.new(overloaded_float: '3.3')
|
|
|
|
|
|
|
|
assert_equal 3, data.overloaded_float
|
|
|
|
end
|
|
|
|
|
2014-10-31 22:06:14 +00:00
|
|
|
test "overloaded properties with limit" do
|
Attribute assignment and type casting has nothing to do with columns
It's finally finished!!!!!!! The reason the Attributes API was kept
private in 4.2 was due to some publicly visible implementation details.
It was previously implemented by overloading `columns` and
`columns_hash`, to make them return column objects which were modified
with the attribute information.
This meant that those methods LIED! We didn't change the database
schema. We changed the attribute information on the class. That is
wrong! It should be the other way around, where schema loading just
calls the attributes API for you. And now it does!
Yes, this means that there is nothing that happens in automatic schema
loading that you couldn't manually do yourself. (There's still some
funky cases where we hit the connection adapter that I need to handle,
before we can turn off automatic schema detection entirely.)
There were a few weird test failures caused by this that had to be
fixed. The main source came from the fact that the attribute methods are
now defined in terms of `attribute_names`, which has a clause like
`return [] unless table_exists?`. I don't *think* this is an issue,
since the only place this caused failures were in a fake adapter which
didn't override `table_exists?`.
Additionally, there were a few cases where tests were failing because a
migration was run, but the model was not reloaded. I'm not sure why
these started failing from this change, I might need to clear an
additional cache in `reload_schema_from_cache`. Again, since this is not
normal usage, and it's expected that `reset_column_information` will be
called after the table is modified, I don't think it's a problem.
Still, test failures that were unrelated to the change are worrying, and
I need to dig into them further.
Finally, I spent a lot of time debugging issues with the mutex used in
`define_attribute_methods`. I think we can just remove that method
entirely, and define the attribute methods *manually* in the call to
`define_attribute`, which would simplify the code *tremendously*.
Ok. now to make this damn thing public, and work on moving it up to
Active Model.
2015-01-30 21:03:36 +00:00
|
|
|
assert_equal 50, OverloadedType.type_for_attribute('overloaded_string_with_limit').limit
|
|
|
|
assert_equal 255, UnoverloadedType.type_for_attribute('overloaded_string_with_limit').limit
|
2014-05-23 18:24:52 +00:00
|
|
|
end
|
|
|
|
|
2014-10-31 22:06:14 +00:00
|
|
|
test "nonexistent attribute" do
|
2014-05-23 18:24:52 +00:00
|
|
|
data = OverloadedType.new(non_existent_decimal: 1)
|
|
|
|
|
|
|
|
assert_equal BigDecimal.new(1), data.non_existent_decimal
|
2015-02-25 14:14:43 +00:00
|
|
|
assert_raise ActiveRecord::UnknownAttributeError do
|
2014-05-23 18:24:52 +00:00
|
|
|
UnoverloadedType.new(non_existent_decimal: 1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-10-31 22:06:14 +00:00
|
|
|
test "changing defaults" do
|
2014-05-23 18:24:52 +00:00
|
|
|
data = OverloadedType.new
|
|
|
|
unoverloaded_data = UnoverloadedType.new
|
|
|
|
|
2014-05-27 00:06:05 +00:00
|
|
|
assert_equal 'the overloaded default', data.string_with_default
|
|
|
|
assert_equal 'the original default', unoverloaded_data.string_with_default
|
2014-05-23 18:24:52 +00:00
|
|
|
end
|
2014-05-28 17:11:57 +00:00
|
|
|
|
2014-10-31 22:06:14 +00:00
|
|
|
test "defaults are not touched on the columns" do
|
|
|
|
assert_equal 'the original default', OverloadedType.columns_hash['string_with_default'].default
|
|
|
|
end
|
|
|
|
|
|
|
|
test "children inherit custom properties" do
|
2014-05-28 17:11:57 +00:00
|
|
|
data = ChildOfOverloadedType.new(overloaded_float: '4.4')
|
|
|
|
|
|
|
|
assert_equal 4, data.overloaded_float
|
|
|
|
end
|
|
|
|
|
2014-10-31 22:06:14 +00:00
|
|
|
test "children can override parents" do
|
2014-05-28 17:11:57 +00:00
|
|
|
data = GrandchildOfOverloadedType.new(overloaded_float: '4.4')
|
|
|
|
|
|
|
|
assert_equal 4.4, data.overloaded_float
|
|
|
|
end
|
2014-05-28 17:32:00 +00:00
|
|
|
|
Attribute assignment and type casting has nothing to do with columns
It's finally finished!!!!!!! The reason the Attributes API was kept
private in 4.2 was due to some publicly visible implementation details.
It was previously implemented by overloading `columns` and
`columns_hash`, to make them return column objects which were modified
with the attribute information.
This meant that those methods LIED! We didn't change the database
schema. We changed the attribute information on the class. That is
wrong! It should be the other way around, where schema loading just
calls the attributes API for you. And now it does!
Yes, this means that there is nothing that happens in automatic schema
loading that you couldn't manually do yourself. (There's still some
funky cases where we hit the connection adapter that I need to handle,
before we can turn off automatic schema detection entirely.)
There were a few weird test failures caused by this that had to be
fixed. The main source came from the fact that the attribute methods are
now defined in terms of `attribute_names`, which has a clause like
`return [] unless table_exists?`. I don't *think* this is an issue,
since the only place this caused failures were in a fake adapter which
didn't override `table_exists?`.
Additionally, there were a few cases where tests were failing because a
migration was run, but the model was not reloaded. I'm not sure why
these started failing from this change, I might need to clear an
additional cache in `reload_schema_from_cache`. Again, since this is not
normal usage, and it's expected that `reset_column_information` will be
called after the table is modified, I don't think it's a problem.
Still, test failures that were unrelated to the change are worrying, and
I need to dig into them further.
Finally, I spent a lot of time debugging issues with the mutex used in
`define_attribute_methods`. I think we can just remove that method
entirely, and define the attribute methods *manually* in the call to
`define_attribute`, which would simplify the code *tremendously*.
Ok. now to make this damn thing public, and work on moving it up to
Active Model.
2015-01-30 21:03:36 +00:00
|
|
|
test "overloading properties does not attribute method order" do
|
|
|
|
attribute_names = OverloadedType.attribute_names
|
|
|
|
assert_equal %w(id overloaded_float unoverloaded_float overloaded_string_with_limit string_with_default non_existent_decimal), attribute_names
|
2014-05-28 17:32:00 +00:00
|
|
|
end
|
2014-05-30 20:51:27 +00:00
|
|
|
|
2014-10-31 22:06:14 +00:00
|
|
|
test "caches are cleared" do
|
2014-05-30 20:51:27 +00:00
|
|
|
klass = Class.new(OverloadedType)
|
|
|
|
|
Attribute assignment and type casting has nothing to do with columns
It's finally finished!!!!!!! The reason the Attributes API was kept
private in 4.2 was due to some publicly visible implementation details.
It was previously implemented by overloading `columns` and
`columns_hash`, to make them return column objects which were modified
with the attribute information.
This meant that those methods LIED! We didn't change the database
schema. We changed the attribute information on the class. That is
wrong! It should be the other way around, where schema loading just
calls the attributes API for you. And now it does!
Yes, this means that there is nothing that happens in automatic schema
loading that you couldn't manually do yourself. (There's still some
funky cases where we hit the connection adapter that I need to handle,
before we can turn off automatic schema detection entirely.)
There were a few weird test failures caused by this that had to be
fixed. The main source came from the fact that the attribute methods are
now defined in terms of `attribute_names`, which has a clause like
`return [] unless table_exists?`. I don't *think* this is an issue,
since the only place this caused failures were in a fake adapter which
didn't override `table_exists?`.
Additionally, there were a few cases where tests were failing because a
migration was run, but the model was not reloaded. I'm not sure why
these started failing from this change, I might need to clear an
additional cache in `reload_schema_from_cache`. Again, since this is not
normal usage, and it's expected that `reset_column_information` will be
called after the table is modified, I don't think it's a problem.
Still, test failures that were unrelated to the change are worrying, and
I need to dig into them further.
Finally, I spent a lot of time debugging issues with the mutex used in
`define_attribute_methods`. I think we can just remove that method
entirely, and define the attribute methods *manually* in the call to
`define_attribute`, which would simplify the code *tremendously*.
Ok. now to make this damn thing public, and work on moving it up to
Active Model.
2015-01-30 21:03:36 +00:00
|
|
|
assert_equal 6, klass.attribute_types.length
|
2014-05-30 20:51:27 +00:00
|
|
|
assert_equal 6, klass.column_defaults.length
|
Attribute assignment and type casting has nothing to do with columns
It's finally finished!!!!!!! The reason the Attributes API was kept
private in 4.2 was due to some publicly visible implementation details.
It was previously implemented by overloading `columns` and
`columns_hash`, to make them return column objects which were modified
with the attribute information.
This meant that those methods LIED! We didn't change the database
schema. We changed the attribute information on the class. That is
wrong! It should be the other way around, where schema loading just
calls the attributes API for you. And now it does!
Yes, this means that there is nothing that happens in automatic schema
loading that you couldn't manually do yourself. (There's still some
funky cases where we hit the connection adapter that I need to handle,
before we can turn off automatic schema detection entirely.)
There were a few weird test failures caused by this that had to be
fixed. The main source came from the fact that the attribute methods are
now defined in terms of `attribute_names`, which has a clause like
`return [] unless table_exists?`. I don't *think* this is an issue,
since the only place this caused failures were in a fake adapter which
didn't override `table_exists?`.
Additionally, there were a few cases where tests were failing because a
migration was run, but the model was not reloaded. I'm not sure why
these started failing from this change, I might need to clear an
additional cache in `reload_schema_from_cache`. Again, since this is not
normal usage, and it's expected that `reset_column_information` will be
called after the table is modified, I don't think it's a problem.
Still, test failures that were unrelated to the change are worrying, and
I need to dig into them further.
Finally, I spent a lot of time debugging issues with the mutex used in
`define_attribute_methods`. I think we can just remove that method
entirely, and define the attribute methods *manually* in the call to
`define_attribute`, which would simplify the code *tremendously*.
Ok. now to make this damn thing public, and work on moving it up to
Active Model.
2015-01-30 21:03:36 +00:00
|
|
|
assert_not klass.attribute_types.include?('wibble')
|
2014-05-30 20:51:27 +00:00
|
|
|
|
2014-06-07 13:09:45 +00:00
|
|
|
klass.attribute :wibble, Type::Value.new
|
2014-05-30 20:51:27 +00:00
|
|
|
|
Attribute assignment and type casting has nothing to do with columns
It's finally finished!!!!!!! The reason the Attributes API was kept
private in 4.2 was due to some publicly visible implementation details.
It was previously implemented by overloading `columns` and
`columns_hash`, to make them return column objects which were modified
with the attribute information.
This meant that those methods LIED! We didn't change the database
schema. We changed the attribute information on the class. That is
wrong! It should be the other way around, where schema loading just
calls the attributes API for you. And now it does!
Yes, this means that there is nothing that happens in automatic schema
loading that you couldn't manually do yourself. (There's still some
funky cases where we hit the connection adapter that I need to handle,
before we can turn off automatic schema detection entirely.)
There were a few weird test failures caused by this that had to be
fixed. The main source came from the fact that the attribute methods are
now defined in terms of `attribute_names`, which has a clause like
`return [] unless table_exists?`. I don't *think* this is an issue,
since the only place this caused failures were in a fake adapter which
didn't override `table_exists?`.
Additionally, there were a few cases where tests were failing because a
migration was run, but the model was not reloaded. I'm not sure why
these started failing from this change, I might need to clear an
additional cache in `reload_schema_from_cache`. Again, since this is not
normal usage, and it's expected that `reset_column_information` will be
called after the table is modified, I don't think it's a problem.
Still, test failures that were unrelated to the change are worrying, and
I need to dig into them further.
Finally, I spent a lot of time debugging issues with the mutex used in
`define_attribute_methods`. I think we can just remove that method
entirely, and define the attribute methods *manually* in the call to
`define_attribute`, which would simplify the code *tremendously*.
Ok. now to make this damn thing public, and work on moving it up to
Active Model.
2015-01-30 21:03:36 +00:00
|
|
|
assert_equal 7, klass.attribute_types.length
|
2014-05-30 20:51:27 +00:00
|
|
|
assert_equal 7, klass.column_defaults.length
|
Attribute assignment and type casting has nothing to do with columns
It's finally finished!!!!!!! The reason the Attributes API was kept
private in 4.2 was due to some publicly visible implementation details.
It was previously implemented by overloading `columns` and
`columns_hash`, to make them return column objects which were modified
with the attribute information.
This meant that those methods LIED! We didn't change the database
schema. We changed the attribute information on the class. That is
wrong! It should be the other way around, where schema loading just
calls the attributes API for you. And now it does!
Yes, this means that there is nothing that happens in automatic schema
loading that you couldn't manually do yourself. (There's still some
funky cases where we hit the connection adapter that I need to handle,
before we can turn off automatic schema detection entirely.)
There were a few weird test failures caused by this that had to be
fixed. The main source came from the fact that the attribute methods are
now defined in terms of `attribute_names`, which has a clause like
`return [] unless table_exists?`. I don't *think* this is an issue,
since the only place this caused failures were in a fake adapter which
didn't override `table_exists?`.
Additionally, there were a few cases where tests were failing because a
migration was run, but the model was not reloaded. I'm not sure why
these started failing from this change, I might need to clear an
additional cache in `reload_schema_from_cache`. Again, since this is not
normal usage, and it's expected that `reset_column_information` will be
called after the table is modified, I don't think it's a problem.
Still, test failures that were unrelated to the change are worrying, and
I need to dig into them further.
Finally, I spent a lot of time debugging issues with the mutex used in
`define_attribute_methods`. I think we can just remove that method
entirely, and define the attribute methods *manually* in the call to
`define_attribute`, which would simplify the code *tremendously*.
Ok. now to make this damn thing public, and work on moving it up to
Active Model.
2015-01-30 21:03:36 +00:00
|
|
|
assert klass.attribute_types.include?('wibble')
|
|
|
|
end
|
|
|
|
|
|
|
|
test "the given default value is cast from user" do
|
|
|
|
custom_type = Class.new(Type::Value) do
|
2015-02-17 20:39:42 +00:00
|
|
|
def cast(*)
|
Attribute assignment and type casting has nothing to do with columns
It's finally finished!!!!!!! The reason the Attributes API was kept
private in 4.2 was due to some publicly visible implementation details.
It was previously implemented by overloading `columns` and
`columns_hash`, to make them return column objects which were modified
with the attribute information.
This meant that those methods LIED! We didn't change the database
schema. We changed the attribute information on the class. That is
wrong! It should be the other way around, where schema loading just
calls the attributes API for you. And now it does!
Yes, this means that there is nothing that happens in automatic schema
loading that you couldn't manually do yourself. (There's still some
funky cases where we hit the connection adapter that I need to handle,
before we can turn off automatic schema detection entirely.)
There were a few weird test failures caused by this that had to be
fixed. The main source came from the fact that the attribute methods are
now defined in terms of `attribute_names`, which has a clause like
`return [] unless table_exists?`. I don't *think* this is an issue,
since the only place this caused failures were in a fake adapter which
didn't override `table_exists?`.
Additionally, there were a few cases where tests were failing because a
migration was run, but the model was not reloaded. I'm not sure why
these started failing from this change, I might need to clear an
additional cache in `reload_schema_from_cache`. Again, since this is not
normal usage, and it's expected that `reset_column_information` will be
called after the table is modified, I don't think it's a problem.
Still, test failures that were unrelated to the change are worrying, and
I need to dig into them further.
Finally, I spent a lot of time debugging issues with the mutex used in
`define_attribute_methods`. I think we can just remove that method
entirely, and define the attribute methods *manually* in the call to
`define_attribute`, which would simplify the code *tremendously*.
Ok. now to make this damn thing public, and work on moving it up to
Active Model.
2015-01-30 21:03:36 +00:00
|
|
|
"from user"
|
|
|
|
end
|
|
|
|
|
2015-02-17 18:29:51 +00:00
|
|
|
def deserialize(*)
|
Attribute assignment and type casting has nothing to do with columns
It's finally finished!!!!!!! The reason the Attributes API was kept
private in 4.2 was due to some publicly visible implementation details.
It was previously implemented by overloading `columns` and
`columns_hash`, to make them return column objects which were modified
with the attribute information.
This meant that those methods LIED! We didn't change the database
schema. We changed the attribute information on the class. That is
wrong! It should be the other way around, where schema loading just
calls the attributes API for you. And now it does!
Yes, this means that there is nothing that happens in automatic schema
loading that you couldn't manually do yourself. (There's still some
funky cases where we hit the connection adapter that I need to handle,
before we can turn off automatic schema detection entirely.)
There were a few weird test failures caused by this that had to be
fixed. The main source came from the fact that the attribute methods are
now defined in terms of `attribute_names`, which has a clause like
`return [] unless table_exists?`. I don't *think* this is an issue,
since the only place this caused failures were in a fake adapter which
didn't override `table_exists?`.
Additionally, there were a few cases where tests were failing because a
migration was run, but the model was not reloaded. I'm not sure why
these started failing from this change, I might need to clear an
additional cache in `reload_schema_from_cache`. Again, since this is not
normal usage, and it's expected that `reset_column_information` will be
called after the table is modified, I don't think it's a problem.
Still, test failures that were unrelated to the change are worrying, and
I need to dig into them further.
Finally, I spent a lot of time debugging issues with the mutex used in
`define_attribute_methods`. I think we can just remove that method
entirely, and define the attribute methods *manually* in the call to
`define_attribute`, which would simplify the code *tremendously*.
Ok. now to make this damn thing public, and work on moving it up to
Active Model.
2015-01-30 21:03:36 +00:00
|
|
|
"from database"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
klass = Class.new(OverloadedType) do
|
|
|
|
attribute :wibble, custom_type.new, default: "default"
|
|
|
|
end
|
|
|
|
model = klass.new
|
|
|
|
|
|
|
|
assert_equal "from user", model.wibble
|
2014-05-30 20:51:27 +00:00
|
|
|
end
|
2015-02-06 18:05:38 +00:00
|
|
|
|
|
|
|
if current_adapter?(:PostgreSQLAdapter)
|
|
|
|
test "arrays types can be specified" do
|
|
|
|
klass = Class.new(OverloadedType) do
|
|
|
|
attribute :my_array, :string, limit: 50, array: true
|
|
|
|
attribute :my_int_array, :integer, array: true
|
|
|
|
end
|
|
|
|
|
|
|
|
string_array = ConnectionAdapters::PostgreSQL::OID::Array.new(
|
|
|
|
Type::String.new(limit: 50))
|
|
|
|
int_array = ConnectionAdapters::PostgreSQL::OID::Array.new(
|
|
|
|
Type::Integer.new)
|
|
|
|
refute_equal string_array, int_array
|
|
|
|
assert_equal string_array, klass.type_for_attribute("my_array")
|
|
|
|
assert_equal int_array, klass.type_for_attribute("my_int_array")
|
|
|
|
end
|
|
|
|
|
|
|
|
test "range types can be specified" do
|
|
|
|
klass = Class.new(OverloadedType) do
|
|
|
|
attribute :my_range, :string, limit: 50, range: true
|
|
|
|
attribute :my_int_range, :integer, range: true
|
|
|
|
end
|
|
|
|
|
|
|
|
string_range = ConnectionAdapters::PostgreSQL::OID::Range.new(
|
|
|
|
Type::String.new(limit: 50))
|
|
|
|
int_range = ConnectionAdapters::PostgreSQL::OID::Range.new(
|
|
|
|
Type::Integer.new)
|
|
|
|
refute_equal string_range, int_range
|
|
|
|
assert_equal string_range, klass.type_for_attribute("my_range")
|
|
|
|
assert_equal int_range, klass.type_for_attribute("my_int_range")
|
|
|
|
end
|
|
|
|
end
|
2014-05-23 18:24:52 +00:00
|
|
|
end
|
|
|
|
end
|