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 364
364:         def self.extended(db)
365:           # Return right away if row_types has already been set. This
366:           # makes things not break if a user extends the database with
367:           # this module more than once (since extended is called every
368:           # time).
369:           return if db.row_types
370: 
371:           db.instance_eval do
372:             @row_types = {}
373:             @row_schema_types = {}
374:             extend(@row_type_method_module = Module.new)
375:           end
376:         end

Public Instance methods

Handle ArrayRow and HashRow values in bound variables.

[Source]

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

Make the column type detection handle registered row types.

[Source]

     # File lib/sequel/extensions/pg_row.rb, line 517
517:         def schema_column_type(db_type)
518:           if type = @row_schema_types[db_type]
519:             type
520:           else
521:             super
522:           end
523:         end

[Validate]