Module: ActiveRecord::Metal::Postgresql::Conversions::HStore

Included in:
ActiveRecord::Metal::Postgresql::Conversions
Defined in:
lib/active_record/metal/postgresql/conversions.rb,
lib/active_record/metal/postgresql/conversions.rb

Constant Summary collapse

SELF =
self
T =
::Hash
NULL =
nil
HSTORE_ESCAPED =
/[,\s=>\\]/

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.escape(hsh, connection = ActiveRecord::Base.connection) ⇒ Object



144
145
146
147
148
# File 'lib/active_record/metal/postgresql/conversions.rb', line 144

def self.escape(hsh, connection=ActiveRecord::Base.connection)
  hsh.map do |idx, val| 
    "%s=>%s" % [escape_string(idx), escape_string(val)]
  end * ","
end

.escape_string(str) ⇒ Object

From activerecord-postgres-hstore, r0.6 Escapes values such that they will work in an hstore string



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/active_record/metal/postgresql/conversions.rb', line 125

def self.escape_string(str)
  if str.nil?
    return 'NULL'
  end

  str = str.to_s
  # backslash is an escape character for strings, and an escape character for gsub, so you need 6 backslashes to get 2 in the output.
  # see http://stackoverflow.com/questions/1542214/weird-backslash-substitution-in-ruby for the gory details
  str = str.gsub(/\\/, '\\\\\\')
  # escape backslashes before injecting more backslashes
  str = str.gsub(/"/, '\"')

  if str =~ HSTORE_ESCAPED or str.empty?
    str = '"%s"' % str
  end

  return str
end

.hstore_pairObject



168
169
170
171
172
173
# File 'lib/active_record/metal/postgresql/conversions.rb', line 168

def self.hstore_pair
  quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
  unquoted_string = /[^\s=,][^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
  string = /(#{quoted_string}|#{unquoted_string})/
  /#{string}\s*=>\s*#{string}/
end

.unescape(str) ⇒ Object

Creates a hash from a valid double quoted hstore format, ‘cause this is the format that postgresql spits out.



152
153
154
155
156
157
158
# File 'lib/active_record/metal/postgresql/conversions.rb', line 152

def self.unescape(str)
  token_pairs = (str.scan(hstore_pair)).map { |k,v| [k,v =~ /^NULL$/i ? nil : v] }
  token_pairs = token_pairs.map { |k,v|
    [ unescape_string(k).to_sym, unescape_string(v) ]
  }
  ::Hash[ token_pairs ]
end

.unescape_string(str) ⇒ Object



160
161
162
163
164
165
166
# File 'lib/active_record/metal/postgresql/conversions.rb', line 160

def self.unescape_string(str)
  case str
  when nil then str
  when /\A"(.*)"\Z/m then $1.gsub(/\\(.)/, '\1')
  else str.gsub(/\\(.)/, '\1')
  end
end

Instance Method Details

#_hstore(s) ⇒ Object



117
118
119
# File 'lib/active_record/metal/postgresql/conversions.rb', line 117

def _hstore(s)
  SELF.unescape(s)
end