module Sequel::Postgres::PGRow::DatabaseMethods

Attributes

row_types[R]

A hash mapping row type keys (usually symbols), to option hashes. At the least, the values will contain the :parser option for the Parser instance that the type will use.

Public Class Methods

extended(db) click to toggle source

Do some setup for the data structures the module uses.

    # File lib/sequel/extensions/pg_row.rb
371 def self.extended(db)
372   db.instance_exec do
373     @row_types = {}
374     @row_schema_types = {}
375     extend(@row_type_method_module = Module.new)
376     add_conversion_proc(2249, PGRow::Parser.new(:converter=>PGRow::ArrayRow))
377     if respond_to?(:register_array_type)
378       register_array_type('record', :oid=>2287, :scalar_oid=>2249)
379     end
380   end
381 end

Public Instance Methods

bound_variable_arg(arg, conn) click to toggle source

Handle ArrayRow and HashRow values in bound variables.

Calls superclass method
    # File lib/sequel/extensions/pg_row.rb
384 def bound_variable_arg(arg, conn)
385   case arg
386   when ArrayRow
387     "(#{arg.map{|v| bound_variable_array(v) if v}.join(',')})"
388   when HashRow
389     arg.check_columns!
390     "(#{arg.values_at(*arg.columns).map{|v| bound_variable_array(v) if v}.join(',')})"
391   else
392     super
393   end
394 end
freeze() click to toggle source

Freeze the row types and row schema types to prevent adding new ones.

Calls superclass method
    # File lib/sequel/extensions/pg_row.rb
397 def freeze
398   @row_types.freeze
399   @row_schema_types.freeze
400   @row_type_method_module.freeze
401   super
402 end
register_row_type(db_type, opts=OPTS) click to toggle source

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
413 def register_row_type(db_type, opts=OPTS)
414   procs = @conversion_procs
415   rel_oid = nil
416   array_oid = nil
417   parser_opts = {}
418 
419   # Try to handle schema-qualified types.
420   type_schema, type_name = schema_and_table(db_type)
421   schema_type_string = type_name.to_s
422 
423   # Get basic oid information for the composite type.
424   ds = from(:pg_type).
425     select{[pg_type[:oid], :typrelid, :typarray]}.
426     where([[:typtype, 'c'], [:typname, type_name.to_s]])
427   if type_schema
428     ds = ds.join(:pg_namespace, [[:oid, :typnamespace], [:nspname, type_schema.to_s]])
429     schema_type_symbol = :"pg_row_#{type_schema}__#{type_name}" 
430   else
431     schema_type_symbol = :"pg_row_#{type_name}"
432   end
433   unless row = ds.first
434     raise Error, "row type #{db_type.inspect} not found in database"
435   end
436   # Manually cast to integer using to_i, because adapter may not cast oid type
437   # correctly (e.g. swift)
438   parser_opts[:oid], rel_oid, array_oid = row.values_at(:oid, :typrelid, :typarray).map(&:to_i)
439 
440   # Get column names and oids for each of the members of the composite type.
441   res = from(:pg_attribute).
442     join(:pg_type, :oid=>:atttypid).
443     where(:attrelid=>rel_oid).
444     where{attnum > 0}.
445     exclude(:attisdropped).
446     order(:attnum).
447     select_map{[:attname, Sequel.case({0=>:atttypid}, pg_type[:typbasetype], pg_type[:typbasetype]).as(:atttypid)]}
448   if res.empty?
449     raise Error, "no columns for row type #{db_type.inspect} in database"
450   end
451   parser_opts[:columns] = res.map{|r| r[0].to_sym}
452   parser_opts[:column_oids] = res.map{|r| r[1].to_i}
453 
454   # Using the conversion_procs, lookup converters for each member of the composite type
455   parser_opts[:column_converters] = parser_opts[:column_oids].map do |oid|
456     procs[oid]
457   end
458 
459   # Setup the converter and typecaster
460   parser_opts[:converter] = opts.fetch(:converter){HashRow.subclass(db_type, parser_opts[:columns])}
461   parser_opts[:typecaster] = opts.fetch(:typecaster, parser_opts[:converter])
462 
463   parser = Parser.new(parser_opts)
464   add_conversion_proc(parser.oid, parser)
465 
466   if respond_to?(:register_array_type) && array_oid && array_oid > 0
467     array_type_name = if type_schema
468       "#{type_schema}.#{type_name}"
469     else
470       type_name
471     end
472     register_array_type(array_type_name, :oid=>array_oid, :converter=>parser, :scalar_typecast=>schema_type_symbol)
473   end
474 
475   @row_types[literal(db_type)] = opts.merge(:parser=>parser, :type=>db_type)
476   @row_schema_types[schema_type_string] = schema_type_symbol 
477   @schema_type_classes[schema_type_symbol] = ROW_TYPE_CLASSES
478   @row_type_method_module.class_eval do
479     meth = :"typecast_value_#{schema_type_symbol}"
480     define_method(meth) do |v|
481       row_type(db_type, v)
482     end
483     private meth
484   end
485 
486   nil
487 end
row_type(db_type, obj) click to toggle source

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
492 def row_type(db_type, obj)
493   (type_hash = @row_types[literal(db_type)]) &&
494     (parser = type_hash[:parser])
495 
496   case obj
497   when ArrayRow, HashRow
498     obj
499   when Array
500     if parser
501       parser.typecast(obj)
502     else
503       obj = ArrayRow.new(obj)
504       obj.db_type = db_type
505       obj
506     end
507   when Hash
508     if parser 
509       parser.typecast(obj)
510     else
511       raise InvalidValue, "Database#row_type requires the #{db_type.inspect} type have a registered parser and typecaster when called with a hash"
512     end
513   else
514     raise InvalidValue, "cannot convert #{obj.inspect} to row type #{db_type.inspect}"
515   end
516 end

Private Instance Methods

bound_variable_array(arg) click to toggle source

Format composite types used in bound variable arrays.

Calls superclass method
    # File lib/sequel/extensions/pg_row.rb
521 def bound_variable_array(arg)
522   case arg
523   when ArrayRow
524     "\"(#{arg.map{|v| bound_variable_array(v) if v}.join(',').gsub(/("|\\)/, '\\\\\1')})\""
525   when HashRow
526     arg.check_columns!
527     "\"(#{arg.values_at(*arg.columns).map{|v| bound_variable_array(v) if v}.join(',').gsub(/("|\\)/, '\\\\\1')})\""
528   else
529     super
530   end
531 end
schema_column_type(db_type) click to toggle source

Make the column type detection handle registered row types.

Calls superclass method
    # File lib/sequel/extensions/pg_row.rb
534 def schema_column_type(db_type)
535   if type = @row_schema_types[db_type]
536     type
537   else
538     super
539   end
540 end