Class: PgFuncall
- Inherits:
-
Object
show all
- Extended by:
- HelperMethods
- Defined in:
- lib/pg_funcall.rb,
lib/pg_funcall/version.rb,
lib/pg_funcall/type_map.rb,
lib/pg_funcall/type_info.rb
Defined Under Namespace
Modules: HelperMethods, PGReadable, PGTyped, PGWritable
Classes: AR40TypeMap, AR41TypeMap, AR42TypeMap, FunctionSig, Literal, PGTime, PGTimeInterval, PGUUID, PgType, TypeInfo, TypeMap, Typed, TypedArray
Constant Summary
collapse
- VERSION =
"0.1.1"
Class Method Summary
collapse
Instance Method Summary
collapse
-
#_ar_conn ⇒ Object
-
#_cast_pgresult(res) ⇒ Object
Take a PGResult and cast the first column of each tuple to the Ruby equivalent of the PG type as described in the PGResult.
-
#_format_param_for_descriptor(param, type = nil) ⇒ Object
Represent a Ruby object in a string form to be passed as a parameter within a descriptor hash, rather than substituted into a string-form query.
-
#_pg_conn ⇒ Object
-
#_pg_param_descriptors(params) ⇒ Object
-
#_pgtype_for_value(value) ⇒ Object
-
#_quote_param(param, type = nil) ⇒ Object
“Quote”, which means to format and quote, a parameter for inclusion into a SQL query as a string.
-
#call_cast(fn, *args) ⇒ Object
(also: #call)
-
#call_raw_inline(fn, *args) ⇒ Object
(also: #call_raw)
-
#call_raw_pg(fn, *args, &blk) ⇒ Object
-
#call_returning_array(fn, *args) ⇒ Object
-
#call_returning_type(fn, ret_type, *args) ⇒ Object
Force a typecast of the return value.
-
#call_uncast(fn, *args) ⇒ Object
(also: #call_scalar)
Calls Database function with a given set of arguments.
-
#casting_query(query, params) ⇒ Object
-
#clear_cache ⇒ Object
-
#initialize(connection) ⇒ PgFuncall
constructor
A new instance of PgFuncall.
-
#search_path ⇒ Object
Return an array of schema names for the current session’s search path.
-
#type_for_name(name) ⇒ Object
-
#type_for_typeid(typeid) ⇒ Object
-
#type_map ⇒ Object
Constructor Details
#initialize(connection) ⇒ PgFuncall
Returns a new instance of PgFuncall.
30
31
32
33
34
35
36
37
|
# File 'lib/pg_funcall.rb', line 30
def initialize(connection)
raise ArgumentError, "Requires ActiveRecord PG connection" unless
connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
@ar_connection = connection
clear_cache
end
|
Class Method Details
._assign_pg_type_map_to_res(res, conn) ⇒ Object
245
246
247
248
249
250
251
252
253
254
|
# File 'lib/pg_funcall.rb', line 245
def self._assign_pg_type_map_to_res(res, conn)
return res
end
|
.default_instance ⇒ Object
22
23
24
|
# File 'lib/pg_funcall.rb', line 22
def self.default_instance
@default_instance ||= PgFuncall.new(ActiveRecord::Base.connection)
end
|
.default_instance=(instance) ⇒ Object
26
27
28
|
# File 'lib/pg_funcall.rb', line 26
def self.default_instance=(instance)
@default_instance = instance
end
|
.literal(arg) ⇒ Object
wrap a value so that it is inserted into the query as-is
119
120
121
|
# File 'lib/pg_funcall.rb', line 119
def self.literal(arg)
Literal.new(arg)
end
|
.tag_pg_type(value, tagtype, pgvalue = nil) ⇒ Object
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
# File 'lib/pg_funcall.rb', line 98
def self.tag_pg_type(value, tagtype, pgvalue = nil)
pgvalue ||= value
value.class_eval do
include PGTyped
define_method(:__pg_value, lambda do
pgvalue
end)
define_method(:__pg_type, lambda do
tagtype
end)
end
value
end
|
Instance Method Details
#_ar_conn ⇒ Object
371
372
373
|
# File 'lib/pg_funcall.rb', line 371
def _ar_conn
@ar_connection
end
|
#_cast_pgresult(res) ⇒ Object
Take a PGResult and cast the first column of each tuple to the Ruby equivalent of the PG type as described in the PGResult.
260
261
262
263
264
265
266
|
# File 'lib/pg_funcall.rb', line 260
def _cast_pgresult(res)
PgFuncall._assign_pg_type_map_to_res(res, _pg_conn)
res.column_values(0).map do |val|
type_map.type_cast_from_database(val,
type_for_typeid(res.ftype(0)))
end
end
|
Represent a Ruby object in a string form to be passed as a parameter within a descriptor hash, rather than substituted into a string-form query.
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
# File 'lib/pg_funcall.rb', line 161
def _format_param_for_descriptor(param, type=nil)
return param.value if param.is_a?(Literal)
case param
when TypedArray
_format_param_for_descriptor(param.value, param.type + "[]")
when Typed
_format_param_for_descriptor(param.value, param.type)
when PGTyped
param.respond_to?(:__pg_value) ?
param.__pg_value :
_format_param_for_descriptor(param, type)
when TrueClass
'true'
when FalseClass
'false'
when String
if type == 'bytea' || param.encoding == Encoding::BINARY
'\x' + param.unpack('C*').map {|x| sprintf("%02X", x)}.join("")
else
param
end
when Array
"{" + param.map {|p| _format_param_for_descriptor(p)}.join(",") + "}"
when IPAddr
param.to_cidr_string
when Range
last_char = param.exclude_end? ? ')' : ']'
case type
when 'tsrange', 'tstzrange'
"[#{param.first.utc},#{param.last.utc}#{last_char}"
else
"[#{param.first},#{param.last}#{last_char}"
end
when Set
_format_param_for_descriptor(param.to_a)
when Hash
param.map do |k,v|
"#{k} => #{v}"
end.join(',')
else
ActiveRecord::Base.connection.quote(param)
end
end
|
#_pg_conn ⇒ Object
375
376
377
|
# File 'lib/pg_funcall.rb', line 375
def _pg_conn
_ar_conn.raw_connection
end
|
#_pg_param_descriptors(params) ⇒ Object
281
282
283
284
285
286
287
288
289
290
291
292
293
|
# File 'lib/pg_funcall.rb', line 281
def _pg_param_descriptors(params)
params.map do |p|
pgtype = _pgtype_for_value(p)
typeinfo = type_map.resolve(pgtype)
{
value: _format_param_for_descriptor(p, pgtype),
type: (typeinfo && typeinfo.oid) || 0,
format: 0
}
end
end
|
#_pgtype_for_value(value) ⇒ Object
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
|
# File 'lib/pg_funcall.rb', line 303
def _pgtype_for_value(value)
case value
when TypedArray
value.type + '[]'
when Typed
value.type
when PGTyped
value.__pg_type
when String
if value.encoding == Encoding::BINARY
'bytea'
else
'text'
end
when Fixnum, Bignum
'int4'
when Float
'float4'
when TrueClass, FalseClass
'bool'
when BigDecimal
'numeric'
when Hash
'hstore'
when UUID
'uuid'
when Time, DateTime
'timestamp'
when Date
'date'
when IPAddr
if value.host?
'inet'
else
'cidr'
end
when Range
case value.last
when Fixnum
if value.last > (2**31)-1
'int8range'
else
'int4range'
end
when Bignum then 'int8range'
when DateTime, Time then 'tsrange'
when Date then 'daterange'
when Float, BigDecimal, Numeric then 'numrange'
else
raise "Unknown range type: #{value.first.type}"
end
when Array, Set
first = value.flatten.first
raise "Empty untyped array" if first.nil?
_pgtype_for_value(first) + '[]'
else
'text'
end
end
|
#_quote_param(param, type = nil) ⇒ Object
“Quote”, which means to format and quote, a parameter for inclusion into a SQL query as a string.
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
# File 'lib/pg_funcall.rb', line 139
def _quote_param(param, type=nil)
return param.value if param.is_a?(Literal)
case param
when Array
"ARRAY[" + param.map {|p| _quote_param(p)}.join(",") + "]"
when Set
_quote_param(param.to_a)
when Hash
'$$' + param.map do |k,v|
"#{k} => #{v}"
end.join(',') + '$$::hstore'
else
ActiveRecord::Base.connection.quote(param)
end
end
|
#call_cast(fn, *args) ⇒ Object
Also known as:
call
268
269
270
271
272
273
274
275
276
277
278
279
|
# File 'lib/pg_funcall.rb', line 268
def call_cast(fn, *args)
fn_sig = type_map.function_types(fn)
call_raw_pg(fn, *args) do |res|
results = _cast_pgresult(res)
results.first
end
end
|
#call_raw_inline(fn, *args) ⇒ Object
Also known as:
call_raw
206
207
208
209
210
211
212
|
# File 'lib/pg_funcall.rb', line 206
def call_raw_inline(fn, *args)
query = "SELECT #{fn}(" +
args.map {|arg| _quote_param(arg) }.join(", ") + ") as res;"
ActiveRecord::Base.connection.exec_query(query,
"calling for DB function #{fn}")
end
|
#call_raw_pg(fn, *args, &blk) ⇒ Object
214
215
216
217
218
219
220
221
|
# File 'lib/pg_funcall.rb', line 214
def call_raw_pg(fn, *args, &blk)
query = "SELECT #{fn}(" +
args.map {|arg| _quote_param(arg) }.join(", ") + ") as res;"
_pg_conn.query(query, &blk).tap do |res|
PgFuncall._assign_pg_type_map_to_res(res, _pg_conn)
end
end
|
#call_returning_array(fn, *args) ⇒ Object
131
132
133
|
# File 'lib/pg_funcall.rb', line 131
def call_returning_array(fn, *args)
call_raw(fn, *args).rows
end
|
#call_returning_type(fn, ret_type, *args) ⇒ Object
Force a typecast of the return value
240
241
242
243
|
# File 'lib/pg_funcall.rb', line 240
def call_returning_type(fn, ret_type, *args)
type_map.type_cast_from_database(call(fn, *args),
type_for_name(ret_type))
end
|
#call_uncast(fn, *args) ⇒ Object
Also known as:
call_scalar
Calls Database function with a given set of arguments. Returns result as a string.
126
127
128
|
# File 'lib/pg_funcall.rb', line 126
def call_uncast(fn, *args)
call_raw(fn, *args).rows.first.first
end
|
#casting_query(query, params) ⇒ Object
295
296
297
298
299
300
|
# File 'lib/pg_funcall.rb', line 295
def casting_query(query, params)
_pg_conn.exec_params(query, _pg_param_descriptors(params)) do |res|
_cast_pgresult(res)
end
end
|
#clear_cache ⇒ Object
39
40
41
42
43
|
# File 'lib/pg_funcall.rb', line 39
def clear_cache
(@ftype_cache ||= {}).clear
@type_map = nil
true
end
|
#search_path ⇒ Object
Return an array of schema names for the current session’s search path
382
383
384
385
386
|
# File 'lib/pg_funcall.rb', line 382
def search_path
_pg_conn.query("SHOW search_path;") do |res|
res.column_values(0).first.split(/, ?/)
end
end
|
#type_for_name(name) ⇒ Object
229
230
231
|
# File 'lib/pg_funcall.rb', line 229
def type_for_name(name)
type_map.resolve(name)
end
|
#type_for_typeid(typeid) ⇒ Object
225
226
227
|
# File 'lib/pg_funcall.rb', line 225
def type_for_typeid(typeid)
type_map.resolve(typeid.to_i)
end
|
#type_map ⇒ Object
233
234
235
|
# File 'lib/pg_funcall.rb', line 233
def type_map
@type_map ||= TypeMap.fetch(@ar_connection, search_path: search_path)
end
|