module Sequel::Postgres::PGArray::DatabaseMethods

Constants

BLOB_RANGE

Public Class Methods

extended(db) click to toggle source

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

add_named_conversion_proc(name, &block) click to toggle source
Calls superclass method
    # 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
bound_variable_arg(arg, conn) click to toggle source

Handle arrays in bound variables

Calls superclass method
    # 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() click to toggle source

Freeze the pg array schema types to prevent adding new ones.

Calls superclass method
    # File lib/sequel/extensions/pg_array.rb
152 def freeze
153   @pg_array_schema_types.freeze
154   super
155 end
register_array_type(db_type, opts=OPTS, &block) click to toggle source

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     alias_method(meth, meth)
217   end
218 
219   @schema_type_classes[:"#{type}_array"] = PGArray
220   nil
221 end

Private Instance Methods

bound_variable_array(a) click to toggle source

Format arrays used in bound variables.

    # File lib/sequel/extensions/pg_array.rb
226 def bound_variable_array(a)
227   case a
228   when Array
229     "{#{a.map{|i| bound_variable_array(i)}.join(',')}}"
230   when Sequel::SQL::Blob
231     bound_variable_array_string(literal(a)[BLOB_RANGE].gsub("''", "'"))
232   when Sequel::LiteralString
233     a
234   when String
235     bound_variable_array_string(a)
236   when Float
237     if a.infinite?
238       a > 0 ? '"Infinity"' : '"-Infinity"'
239     elsif a.nan?
240       '"NaN"'
241     else
242       literal(a)
243     end
244   when Time, Date
245     @default_dataset.literal_date_or_time(a)
246   else
247     if (s = bound_variable_arg(a, nil)).is_a?(String)
248       bound_variable_array_string(s)
249     else
250       literal(a)
251     end
252   end
253 end
bound_variable_array_string(s) click to toggle source

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.

    # File lib/sequel/extensions/pg_array.rb
258 def bound_variable_array_string(s)
259   "\"#{s.gsub(/("|\\)/, '\\\\\1')}\""
260 end
column_definition_default_sql(sql, column) click to toggle source

Convert ruby arrays to PostgreSQL arrays when used as default values.

Calls superclass method
    # File lib/sequel/extensions/pg_array.rb
290 def column_definition_default_sql(sql, column)
291   if (d = column[:default]) && d.is_a?(Array) && !Sequel.condition_specifier?(d)
292     sql << " DEFAULT (#{literal(Sequel.pg_array(d))}::#{type_literal(column)})"
293   else
294     super
295   end
296 end
pg_array_schema_type(type) click to toggle source

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
265 def pg_array_schema_type(type)
266   @pg_array_schema_types[type]
267 end
schema_array_type(db_type) click to toggle source

Make the column type detection handle registered array types.

Calls superclass method
    # File lib/sequel/extensions/pg_array.rb
270 def schema_array_type(db_type)
271   if (db_type =~ /\A([^(]+)(?:\([^(]+\))?\[\]\z/io) && (type = pg_array_schema_type($1))
272     type
273   else
274     super
275   end
276 end
schema_post_process(_) click to toggle source

Set the :callable_default value if the default value is recognized as an empty array.

Calls superclass method
    # File lib/sequel/extensions/pg_array.rb
279 def schema_post_process(_)
280   super.each do |a|
281     h = a[1]
282     if h[:default] =~ /\A(?:'\{\}'|ARRAY\[\])::([\w ]+)\[\]\z/
283       type = $1.freeze
284       h[:callable_default] = lambda{Sequel.pg_array([], type)}
285     end
286   end
287 end
typecast_value_pg_array(value, creator, scalar_typecast_method=nil) click to toggle source

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
306 def typecast_value_pg_array(value, creator, scalar_typecast_method=nil)
307   case value
308   when PGArray
309     if value.array_type != creator.type
310       PGArray.new(value.to_a, creator.type)
311     else
312       value
313     end
314   when Array
315     if scalar_typecast_method && respond_to?(scalar_typecast_method, true)
316       value = Sequel.recursive_map(value, method(scalar_typecast_method))
317     end
318     PGArray.new(value, creator.type)
319   else
320     raise Sequel::InvalidValue, "invalid value for array type: #{value.inspect}"
321   end
322 end