module Sequel::Postgres::PGArray::DatabaseMethods
Constants
- BLOB_RANGE
Public Class Methods
Create the local hash of database type strings to schema type symbols, used for array types local to this database.
# File lib/sequel/extensions/pg_array.rb, line 86 def self.extended(db) db.instance_exec do @pg_array_schema_types ||= {} register_array_type('timestamp without time zone', :oid=>1115, :scalar_oid=>1114, :type_symbol=>:datetime) register_array_type('timestamp with time zone', :oid=>1185, :scalar_oid=>1184, :type_symbol=>:datetime_timezone, :scalar_typecast=>:datetime) register_array_type('text', :oid=>1009, :scalar_oid=>25, :type_symbol=>:string) register_array_type('integer', :oid=>1007, :scalar_oid=>23) register_array_type('bigint', :oid=>1016, :scalar_oid=>20, :scalar_typecast=>:integer) register_array_type('numeric', :oid=>1231, :scalar_oid=>1700, :type_symbol=>:decimal) register_array_type('double precision', :oid=>1022, :scalar_oid=>701, :type_symbol=>:float) register_array_type('boolean', :oid=>1000, :scalar_oid=>16) register_array_type('bytea', :oid=>1001, :scalar_oid=>17, :type_symbol=>:blob) register_array_type('date', :oid=>1182, :scalar_oid=>1082) register_array_type('time without time zone', :oid=>1183, :scalar_oid=>1083, :type_symbol=>:time) register_array_type('time with time zone', :oid=>1270, :scalar_oid=>1083, :type_symbol=>:time_timezone, :scalar_typecast=>:time) register_array_type('smallint', :oid=>1005, :scalar_oid=>21, :scalar_typecast=>:integer) register_array_type('oid', :oid=>1028, :scalar_oid=>26, :scalar_typecast=>:integer) register_array_type('real', :oid=>1021, :scalar_oid=>700, :scalar_typecast=>:float) register_array_type('character', :oid=>1014, :converter=>nil, :array_type=>:text, :scalar_typecast=>:string) register_array_type('character varying', :oid=>1015, :converter=>nil, :scalar_typecast=>:string, :type_symbol=>:varchar) register_array_type('xml', :oid=>143, :scalar_oid=>142) register_array_type('money', :oid=>791, :scalar_oid=>790) register_array_type('bit', :oid=>1561, :scalar_oid=>1560) register_array_type('bit varying', :oid=>1563, :scalar_oid=>1562, :type_symbol=>:varbit) register_array_type('uuid', :oid=>2951, :scalar_oid=>2950) register_array_type('xid', :oid=>1011, :scalar_oid=>28) register_array_type('cid', :oid=>1012, :scalar_oid=>29) register_array_type('name', :oid=>1003, :scalar_oid=>19) register_array_type('tid', :oid=>1010, :scalar_oid=>27) register_array_type('int2vector', :oid=>1006, :scalar_oid=>22) register_array_type('oidvector', :oid=>1013, :scalar_oid=>30) [:string_array, :integer_array, :decimal_array, :float_array, :boolean_array, :blob_array, :date_array, :time_array, :datetime_array].each do |v| @schema_type_classes[v] = PGArray end end end
Public Instance Methods
# File lib/sequel/extensions/pg_array.rb, line 130 def add_named_conversion_proc(name, &block) ret = super name = name.to_s if name.is_a?(Symbol) from(:pg_type).where(:typname=>name).select_map([:oid, :typarray]).each do |scalar_oid, array_oid| register_array_type(name, :oid=>array_oid.to_i, :scalar_oid=>scalar_oid.to_i) end ret end
Handle arrays in bound variables
# File lib/sequel/extensions/pg_array.rb, line 140 def bound_variable_arg(arg, conn) case arg when PGArray bound_variable_array(arg.to_a) when Array bound_variable_array(arg) else super end end
Freeze the pg array schema types to prevent adding new ones.
# File lib/sequel/extensions/pg_array.rb, line 152 def freeze @pg_array_schema_types.freeze super end
Register a database specific array type. Options:
- :array_type
-
The type to automatically cast the array to when literalizing the array. Usually the same as db_type.
- :converter
-
A callable object (e.g. Proc), that is called with each element of the array (usually a string), and should return the appropriate typecasted object.
- :oid
-
The PostgreSQL OID for the array type. This is used by the Sequel postgres adapter to set up automatic type conversion on retrieval from the database.
- :scalar_oid
-
Should be the PostgreSQL OID for the scalar version of this array type. If given, automatically sets the :converter option by looking for scalar conversion proc.
- :scalar_typecast
-
Should be a symbol indicating the typecast method that should be called on each element of the array, when a plain array is passed into a database typecast method. For example, for an array of integers, this could be set to :integer, so that the typecast_value_integer method is called on all of the array elements. Defaults to :type_symbol option.
- :type_symbol
-
The base of the schema type symbol for this type. For example, if you provide :integer, Sequel will recognize this type as :integer_array during schema parsing. Defaults to the db_type argument.
If a block is given, it is treated as the :converter option.
# File lib/sequel/extensions/pg_array.rb, line 178 def register_array_type(db_type, opts=OPTS, &block) oid = opts[:oid] soid = opts[:scalar_oid] if has_converter = opts.has_key?(:converter) raise Error, "can't provide both a block and :converter option to register_array_type" if block converter = opts[:converter] else has_converter = true if block converter = block end unless (soid || has_converter) && oid array_oid, scalar_oid = from(:pg_type).where(:typname=>db_type.to_s).get([:typarray, :oid]) soid ||= scalar_oid unless has_converter oid ||= array_oid end db_type = db_type.to_s type = (opts[:type_symbol] || db_type).to_sym typecast_method_map = @pg_array_schema_types if soid raise Error, "can't provide both a converter and :scalar_oid option to register" if has_converter converter = conversion_procs[soid] end array_type = (opts[:array_type] || db_type).to_s.dup.freeze creator = Creator.new(array_type, converter) add_conversion_proc(oid, creator) typecast_method_map[db_type] = :"#{type}_array" singleton_class.class_eval do meth = :"typecast_value_#{type}_array" scalar_typecast_method = :"typecast_value_#{opts.fetch(:scalar_typecast, type)}" define_method(meth){|v| typecast_value_pg_array(v, creator, scalar_typecast_method)} private meth end @schema_type_classes[:"#{type}_array"] = PGArray nil end
Private Instance Methods
Format arrays used in bound variables.
# File lib/sequel/extensions/pg_array.rb, line 225 def bound_variable_array(a) case a when Array "{#{a.map{|i| bound_variable_array(i)}.join(',')}}" when Sequel::SQL::Blob "\"#{literal(a)[BLOB_RANGE].gsub("''", "'").gsub(/("|\\)/, '\\\\\1')}\"" when Sequel::LiteralString a when String "\"#{a.gsub(/("|\\)/, '\\\\\1')}\"" else literal(a) end end
Convert ruby arrays to PostgreSQL arrays when used as default values.
# File lib/sequel/extensions/pg_array.rb, line 257 def column_definition_default_sql(sql, column) if (d = column[:default]) && d.is_a?(Array) && !Sequel.condition_specifier?(d) sql << " DEFAULT (#{literal(Sequel.pg_array(d))}::#{type_literal(column)})" else super end end
Look into both the current database's array schema types and the global array schema types to get the type symbol for the given database type string.
# File lib/sequel/extensions/pg_array.rb, line 243 def pg_array_schema_type(type) @pg_array_schema_types[type] end
Make the column type detection handle registered array types.
# File lib/sequel/extensions/pg_array.rb, line 248 def schema_column_type(db_type) if (db_type =~ /\A([^(]+)(?:\([^(]+\))?\[\]\z/io) && (type = pg_array_schema_type($1)) type else super end end
Given a value to typecast and the type of PGArray subclass:
-
If given a PGArray with a matching array_type, use it directly.
-
If given a PGArray with a different array_type, return a PGArray with the creator's type.
-
If given an Array, create a new PGArray instance for it. This does not typecast all members of the array in ruby for performance reasons, but it will cast the array the appropriate database type when the array is literalized.
# File lib/sequel/extensions/pg_array.rb, line 273 def typecast_value_pg_array(value, creator, scalar_typecast_method=nil) case value when PGArray if value.array_type != creator.type PGArray.new(value.to_a, creator.type) else value end when Array if scalar_typecast_method && respond_to?(scalar_typecast_method, true) value = Sequel.recursive_map(value, method(scalar_typecast_method)) end PGArray.new(value, creator.type) else raise Sequel::InvalidValue, "invalid value for array type: #{value.inspect}" end end