From b04880cecc6fdc452aeea5d64d078d90dfa2693a Mon Sep 17 00:00:00 2001 From: Joel Date: Sun, 5 Feb 2012 20:36:22 -0800 Subject: string_to_hstore / hstore_to_string, serializing --- .../active_record/connection_adapters/column.rb | 4 ++-- .../connection_adapters/postgresql_adapter.rb | 27 ++++++++++++++-------- .../test/cases/adapters/postgresql/hstore_test.rb | 12 +++++----- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index 34d88edff3..7ef3218a49 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -98,7 +98,7 @@ module ActiveRecord when :date then klass.value_to_date(value) when :binary then klass.binary_to_string(value) when :boolean then klass.value_to_boolean(value) - when :hstore then klass.cast_hstore(value) + when :hstore then klass.string_to_hstore(value) else value end end @@ -116,7 +116,7 @@ module ActiveRecord when :date then "#{klass}.value_to_date(#{var_name})" when :binary then "#{klass}.binary_to_string(#{var_name})" when :boolean then "#{klass}.value_to_boolean(#{var_name})" - when :hstore then "#{klass}.cast_hstore(#{var_name})" + when :hstore then "#{klass}.string_to_hstore(#{var_name})" else var_name end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 52693e19d9..abb0a4adea 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -52,25 +52,31 @@ module ActiveRecord end end - def cast_hstore(object) + def hstore_to_string(object) if Hash === object object.map { |k,v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join ',' else - hash_from_hstore_string(object) + object end end - private - 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] - }] + def string_to_hstore(string) + if string.nil? + nil + elsif 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] + }] + else + string + end end + private HstorePair = begin quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/ unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/ @@ -501,6 +507,9 @@ module ActiveRecord when String return super unless 'bytea' == column.sql_type { :value => value, :format => 1 } + when Hash + return super unless 'hstore' == column.sql_type + PostgreSQLColumn.hstore_to_string(value) else super end diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index 28b5a50126..82c52b38a3 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -12,7 +12,7 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase begin @connection.transaction do @connection.create_table('hstores') do |t| - t.hstore 'tags' + t.hstore 'tags', :default => '' end end rescue ActiveRecord::StatementInvalid @@ -33,7 +33,7 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase assert @column data = "\"1\"=>\"2\"" - hash = @column.class.cast_hstore data + hash = @column.class.string_to_hstore data assert_equal({'1' => '2'}, hash) assert_equal({'1' => '2'}, @column.type_cast(data)) @@ -43,19 +43,19 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase end def test_gen1 - assert_equal(%q(" "=>""), @column.type_cast({' '=>''})) + assert_equal(%q(" "=>""), @column.class.hstore_to_string({' '=>''})) end def test_gen2 - assert_equal(%q(","=>""), @column.type_cast({','=>''})) + assert_equal(%q(","=>""), @column.class.hstore_to_string({','=>''})) end def test_gen3 - assert_equal(%q("="=>""), @column.type_cast({'='=>''})) + assert_equal(%q("="=>""), @column.class.hstore_to_string({'='=>''})) end def test_gen4 - assert_equal(%q(">"=>""), @column.type_cast({'>'=>''})) + assert_equal(%q(">"=>""), @column.class.hstore_to_string({'>'=>''})) end def test_parse1 -- cgit v1.2.3