Module: ArJdbc::PostgreSQL::Column

Included in:
ActiveRecord::ConnectionAdapters::PostgreSQLColumn
Defined in:
lib/arjdbc/postgresql/column.rb

Overview

Column behavior based on PostgreSQL adapter in Rails.

Defined Under Namespace

Modules: Cast

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#arrayObject

Returns the value of attribute array.



21
22
23
# File 'lib/arjdbc/postgresql/column.rb', line 21

def array
  @array
end

Instance Method Details

#array?Boolean

in case we remove the array reader

Returns:

  • (Boolean)


22
# File 'lib/arjdbc/postgresql/column.rb', line 22

def array?; array; end

#default_value(default) ⇒ Object

Extracts the value from a PostgreSQL column default definition.

NOTE: based on self.extract_value_from_default(default) code



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/arjdbc/postgresql/column.rb', line 28

def default_value(default)
  # This is a performance optimization for Ruby 1.9.2 in development.
  # If the value is nil, we return nil straight away without checking
  # the regular expressions. If we check each regular expression,
  # Regexp#=== will call NilClass#to_str, which will trigger
  # method_missing (defined by whiny nil in ActiveSupport) which
  # makes this method very very slow.
  return default unless default

  case default
    when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
      $1
    # Numeric types
    when /\A\(?(-?\d+(\.\d*)?\)?)\z/
      $1
    # Character types
    when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
      $1
    # Binary data types
    when /\A'(.*)'::bytea\z/m
      $1
    # Date/time types
    when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
      $1
    when /\A'(.*)'::interval\z/
      $1
    # Boolean type
    when 'true'
      true
    when 'false'
      false
    # Geometric types
    when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
      $1
    # Network address types
    when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
      $1
    # Bit string types
    when /\AB'(.*)'::"?bit(?: varying)?"?\z/
      $1
    # XML type
    when /\A'(.*)'::xml\z/m
      $1
    # Arrays
    when /\A'(.*)'::"?\D+"?\[\]\z/
      $1
    when /\AARRAY\[(.*)\](::\D+)?\z/
      "{#{$1.gsub(/'(.*?)'::[a-z]+(,)?\s?/, '\1\2')}}"
    # Hstore
    when /\A'(.*)'::hstore\z/
      $1
    # JSON
    when /\A'(.*)'::json\z/
      $1
    # Object identifier types
    when /\A-?\d+\z/
      $1
    else
      # Anything else is blank, some user type, or some function
      # and we can't know the value of that, so return nil.
      nil
  end
end

#extract_bounds(value) ⇒ Object

OID Type::Range helpers :



282
283
284
285
286
287
288
289
# File 'lib/arjdbc/postgresql/column.rb', line 282

def extract_bounds(value)
  f, t = value[1..-2].split(',')
  {
    :from => (value[1] == ',' || f == '-infinity') ? infinity(:negative => true) : f,
    :to   => (value[-2] == ',' || t == 'infinity') ? infinity : t,
    :exclude_start => (value[0] == '('), :exclude_end => (value[-1] == ')')
  }
end

#infinity(options = {}) ⇒ Object



291
292
293
# File 'lib/arjdbc/postgresql/column.rb', line 291

def infinity(options = {})
  ::Float::INFINITY * (options[:negative] ? -1 : 1)
end

#to_integer(value) ⇒ Object



295
296
297
# File 'lib/arjdbc/postgresql/column.rb', line 295

def to_integer(value)
  (value.respond_to?(:infinite?) && value.infinite?) ? value : value.to_i
end

#type_cast(value) ⇒ Object

Casts value (which is a String) to an appropriate instance.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/arjdbc/postgresql/column.rb', line 93

def type_cast(value)
  return if value.nil?
  return super if encoded? # respond_to?(:encoded?) only since AR-3.2

  # NOTE: we do not use OID::Type
  # @oid_type.type_cast value

  return value if array? # handled on the connection (JDBC) side

  case type
  when :hstore then self.class.string_to_hstore value
  when :json then self.class.string_to_json value
  when :cidr, :inet then self.class.string_to_cidr value
  when :macaddr then value
  when :tsvector then value
  when :datetime, :timestamp then self.class.string_to_time value
  else
    case sql_type
    when 'money'
      # Because money output is formatted according to the locale, there
      # are two cases to consider (note the decimal separators) :
      # (1) $12,345,678.12
      # (2) $12.345.678,12
      case value
      when /^-?\D+[\d,]+\.\d{2}$/ # (1)
        value.gsub!(/[^-\d.]/, '')
      when /^-?\D+[\d.]+,\d{2}$/ # (2)
        value.gsub!(/[^-\d,]/, '')
        value.sub!(/,/, '.')
      end
      self.class.value_to_decimal value
    when /^point/
      value.is_a?(String) ? self.class.string_to_point(value) : value
    when /^(bit|varbit)/
      value.is_a?(String) ? self.class.string_to_bit(value) : value
    when /(.*?)range$/
      return if value.nil? || value == 'empty'
      return value if value.is_a?(::Range)

      extracted = extract_bounds(value)

      case $1 # subtype
      when 'date' # :date
        from = self.class.value_to_date(extracted[:from])
        from -= 1.day if extracted[:exclude_start]
        to = self.class.value_to_date(extracted[:to])
      when 'num' # :decimal
        from = BigDecimal.new(extracted[:from].to_s)
        # FIXME: add exclude start for ::Range, same for timestamp ranges
        to = BigDecimal.new(extracted[:to].to_s)
      when 'ts', 'tstz' # :time
        from = self.class.string_to_time(extracted[:from])
        to = self.class.string_to_time(extracted[:to])
      when 'int4', 'int8' # :integer
        from = to_integer(extracted[:from]) rescue value ? 1 : 0
        from -= 1 if extracted[:exclude_start]
        to = to_integer(extracted[:to]) rescue value ? 1 : 0
      else
        return value
      end

      ::Range.new(from, to, extracted[:exclude_end])
    else super
    end
  end
end