# frozen_string_literal: true module Torque module PostgreSQL class GeometryBuilder < ActiveModel::Type::Value DESTRUCTOR = /[<>{}()]/.freeze NUMBER_SERIALIZER = ->(num) { num.to_s.gsub(/\.0$/, '') } def type return self.class.const_get('TYPE') if self.class.const_defined?('TYPE') self.class.const_set('TYPE', self.class.name.demodulize.underscore.to_sym) end def pieces self.class.const_get('PIECES') end def formation self.class.const_get('FORMATION') end def cast(value) case value when ::String return if value.blank? value.gsub!(DESTRUCTOR, '') build_klass(*value.split(',')) when ::Hash build_klass(*value.symbolize_keys.slice(*pieces).values) when ::Array build_klass(*(value.flatten)) else value end end def serialize(value) parts = case value when config_class pieces.map { |piece| value.public_send(piece) } when ::Hash value.symbolize_keys.slice(*pieces).values when ::Array value.flatten end parts = parts&.compact&.flatten return if parts.blank? raise 'Invalid format' if parts.size < pieces.size format(formation, *parts.first(pieces.size).map(&number_serializer)) end def deserialize(value) build_klass(*value.gsub(DESTRUCTOR, '').split(',')) unless value.nil? end def type_cast_for_schema(value) if config_class === value pieces.map { |piece| value.public_send(piece) } else super end end def changed_in_place?(raw_old_value, new_value) raw_old_value != serialize(new_value) end protected def number_serializer self.class.const_get('NUMBER_SERIALIZER') end def config_class Torque::PostgreSQL.config.geometry.public_send("#{type}_class") end def build_klass(*args) return nil if args.empty? check_invalid_format!(args) config_class.new(*args.try(:first, pieces.size)&.map(&:to_f)) end def check_invalid_format!(args) raise 'Invalid format' if args.size < pieces.size end end end end