diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb')
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb new file mode 100644 index 0000000000..b1dfbde86e --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +module ActiveRecord + module ConnectionAdapters + module PostgreSQL + module OID # :nodoc: + class Array < Type::Value # :nodoc: + include ActiveModel::Type::Helpers::Mutable + + Data = Struct.new(:encoder, :values) # :nodoc: + + attr_reader :subtype, :delimiter + delegate :type, :user_input_in_time_zone, :limit, :precision, :scale, to: :subtype + + def initialize(subtype, delimiter = ",") + @subtype = subtype + @delimiter = delimiter + + @pg_encoder = PG::TextEncoder::Array.new name: "#{type}[]", delimiter: delimiter + @pg_decoder = PG::TextDecoder::Array.new name: "#{type}[]", delimiter: delimiter + end + + def deserialize(value) + case value + when ::String + type_cast_array(@pg_decoder.decode(value), :deserialize) + when Data + type_cast_array(value.values, :deserialize) + else + super + end + end + + def cast(value) + if value.is_a?(::String) + value = begin + @pg_decoder.decode(value) + rescue TypeError + # malformed array string is treated as [], will raise in PG 2.0 gem + # this keeps a consistent implementation + [] + end + end + type_cast_array(value, :cast) + end + + def serialize(value) + if value.is_a?(::Array) + casted_values = type_cast_array(value, :serialize) + Data.new(@pg_encoder, casted_values) + else + super + end + end + + def ==(other) + other.is_a?(Array) && + subtype == other.subtype && + delimiter == other.delimiter + end + + def type_cast_for_schema(value) + return super unless value.is_a?(::Array) + "[" + value.map { |v| subtype.type_cast_for_schema(v) }.join(", ") + "]" + end + + def map(value, &block) + value.map(&block) + end + + def changed_in_place?(raw_old_value, new_value) + deserialize(raw_old_value) != new_value + end + + def force_equality?(value) + value.is_a?(::Array) + end + + private + + def type_cast_array(value, method) + if value.is_a?(::Array) + value.map { |item| type_cast_array(item, method) } + else + @subtype.public_send(method, value) + end + end + end + end + end + end +end |