Method: Sequel::Postgres::PGRow::DatabaseMethods#register_row_type

Defined in:
lib/sequel/extensions/pg_row.rb

#register_row_type(db_type, opts = OPTS) ⇒ Object

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.



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'lib/sequel/extensions/pg_row.rb', line 434

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(&: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|
    procs[oid]
  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)
  add_conversion_proc(parser.oid, parser)

  if respond_to?(:register_array_type) && array_oid && array_oid > 0
    array_type_name = if type_schema
      "#{type_schema}.#{type_name}"
    else
      type_name
    end
    register_array_type(array_type_name, :oid=>array_oid, :converter=>parser, :scalar_typecast=>schema_type_symbol)
  end

  @row_types[literal(db_type)] = opts.merge(:parser=>parser, :type=>db_type)
  @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
    alias_method(meth, meth)
  end

  nil
end