class Sequel::Postgres::PGRange::Parser

  1. lib/sequel/extensions/pg_range.rb
Parent: PGRange

Creates callable objects that convert strings into PGRange instances.

Methods

Public Class

  1. new

Public Instance

  1. call
  2. converter
  3. db_type

Constants

PARSER = /\A(\[|\()("((?:\\"|[^"])*)"|[^"]*),("((?:\\"|[^"])*)"|[^"]*)(\]|\))\z/o  

Regexp that parses the full range of PostgreSQL range type output, except for empty ranges.

REPLACE_RE = /\\(.)/.freeze  
REPLACE_WITH = '\1'.freeze  

Attributes

converter [R]

A callable object to convert the beginning and ending of the range into the appropriate ruby type.

db_type [R]

The database range type for this parser (e.g. ‘int4range’), automatically setting the #db_type for the returned PGRange instances.

Public Class methods

new (db_type, converter=nil)

Set the #db_type and converter on initialization.

[show source]
# File lib/sequel/extensions/pg_range.rb, line 140
def initialize(db_type, converter=nil)
  @db_type = db_type.to_s.dup.freeze if db_type
  @converter = converter
end

Public Instance methods

call (string)

Parse the range type input string into a PGRange value.

[show source]
# File lib/sequel/extensions/pg_range.rb, line 146
def call(string)
  if string == EMPTY
    return PGRange.empty(db_type)
  end

  raise(InvalidValue, "invalid or unhandled range format: #{string.inspect}") unless matches = PARSER.match(string)

  exclude_begin = matches[1] == '('
  exclude_end = matches[6] == ')'

  # If the input is quoted, it needs to be unescaped.  Also, quoted input isn't
  # checked for emptiness, since the empty quoted string is considered an 
  # element that happens to be the empty string, while an unquoted empty string
  # is considered unbounded.
  #
  # While PostgreSQL allows pure escaping for input (without quoting), it appears
  # to always use the quoted output form when characters need to be escaped, so
  # there isn't a need to unescape unquoted output.
  if beg = matches[3]
    beg.gsub!(REPLACE_RE, REPLACE_WITH)
  else
    beg = matches[2] unless matches[2].empty?
  end
  if en = matches[5]
    en.gsub!(REPLACE_RE, REPLACE_WITH)
  else
    en = matches[4] unless matches[4].empty?
  end

  if c = converter
    beg = c.call(beg) if beg
    en = c.call(en) if en
  end

  PGRange.new(beg, en, :exclude_begin=>exclude_begin, :exclude_end=>exclude_end, :db_type=>db_type)
end