aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
diff options
context:
space:
mode:
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.rb92
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