Methods
Public Class
Public Instance
Constants
COMMA | = | ','.freeze | ||
ESCAPE_RE | = | /("|\\)/.freeze | ||
ESCAPE_REPLACEMENT | = | '\\\\\1'.freeze |
Attributes
Public Class methods
Do some setup for the data structures the module uses.
# File lib/sequel/extensions/pg_row.rb, line 383 def self.extended(db) # Return right away if row_types has already been set. This # makes things not break if a user extends the database with # this module more than once (since extended is called every # time). return if db.row_types db.instance_eval do @row_types = {} @row_schema_types = {} extend(@row_type_method_module = Module.new) copy_conversion_procs([2249, 2287]) end end
Public Instance methods
# File lib/sequel/extensions/pg_row.rb, line 399 def bound_variable_arg(arg, conn) case arg when ArrayRow "(#{arg.map{|v| bound_variable_array(v) if v}.join(COMMA)})" when HashRow arg.check_columns! "(#{arg.values_at(*arg.columns).map{|v| bound_variable_array(v) if v}.join(COMMA)})" else super end end
Register a new row type for the Database instance. db_type should be the type symbol. This parses the PostgreSQL system tables to get information the composite type, and by default has the type return instances of a subclass of HashRow.
The following options are supported:
- :converter
-
Use a custom converter for the parser.
- :typecaster
-
Use a custom typecaster for the parser.
# File lib/sequel/extensions/pg_row.rb, line 420 def register_row_type(db_type, opts=OPTS) procs = @conversion_procs rel_oid = nil array_oid = nil parser_opts = {} # Try to handle schema-qualified types. type_schema, type_name = schema_and_table(db_type) schema_type_string = type_name.to_s # Get basic oid information for the composite type. ds = from(:pg_type). select(:pg_type__oid, :typrelid, :typarray). where([[:typtype, 'c'], [:typname, type_name.to_s]]) if type_schema ds = ds.join(:pg_namespace, [[:oid, :typnamespace], [:nspname, type_schema.to_s]]) schema_type_symbol = :"pg_row_#{type_schema}__#{type_name}" else schema_type_symbol = :"pg_row_#{type_name}" end unless row = ds.first raise Error, "row type #{db_type.inspect} not found in database" end # Manually cast to integer using to_i, because adapter may not cast oid type # correctly (e.g. swift) parser_opts[:oid], rel_oid, array_oid = row.values_at(:oid, :typrelid, :typarray).map{|i| i.to_i} # Get column names and oids for each of the members of the composite type. res = from(:pg_attribute). join(:pg_type, :oid=>:atttypid). where(:attrelid=>rel_oid). where{attnum > 0}. exclude(:attisdropped). order(:attnum). select_map([:attname, Sequel.case({0=>:atttypid}, :pg_type__typbasetype, :pg_type__typbasetype).as(:atttypid)]) if res.empty? raise Error, "no columns for row type #{db_type.inspect} in database" end parser_opts[:columns] = res.map{|r| r[0].to_sym} parser_opts[:column_oids] = res.map{|r| r[1].to_i} # Using the conversion_procs, lookup converters for each member of the composite type parser_opts[:column_converters] = parser_opts[:column_oids].map do |oid| if pr = procs[oid] pr elsif !Sequel::Postgres::STRING_TYPES.include?(oid) # It's not a string type, and it's possible a conversion proc for this # oid will be added later, so do a runtime check for it. lambda{|s| (pr = procs[oid]) ? pr.call(s) : s} end end # Setup the converter and typecaster parser_opts[:converter] = opts.fetch(:converter){HashRow.subclass(db_type, parser_opts[:columns])} parser_opts[:typecaster] = opts.fetch(:typecaster, parser_opts[:converter]) parser = Parser.new(parser_opts) @conversion_procs[parser.oid] = parser if defined?(PGArray) && PGArray.respond_to?(:register) && array_oid && array_oid > 0 array_type_name = if type_schema "#{type_schema}.#{type_name}" else type_name end PGArray.register(array_type_name, :oid=>array_oid, :converter=>parser, :type_procs=>@conversion_procs, :scalar_typecast=>schema_type_symbol) end @row_types[db_type] = opts.merge(:parser=>parser) @row_schema_types[schema_type_string] = schema_type_symbol @schema_type_classes[schema_type_symbol] = ROW_TYPE_CLASSES @row_type_method_module.class_eval do meth = :"typecast_value_#{schema_type_symbol}" define_method(meth) do |v| row_type(db_type, v) end private meth end nil end
When reseting conversion procs, reregister all the row types so that the system tables are introspected again, picking up database changes.
# File lib/sequel/extensions/pg_row.rb, line 504 def reset_conversion_procs procs = super row_types.each do |db_type, opts| register_row_type(db_type, opts) end procs end
Handle typecasting of the given object to the given database type. In general, the given database type should already be registered, but if obj is an array, this will handled unregistered types.
# File lib/sequel/extensions/pg_row.rb, line 517 def row_type(db_type, obj) (type_hash = @row_types[db_type]) && (parser = type_hash[:parser]) case obj when ArrayRow, HashRow obj when Array if parser parser.typecast(obj) else obj = ArrayRow.new(obj) obj.db_type = db_type obj end when Hash if parser parser.typecast(obj) else raise InvalidValue, "Database#row_type requires the #{db_type.inspect} type have a registered parser and typecaster when called with a hash" end else raise InvalidValue, "cannot convert #{obj.inspect} to row type #{db_type.inspect}" end end