From 5718c8741993c3fe349dca5f40c8768c8496da65 Mon Sep 17 00:00:00 2001 From: Peter van Hardenberg Date: Fri, 8 Jul 2011 13:05:52 -0700 Subject: [PATCH] wip --- lib/hstore/hstore.rb | 9 ++++-- test.rb | 71 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/lib/hstore/hstore.rb b/lib/hstore/hstore.rb index bcd2c26..1d55b00 100644 --- a/lib/hstore/hstore.rb +++ b/lib/hstore/hstore.rb @@ -2,7 +2,7 @@ class Sequel::Postgres::HStore < Hash def self.quoted_string(scanner) - key = scanner.scan(/(\\"|[^"])*/).gsub("\\", "") + key = scanner.scan(/(\\"|[^"])*/).gsub("\\\\", "\\") scanner.skip(/"/) key end @@ -26,6 +26,10 @@ def self.skip_pair_delimiter(scanner) def self.new_from_string(string) hash = {} + + # remove single quotes around literal if necessary + string = string[1..-2] if string[0] == "'" and string[-1] == "'" + scanner = StringScanner.new(string) while !scanner.eos? k = parse_quotable_string(scanner) @@ -44,7 +48,8 @@ def initialize(hash) end def to_s_escaped(str) - str.to_s.gsub(/"/, '\"').gsub(/'/, "''") + puts str + str.to_s.gsub(/\\(?!")/) {'\\\\'}.gsub(/"/, '\"').gsub(/'/, "''").tap {|s| puts s} end def sql_literal(dataset) diff --git a/test.rb b/test.rb index e45e245..2fe57ce 100644 --- a/test.rb +++ b/test.rb @@ -1,7 +1,37 @@ require 'sequel' require './lib/sequel-hstore' + db = Sequel.connect(ENV["TEST_URL"]) +require 'logger' +#db.logger = Logger.new($stdout) + +db.create_table! :hstore_tests do + column :hstore, :hstore +end + +describe "hstores in the database" do + before do + db[:hstore_tests].delete + @h = {:a => "b", :foo => "bar"}.to_hstore + end + + it "should be able to store an hstore" do + db[:hstore_tests].insert(@h) + end + + it "should be able to round-trip an hstore" do + db[:hstore_tests].insert(@h) + db[:hstore_tests].first[:hstore].should == @h + end + + it "should be able to round-trip an hstore with backslashes" do + h = @h.merge(:slasher => 'oh \$ hell') + db[:hstore_tests].insert(h) + db[:hstore_tests].first[:hstore].should == h + end +end + describe "hstores from hashes" do before do @h = {:a => "b", :foo => "bar"}.to_hstore @@ -17,7 +47,7 @@ end it "should translate into a sequel literal" do - db[:resources].literal(@h).should == '\'"a" => "b", "foo" => "bar"\'' + db[:hstore_tests].literal(@h).should == '\'"a" => "b", "foo" => "bar"\'' end end @@ -37,17 +67,22 @@ it "should store an empty string" do empty = {:nothing => ""}.to_hstore - db[:resources].literal(empty).should == '\'"nothing" => ""\'' + db[:hstore_tests].literal(empty).should == '\'"nothing" => ""\'' end it "should support single quotes in strings" do empty = {:journey => "don't stop believin'"}.to_hstore - db[:resources].literal(empty).should == %q{'"journey" => "don''t stop believin''"'} + db[:hstore_tests].literal(empty).should == %q{'"journey" => "don''t stop believin''"'} end it "should support double quotes in strings" do empty = {:journey => 'He said he was "ready"'}.to_hstore - db[:resources].literal(empty).should == %q{'"journey" => "He said he was \"ready\""'} + db[:hstore_tests].literal(empty).should == %q{'"journey" => "He said he was \"ready\""'} + end + + it "should escape \ garbage in strings" do + empty = {:line_noise => %q[perl -p -e 's/\$\{([^}]+)\}/]}.to_hstore + db[:hstore_tests].literal(empty).should == %q['"line_noise" => "perl -p -e ''s/\\\\$\\\\{([^}]+)\\\\}/"'] end it "should parse an empty string" do @@ -57,5 +92,33 @@ empty[:ip].should == "" empty[:ip].should_not == nil end + + it "should be able to parse its own output" do + hstore = {:journey => 'He said he was ready'}.to_hstore + literal = db[:hstore_tests].literal(hstore) + parsed = Sequel::Postgres::HStore.new_from_string(literal) + parsed.should == hstore + end + + it "should be able to parse hstore strings without ''" do + hstore = {:journey => 'He said he was ready'}.to_hstore + literal = db[:hstore_tests].literal(hstore) + parsed = Sequel::Postgres::HStore.new_from_string(literal[1..-2]) + parsed.should == hstore + end + + it "should be stable over iteration" do + hstore = {:journey => 'He said he was "ready"'}.to_hstore + literal = db[:hstore_tests].literal(hstore) + + original = literal + + 10.times do + parsed = Sequel::Postgres::HStore.new_from_string(literal) + literal = db[:hstore_tests].literal(parsed) + parsed.should == hstore + literal.should == original + end + end end