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     "\"#{literal(a)[BLOB_RANGE].gsub("''", "'").gsub(/("|\\)/, '\\\\\1')}\""
232   when Sequel::LiteralString
233     a
234   when String
235     "\"#{a.gsub(/("|\\)/, '\\\\\1')}\""
236   else
237     literal(a)
238   end
239 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
269 def column_definition_default_sql(sql, column)
270   if (d = column[:default]) && d.is_a?(Array) && !Sequel.condition_specifier?(d)
271     sql << " DEFAULT (#{literal(Sequel.pg_array(d))}::#{type_literal(column)})"
272   else
273     super
274   end
275 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
244 def pg_array_schema_type(type)
245   @pg_array_schema_types[type]
246 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
249 def schema_column_type(db_type)
250   if (db_type =~ /\A([^(]+)(?:\([^(]+\))?\[\]\z/io) && (type = pg_array_schema_type($1))
251     type
252   else
253     super
254   end
255 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
258 def schema_post_process(_)
259   super.each do |a|
260     h = a[1]
261     if h[:default] =~ /\A(?:'\{\}'|ARRAY\[\])::([\w ]+)\[\]\z/
262       type = $1.freeze
263       h[:callable_default] = lambda{Sequel.pg_array([], type)}
264     end
265   end
266 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
285 def typecast_value_pg_array(value, creator, scalar_typecast_method=nil)
286   case value
287   when PGArray
288     if value.array_type != creator.type
289       PGArray.new(value.to_a, creator.type)
290     else
291       value
292     end
293   when Array
294     if scalar_typecast_method && respond_to?(scalar_typecast_method, true)
295       value = Sequel.recursive_map(value, method(scalar_typecast_method))
296     end
297     PGArray.new(value, creator.type)
298   else
299     raise Sequel::InvalidValue, "invalid value for array type: #{value.inspect}"
300   end
301 end