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 86 def self.extended(db) 87 db.instance_exec do 88 @pg_array_schema_types ||= {} 89 register_array_type('timestamp without time zone', :oid=>1115, :scalar_oid=>1114, :type_symbol=>:datetime) 90 register_array_type('timestamp with time zone', :oid=>1185, :scalar_oid=>1184, :type_symbol=>:datetime_timezone, :scalar_typecast=>:datetime) 91 92 register_array_type('text', :oid=>1009, :scalar_oid=>25, :type_symbol=>:string) 93 register_array_type('integer', :oid=>1007, :scalar_oid=>23) 94 register_array_type('bigint', :oid=>1016, :scalar_oid=>20, :scalar_typecast=>:integer) 95 register_array_type('numeric', :oid=>1231, :scalar_oid=>1700, :type_symbol=>:decimal) 96 register_array_type('double precision', :oid=>1022, :scalar_oid=>701, :type_symbol=>:float) 97 98 register_array_type('boolean', :oid=>1000, :scalar_oid=>16) 99 register_array_type('bytea', :oid=>1001, :scalar_oid=>17, :type_symbol=>:blob) 100 register_array_type('date', :oid=>1182, :scalar_oid=>1082) 101 register_array_type('time without time zone', :oid=>1183, :scalar_oid=>1083, :type_symbol=>:time) 102 register_array_type('time with time zone', :oid=>1270, :scalar_oid=>1266, :type_symbol=>:time_timezone, :scalar_typecast=>:time) 103 104 register_array_type('smallint', :oid=>1005, :scalar_oid=>21, :scalar_typecast=>:integer) 105 register_array_type('oid', :oid=>1028, :scalar_oid=>26, :scalar_typecast=>:integer) 106 register_array_type('real', :oid=>1021, :scalar_oid=>700, :scalar_typecast=>:float) 107 register_array_type('character', :oid=>1014, :converter=>nil, :array_type=>:text, :scalar_typecast=>:string) 108 register_array_type('character varying', :oid=>1015, :converter=>nil, :scalar_typecast=>:string, :type_symbol=>:varchar) 109 110 register_array_type('xml', :oid=>143, :scalar_oid=>142) 111 register_array_type('money', :oid=>791, :scalar_oid=>790) 112 register_array_type('bit', :oid=>1561, :scalar_oid=>1560) 113 register_array_type('bit varying', :oid=>1563, :scalar_oid=>1562, :type_symbol=>:varbit) 114 register_array_type('uuid', :oid=>2951, :scalar_oid=>2950) 115 116 register_array_type('xid', :oid=>1011, :scalar_oid=>28) 117 register_array_type('cid', :oid=>1012, :scalar_oid=>29) 118 119 register_array_type('name', :oid=>1003, :scalar_oid=>19) 120 register_array_type('tid', :oid=>1010, :scalar_oid=>27) 121 register_array_type('int2vector', :oid=>1006, :scalar_oid=>22) 122 register_array_type('oidvector', :oid=>1013, :scalar_oid=>30) 123 124 [:string_array, :integer_array, :decimal_array, :float_array, :boolean_array, :blob_array, :date_array, :time_array, :datetime_array].each do |v| 125 @schema_type_classes[v] = PGArray 126 end 127 end 128 end
Public Instance Methods
# File lib/sequel/extensions/pg_array.rb 130 def add_named_conversion_proc(name, &block) 131 ret = super 132 name = name.to_s if name.is_a?(Symbol) 133 from(:pg_type).where(:typname=>name).select_map([:oid, :typarray]).each do |scalar_oid, array_oid| 134 register_array_type(name, :oid=>array_oid.to_i, :scalar_oid=>scalar_oid.to_i) 135 end 136 ret 137 end
Handle arrays in bound variables
# File lib/sequel/extensions/pg_array.rb 140 def bound_variable_arg(arg, conn) 141 case arg 142 when PGArray 143 bound_variable_array(arg.to_a) 144 when Array 145 bound_variable_array(arg) 146 else 147 super 148 end 149 end
Freeze the pg array schema types to prevent adding new ones.
# File lib/sequel/extensions/pg_array.rb 152 def freeze 153 @pg_array_schema_types.freeze 154 super 155 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 178 def register_array_type(db_type, opts=OPTS, &block) 179 oid = opts[:oid] 180 soid = opts[:scalar_oid] 181 182 if has_converter = opts.has_key?(:converter) 183 raise Error, "can't provide both a block and :converter option to register_array_type" if block 184 converter = opts[:converter] 185 else 186 has_converter = true if block 187 converter = block 188 end 189 190 unless (soid || has_converter) && oid 191 array_oid, scalar_oid = from(:pg_type).where(:typname=>db_type.to_s).get([:typarray, :oid]) 192 soid ||= scalar_oid unless has_converter 193 oid ||= array_oid 194 end 195 196 db_type = db_type.to_s 197 type = (opts[:type_symbol] || db_type).to_sym 198 typecast_method_map = @pg_array_schema_types 199 200 if soid 201 raise Error, "can't provide both a converter and :scalar_oid option to register" if has_converter 202 converter = conversion_procs[soid] 203 end 204 205 array_type = (opts[:array_type] || db_type).to_s.dup.freeze 206 creator = Creator.new(array_type, converter) 207 add_conversion_proc(oid, creator) 208 209 typecast_method_map[db_type] = :"#{type}_array" 210 211 singleton_class.class_eval do 212 meth = :"typecast_value_#{type}_array" 213 scalar_typecast_method = :"typecast_value_#{opts.fetch(:scalar_typecast, type)}" 214 define_method(meth){|v| typecast_value_pg_array(v, creator, scalar_typecast_method)} 215 private meth 216 end 217 218 @schema_type_classes[:"#{type}_array"] = PGArray 219 nil 220 end
Private Instance Methods
Format arrays used in bound variables.
# File lib/sequel/extensions/pg_array.rb 225 def bound_variable_array(a) 226 case a 227 when Array 228 "{#{a.map{|i| bound_variable_array(i)}.join(',')}}" 229 when Sequel::SQL::Blob 230 "\"#{literal(a)[BLOB_RANGE].gsub("''", "'").gsub(/("|\\)/, '\\\\\1')}\"" 231 when Sequel::LiteralString 232 a 233 when String 234 "\"#{a.gsub(/("|\\)/, '\\\\\1')}\"" 235 else 236 literal(a) 237 end 238 end
Convert ruby arrays to PostgreSQL arrays when used as default values.
# File lib/sequel/extensions/pg_array.rb 268 def column_definition_default_sql(sql, column) 269 if (d = column[:default]) && d.is_a?(Array) && !Sequel.condition_specifier?(d) 270 sql << " DEFAULT (#{literal(Sequel.pg_array(d))}::#{type_literal(column)})" 271 else 272 super 273 end 274 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 243 def pg_array_schema_type(type) 244 @pg_array_schema_types[type] 245 end
Make the column type detection handle registered array types.
# File lib/sequel/extensions/pg_array.rb 248 def schema_column_type(db_type) 249 if (db_type =~ /\A([^(]+)(?:\([^(]+\))?\[\]\z/io) && (type = pg_array_schema_type($1)) 250 type 251 else 252 super 253 end 254 end
Set the :callable_default value if the default value is recognized as an empty array.
# File lib/sequel/extensions/pg_array.rb 257 def schema_post_process(_) 258 super.each do |a| 259 h = a[1] 260 if h[:default] =~ /\A(?:'\{\}'|ARRAY\[\])::([\w ]+)\[\]\z/ 261 type = $1.freeze 262 h[:callable_default] = lambda{Sequel.pg_array([], type)} 263 end 264 end 265 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 aPGArray
with the creator's type. -
If given an
Array
, create a newPGArray
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 284 def typecast_value_pg_array(value, creator, scalar_typecast_method=nil) 285 case value 286 when PGArray 287 if value.array_type != creator.type 288 PGArray.new(value.to_a, creator.type) 289 else 290 value 291 end 292 when Array 293 if scalar_typecast_method && respond_to?(scalar_typecast_method, true) 294 value = Sequel.recursive_map(value, method(scalar_typecast_method)) 295 end 296 PGArray.new(value, creator.type) 297 else 298 raise Sequel::InvalidValue, "invalid value for array type: #{value.inspect}" 299 end 300 end