module Sequel::Postgres::PGRange::DatabaseMethods

Public Class Methods

extended(db) click to toggle source

Add the conversion procs to the database and extend the datasets to correctly literalize ruby Range values.

    # File lib/sequel/extensions/pg_range.rb
136 def self.extended(db)
137   db.instance_exec do
138     @pg_range_schema_types ||= {}
139     extend_datasets(DatasetMethods)
140     register_range_type('int4range', :oid=>3904, :subtype_oid=>23)
141     register_range_type('numrange', :oid=>3906, :subtype_oid=>1700)
142     register_range_type('tsrange', :oid=>3908, :subtype_oid=>1114)
143     register_range_type('tstzrange', :oid=>3910, :subtype_oid=>1184)
144     register_range_type('daterange', :oid=>3912, :subtype_oid=>1082)
145     register_range_type('int8range', :oid=>3926, :subtype_oid=>20)
146     if respond_to?(:register_array_type)
147       register_array_type('int4range', :oid=>3905, :scalar_oid=>3904, :scalar_typecast=>:int4range)
148       register_array_type('numrange', :oid=>3907, :scalar_oid=>3906, :scalar_typecast=>:numrange)
149       register_array_type('tsrange', :oid=>3909, :scalar_oid=>3908, :scalar_typecast=>:tsrange)
150       register_array_type('tstzrange', :oid=>3911, :scalar_oid=>3910, :scalar_typecast=>:tstzrange)
151       register_array_type('daterange', :oid=>3913, :scalar_oid=>3912, :scalar_typecast=>:daterange)
152       register_array_type('int8range', :oid=>3927, :scalar_oid=>3926, :scalar_typecast=>:int8range)
153     end
154     [:int4range, :numrange, :tsrange, :tstzrange, :daterange, :int8range].each do |v|
155       @schema_type_classes[v] = PGRange
156     end
157 
158     procs = conversion_procs
159     add_conversion_proc(3908, Parser.new("tsrange", procs[1114]))
160     add_conversion_proc(3910, Parser.new("tstzrange", procs[1184]))
161     if respond_to?(:register_array_type) && defined?(PGArray::Creator)
162       add_conversion_proc(3909, PGArray::Creator.new("tsrange", procs[3908]))
163       add_conversion_proc(3911, PGArray::Creator.new("tstzrange", procs[3910]))
164     end
165   end
166 end

Public Instance Methods

bound_variable_arg(arg, conn) click to toggle source

Handle Range and PGRange values in bound variables

Calls superclass method
    # File lib/sequel/extensions/pg_range.rb
169 def bound_variable_arg(arg, conn)
170   case arg
171   when PGRange 
172     arg.unquoted_literal(schema_utility_dataset)
173   when Range
174     PGRange.from_range(arg).unquoted_literal(schema_utility_dataset)
175   else
176     super
177   end
178 end
freeze() click to toggle source

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

Calls superclass method
    # File lib/sequel/extensions/pg_range.rb
181 def freeze
182   @pg_range_schema_types.freeze
183   super
184 end
register_range_type(db_type, opts=OPTS, &block) click to toggle source

Register a database specific range type. This can be used to support different range types per Database. Options:

:converter

A callable object (e.g. Proc), that is called with the start or end of the range (usually a string), and should return the appropriate typecasted object.

:oid

The PostgreSQL OID for the range type. This is used by the Sequel postgres adapter to set up automatic type conversion on retrieval from the database.

:subtype_oid

Should be the PostgreSQL OID for the range's subtype. If given, automatically sets the :converter option by looking for scalar conversion proc.

If a block is given, it is treated as the :converter option.

    # File lib/sequel/extensions/pg_range.rb
198 def register_range_type(db_type, opts=OPTS, &block)
199   oid = opts[:oid]
200   soid = opts[:subtype_oid]
201 
202   if has_converter = opts.has_key?(:converter)
203     raise Error, "can't provide both a block and :converter option to register_range_type" if block
204     converter = opts[:converter]
205   else
206     has_converter = true if block
207     converter = block
208   end
209 
210   unless (soid || has_converter) && oid
211     range_oid, subtype_oid = from(:pg_range).join(:pg_type, :oid=>:rngtypid).where(:typname=>db_type.to_s).get([:rngtypid, :rngsubtype])
212     soid ||= subtype_oid unless has_converter
213     oid ||= range_oid
214   end
215 
216   db_type = db_type.to_s.dup.freeze
217 
218   if soid
219     raise Error, "can't provide both a converter and :subtype_oid option to register" if has_converter 
220     raise Error, "no conversion proc for :subtype_oid=>#{soid.inspect} in conversion_procs" unless converter = conversion_procs[soid]
221   end
222 
223   parser = Parser.new(db_type, converter)
224   add_conversion_proc(oid, parser)
225 
226   @pg_range_schema_types[db_type] = db_type.to_sym
227 
228   singleton_class.class_eval do
229     meth = :"typecast_value_#{db_type}"
230     define_method(meth){|v| typecast_value_pg_range(v, parser)}
231     private meth
232   end
233 
234   @schema_type_classes[:"#{opts[:type_symbol] || db_type}"] = PGRange
235   nil
236 end

Private Instance Methods

bound_variable_array(a) click to toggle source

Handle arrays of range types in bound variables.

Calls superclass method
    # File lib/sequel/extensions/pg_range.rb
241 def bound_variable_array(a)
242   case a
243   when PGRange, Range
244     "\"#{bound_variable_arg(a, nil)}\""
245   else
246     super
247   end
248 end
schema_column_type(db_type) click to toggle source

Recognize the registered database range types.

Calls superclass method
    # File lib/sequel/extensions/pg_range.rb
251 def schema_column_type(db_type)
252   if type = @pg_range_schema_types[db_type]
253     type
254   else
255     super
256   end
257 end
schema_post_process(_) click to toggle source

Set the :ruby_default value if the default value is recognized as a range.

Calls superclass method
    # File lib/sequel/extensions/pg_range.rb
260 def schema_post_process(_)
261   super.each do |a|
262     h = a[1]
263     db_type = h[:db_type]
264     if @pg_range_schema_types[db_type] && h[:default] =~ /\A'([^']+)'::#{db_type}\z/
265       default = $1
266       if convertor = conversion_procs[h[:oid]]
267         h[:ruby_default] = convertor.call(default)
268       end
269     end
270   end
271 end
typecast_value_pg_range(value, parser) click to toggle source

Typecast value correctly to a PGRange. If already an PGRange instance with the same db_type, return as is. If a PGRange with a different subtype, return a new PGRange with the same values and the expected subtype. If a Range object, create a PGRange with the given db_type. If a string, assume it is in PostgreSQL output format and parse it using the parser.

    # File lib/sequel/extensions/pg_range.rb
280 def typecast_value_pg_range(value, parser)
281   case value
282   when PGRange
283     if value.db_type.to_s == parser.db_type
284       value
285     elsif value.empty?
286       PGRange.empty(parser.db_type)
287     else
288       PGRange.new(value.begin, value.end, :exclude_begin=>value.exclude_begin?, :exclude_end=>value.exclude_end?, :db_type=>parser.db_type)
289     end
290   when Range
291     PGRange.from_range(value, parser.db_type)
292   when String
293     parser.call(value)
294   else
295     raise Sequel::InvalidValue, "invalid value for range type: #{value.inspect}"
296   end
297 end