# frozen_string_literal: true module ROM module SQL module Postgres class TypeBuilder < Schema::TypeBuilder defines :db_numeric_types, :db_type_mapping, :db_array_type_matcher db_numeric_types ["smallint", "integer", "bigint", "decimal", "numeric", "real", "double precision", "serial", "bigserial"].to_set.freeze db_type_mapping( "uuid" => Types::UUID, "money" => Types::Money, "bytea" => Types::Bytea, "json" => Types::JSON, "jsonb" => Types::JSONB, "xml" => Types::XML, "inet" => Types::IPAddress, "cidr" => Types::IPAddress, "macaddr" => SQL::Types::String, "point" => Types::Point, "hstore" => Types::HStore, "line" => Types::Line, "circle" => Types::Circle, "box" => Types::Box, "lseg" => Types::LineSegment, "polygon" => Types::Polygon, "path" => Types::Path, "int4range" => Types::Int4Range, "int8range" => Types::Int8Range, "numrange" => Types::NumRange, "tsrange" => Types::TsRange, "tstzrange" => Types::TsTzRange, "daterange" => Types::DateRange, "ltree" => Types::LTree ).freeze db_array_type_matcher "[]" def map_pk_type(type, db_type, **options) if numeric?(type, db_type) type = self.class.numeric_pk_type else type = map_type(type, db_type, **options) end type.meta(primary_key: true) end def map_type(ruby_type, db_type, enum_values: nil, **_) if db_type.end_with?(self.class.db_array_type_matcher) member_name = db_type[0...-2] member_type = self.class.db_type_mapping[member_name] Types::Array(member_name, member_type) elsif enum_values SQL::Types::String.enum(*enum_values) else map_db_type(db_type) || super end end def map_db_type(db_type) self.class.db_type_mapping[db_type] || (db_type.start_with?("timestamp") ? SQL::Types::Time : nil) end def numeric?(ruby_type, db_type) self.class.db_numeric_types.include?(db_type) || ruby_type == :integer end end end Schema::TypeBuilder.register(:postgres, Postgres::TypeBuilder.new.freeze) end end