class PgFuncall::TypeMap

See www.postgresql.org/docs/9.4/static/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE

Constants

FMETAQUERY

Public Class Methods

fetch(connection, options = {}) click to toggle source
# File lib/pg_funcall/type_map.rb, line 38
def self.fetch(connection, options = {})
  case ActiveRecord.version.segments[0..1]
    when [4,0] then AR40TypeMap.new(connection, options)
    when [4,1] then AR41TypeMap.new(connection, options)
    when [4,2] then AR42TypeMap.new(connection, options)
    else
      raise ArgumentError, "Unsupported ActiveRecord version #{ActiveRecord.version}"
  end
end
new(connection, options = {}) click to toggle source
# File lib/pg_funcall/type_map.rb, line 49
def initialize(connection, options = {})
  @ftype_cache = {}
  @ar_connection = connection
  @options = options
  @typeinfo         = []
  @typeinfo_by_name = {}
  @typeinfo_by_oid  = {}

  load_types
end

Public Instance Methods

_canonicalize_type_name(name) click to toggle source
# File lib/pg_funcall/type_map.rb, line 96
def _canonicalize_type_name(name)
  if name.end_with?('[]')
    name = '_' + name.gsub(/(\[\])+$/, '')
  end
  name
end
ar_connection() click to toggle source
# File lib/pg_funcall/type_map.rb, line 84
def ar_connection
  @ar_connection
end
function_types(fn, search_path = @options[:search_path]) click to toggle source

Query PostgreSQL metadata about function to find its return type and argument types

# File lib/pg_funcall/type_map.rb, line 136
def function_types(fn, search_path = @options[:search_path])
  return @ftype_cache[fn] if @ftype_cache[fn]

  parts = fn.split('.')
  info =  if parts.length == 1
            raise ArgumentError, "Must supply search_path for non-namespaced function" unless
              search_path && search_path.is_a?(Enumerable) && !search_path.empty?
            search_path.map do |ns|
              res = pg_connection.query(FMETAQUERY % [parts[0], ns])
              PgFuncall._assign_pg_type_map_to_res(res, pg_connection)
              res.ntuples == 1 ? res : nil
            end.compact.first
          else
            PgFuncall._assign_pg_type_map_to_res(pg_connection.query(FMETAQUERY % [parts[1], parts[0]]),
                                                 pg_connection)
          end

  return nil unless info && info.ntuples >= 1

  @ftype_cache[fn] =
      FunctionSig.new(fn,
                      info.getvalue(0,0).to_i,
                      (0..info.ntuples-1).map { |row|
                        info.getvalue(row, 1).split(/ +/).map(&:to_i)
                      })
end
load_types() click to toggle source
# File lib/pg_funcall/type_map.rb, line 60
    def load_types
      res = pg_connection.query <<-SQL
         SELECT pgt.oid, ns.nspname, *
         FROM pg_type as pgt
         JOIN pg_namespace as ns on pgt.typnamespace = ns.oid;
      SQL

      PgFuncall._assign_pg_type_map_to_res(res, pg_connection)

      fields = res.fields
      @typeinfo = res.values.map do |values|
        row = Hash[fields.zip(values)]
        TypeInfo.new(row, lookup_ar_by_oid(row['oid'].to_i))
      end

      @typeinfo_by_name.clear
      @typeinfo_by_oid.clear

      @typeinfo.each do |ti|
        @typeinfo_by_name[ti.name] = ti
        @typeinfo_by_oid[ti.oid]   = ti
      end
    end
oid_for_type(type, array = false) click to toggle source

Given a type name, with optional appended [] or prefixed _ for array types, return the OID for it.

If array = true, find array type for given base type.

# File lib/pg_funcall/type_map.rb, line 119
def oid_for_type(type, array = false)
  type = _canonicalize_type_name(type)
  type = '_' + type if array && !type.start_with?('_')
  @typeinfo_by_name[type]
end
pg_connection() click to toggle source
# File lib/pg_funcall/type_map.rb, line 88
def pg_connection
  @ar_connection.raw_connection
end
resolve(oid_or_name) click to toggle source
# File lib/pg_funcall/type_map.rb, line 103
def resolve(oid_or_name)
  if oid_or_name.is_a?(Integer) || (oid_or_name.is_a?(String) && oid_or_name.match(/^[0-9]+$/))
    @typeinfo_by_oid[oid_or_name.to_i]
  elsif oid_or_name.is_a?(String) || oid_or_name.is_a?(Symbol)
    @typeinfo_by_name[_canonicalize_type_name(oid_or_name.to_s)]
  else
    raise ArgumentError, "You must supply a numeric OID or a string Type name"
  end
end
type_cast_from_database(value, type) click to toggle source
# File lib/pg_funcall/type_map.rb, line 92
def type_cast_from_database(value, type)
  type.cast_from_database(value)
end