Browse files

hstores can cycle

  • Loading branch information...
1 parent 96838b5 commit 8daaff5dac0725c5cf62811ac4a67b21f62aca2f @tenderlove tenderlove committed Dec 20, 2011
View
35 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -52,12 +52,39 @@ def string_to_time(string)
def cast_hstore(object)
if Hash === object
- object.map { |k,v| "#{k}=>#{v}" }.join ', '
+ object.map { |k,v|
+ "#{escape_hstore(k)}=>#{escape_hstore(v)}"
+ }.join ', '
else
- kvs = object.split(', ').map { |kv|
- kv.split('=>').map { |k| k[1...-1] }
+ kvs = object.scan(/(?<!\\)".*?(?<!\\)"/).map { |o|
+ unescape_hstore(o[1...-1])
}
- Hash[kvs]
+ Hash[kvs.each_slice(2).to_a]
+ end
+ end
+
+ private
+ def unescape_hstore(value)
+ escape_values = {
+ '\\ ' => ' ',
+ '\\\\' => '\\',
+ '\\"' => '"',
+ '\\=' => '=',
+ }
+ value.gsub(Regexp.union(escape_values.keys)) do |match|
+ escape_values[match]
+ end
+ end
+
+ def escape_hstore(value)
+ escape_values = {
+ ' ' => '\\ ',
+ '\\' => '\\\\',
+ '"' => '\\"',
+ '=' => '\\=',
+ }
+ value.gsub(Regexp.union(escape_values.keys)) do |match|
+ escape_values[match]
end
end
end
View
28 activerecord/test/cases/adapters/postgresql/hstore_test.rb
@@ -45,9 +45,33 @@ def test_select_multikey
end
def test_create
- hash = { 'a' => 'b', '1' => '2' }
+ assert_cycle_hstore('a' => 'b', '1' => '2')
+ end
+
+ def test_quotes
+ assert_cycle_hstore('a' => 'b"ar', '1"foo' => '2')
+ end
+
+ def test_whitespace
+ assert_cycle_hstore('a b' => 'b ar', '1"foo' => '2')
+ end
+
+ def test_backslash
+ assert_cycle_hstore('a\\b' => 'b\\ar', '1"foo' => '2')
+ end
+
+ def test_comma
+ assert_cycle_hstore('a, b' => 'bar', '1"foo' => '2')
+ end
+
+ def test_arrow
+ assert_cycle_hstore('a=>b' => 'bar', '1"foo' => '2')
+ end
+
+ private
+ def assert_cycle_hstore hash
x = Hstore.create!(:tags => hash)
x.reload
- assert_equal hash, x.tags
+ assert_equal(hash, x.tags)
end
end

0 comments on commit 8daaff5

Please sign in to comment.