From 2c98042440e17fae363457ac25e0d3466830ddd4 Mon Sep 17 00:00:00 2001 From: fatkodima Date: Sun, 5 Nov 2023 23:42:53 +0200 Subject: [PATCH] Fix PostgreSQL `Uuid#change?` to ignore uuid's value formatting --- .../connection_adapters/postgresql/oid/uuid.rb | 18 ++++++++++++++---- .../cases/adapters/postgresql/uuid_test.rb | 5 ++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb index 78f05429d8..6f81917e31 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb @@ -6,6 +6,7 @@ module PostgreSQL module OID # :nodoc: class Uuid < Type::Value # :nodoc: ACCEPTABLE_UUID = %r{\A(\{)?([a-fA-F0-9]{4}-?){8}(?(1)\}|)\z} + CANONICAL_UUID = %r{\A[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}\z} alias :serialize :deserialize @@ -15,18 +16,27 @@ def type def changed?(old_value, new_value, _new_value_before_type_cast) old_value.class != new_value.class || - new_value && old_value.casecmp(new_value) != 0 + new_value != old_value end def changed_in_place?(raw_old_value, new_value) raw_old_value.class != new_value.class || - new_value && raw_old_value.casecmp(new_value) != 0 + new_value != raw_old_value end private def cast_value(value) - casted = value.to_s - casted if casted.match?(ACCEPTABLE_UUID) + value = value.to_s + format_uuid(value) if value.match?(ACCEPTABLE_UUID) + end + + def format_uuid(uuid) + if uuid.match?(CANONICAL_UUID) + uuid + else + uuid = uuid.delete("{}-").downcase + "#{uuid[..7]}-#{uuid[8..11]}-#{uuid[12..15]}-#{uuid[16..19]}-#{uuid[20..]}" + end end end end diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb index d62dad1a69..f7b3d6e85e 100644 --- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -121,10 +121,13 @@ def test_invalid_uuid_dont_match_to_nil assert_empty UUIDType.where(guid: "foobar") end - def test_uuid_change_case_does_not_mark_dirty + def test_uuid_change_format_does_not_mark_dirty model = UUIDType.create!(guid: "abcd-0123-4567-89ef-dead-beef-0101-1010") model.guid = model.guid.swapcase assert_not_predicate model, :changed? + + model.guid = "{#{model.guid}}" + assert_not_predicate model, :changed? end class DuckUUID