class PgFuncall
Constants
- Literal
- Typed
- VERSION
Public Class Methods
_assign_pg_type_map_to_res(res, conn)
click to toggle source
# File lib/pg_funcall.rb, line 245 def self._assign_pg_type_map_to_res(res, conn) return res ## this appears to fail to roundtrip on bytea and date types ## #if res.respond_to?(:type_map=) # res.type_map = PG::BasicTypeMapForResults.new(conn) #end #res end
default_instance()
click to toggle source
# File lib/pg_funcall.rb, line 22 def self.default_instance @default_instance ||= PgFuncall.new(ActiveRecord::Base.connection) end
default_instance=(instance)
click to toggle source
# File lib/pg_funcall.rb, line 26 def self.default_instance=(instance) @default_instance = instance end
literal(arg)
click to toggle source
wrap a value so that it is inserted into the query as-is
# File lib/pg_funcall.rb, line 119 def self.literal(arg) Literal.new(arg) end
new(connection)
click to toggle source
# 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
tag_pg_type(value, tagtype, pgvalue = nil)
click to toggle source
# File lib/pg_funcall.rb, line 98 def self.tag_pg_type(value, tagtype, pgvalue = nil) pgvalue ||= value # XXX: this is going to blow the method cache every time it runs 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
Public Instance Methods
_ar_conn()
click to toggle source
# File lib/pg_funcall.rb, line 371 def _ar_conn @ar_connection end
_cast_pgresult(res)
click to toggle source
Take a PGResult and cast the first column of each tuple to the Ruby equivalent of the PG type as described in the PGResult.
# 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
_format_param_for_descriptor(param, type=nil)
click to toggle source
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.
# 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()
click to toggle source
# File lib/pg_funcall.rb, line 375 def _pg_conn _ar_conn.raw_connection end
_pg_param_descriptors(params)
click to toggle source
# 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: typeinfo.cast_to_database(p), value: _format_param_for_descriptor(p, pgtype), # if we can't find a type, let PG guess type: (typeinfo && typeinfo.oid) || 0, format: 0 } end end
_pgtype_for_value(value)
click to toggle source
# File lib/pg_funcall.rb, line 303 def _pgtype_for_value(value) case value # type-forcing wrapper for arrays when TypedArray value.type + '[]' # type-forcing wrapper when Typed value.type # marker ancestor 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)
click to toggle source
“Quote”, which means to format and quote, a parameter for inclusion into a SQL query as a string.
# 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)
click to toggle source
# File lib/pg_funcall.rb, line 268 def call_cast(fn, *args) fn_sig = type_map.function_types(fn) ## TODO: finish this with the new type info class # unwrap = fn_sig && type_map.is_scalar_type?(type_map.lookup_by_oid(fn_sig.ret_type)) call_raw_pg(fn, *args) do |res| results = _cast_pgresult(res) # unwrap && results.ntuples < 2 ? results.first : results results.first end end
Also aliased as: call
call_raw_inline(fn, *args)
click to toggle source
# 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
Also aliased as: call_raw
call_raw_pg(fn, *args, &blk)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
Force a typecast of the return value
# 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)
click to toggle source
Calls Database function with a given set of arguments. Returns result as a string.
# File lib/pg_funcall.rb, line 126 def call_uncast(fn, *args) call_raw(fn, *args).rows.first.first end
Also aliased as: call_scalar
casting_query(query, params)
click to toggle source
# File lib/pg_funcall.rb, line 295 def casting_query(query, params) # puts "param descriptors = #{_pg_param_descriptors(params)}.inspect" _pg_conn.exec_params(query, _pg_param_descriptors(params)) do |res| _cast_pgresult(res) end end
clear_cache()
click to toggle source
# File lib/pg_funcall.rb, line 39 def clear_cache (@ftype_cache ||= {}).clear @type_map = nil true end
search_path()
click to toggle source
Return an array of schema names for the current session’s search path
# 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)
click to toggle source
# File lib/pg_funcall.rb, line 229 def type_for_name(name) type_map.resolve(name) end
type_for_typeid(typeid)
click to toggle source
# File lib/pg_funcall.rb, line 225 def type_for_typeid(typeid) type_map.resolve(typeid.to_i) end
type_map()
click to toggle source
# File lib/pg_funcall.rb, line 233 def type_map @type_map ||= TypeMap.fetch(@ar_connection, search_path: search_path) end