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
373 def self.extended(db)
374   db.instance_exec do
375     @row_types = {}
376     @row_schema_types = {}
377     extend(@row_type_method_module = Module.new)
378     add_conversion_proc(2249, PGRow::Parser.new(:converter=>PGRow::ArrayRow))
379     if respond_to?(:register_array_type)
380       register_array_type('record', :oid=>2287, :scalar_oid=>2249)
381     end
382   end
383 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
386 def bound_variable_arg(arg, conn)
387   case arg
388   when ArrayRow
389     "(#{arg.map{|v| bound_variable_array(v) if v}.join(',')})"
390   when HashRow
391     arg.check_columns!
392     "(#{arg.values_at(*arg.columns).map{|v| bound_variable_array(v) if v}.join(',')})"
393   else
394     super
395   end
396 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
399 def freeze
400   @row_types.freeze
401   @row_schema_types.freeze
402   @row_type_method_module.freeze
403   super
404 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
415 def register_row_type(db_type, opts=OPTS)
416   procs = @conversion_procs
417   rel_oid = nil
418   array_oid = nil
419   parser_opts = {}
420 
421   # Try to handle schema-qualified types.
422   type_schema, type_name = schema_and_table(db_type)
423   schema_type_string = type_name.to_s
424 
425   # Get basic oid information for the composite type.
426   ds = from(:pg_type).
427     select{[pg_type[:oid], :typrelid, :typarray]}.
428     where([[:typtype, 'c'], [:typname, type_name.to_s]])
429   if type_schema
430     ds = ds.join(:pg_namespace, [[:oid, :typnamespace], [:nspname, type_schema.to_s]])
431     schema_type_symbol = :"pg_row_#{type_schema}__#{type_name}" 
432   else
433     schema_type_symbol = :"pg_row_#{type_name}"
434   end
435   unless row = ds.first
436     raise Error, "row type #{db_type.inspect} not found in database"
437   end
438   # Manually cast to integer using to_i, because adapter may not cast oid type
439   # correctly (e.g. swift)
440   parser_opts[:oid], rel_oid, array_oid = row.values_at(:oid, :typrelid, :typarray).map(&:to_i)
441 
442   # Get column names and oids for each of the members of the composite type.
443   res = from(:pg_attribute).
444     join(:pg_type, :oid=>:atttypid).
445     where(:attrelid=>rel_oid).
446     where{attnum > 0}.
447     exclude(:attisdropped).
448     order(:attnum).
449     select_map{[:attname, Sequel.case({0=>:atttypid}, pg_type[:typbasetype], pg_type[:typbasetype]).as(:atttypid)]}
450   if res.empty?
451     raise Error, "no columns for row type #{db_type.inspect} in database"
452   end
453   parser_opts[:columns] = res.map{|r| r[0].to_sym}
454   parser_opts[:column_oids] = res.map{|r| r[1].to_i}
455 
456   # Using the conversion_procs, lookup converters for each member of the composite type
457   parser_opts[:column_converters] = parser_opts[:column_oids].map do |oid|
458     procs[oid]
459   end
460 
461   # Setup the converter and typecaster
462   parser_opts[:converter] = opts.fetch(:converter){HashRow.subclass(db_type, parser_opts[:columns])}
463   parser_opts[:typecaster] = opts.fetch(:typecaster, parser_opts[:converter])
464 
465   parser = Parser.new(parser_opts)
466   add_conversion_proc(parser.oid, parser)
467 
468   if respond_to?(:register_array_type) && array_oid && array_oid > 0
469     array_type_name = if type_schema
470       "#{type_schema}.#{type_name}"
471     else
472       type_name
473     end
474     register_array_type(array_type_name, :oid=>array_oid, :converter=>parser, :scalar_typecast=>schema_type_symbol)
475   end
476 
477   @row_types[literal(db_type)] = opts.merge(:parser=>parser, :type=>db_type)
478   @row_schema_types[schema_type_string] = schema_type_symbol 
479   @schema_type_classes[schema_type_symbol] = ROW_TYPE_CLASSES
480   @row_type_method_module.class_eval do
481     meth = :"typecast_value_#{schema_type_symbol}"
482     define_method(meth) do |v|
483       row_type(db_type, v)
484     end
485     private meth
486   end
487 
488   nil
489 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
494 def row_type(db_type, obj)
495   (type_hash = @row_types[literal(db_type)]) &&
496     (parser = type_hash[:parser])
497 
498   case obj
499   when ArrayRow, HashRow
500     obj
501   when Array
502     if parser
503       parser.typecast(obj)
504     else
505       obj = ArrayRow.new(obj)
506       obj.db_type = db_type
507       obj
508     end
509   when Hash
510     if parser 
511       parser.typecast(obj)
512     else
513       raise InvalidValue, "Database#row_type requires the #{db_type.inspect} type have a registered parser and typecaster when called with a hash"
514     end
515   else
516     raise InvalidValue, "cannot convert #{obj.inspect} to row type #{db_type.inspect}"
517   end
518 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
523 def bound_variable_array(arg)
524   case arg
525   when ArrayRow
526     "\"(#{arg.map{|v| bound_variable_array(v) if v}.join(',').gsub(/("|\\)/, '\\\\\1')})\""
527   when HashRow
528     arg.check_columns!
529     "\"(#{arg.values_at(*arg.columns).map{|v| bound_variable_array(v) if v}.join(',').gsub(/("|\\)/, '\\\\\1')})\""
530   else
531     super
532   end
533 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
536 def schema_column_type(db_type)
537   if type = @row_schema_types[db_type]
538     type
539   else
540     super
541   end
542 end