diff options
author | Thomas Cannon <tcannon00@gmail.com> | 2017-09-26 10:37:32 -0400 |
---|---|---|
committer | Thomas Cannon <tcannon00@gmail.com> | 2017-09-26 20:04:36 -0400 |
commit | 51b6c3429f41ebbc571b8fcbe7c21d3131b832d8 (patch) | |
tree | 287cf94ccee0a1d626fe2525f94405bdd3b5c506 /activesupport/test/multibyte_conformance_test.rb | |
parent | 40a63e52d275a94227761f79b4a2544aaad8210a (diff) | |
download | rails-51b6c3429f41ebbc571b8fcbe7c21d3131b832d8.tar.gz rails-51b6c3429f41ebbc571b8fcbe7c21d3131b832d8.tar.bz2 rails-51b6c3429f41ebbc571b8fcbe7c21d3131b832d8.zip |
`Postgres::OID::Range` serializes to a `Range`, quote in `Quoting`
PostgreSQL 9.1+ introduced range types, and Rails added support for
using this datatype in ActiveRecord. However, the serialization of
`PostgreSQL::OID::Range` was incomplete, because it did not properly
quote the bounds that make up the range. A clear example of this is a
`tsrange`.
Normally, ActiveRecord quotes Date/Time objects to include the
milliseconds. However, the way `PostgreSQL::OID::Range` serialized its
bounds, the milliseconds were dropped. This meant that the value was
incomplete and not equal to the submitted value.
An example of normal timestamps vs. a `tsrange`. Note how the bounds
for the range do not include their milliseconds (they were present in
the ruby Range):
UPDATE "iterations" SET "updated_at" = $1, "range" = $2 WHERE
"iterations"."id" = $3
[["updated_at", "2017-09-23 17:07:01.304864"],
["range", "[2017-09-23 00:00:00 UTC,2017-09-23 23:59:59 UTC]"],
["id", 1234]]
`PostgreSQL::OID::Range` serialized the range by interpolating a
string for the range, which works for most cases, but does not work
for timestamps:
def serialize(value)
if value.is_a?(::Range)
from = type_cast_single_for_database(value.begin)
to = type_cast_single_for_database(value.end)
"[#{from},#{to}#{value.exclude_end? ? ')' : ']'}"
else
super
end
end
(byebug) from = type_cast_single_for_database(value.begin)
2010-01-01 13:30:00 UTC
(byebug) to = type_cast_single_for_database(value.end)
2011-02-02 19:30:00 UTC
(byebug) "[#{from},#{to}#{value.exclude_end? ? ')' : ']'}"
"[2010-01-01 13:30:00 UTC,2011-02-02 19:30:00 UTC)"
@sgrif (the original implementer for Postgres Range support) provided
some feedback about where the quoting should occur:
Yeah, quoting at all is definitely wrong here. I'm not sure what I
was thinking in 02579b5, but what this is doing is definitely in the
wrong place. It should probably just be returning a range of
subtype.serialize(value.begin) and subtype.serialize(value.end), and
letting the adapter handle the rest.
`Postgres::OID::Range` now returns a `Range` object, and
`ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting` can now encode
and quote a `Range`:
def encode_range(range)
"[#{type_cast(range.first)},#{type_cast(range.last)}#{range.exclude_end? ? ')' : ']'}"
end
...
encode_range(range)
#=> "['2010-01-01 13:30:00.670277','2011-02-02 19:30:00.745125')"
This commit includes tests to make sure the milliseconds are
preserved in `tsrange` and `tstzrange` columns
Diffstat (limited to 'activesupport/test/multibyte_conformance_test.rb')
0 files changed, 0 insertions, 0 deletions