diff options
author | Joel <joel@renewfund.com> | 2012-02-04 23:51:03 -0800 |
---|---|---|
committer | Joel <joel@renewfund.com> | 2012-02-08 22:28:51 -0800 |
commit | cf572114608b7813cacd88076dc272ac2a2a7955 (patch) | |
tree | 65bced5ba3c994dd4108fb41a5280b8e5b5f8cc2 /activerecord/lib | |
parent | a110789ca4b89c2ad984d044c175a0b8a018c54b (diff) | |
download | rails-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.rb | 38 |
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: |