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 383
383:         def self.extended(db)
384:           # Return right away if row_types has already been set. This
385:           # makes things not break if a user extends the database with
386:           # this module more than once (since extended is called every
387:           # time).
388:           return if db.row_types
389: 
390:           db.instance_eval do
391:             @row_types = {}
392:             @row_schema_types = {}
393:             extend(@row_type_method_module = Module.new)
394:             copy_conversion_procs([2249, 2287])
395:           end
396:         end

Public Instance methods

Handle ArrayRow and HashRow values in bound variables.

[Source]

     # File lib/sequel/extensions/pg_row.rb, line 399
399:         def bound_variable_arg(arg, conn)
400:           case arg
401:           when ArrayRow
402:             "(#{arg.map{|v| bound_variable_array(v) if v}.join(COMMA)})"
403:           when HashRow
404:             arg.check_columns!
405:             "(#{arg.values_at(*arg.columns).map{|v| bound_variable_array(v) if v}.join(COMMA)})"
406:           else
407:             super
408:           end
409:         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 420
420:         def register_row_type(db_type, opts=OPTS)
421:           procs = @conversion_procs
422:           rel_oid = nil
423:           array_oid = nil
424:           parser_opts = {}
425: 
426:           # Try to handle schema-qualified types.
427:           type_schema, type_name = schema_and_table(db_type)
428:           schema_type_string = type_name.to_s
429: 
430:           # Get basic oid information for the composite type.
431:           ds = from(:pg_type).
432:             select(:pg_type__oid, :typrelid, :typarray).
433:             where([[:typtype, 'c'], [:typname, type_name.to_s]])
434:           if type_schema
435:             ds = ds.join(:pg_namespace, [[:oid, :typnamespace], [:nspname, type_schema.to_s]])
436:             schema_type_symbol = "pg_row_#{type_schema}__#{type_name}""pg_row_#{type_schema}__#{type_name}" 
437:           else
438:             schema_type_symbol = "pg_row_#{type_name}""pg_row_#{type_name}"
439:           end
440:           unless row = ds.first
441:             raise Error, "row type #{db_type.inspect} not found in database"
442:           end
443:           # Manually cast to integer using to_i, because adapter may not cast oid type
444:           # correctly (e.g. swift)
445:           parser_opts[:oid], rel_oid, array_oid = row.values_at(:oid, :typrelid, :typarray).map{|i| i.to_i}
446: 
447:           # Get column names and oids for each of the members of the composite type.
448:           res = from(:pg_attribute).
449:             join(:pg_type, :oid=>:atttypid).
450:             where(:attrelid=>rel_oid).
451:             where{attnum > 0}.
452:             exclude(:attisdropped).
453:             order(:attnum).
454:             select_map([:attname, Sequel.case({0=>:atttypid}, :pg_type__typbasetype, :pg_type__typbasetype).as(:atttypid)])
455:           if res.empty?
456:             raise Error, "no columns for row type #{db_type.inspect} in database"
457:           end
458:           parser_opts[:columns] = res.map{|r| r[0].to_sym}
459:           parser_opts[:column_oids] = res.map{|r| r[1].to_i}
460: 
461:           # Using the conversion_procs, lookup converters for each member of the composite type
462:           parser_opts[:column_converters] = parser_opts[:column_oids].map do |oid|
463:             if pr = procs[oid]
464:               pr
465:             elsif !Sequel::Postgres::STRING_TYPES.include?(oid)
466:               # It's not a string type, and it's possible a conversion proc for this
467:               # oid will be added later, so do a runtime check for it.
468:               lambda{|s| (pr = procs[oid]) ? pr.call(s) : s}
469:             end
470:           end
471: 
472:           # Setup the converter and typecaster
473:           parser_opts[:converter] = opts.fetch(:converter){HashRow.subclass(db_type, parser_opts[:columns])}
474:           parser_opts[:typecaster] = opts.fetch(:typecaster, parser_opts[:converter])
475: 
476:           parser = Parser.new(parser_opts)
477:           @conversion_procs[parser.oid] = parser
478: 
479:           if defined?(PGArray) && PGArray.respond_to?(:register) && array_oid && array_oid > 0
480:             array_type_name = if type_schema
481:               "#{type_schema}.#{type_name}"
482:             else
483:               type_name
484:             end
485:             PGArray.register(array_type_name, :oid=>array_oid, :converter=>parser, :type_procs=>@conversion_procs, :scalar_typecast=>schema_type_symbol)
486:           end
487: 
488:           @row_types[db_type] = opts.merge(:parser=>parser)
489:           @row_schema_types[schema_type_string] = schema_type_symbol 
490:           @schema_type_classes[schema_type_symbol] = ROW_TYPE_CLASSES
491:           @row_type_method_module.class_eval do
492:             meth = "typecast_value_#{schema_type_symbol}""typecast_value_#{schema_type_symbol}"
493:             define_method(meth) do |v|
494:               row_type(db_type, v)
495:             end
496:             private meth
497:           end
498: 
499:           nil
500:         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 504
504:         def reset_conversion_procs
505:           procs = super
506: 
507:           row_types.each do |db_type, opts|
508:             register_row_type(db_type, opts)
509:           end
510: 
511:           procs
512:         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 517
517:         def row_type(db_type, obj)
518:           (type_hash = @row_types[db_type]) &&
519:             (parser = type_hash[:parser])
520: 
521:           case obj
522:           when ArrayRow, HashRow
523:             obj
524:           when Array
525:             if parser
526:               parser.typecast(obj)
527:             else
528:               obj = ArrayRow.new(obj)
529:               obj.db_type = db_type
530:               obj
531:             end
532:           when Hash
533:             if parser 
534:               parser.typecast(obj)
535:             else
536:               raise InvalidValue, "Database#row_type requires the #{db_type.inspect} type have a registered parser and typecaster when called with a hash"
537:             end
538:           else
539:             raise InvalidValue, "cannot convert #{obj.inspect} to row type #{db_type.inspect}"
540:           end
541:         end

[Validate]