Class: PgFuncall::TypeMap
- Inherits:
-
Object
- Object
- PgFuncall::TypeMap
show all
- Defined in:
- lib/pg_funcall/type_map.rb
Overview
Constant Summary
collapse
- FMETAQUERY =
<<-"SQL"
SELECT prorettype, proargtypes
FROM pg_proc as pgp
JOIN pg_namespace as ns on pgp.pronamespace = ns.oid
WHERE proname = '%s' AND ns.nspname = '%s';
SQL
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(connection, options = {}) ⇒ TypeMap
Returns a new instance of TypeMap.
49
50
51
52
53
54
55
56
57
58
|
# 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
|
Class Method Details
.fetch(connection, options = {}) ⇒ Object
38
39
40
41
42
43
44
45
46
|
# 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
|
Instance Method Details
#_canonicalize_type_name(name) ⇒ Object
96
97
98
99
100
101
|
# 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 ⇒ Object
84
85
86
|
# File 'lib/pg_funcall/type_map.rb', line 84
def ar_connection
@ar_connection
end
|
#function_types(fn, search_path = ) ⇒ Object
Query PostgreSQL metadata about function to find its return type and argument types
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
# 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 ⇒ Object
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
# 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) ⇒ Object
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.
119
120
121
122
123
|
# 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 ⇒ Object
88
89
90
|
# File 'lib/pg_funcall/type_map.rb', line 88
def pg_connection
@ar_connection.raw_connection
end
|
#resolve(oid_or_name) ⇒ Object
103
104
105
106
107
108
109
110
111
|
# 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) ⇒ Object
92
93
94
|
# File 'lib/pg_funcall/type_map.rb', line 92
def type_cast_from_database(value, type)
type.cast_from_database(value)
end
|