diff --git a/lib/couchrest/helper/streamer.rb b/lib/couchrest/helper/streamer.rb index b320bc7..d553ad9 100644 --- a/lib/couchrest/helper/streamer.rb +++ b/lib/couchrest/helper/streamer.rb @@ -27,14 +27,19 @@ def escape_quotes(data) def open_pipe(cmd, &block) first = nil + prev = nil IO.popen(cmd) do |f| first = f.gets # discard header while line = f.gets row = parse_line(line) block.call row unless row.nil? # last line "}]" discarded + prev = line end end - parse_first(first) + + raise RestClient::ServerBrokeConnection if $? && $?.exitstatus != 0 + + parse_first(first, prev) end def parse_line line @@ -44,14 +49,11 @@ def parse_line line end end - def parse_first first + def parse_first first, last return nil unless first - parts = first.split(',') - parts.pop - line = parts.join(',') - MultiJson.decode("#{line}}") - rescue - nil + header = MultiJson.decode(last ? first + last : first) + header.delete("rows") + header end end diff --git a/spec/couchrest/helpers/streamer_spec.rb b/spec/couchrest/helpers/streamer_spec.rb index 7df67a7..56f43d8 100644 --- a/spec/couchrest/helpers/streamer_spec.rb +++ b/spec/couchrest/helpers/streamer_spec.rb @@ -40,6 +40,78 @@ count.should == 5 header.should == {"total_rows" => 1001, "offset" => 0} end + + it "should GET no rows in a view with limit=0" do + count = 0 + header = @streamer.get("#{@db.root}/_all_docs?include_docs=true&limit=0") do |row| + count += 1 + end + count.should == 0 + header.should == {"total_rows" => 1001, "offset" => 0} + end + + it "should raise an exception receives malformed data" do + IO.stub(:popen) do |cmd, block| + class F + def initialize + @lines = [ + '{"total_rows": 123, "offset": "0", "rows": [', + '{"foo": 1},', + '{"foo": 2},', + ] + end + + def gets + @lines.shift + end + end + + f = F.new + block.call f + + IO.unstub(:popen) + IO.popen 'true' do; end + end + + count = 0 + expect do + @streamer.get("#{@db.root}/_all_docs?include_docs=true&limit=0") do |row| + count += 1 + end + end.should raise_error(MultiJson::DecodeError) + end + + it "should raise an exception if the couch connection fails" do + IO.stub(:popen) do |cmd, block| + class F + def initialize + @lines = [ + '{"total_rows": 123, "offset": "0", "rows": [', + '{"foo": 1},', + '{"foo": 2},', + ] + end + + def gets + @lines.shift + end + end + + block.call F.new + + IO.unstub(:popen) + IO.popen 'false' do; end + end + + count = 0 + + expect do + @streamer.get("#{@db.root}/_all_docs?include_docs=true&limit=0") do |row| + count += 1 + end + end.should raise_error(RestClient::ServerBrokeConnection) + + count.should == 2 end it "should POST for each row in a view" do