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