Kouhei Sutou
null+****@clear*****
Fri Jul 13 17:44:59 JST 2018
Kouhei Sutou 2018-07-13 17:44:59 +0900 (Fri, 13 Jul 2018) New Revision: 4fe10957e24d0fd89614d46b22b997635f3a31ec https://github.com/ranguba/groonga-client/commit/4fe10957e24d0fd89614d46b22b997635f3a31ec Message: Support TSV response format Added files: test/response/test-select-tsv.rb Modified files: lib/groonga/client/response/base.rb lib/groonga/client/response/select.rb test/response/helper.rb Modified: lib/groonga/client/response/base.rb (+44 -0) =================================================================== --- lib/groonga/client/response/base.rb 2018-07-13 17:03:23 +0900 (d123778) +++ lib/groonga/client/response/base.rb 2018-07-13 17:44:59 +0900 (41b74e8) @@ -17,6 +17,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +require "csv" require "rexml/document" require "json" @@ -78,6 +79,9 @@ module Groonga when :xml header, body = parse_xml(raw_response) return_code = header[0] if header + when :tsv + header, body = parse_tsv(raw_response) + return_code = header["return_code"] if header else header = nil body = raw_response @@ -129,6 +133,46 @@ module Groonga end end end + + def parse_tsv(response) + tsv = CSV.new(response, col_sep: "\t") + raw_header = tsv.shift + return nil, nil if raw_header.nil? + + header = parse_tsv_header(raw_header) + return header, nil unless header["return_code"].zero? + + body = parse_tsv_body(tsv) + [header, body] + end + + def parse_tsv_header(raw_header) + header = { + "return_code" => Integer(raw_header[0], 10), + "start_time" => Float(raw_header[1]), + "elapsed_time" => Float(raw_header[2]), + } + if raw_header.size >= 4 + header["error"] = { + "message" => raw_header[3], + } + if raw_header.size >= 5 + header["error"]["function"] = raw_header[4] + header["error"]["file"] = raw_header[5] + header["error"]["line"] = Integer(raw_header[6]) + end + end + header + end + + def parse_tsv_body(tsv) + body = [] + tsv.each do |row| + break if row.size == 1 and row[0] == "END" + body << row + end + body + end end # @return [Groonga::Command] The command for the request. Modified: lib/groonga/client/response/select.rb (+72 -0) =================================================================== --- lib/groonga/client/response/select.rb 2018-07-13 17:03:23 +0900 (72b8e07) +++ lib/groonga/client/response/select.rb 2018-07-13 17:44:59 +0900 (aab9a42) @@ -100,6 +100,78 @@ module Groonga drilldowns end + + def parse_tsv_body(tsv) + record_sets = [] + + n_hits = parse_tsv_n_hits(tsv.shift) + columns = parse_tsv_columns(tsv.shift) + records = [] + loop do + row = tsv.shift + break if row.size == 1 and row[0] == "END" + if (row.size % 4).zero? and row[0] == "[" and row[-1] == "]" + next_n_hits_row = records.pop + record_sets << [ + [n_hits], + columns, + *records, + ] + n_hits = parse_tsv_n_hits(next_n_hits_row) + columns = parse_tsv_columns(row) + records = [] + next + end + records << parse_tsv_record(row) + end + + record_sets << [ + [n_hits], + columns, + *records, + ] + record_sets + end + + def parse_tsv_n_hits(row) + Integer(row[0], 10) + end + + def parse_tsv_columns(row) + columns = [] + column = nil + row.each do |value| + case value + when "[" + column = [] + when "]" + columns << column + else + column << value + end + end + columns + end + + def parse_tsv_record(row) + record = [] + column_value = nil + row.each do |value| + case value + when "[" + column_value = [] + when "]" + record << column_value + else + if column_value + column_value << value + else + record << value + end + end + end + record + end end include Enumerable Modified: test/response/helper.rb (+5 -0) =================================================================== --- test/response/helper.rb 2018-07-13 17:03:23 +0900 (4116433) +++ test/response/helper.rb 2018-07-13 17:44:59 +0900 (11096d5) @@ -30,4 +30,9 @@ module TestResponseHelper parse_raw_response_raw(command_name, {"output_type" => "xml"}, raw_response) end + + def parse_raw_tsv_response(command_name, raw_response) + parse_raw_response_raw(command_name, {"output_type" => "tsv"}, + raw_response) + end end Added: test/response/test-select-tsv.rb (+127 -0) 100644 =================================================================== --- /dev/null +++ test/response/test-select-tsv.rb 2018-07-13 17:44:59 +0900 (ab278f8) @@ -0,0 +1,127 @@ +# Copyright (C) 2018 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +require "response/helper" + +class TestResponseSelectTSV < Test::Unit::TestCase + include TestResponseHelper + + def drilldown(key, n_hits, records) + Groonga::Client::Response::Select::Drilldown.new(key, n_hits, records) + end + + def test_error + raw_response = <<-TSV +-22 0 0.0 "message" "function" "file" 29 + +END + TSV + + response = parse_raw_tsv_response("select", raw_response) + assert_equal({ + :return_code => -22, + :start_time => Time.at(0), + :elapsed_time => 0.0, + :error => { + :message => "message", + :function => "function", + :file => "file", + :line => 29, + }, + }, + { + :return_code => response.return_code, + :start_time => response.start_time, + :elapsed_time => response.elapsed_time, + :error => { + :message => response.message, + :function => response.function, + :file => response.file, + :line => response.line, + }, + }) + end + + def test_basic + raw_response = <<-TSV + 0 0 0.0 +100 +[ "_id" "UInt32" ] +1 +2 +END + TSV + + response = parse_raw_tsv_response("select", raw_response) + assert_equal({ + :return_code => 0, + :start_time => Time.at(0), + :elapsed_time => 0.0, + :records => [ + {"_id" => "1"}, + {"_id" => "2"}, + ], + }, + { + :return_code => response.return_code, + :start_time => response.start_time, + :elapsed_time => response.elapsed_time, + :records => response.records, + }) + end + + def test_drilldown + raw_response = <<-TSV + 0 0 0.0 +100 +[ "_id" "UInt32" ] +7 +[ "_key" "ShortText" ] [ "_nsubrecs" "UInt32" ] +"2.2.0" "18044" +"2.3.0" "18115" +"2.4.0" "14594" +END + TSV + + response = parse_raw_response_raw("select", + { + "drilldown" => "version", + "output_type" => "tsv", + }, + raw_response) + drilldown_records = [ + {"_key" => "2.2.0", "_nsubrecs" => "18044"}, + {"_key" => "2.3.0", "_nsubrecs" => "18115"}, + {"_key" => "2.4.0", "_nsubrecs" => "14594"}, + ] + assert_equal({ + :return_code => 0, + :start_time => Time.at(0), + :elapsed_time => 0.0, + :records => [], + :drilldowns => [ + drilldown("version", 7, drilldown_records), + ], + }, + { + :return_code => response.return_code, + :start_time => response.start_time, + :elapsed_time => response.elapsed_time, + :records => response.records, + :drilldowns => response.drilldowns, + }) + end +end -------------- next part -------------- HTML����������������������������... URL: https://lists.osdn.me/mailman/archives/groonga-commit/attachments/20180713/fa6c9099/attachment-0001.htm