module Sequel::Postgres::PGArray::DatabaseMethods
Constants
- BLOB_RANGE
Public Class Methods
Source
# File lib/sequel/extensions/pg_array.rb 87 def self.extended(db) 88 db.instance_exec do 89 @pg_array_schema_types ||= {} 90 register_array_type('timestamp without time zone', :oid=>1115, :scalar_oid=>1114, :type_symbol=>:datetime) 91 register_array_type('timestamp with time zone', :oid=>1185, :scalar_oid=>1184, :type_symbol=>:datetime_timezone, :scalar_typecast=>:datetime) 92 93 register_array_type('text', :oid=>1009, :scalar_oid=>25, :type_symbol=>:string) 94 register_array_type('integer', :oid=>1007, :scalar_oid=>23) 95 register_array_type('bigint', :oid=>1016, :scalar_oid=>20, :scalar_typecast=>:integer) 96 register_array_type('numeric', :oid=>1231, :scalar_oid=>1700, :type_symbol=>:decimal) 97 register_array_type('double precision', :oid=>1022, :scalar_oid=>701, :type_symbol=>:float) 98 99 register_array_type('boolean', :oid=>1000, :scalar_oid=>16) 100 register_array_type('bytea', :oid=>1001, :scalar_oid=>17, :type_symbol=>:blob) 101 register_array_type('date', :oid=>1182, :scalar_oid=>1082) 102 register_array_type('time without time zone', :oid=>1183, :scalar_oid=>1083, :type_symbol=>:time) 103 register_array_type('time with time zone', :oid=>1270, :scalar_oid=>1266, :type_symbol=>:time_timezone, :scalar_typecast=>:time) 104 105 register_array_type('smallint', :oid=>1005, :scalar_oid=>21, :scalar_typecast=>:integer) 106 register_array_type('oid', :oid=>1028, :scalar_oid=>26, :scalar_typecast=>:integer) 107 register_array_type('real', :oid=>1021, :scalar_oid=>700, :scalar_typecast=>:float) 108 register_array_type('character', :oid=>1014, :converter=>nil, :array_type=>:text, :scalar_typecast=>:string) 109 register_array_type('character varying', :oid=>1015, :converter=>nil, :scalar_typecast=>:string, :type_symbol=>:varchar) 110 111 register_array_type('xml', :oid=>143, :scalar_oid=>142) 112 register_array_type('money', :oid=>791, :scalar_oid=>790) 113 register_array_type('bit', :oid=>1561, :scalar_oid=>1560) 114 register_array_type('bit varying', :oid=>1563, :scalar_oid=>1562, :type_symbol=>:varbit) 115 register_array_type('uuid', :oid=>2951, :scalar_oid=>2950) 116 117 register_array_type('xid', :oid=>1011, :scalar_oid=>28) 118 register_array_type('cid', :oid=>1012, :scalar_oid=>29) 119 120 register_array_type('name', :oid=>1003, :scalar_oid=>19) 121 register_array_type('tid', :oid=>1010, :scalar_oid=>27) 122 register_array_type('int2vector', :oid=>1006, :scalar_oid=>22) 123 register_array_type('oidvector', :oid=>1013, :scalar_oid=>30) 124 125 [:string_array, :integer_array, :decimal_array, :float_array, :boolean_array, :blob_array, :date_array, :time_array, :datetime_array].each do |v| 126 @schema_type_classes[v] = PGArray 127 end 128 end 129 end
Create the local hash of database type strings to schema type symbols, used for array types local to this database.
Public Instance Methods
Source
# File lib/sequel/extensions/pg_array.rb 131 def add_named_conversion_proc(name, &block) 132 ret = super 133 name = name.to_s if name.is_a?(Symbol) 134 from(:pg_type).where(:typname=>name).select_map([:oid, :typarray]).each do |scalar_oid, array_oid| 135 register_array_type(name, :oid=>array_oid.to_i, :scalar_oid=>scalar_oid.to_i) 136 end 137 ret 138 end
Source
# File lib/sequel/extensions/pg_array.rb 141 def bound_variable_arg(arg, conn) 142 case arg 143 when PGArray 144 bound_variable_array(arg.to_a) 145 when Array 146 bound_variable_array(arg) 147 else 148 super 149 end 150 end
Handle arrays in bound variables
Source
# File lib/sequel/extensions/pg_array.rb 153 def freeze 154 @pg_array_schema_types.freeze 155 super 156 end
Freeze the pg array schema types to prevent adding new ones.
Source
# File lib/sequel/extensions/pg_array.rb 179 def register_array_type(db_type, opts=OPTS, &block) 180 oid = opts[:oid] 181 soid = opts[:scalar_oid] 182 183 if has_converter = opts.has_key?(:converter) 184 raise Error, "can't provide both a block and :converter option to register_array_type" if block 185 converter = opts[:converter] 186 else 187 has_converter = true if block 188 converter = block 189 end 190 191 unless (soid || has_converter) && oid 192 array_oid, scalar_oid = from(:pg_type).where(:typname=>db_type.to_s).get([:typarray, :oid]) 193 soid ||= scalar_oid unless has_converter 194 oid ||= array_oid 195 end 196 197 db_type = db_type.to_s 198 type = (opts[:type_symbol] || db_type).to_sym 199 typecast_method_map = @pg_array_schema_types 200 201 if soid 202 raise Error, "can't provide both a converter and :scalar_oid option to register" if has_converter 203 converter = conversion_procs[soid] 204 end 205 206 array_type = (opts[:array_type] || db_type).to_s.dup.freeze 207 creator = Creator.new(array_type, converter) 208 add_conversion_proc(oid, creator) 209 210 typecast_method_map[db_type] = :"#{type}_array" 211 212 singleton_class.class_eval do 213 meth = :"typecast_value_#{type}_array" 214 scalar_typecast_method = :"typecast_value_#{opts.fetch(:scalar_typecast, type)}" 215 define_method(meth){|v| typecast_value_pg_array(v, creator, scalar_typecast_method)} 216 private meth 217 alias_method(meth, meth) 218 end 219 220 @schema_type_classes[:"#{type}_array"] = PGArray 221 nil 222 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
Sequelpostgres 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,
Sequelwill 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.
Private Instance Methods
Source
# File lib/sequel/extensions/pg_array.rb 227 def bound_variable_array(a) 228 case a 229 when Array 230 "{#{a.map{|i| bound_variable_array(i)}.join(',')}}" 231 when Sequel::SQL::Blob 232 bound_variable_array_string(literal(a)[BLOB_RANGE].gsub("''", "'")) 233 when Sequel::LiteralString 234 a 235 when String 236 bound_variable_array_string(a) 237 when Float 238 if a.infinite? 239 a > 0 ? '"Infinity"' : '"-Infinity"' 240 elsif a.nan? 241 '"NaN"' 242 else 243 literal(a) 244 end 245 when Time, Date 246 @default_dataset.literal_date_or_time(a) 247 else 248 if (s = bound_variable_arg(a, nil)).is_a?(String) 249 bound_variable_array_string(s) 250 else 251 literal(a) 252 end 253 end 254 end
Format arrays used in bound variables.
Source
# File lib/sequel/extensions/pg_array.rb 259 def bound_variable_array_string(s) 260 "\"#{s.gsub(/("|\\)/, '\\\\\1')}\"" 261 end
Escape strings used as array members in bound variables. Most complex will create a regular string with bound_variable_arg, and then use this escaping to format it as an array member.
Source
# File lib/sequel/extensions/pg_array.rb 291 def column_definition_default_sql(sql, column) 292 if (d = column[:default]) && d.is_a?(Array) && !Sequel.condition_specifier?(d) 293 sql << " DEFAULT (#{literal(Sequel.pg_array(d))}::#{type_literal(column)})" 294 else 295 super 296 end 297 end
Convert ruby arrays to PostgreSQL arrays when used as default values.
Source
# File lib/sequel/extensions/pg_array.rb 266 def pg_array_schema_type(type) 267 @pg_array_schema_types[type] 268 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.
Source
# File lib/sequel/extensions/pg_array.rb 271 def schema_array_type(db_type) 272 if (db_type =~ /\A([^(]+)(?:\([^(]+\))?\[\]\z/io) && (type = pg_array_schema_type($1)) 273 type 274 else 275 super 276 end 277 end
Make the column type detection handle registered array types.
Source
# File lib/sequel/extensions/pg_array.rb 280 def schema_post_process(_) 281 super.each do |a| 282 h = a[1] 283 if h[:default] =~ /\A(?:'\{\}'|ARRAY\[\])::([\w ]+)\[\]\z/ 284 type = $1.freeze 285 h[:callable_default] = lambda{Sequel.pg_array([], type)} 286 end 287 end 288 end
Set the :callable_default value if the default value is recognized as an empty array.
Source
# File lib/sequel/extensions/pg_array.rb 307 def typecast_value_pg_array(value, creator, scalar_typecast_method=nil) 308 case value 309 when PGArray 310 if value.array_type != creator.type 311 PGArray.new(value.to_a, creator.type) 312 else 313 value 314 end 315 when Array 316 if scalar_typecast_method && respond_to?(scalar_typecast_method, true) 317 value = Sequel.recursive_map(value, method(scalar_typecast_method)) 318 end 319 PGArray.new(value, creator.type) 320 else 321 raise Sequel::InvalidValue, "invalid value for array type: #{value.inspect}" 322 end 323 end
Given a value to typecast and the type of PGArray subclass:
-
If given a
PGArraywith a matching array_type, use it directly. -
If given a
PGArraywith a different array_type, return aPGArraywith the creator’s type. -
If given an
Array, create a newPGArrayinstance 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.