Module Sequel::Postgres::PGRow::DatabaseMethods
In: lib/sequel/extensions/pg_row.rb

Methods

Constants

ESCAPE_RE = /("|\\)/.freeze
ESCAPE_REPLACEMENT = '\\\\\1'.freeze
COMMA = ','.freeze

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

Do some setup for the data structures the module uses.

[Source]

     # File lib/sequel/extensions/pg_row.rb, line 386
386:         def self.extended(db)
387:           # Return right away if row_types has already been set. This
388:           # makes things not break if a user extends the database with
389:           # this module more than once (since extended is called every
390:           # time).
391:           return if db.row_types
392: 
393:           db.instance_eval do
394:             @row_types = {}
395:             @row_schema_types = {}
396:             extend(@row_type_method_module = Module.new)
397:             copy_conversion_procs([2249, 2287])
398:           end
399:         end

Public Instance methods

Handle ArrayRow and HashRow values in bound variables.

[Source]

     # File lib/sequel/extensions/pg_row.rb, line 402
402:         def bound_variable_arg(arg, conn)
403:           case arg
404:           when ArrayRow
405:             "(#{arg.map{|v| bound_variable_array(v) if v}.join(COMMA)})"
406:           when HashRow
407:             arg.check_columns!
408:             "(#{arg.values_at(*arg.columns).map{|v| bound_variable_array(v) if v}.join(COMMA)})"
409:           else
410:             super
411:           end
412:         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.

[Source]

     # File lib/sequel/extensions/pg_row.rb, line 423
423:         def register_row_type(db_type, opts=OPTS)
424:           procs = @conversion_procs
425:           rel_oid = nil
426:           array_oid = nil
427:           parser_opts = {}
428: 
429:           # Try to handle schema-qualified types.
430:           type_schema, type_name = schema_and_table(db_type)
431:           schema_type_string = type_name.to_s
432: 
433:           # Get basic oid information for the composite type.
434:           ds = from(:pg_type).
435:             select(:pg_type__oid, :typrelid, :typarray).
436:             where([[:typtype, 'c'], [:typname, type_name.to_s]])
437:           if type_schema
438:             ds = ds.join(:pg_namespace, [[:oid, :typnamespace], [:nspname, type_schema.to_s]])
439:             schema_type_symbol = "pg_row_#{type_schema}__#{type_name}""pg_row_#{type_schema}__#{type_name}" 
440:           else
441:             schema_type_symbol = "pg_row_#{type_name}""pg_row_#{type_name}"
442:           end
443:           unless row = ds.first
444:             raise Error, "row type #{db_type.inspect} not found in database"
445:           end
446:           # Manually cast to integer using to_i, because adapter may not cast oid type
447:           # correctly (e.g. swift)
448:           parser_opts[:oid], rel_oid, array_oid = row.values_at(:oid, :typrelid, :typarray).map(&:to_i)
449: 
450:           # Get column names and oids for each of the members of the composite type.
451:           res = from(:pg_attribute).
452:             join(:pg_type, :oid=>:atttypid).
453:             where(:attrelid=>rel_oid).
454:             where{attnum > 0}.
455:             exclude(:attisdropped).
456:             order(:attnum).
457:             select_map([:attname, Sequel.case({0=>:atttypid}, :pg_type__typbasetype, :pg_type__typbasetype).as(:atttypid)])
458:           if res.empty?
459:             raise Error, "no columns for row type #{db_type.inspect} in database"
460:           end
461:           parser_opts[:columns] = res.map{|r| r[0].to_sym}
462:           parser_opts[:column_oids] = res.map{|r| r[1].to_i}
463: 
464:           # Using the conversion_procs, lookup converters for each member of the composite type
465:           parser_opts[:column_converters] = parser_opts[:column_oids].map do |oid|
466:             if pr = procs[oid]
467:               pr
468:             elsif !Sequel::Postgres::STRING_TYPES.include?(oid)
469:               # It's not a string type, and it's possible a conversion proc for this
470:               # oid will be added later, so do a runtime check for it.
471:               lambda{|s| (pr = procs[oid]) ? pr.call(s) : s}
472:             end
473:           end
474: 
475:           # Setup the converter and typecaster
476:           parser_opts[:converter] = opts.fetch(:converter){HashRow.subclass(db_type, parser_opts[:columns])}
477:           parser_opts[:typecaster] = opts.fetch(:typecaster, parser_opts[:converter])
478: 
479:           parser = Parser.new(parser_opts)
480:           @conversion_procs[parser.oid] = parser
481: 
482:           if defined?(PGArray) && PGArray.respond_to?(:register) && array_oid && array_oid > 0
483:             array_type_name = if type_schema
484:               "#{type_schema}.#{type_name}"
485:             else
486:               type_name
487:             end
488:             PGArray.register(array_type_name, :oid=>array_oid, :converter=>parser, :type_procs=>@conversion_procs, :scalar_typecast=>schema_type_symbol)
489:           end
490: 
491:           @row_types[literal(db_type)] = opts.merge(:parser=>parser, :type=>db_type)
492:           @row_schema_types[schema_type_string] = schema_type_symbol 
493:           @schema_type_classes[schema_type_symbol] = ROW_TYPE_CLASSES
494:           @row_type_method_module.class_eval do
495:             meth = "typecast_value_#{schema_type_symbol}""typecast_value_#{schema_type_symbol}"
496:             define_method(meth) do |v|
497:               row_type(db_type, v)
498:             end
499:             private meth
500:           end
501: 
502:           conversion_procs_updated
503:           nil
504:         end

When reseting conversion procs, reregister all the row types so that the system tables are introspected again, picking up database changes.

[Source]

     # File lib/sequel/extensions/pg_row.rb, line 508
508:         def reset_conversion_procs
509:           procs = super
510: 
511:           row_types.values.each do |opts|
512:             register_row_type(opts[:type], opts)
513:           end
514: 
515:           procs
516:         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.

[Source]

     # File lib/sequel/extensions/pg_row.rb, line 521
521:         def row_type(db_type, obj)
522:           (type_hash = @row_types[literal(db_type)]) &&
523:             (parser = type_hash[:parser])
524: 
525:           case obj
526:           when ArrayRow, HashRow
527:             obj
528:           when Array
529:             if parser
530:               parser.typecast(obj)
531:             else
532:               obj = ArrayRow.new(obj)
533:               obj.db_type = db_type
534:               obj
535:             end
536:           when Hash
537:             if parser 
538:               parser.typecast(obj)
539:             else
540:               raise InvalidValue, "Database#row_type requires the #{db_type.inspect} type have a registered parser and typecaster when called with a hash"
541:             end
542:           else
543:             raise InvalidValue, "cannot convert #{obj.inspect} to row type #{db_type.inspect}"
544:           end
545:         end

[Validate]