class Groonga::Client::Response::Base

Attributes

body[RW]

@return [::Hash] The body of response. Its content is depends on

command.

@see groonga.org/docs/reference/command.html

The list of built-in commands.
command[RW]

@return [Groonga::Command] The command for the request.

header[RW]

@return [::Array<Integer, Float, Float>] The header of response.

It consists of `[return_code, start_time, elapsed_time_in_seconds]`
for success case.
It consists of
`[return_code, start_time, elapsed_time_in_seconds, error_message, error_location]`
for error case.

@see groonga.org/docs/reference/command/output_format.html#header

Details for header format.
raw[RW]

@return [String] The unparsed response. It may be JSON, XML or

Groonga command format.
trace_logs[RW]

@return [::Array, nil] The trace logs of response. @see groonga.org/docs/reference/command/output_trace_log.html

The trace log document.

Public Class Methods

new(command, header, body) click to toggle source
# File lib/groonga/client/response/base.rb, line 265
def initialize(command, header, body)
  self.command = command
  self.header = header
  self.body = body
  self.trace_logs = nil
  self.raw = nil
end
parse(command, raw_response) click to toggle source
# File lib/groonga/client/response/base.rb, line 68
def parse(command, raw_response)
  return_code = nil
  trace_logs = nil
  case command.output_type
  when :json
    callback = command["callback"]
    if callback and
        /\A#{Regexp.escape(callback)}\((.+)\);\z/ =~ raw_response
      json = $1
    else
      json = raw_response
    end
    begin
      response = JSON.parse(json)
    rescue JSON::ParserError => error
      raise InvalidResponse.new(command,
                                raw_response,
                                "invalid JSON: #{error}")
    end
    if response.is_a?(::Array)
      header, body = response
      return_code = header[0] if header
    else
      header = response["header"]
      trace_log = response["trace_log"]
      if trace_log
        names = trace_log["columns"].collect {|column| column["name"]}
        trace_logs = trace_log["logs"].collect do |log|
          Hash[names.zip(log)]
        end
      end
      body = response["body"]
      return_code = header["return_code"] if header
    end
  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
  when :arrow, :"apache-arrow"
    header, trace_logs, body = parse_apache_arrow(raw_response)
    return_code = header["return_code"] if header
  else
    header = nil
    body = raw_response
  end
  if header.nil? or return_code == 0
    response = new(command, header, body)
  else
    response = Error.new(command, header, body)
  end
  response.trace_logs = trace_logs
  response.raw = raw_response
  response
end

Private Class Methods

parse_apache_arrow(response) click to toggle source
# File lib/groonga/client/response/base.rb, line 204
def parse_apache_arrow(response)
  header = nil
  trace_logs = nil
  body = nil
  buffer = Arrow::Buffer.new(response)
  Arrow::BufferInputStream.open(buffer) do |input|
    while input.tell < response.bytesize
      reader = Arrow::RecordBatchStreamReader.new(input)
      schema = reader.schema
      record_batches = reader.to_a
      data_type = (schema.metadata || {})["GROONGA:data_type"]
      case data_type
      when "metadata"
        table = Arrow::Table.new(schema, record_batches)
        header = table.each_record.first.to_h
      when "trace_log"
        table = Arrow::Table.new(schema, record_batches)
        trace_logs = table.raw_records
      else
        body = {}
        body["columns"] = schema.fields.collect do |field|
          [field.name, field.data_type.to_s]
        end
        if record_batches.empty?
          records = []
        else
          table = Arrow::Table.new(schema, record_batches)
          records = table.raw_records
        end
        body["records"] = records
      end
    end
  end
  return header, trace_logs, body
end
parse_tsv(response) click to toggle source
# File lib/groonga/client/response/base.rb, line 164
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
parse_tsv_body(tsv) click to toggle source
# File lib/groonga/client/response/base.rb, line 195
def parse_tsv_body(tsv)
  body = []
  tsv.each do |row|
    break if row.size == 1 and row[0] == "END"
    body << row
  end
  body
end
parse_tsv_header(raw_header) click to toggle source
# File lib/groonga/client/response/base.rb, line 176
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
parse_xml(response) click to toggle source
# File lib/groonga/client/response/base.rb, line 126
def parse_xml(response)
  document = REXML::Document.new(response)
  result_element = document.root
  header = parse_xml_header(result_element)
  body = parse_xml_body(result_element.elements[1])
  [header, body]
end
parse_xml_body(body_element) click to toggle source
# File lib/groonga/client/response/base.rb, line 142
def parse_xml_body(body_element)
  xml_to_ruby(body_element)
end
parse_xml_header(result_element) click to toggle source
# File lib/groonga/client/response/base.rb, line 134
def parse_xml_header(result_element)
  attributes = result_element.attributes
  code    = Integer(attributes["CODE"])
  up      = Float(attributes["UP"])
  elapsed = Float(attributes["ELAPSED"])
  [code, up, elapsed]
end
xml_to_ruby(element) click to toggle source
# File lib/groonga/client/response/base.rb, line 146
def xml_to_ruby(element)
  elements = element.elements
  if elements.empty?
    case element.name
    when "NULL"
      nil
    when "INT"
      Integer(element.text)
    else
      element.text
    end
  else
    elements.collect do |child|
      xml_to_ruby(child)
    end
  end
end

Public Instance Methods

elapsed_time() click to toggle source

@return [Float] The elapsed time of the request. @since 0.1.0

# File lib/groonga/client/response/base.rb, line 307
def elapsed_time
  if header.nil?
    0.0
  elsif header_v1?
    header[2]
  else
    header["elapsed_time"]
  end
end
error_message() click to toggle source

@return [String, nil] The error message of the response. @since 0.2.4

# File lib/groonga/client/response/base.rb, line 319
def error_message
  if header.nil?
    nil
  elsif header_v1?
    header[3]
  else
    (header["error"] || {})["message"]
  end
end
return_code() click to toggle source

@return [Integer] The return code of the response. @since 0.2.6

# File lib/groonga/client/response/base.rb, line 275
def return_code
  if header.nil?
    0
  elsif header_v1?
    header[0]
  else
    header["return_code"] || 0
  end
end
start_time() click to toggle source

@return [Time] The time of the request is accepted. @since 0.1.0

# File lib/groonga/client/response/base.rb, line 295
def start_time
  if header.nil?
    Time.at(0)
  elsif header_v1?
    Time.at(header[1])
  else
    Time.at(header["start_time"])
  end
end
status_code() click to toggle source

@return [Integer] The status code of the response. @since 0.1.0

@deprecated since 0.2.6. Use {return_code} instead.

# File lib/groonga/client/response/base.rb, line 289
def status_code
  return_code
end
success?() click to toggle source

@return [Boolean] ‘true` if the request is processed successfully,

`false` otherwise.

@since 0.1.0

# File lib/groonga/client/response/base.rb, line 332
def success?
  return_code.zero?
end

Private Instance Methods

header_v1?() click to toggle source
# File lib/groonga/client/response/base.rb, line 337
def header_v1?
  header.is_a?(::Array)
end