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

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
Line =
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
Circle =
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
Box =
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
LineSegment =
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
Polygon =
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
Path =
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

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