Module: ROM::SQL::Postgres::Types

Defined in:
lib/rom/sql/extensions/postgres/types/ltree.rb,
lib/rom/sql/extensions/postgres/types.rb,
lib/rom/sql/extensions/postgres/types/json.rb,
lib/rom/sql/extensions/postgres/types/array.rb,
lib/rom/sql/extensions/postgres/types/range.rb,
lib/rom/sql/extensions/postgres/types/network.rb,
lib/rom/sql/extensions/postgres/types/geometric.rb,
lib/rom/sql/extensions/postgres/types/array_types.rb

Defined Under Namespace

Modules: ArrayMethods, JSONMethods, LTreeMethods, RangeFunctions, RangeOperators Classes: ArrayTypes, JSONNullType

Constant Summary collapse

UUID =
Type('uuid', SQL::Types::String)
HStore =
Type('hstore') do
  read = SQL::Types.Constructor(Hash, &:to_hash)

  SQL::Types.Constructor(Hash, &Sequel.method(:hstore))
    .meta(read: read)
end
Bytea =
Type('bytea') do
  SQL::Types.Constructor(Sequel::SQL::Blob, &Sequel::SQL::Blob.method(:new))
end
Money =
Type('money', SQL::Types::Decimal)
XML =
Type('xml', SQL::Types::String)
JSONRead =
(SQL::Types::Array | SQL::Types::Hash).constructor do |value|
  if value.respond_to?(:to_hash)
    value.to_hash
  elsif value.respond_to?(:to_ary)
    value.to_ary
  else
    value
  end
end
JSONNull =
JSONNullType.instance.freeze
JSON =
Type('json') do
  (SQL::Types::Array | SQL::Types::Hash).constructor(Sequel.method(:pg_json)).meta(read: JSONRead)
end
JSONB =
Type('jsonb') do
  (SQL::Types::Array | SQL::Types::Hash).constructor(Sequel.method(:pg_jsonb)).meta(read: JSONRead)
end
Array =
SQL::Types::Array
ArrayRead =
Array.constructor { |v| v.respond_to?(:to_ary) ? v.to_ary : v }
LTree =
Type('ltree') do
  SQL::Types.define(ROM::Types::Values::TreePath) do
    input do |label_path|
      label_path.to_s
    end

    output do |label_path|
      ROM::Types::Values::TreePath.new(label_path.to_s) if label_path
    end
  end
end
Int4Range =
range('int4range', range_read_type(:int4range))
Int8Range =
range('int8range', range_read_type(:int8range))
NumRange =
range('numrange',  range_read_type(:numrange))
TsRange =
range('tsrange',   range_read_type(:tsrange))
TsTzRange =
range('tstzrange', range_read_type(:tstzrange))
DateRange =
range('daterange', range_read_type(:daterange))
IPAddress =
Type('inet') do
  read = SQL::Types.Constructor(IPAddr) { |ip| ::IPAddr.new(ip.to_s) }

  SQL::Types.Constructor(::IPAddr, &:to_s).meta(read: read)
end
IPNetwork =
Type('cidr') do
  read = SQL::Types.Constructor(IPAddr) do |ip|
    case ip
    when ::IPAddr
      ip
    when String
      ::IPAddr.new(ip)
    end
  end

  SQL::Types.Constructor(::IPAddr) { |ip| "#{ip}/#{ip.prefix}" }.meta(read: read)
end
Point =

The list of geometric data types supported by PostgreSQL

Type('point') do
  SQL::Types.define(Values::Point) do
    input do |point|
      "(#{ point.x },#{ point.y })"
    end

    output do |point|
      x, y = point.to_s[1...-1].split(',', 2)
      Values::Point.new(Float(x), Float(y))
    end
  end
end
Line =
Type('line') do
  SQL::Types.define(Values::Line) do
    input do |line|
      "{#{ line.a },#{ line.b },#{line.c}}"
    end

    output do |line|
      a, b, c = line.to_s[1..-2].split(',', 3)
      Values::Line.new(Float(a), Float(b), Float(c))
    end
  end
end
Circle =
Type('circle') do
  SQL::Types.define(Values::Circle) do
    input do |circle|
      "<(#{ circle.center.x },#{ circle.center.y }),#{ circle.radius }>"
    end

    output do |circle|
      x, y, r = circle.to_s.tr('()<>', '').split(',', 3)
      center = Values::Point.new(Float(x), Float(y))
      Values::Circle.new(center, Float(r))
    end
  end
end
Box =
Type('box') do
  SQL::Types.define(Values::Box) do
    input do |box|
      "((#{ box.upper_right.x },#{ box.upper_right.y }),"\
      "(#{ box.lower_left.x },#{ box.lower_left.y }))"
    end

    output do |box|
      x_right, y_right, x_left, y_left = box.to_s.tr('()', '').split(',', 4)
      upper_right = Values::Point.new(Float(x_right), Float(y_right))
      lower_left = Values::Point.new(Float(x_left), Float(y_left))
      Values::Box.new(upper_right, lower_left)
    end
  end
end
LineSegment =
Type('lseg') do
  SQL::Types.define(Values::LineSegment) do
    input do |segment|
      "[(#{ segment.begin.x },#{ segment.begin.y }),"\
      "(#{ segment.end.x },#{ segment.end.y })]"
    end

    output do |segment|
      x_begin, y_begin, x_end, y_end = segment.to_s.tr('()[]', '').split(',', 4)
      point_begin = Values::Point.new(Float(x_begin), Float(y_begin))
      point_end = Values::Point.new(Float(x_end), Float(y_end))
      Values::LineSegment.new(point_begin, point_end)
    end
  end
end
Polygon =
Type('polygon') do
  SQL::Types.define(::Array) do
    input do |points|
      points_joined = points.map { |p| "(#{ p.x },#{ p.y })" }.join(',')
      "(#{ points_joined })"
    end

    output do |polygon|
      coordinates = polygon.to_s.tr('()', '').split(',').each_slice(2)
      coordinates.map { |x, y| Values::Point.new(Float(x), Float(y)) }
    end
  end
end
Path =
Type('path') do
  SQL::Types.define(Values::Path) do
    input do |path|
      points_joined = path.to_a.map { |p| "(#{ p.x },#{ p.y })" }.join(',')

      if path.open?
        "[#{ points_joined }]"
      else
        "(#{ points_joined })"
      end
    end

    output do |path|
      open = path.to_s.start_with?('[') && path.to_s.end_with?(']')
      coordinates = path.to_s.tr('()[]', '').split(',').each_slice(2)
      points = coordinates.map { |x, y| Values::Point.new(Float(x), Float(y)) }

      if open
        Values::Path.new(points, :open)
      else
        Values::Path.new(points, :closed)
      end
    end
  end
end

Class Method Summary collapse

Class Method Details

.Array(db_type, member_type = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



23
24
25
# File 'lib/rom/sql/extensions/postgres/types/array.rb', line 23

def self.Array(db_type, member_type = nil)
  array_types[db_type, member_type]
end

.array_typesObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



18
19
20
# File 'lib/rom/sql/extensions/postgres/types/array.rb', line 18

def self.array_types
  @array_types ||= ArrayTypes.new(Postgres::Types::Array, Postgres::Types::ArrayRead)
end

.range(name, read_type) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/rom/sql/extensions/postgres/types/range.rb', line 78

def self.range(name, read_type)
  Type(name) do
    type = SQL::Types.Nominal(Values::Range).constructor do |range|
      format('%s%s,%s%s',
             range.exclude_begin? ? :'(' : :'[',
             range.lower,
             range.upper,
             range.exclude_end? ? :')' : :']')
    end

    type.meta(read: read_type)
  end
end

.range_read_type(name) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/rom/sql/extensions/postgres/types/range.rb', line 56

def self.range_read_type(name)
  SQL::Types.Constructor(Values::Range) do |value|
    pg_range =
      if value.is_a?(Sequel::Postgres::PGRange)
        value
      elsif value && value.respond_to?(:to_s)
        @range_parsers[name].(value.to_s)
      else
        value
      end

    Values::Range.new(
      pg_range.begin,
      pg_range.end,
      [pg_range.exclude_begin? ? :'(' : :'[',
       pg_range.exclude_end? ? :')' : :']']
      .join('').to_sym
    )
  end
end

.Type(name, type = yield)) ⇒ Object



13
14
15
# File 'lib/rom/sql/extensions/postgres/types.rb', line 13

def self.Type(name, type = yield)
  type.meta(db_type: name, database: 'postgres')
end