aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorJoel <joel@renewfund.com>2012-02-04 23:51:03 -0800
committerJoel <joel@renewfund.com>2012-02-08 22:28:51 -0800
commitcf572114608b7813cacd88076dc272ac2a2a7955 (patch)
tree65bced5ba3c994dd4108fb41a5280b8e5b5f8cc2 /activerecord/lib
parenta110789ca4b89c2ad984d044c175a0b8a018c54b (diff)
downloadrails-cf572114608b7813cacd88076dc272ac2a2a7955.tar.gz
rails-cf572114608b7813cacd88076dc272ac2a2a7955.tar.bz2
rails-cf572114608b7813cacd88076dc272ac2a2a7955.zip
Additional hstore tests, supporting null values, better compliance with postgres docs
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb38
1 files changed, 17 insertions, 21 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index ed82c4d6f6..52693e19d9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -56,36 +56,32 @@ module ActiveRecord
if Hash === object
object.map { |k,v|
"#{escape_hstore(k)}=>#{escape_hstore(v)}"
- }.join ', '
+ }.join ','
else
- kvs = object.scan(/(?<!\\)".*?(?<!\\)"/).map { |o|
- unescape_hstore(o[1...-1])
- }
- Hash[kvs.each_slice(2).to_a]
+ hash_from_hstore_string(object)
end
end
private
- HSTORE_ESCAPE = {
- ' ' => '\\ ',
- '\\' => '\\\\',
- '"' => '\\"',
- '=' => '\\=',
- }
- HSTORE_ESCAPE_RE = Regexp.union(HSTORE_ESCAPE.keys)
- HSTORE_UNESCAPE = HSTORE_ESCAPE.invert
- HSTORE_UNESCAPE_RE = Regexp.union(HSTORE_UNESCAPE.keys)
+ def hash_from_hstore_string(string)
+ Hash[string.scan(HstorePair).map { |k,v|
+ v = v.upcase == 'NULL' ? nil : v.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
+ k = k.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
+ [k,v]
+ }]
+ end
- def unescape_hstore(value)
- value.gsub(HSTORE_UNESCAPE_RE) do |match|
- HSTORE_UNESCAPE[match]
- end
+ HstorePair = begin
+ quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
+ unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
+ /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
end
def escape_hstore(value)
- value.gsub(HSTORE_ESCAPE_RE) do |match|
- HSTORE_ESCAPE[match]
- end
+ value.nil? ? 'NULL'
+ : value =~ /[=\s,>]/ ? '"%s"' % value.gsub(/(["\\])/, '\\\\\1')
+ : value == "" ? '""'
+ : value.gsub(/(["\\])/, '\\\\\1')
end
end
# :startdoc: