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

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
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
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.



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

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.



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

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.



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

def self.range(name, read_type)
  Type(name) do
    type = SQL::Types.Definition(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.



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

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



11
12
13
# File 'lib/rom/sql/extensions/postgres/types.rb', line 11

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