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   end
217 
218   @schema_type_classes[:"#{type}_array"] = PGArray
219   nil
220 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
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
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
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
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
243 def pg_array_schema_type(type)
244   @pg_array_schema_types[type]
245 end
schema_column_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
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
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
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
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
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