From 0f1d0b1b5254e3678abaabbebb3362a100c10262 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Tue, 3 Jan 2017 11:15:16 -0500
Subject: Consistently apply adapter behavior when serializing arrays

In f1a0fa9 we moved backend specific timestamp behavior out of the type
and into the adapter. This was in line with our general attempt to
reduce the number of adapter specific type subclasses. However, on PG,
the array type performs all serialization, including database encoding
in its serialize method.

This means that we have converted the value into a string before
reaching the database, so no adapter specific logic can be applied (and
this also means that timestamp arrays were using the default `.to_s`
method on the given object, which likely meant timestamps were being
ignored in certain cases as well)

Ultimately I want to do a more in depth refactoring which separates
database serializer objects from the active model type objects, to give
us a less awkward API for introducing the attributes API onto Active
Model.

However, in the short term, we follow the solution we've applied
elsewhere for this. Move behavior off of the type and into the adapter,
and use a data object to allow the type to communicate information up
the stack.

Fixes #27514.
---
 .../test/cases/adapters/postgresql/array_test.rb        | 17 ++++++++++++++---
 .../test/cases/adapters/postgresql/type_lookup_test.rb  |  2 +-
 2 files changed, 15 insertions(+), 4 deletions(-)

(limited to 'activerecord/test')

diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index 982a91782f..c78c6178ff 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -21,6 +21,7 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
         t.datetime :datetimes, array: true
         t.hstore :hstores, array: true
         t.decimal :decimals, array: true, default: [], precision: 10, scale: 2
+        t.timestamp :timestamps, array: true, default: [], precision: 6
       end
     end
     PgArray.reset_column_information
@@ -213,7 +214,7 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
     x = PgArray.create!(tags: tags)
     x.reload
 
-    assert_equal x.tags_before_type_cast, PgArray.type_for_attribute("tags").serialize(tags)
+    refute x.changed?
   end
 
   def test_quoting_non_standard_delimiters
@@ -221,9 +222,10 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
     oid = ActiveRecord::ConnectionAdapters::PostgreSQL::OID
     comma_delim = oid::Array.new(ActiveRecord::Type::String.new, ",")
     semicolon_delim = oid::Array.new(ActiveRecord::Type::String.new, ";")
+    conn = PgArray.connection
 
-    assert_equal %({"hello,",world;}), comma_delim.serialize(strings)
-    assert_equal %({hello,;"world;"}), semicolon_delim.serialize(strings)
+    assert_equal %({"hello,",world;}), conn.type_cast(comma_delim.serialize(strings))
+    assert_equal %({hello,;"world;"}), conn.type_cast(semicolon_delim.serialize(strings))
   end
 
   def test_mutate_array
@@ -319,6 +321,15 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
     assert_equal [arrays_of_utf8_strings], @type.deserialize(@type.serialize([arrays_of_utf8_strings]))
   end
 
+  def test_precision_is_respected_on_timestamp_columns
+    time = Time.now.change(usec: 123)
+    record = PgArray.create!(timestamps: [time])
+
+    assert_equal 123, record.timestamps.first.usec
+    record.reload
+    assert_equal 123, record.timestamps.first.usec
+  end
+
   private
     def assert_cycle(field, array)
       # test creation
diff --git a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb
index bd45a9daa0..784d77a8d1 100644
--- a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb
@@ -19,7 +19,7 @@ class PostgresqlTypeLookupTest < ActiveRecord::PostgreSQLTestCase
     big_array = [123456789123456789]
 
     assert_raises(ActiveModel::RangeError) { int_array.serialize(big_array) }
-    assert_equal "{123456789123456789}", bigint_array.serialize(big_array)
+    assert_equal "{123456789123456789}", @connection.type_cast(bigint_array.serialize(big_array))
   end
 
   test "range types correctly respect registration of subtypes" do
-- 
cgit v1.2.3