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