Add support for ActiveRecord::Point type casts using hash values

This allows ActiveRecord::Point to be cast or serialized from a hash
with :x and :y keys of numeric values, mirroring the functionality
of existing casts for string and array values. Both string and symbol
keys are supported.
This commit is contained in:
Stephen Drew 2022-04-04 19:25:52 +00:00 committed by Stephen Drew
parent d8d5554f08
commit 1823d4ab7a
3 changed files with 41 additions and 0 deletions

View File

@ -1,3 +1,27 @@
* Add support for `ActiveRecord::Point` type casts using `Hash` values
This allows `ActiveRecord::Point` to be cast or serialized from a hash
with `:x` and `:y` keys of numeric values, mirroring the functionality of
existing casts for string and array values. Both string and symbol keys are
supported.
```ruby
class PostgresqlPoint < ActiveRecord::Base
attribute :x, :point
attribute :y, :point
attribute :z, :point
end
val = PostgresqlPoint.new({
x: '(12.34, -43.21)',
y: [12.34, '-43.21'],
z: {x: '12.34', y: -43.21}
})
ActiveRecord::Point.new(12.32, -43.21) == val.x == val.y == val.z
```
*Stephen Drew*
* Replace `SQLite3::Database#busy_timeout` with `#busy_handler_timeout=`.
Provides a non-GVL-blocking, fair retry interval busy handler implementation.

View File

@ -25,6 +25,10 @@ module ActiveRecord
build_point(x, y)
when ::Array
build_point(*value)
when ::Hash
return if value.blank?
build_point(*values_array_from_hash(value))
else
value
end
@ -36,6 +40,8 @@ module ActiveRecord
"(#{number_for_point(value.x)},#{number_for_point(value.y)})"
when ::Array
serialize(build_point(*value))
when ::Hash
serialize(build_point(*values_array_from_hash(value)))
else
super
end
@ -57,6 +63,10 @@ module ActiveRecord
def build_point(x, y)
ActiveRecord::Point.new(Float(x), Float(y))
end
def values_array_from_hash(value)
[value.values_at(:x, "x").compact.first, value.values_at(:y, "y").compact.first]
end
end
end
end

View File

@ -88,6 +88,13 @@ class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase
assert_equal ActiveRecord::Point.new(1, 2), p.x
end
def test_hash_assignment
p = PostgresqlPoint.new(x: { x: 1, y: 2 }, y: { "x" => 3, "y" => 4 })
assert_equal ActiveRecord::Point.new(1, 2), p.x
assert_equal ActiveRecord::Point.new(3, 4), p.y
end
def test_string_assignment
p = PostgresqlPoint.new(x: "(1, 2)")