Module: Sequel::Postgres::PGRow::DatabaseMethods
- Defined in:
- lib/sequel/extensions/pg_row.rb
Constant Summary collapse
- ESCAPE_RE =
/("|\\)/.freeze
- ESCAPE_REPLACEMENT =
'\\\\\1'.freeze
- COMMA =
','.freeze
Instance Attribute Summary collapse
-
#row_types ⇒ Object
readonly
A hash mapping row type keys (usually symbols), to option hashes.
Class Method Summary collapse
-
.extended(db) ⇒ Object
Do some setup for the data structures the module uses.
Instance Method Summary collapse
-
#bound_variable_arg(arg, conn) ⇒ Object
Handle ArrayRow and HashRow values in bound variables.
-
#register_row_type(db_type, opts = {}) ⇒ Object
Register a new row type for the Database instance.
-
#reset_conversion_procs ⇒ Object
When reseting conversion procs, reregister all the row types so that the system tables are introspected again, picking up database changes.
-
#row_type(db_type, obj) ⇒ Object
Handle typecasting of the given object to the given database type.
-
#schema_column_type(db_type) ⇒ Object
Make the column type detection handle registered row types.
Instance Attribute Details
#row_types ⇒ Object (readonly)
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.
361 362 363 |
# File 'lib/sequel/extensions/pg_row.rb', line 361 def row_types @row_types end |
Class Method Details
.extended(db) ⇒ Object
Do some setup for the data structures the module uses.
364 365 366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/sequel/extensions/pg_row.rb', line 364 def self.extended(db) # Return right away if row_types has already been set. This # makes things not break if a user extends the database with # this module more than once (since extended is called every # time). return if db.row_types db.instance_eval do @row_types = {} @row_schema_types = {} extend(@row_type_method_module = Module.new) end end |
Instance Method Details
#bound_variable_arg(arg, conn) ⇒ Object
Handle ArrayRow and HashRow values in bound variables.
379 380 381 382 383 384 385 386 387 388 389 |
# File 'lib/sequel/extensions/pg_row.rb', line 379 def bound_variable_arg(arg, conn) case arg when ArrayRow "(#{arg.map{|v| bound_variable_array(v) if v}.join(COMMA)})" when HashRow arg.check_columns! "(#{arg.values_at(*arg.columns).map{|v| bound_variable_array(v) if v}.join(COMMA)})" else super end end |
#register_row_type(db_type, opts = {}) ⇒ Object
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.
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 |
# File 'lib/sequel/extensions/pg_row.rb', line 400 def register_row_type(db_type, opts={}) procs = @conversion_procs rel_oid = nil array_oid = nil parser_opts = {} # Try to handle schema-qualified types. type_schema, type_name = schema_and_table(db_type) schema_type_string = type_name.to_s # Get basic oid information for the composite type. ds = from(:pg_type). select(:pg_type__oid, :typrelid, :typarray). where([[:typtype, 'c'], [:typname, type_name.to_s]]) if type_schema ds = ds.join(:pg_namespace, [[:oid, :typnamespace], [:nspname, type_schema.to_s]]) schema_type_symbol = :"pg_row_#{type_schema}__#{type_name}" else schema_type_symbol = :"pg_row_#{type_name}" end unless row = ds.first raise Error, "row type #{db_type.inspect} not found in database" end # Manually cast to integer using to_i, because adapter may not cast oid type # correctly (e.g. swift) parser_opts[:oid], rel_oid, array_oid = row.values_at(:oid, :typrelid, :typarray).map{|i| i.to_i} # Get column names and oids for each of the members of the composite type. res = from(:pg_attribute). where(:attrelid=>rel_oid). where{attnum > 0}. exclude(:attisdropped). order(:attnum). select_map([:attname, :atttypid]) if res.empty? raise Error, "no columns for row type #{db_type.inspect} in database" end parser_opts[:columns] = res.map{|r| r[0].to_sym} parser_opts[:column_oids] = res.map{|r| r[1].to_i} # Using the conversion_procs, lookup converters for each member of the composite type parser_opts[:column_converters] = parser_opts[:column_oids].map do |oid| if pr = procs[oid] pr elsif !Sequel::Postgres::STRING_TYPES.include?(oid) # It's not a string type, and it's possible a conversion proc for this # oid will be added later, so do a runtime check for it. lambda{|s| (pr = procs[oid]) ? pr.call(s) : s} end end # Setup the converter and typecaster parser_opts[:converter] = opts.fetch(:converter){HashRow.subclass(db_type, parser_opts[:columns])} parser_opts[:typecaster] = opts.fetch(:typecaster, parser_opts[:converter]) parser = Parser.new(parser_opts) @conversion_procs[parser.oid] = parser if defined?(PGArray) && PGArray.respond_to?(:register) && array_oid && array_oid > 0 PGArray.register(db_type, :oid=>array_oid, :converter=>parser, :type_procs=>@conversion_procs, :scalar_typecast=>schema_type_symbol) end @row_types[db_type] = opts.merge(:parser=>parser) @row_schema_types[schema_type_string] = schema_type_symbol @row_type_method_module.class_eval do meth = :"typecast_value_#{schema_type_symbol}" define_method(meth) do |v| row_type(db_type, v) end private meth end nil end |
#reset_conversion_procs ⇒ Object
When reseting conversion procs, reregister all the row types so that the system tables are introspected again, picking up database changes.
477 478 479 480 481 482 483 484 485 |
# File 'lib/sequel/extensions/pg_row.rb', line 477 def reset_conversion_procs procs = super row_types.each do |db_type, opts| register_row_type(db_type, opts) end procs end |
#row_type(db_type, obj) ⇒ Object
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.
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
# File 'lib/sequel/extensions/pg_row.rb', line 490 def row_type(db_type, obj) (type_hash = @row_types[db_type]) && (parser = type_hash[:parser]) case obj when ArrayRow, HashRow obj when Array if parser parser.typecast(obj) else obj = ArrayRow.new(obj) obj.db_type = db_type obj end when Hash if parser parser.typecast(obj) else raise InvalidValue, "Database#row_type requires the #{db_type.inspect} type have a registered parser and typecaster when called with a hash" end else raise InvalidValue, "cannot convert #{obj.inspect} to row type #{db_type.inspect}" end end |
#schema_column_type(db_type) ⇒ Object
Make the column type detection handle registered row types.
517 518 519 520 521 522 523 |
# File 'lib/sequel/extensions/pg_row.rb', line 517 def schema_column_type(db_type) if type = @row_schema_types[db_type] type else super end end |