groonga-client 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,8 +27,9 @@ module Groonga
27
27
 
28
28
  Response.register("column_list", self)
29
29
 
30
- def initialize(header, body)
31
- super(header, parse_body(body))
30
+ def body=(body)
31
+ super(body)
32
+ parse_body(body)
32
33
  end
33
34
 
34
35
  def each
@@ -1,3 +1,20 @@
1
+ # Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
2
+ # Copyright (C) 2013 Kosuke Asami
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
1
18
  require "groonga/client/response/base"
2
19
 
3
20
  module Groonga
@@ -6,32 +23,45 @@ module Groonga
6
23
  class Select < Base
7
24
  Response.register("select", self)
8
25
 
9
- attr_accessor :records, :n_records
26
+ # @return [Integer] The number of records that match againt
27
+ # a search condition.
28
+ attr_accessor :n_hits
29
+ attr_accessor :records
10
30
  attr_accessor :drilldowns
11
31
 
12
- def initialize(header, body)
13
- super(header, parse_body(body))
32
+ def body=(body)
33
+ super(body)
34
+ parse_body(body)
14
35
  end
15
36
 
16
37
  private
17
38
  def parse_body(body)
18
- @n_records, @records = parse_match_records(body.first)
39
+ @n_hits, @records = parse_match_records(body.first)
19
40
  @drilldowns = parse_drilldowns(body[1..-1])
20
41
  body
21
42
  end
22
43
 
23
44
  def parse_result(raw_result)
24
- n_items = raw_result.first.first
45
+ n_hits = raw_result.first.first
25
46
  properties = raw_result[1]
26
- infos = raw_result[2..-1]
47
+ infos = raw_result[2..-1] || []
27
48
  items = infos.collect do |info|
28
49
  item = {}
29
- properties.each_with_index do |(name, _), i|
30
- item[name] = info[i]
50
+ properties.each_with_index do |(name, type), i|
51
+ item[name] = convert_value(info[i], type)
31
52
  end
32
53
  item
33
- end if infos
34
- [n_items, items]
54
+ end
55
+ [n_hits, items]
56
+ end
57
+
58
+ def convert_value(value, type)
59
+ case type
60
+ when "Time"
61
+ Time.at(value)
62
+ else
63
+ value
64
+ end
35
65
  end
36
66
 
37
67
  def parse_match_records(raw_records)
@@ -39,13 +69,15 @@ module Groonga
39
69
  end
40
70
 
41
71
  def parse_drilldowns(raw_drilldowns)
42
- raw_drilldowns.collect do |raw_drilldown|
72
+ (raw_drilldowns || []).collect.with_index do |raw_drilldown, i|
73
+ key = @command.drilldowns[i]
43
74
  n_hits, items = parse_result(raw_drilldown)
44
- Drilldown.new(n_hits, items)
45
- end if raw_drilldowns
75
+ Drilldown.new(key, n_hits, items)
76
+ end
46
77
  end
47
78
 
48
- Drilldown = Struct.new(:n_hits, :items)
79
+ class Drilldown < Struct.new(:key, :n_hits, :items)
80
+ end
49
81
  end
50
82
  end
51
83
  end
@@ -0,0 +1,12 @@
1
+ require "groonga/client/response/base"
2
+
3
+ module Groonga
4
+ class Client
5
+ module Response
6
+ class TableCreate < Base
7
+ Response.register("table_create", self)
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -27,8 +27,9 @@ module Groonga
27
27
 
28
28
  Response.register("table_list", self)
29
29
 
30
- def initialize(header, body)
31
- super(header, parse_body(body))
30
+ def body=(body)
31
+ super(body)
32
+ parse_body(body)
32
33
  end
33
34
 
34
35
  def each
@@ -1,5 +1,5 @@
1
1
  module Groonga
2
2
  class Client
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  end
5
5
  end
@@ -0,0 +1,105 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ require "socket"
20
+
21
+ require "groonga/client/connection/gqtp"
22
+
23
+ class TestConnectionGQTP < Test::Unit::TestCase
24
+ def setup
25
+ setup_server
26
+ setup_connection
27
+ end
28
+
29
+ def teardown
30
+ teardown_connection
31
+ teardown_server
32
+ end
33
+
34
+ def setup_server
35
+ @address = "127.0.0.1"
36
+ @server = TCPServer.new(@address, 0)
37
+ @port = @server.addr[1]
38
+ @protocol = :gqtp
39
+
40
+ @thread = Thread.new do
41
+ client = @server.accept
42
+ @server.close
43
+
44
+ process_client_close(client)
45
+
46
+ client.close
47
+ end
48
+ end
49
+
50
+ def teardown_server
51
+ @thread.kill
52
+ end
53
+
54
+ def setup_connection
55
+ @connection = nil
56
+ end
57
+
58
+ def teardown_connection
59
+ @connection.close {} if @connection
60
+ end
61
+
62
+ private
63
+ def connect(options={})
64
+ default_options = {
65
+ :host => @address,
66
+ :port => @port,
67
+ }
68
+ Groonga::Client::Connection::GQTP.new(default_options.merge(options))
69
+ end
70
+
71
+ def process_client_close(client)
72
+ response_body = [].to_json
73
+ 2.times do
74
+ header = GQTP::Header.parse(client.read(GQTP::Header.size))
75
+ client.read(header.size)
76
+
77
+ response_header = GQTP::Header.new
78
+ response_header.size = response_body.bytesize
79
+
80
+ client.write(response_header.pack)
81
+ client.write(response_body)
82
+ end
83
+ end
84
+
85
+ class TestConnected < self
86
+ def test_opened
87
+ @connection = connect
88
+ assert_true(@connection.connected?)
89
+ end
90
+
91
+ def test_closed
92
+ @connection = connect
93
+ @connection.close
94
+ assert_false(@connection.connected?)
95
+ end
96
+ end
97
+
98
+ class TestClose < self
99
+ def test_twice
100
+ @connection = connect
101
+ @connection.close
102
+ assert_false(@connection.close)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,97 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ require "socket"
20
+
21
+ require "groonga/client/connection/http"
22
+
23
+ class TestConnectionHTTP < Test::Unit::TestCase
24
+ def setup
25
+ setup_server
26
+ setup_connection
27
+ end
28
+
29
+ def teardown
30
+ teardown_connection
31
+ teardown_server
32
+ end
33
+
34
+ def setup_server
35
+ @address = "127.0.0.1"
36
+ @server = TCPServer.new(@address, 0)
37
+ @port = @server.addr[1]
38
+ @protocol = :http
39
+
40
+ @response_body = nil
41
+ @thread = Thread.new do
42
+ client = @server.accept
43
+ @server.close
44
+
45
+ status = 0
46
+ start = Time.now.to_f
47
+ elapsed = rand
48
+ header = "[#{status},#{start},#{elapsed}]"
49
+ body = "[#{header},#{@response_body}]"
50
+
51
+ http_header = <<-EOH
52
+ HTTP/1.1 200 OK
53
+ Connection: close
54
+ Content-Type: application/json
55
+ Content-Length: #{body.bytesize}
56
+
57
+ EOH
58
+
59
+ client.write(http_header)
60
+ client.write(body)
61
+ client.close
62
+ end
63
+ end
64
+
65
+ def teardown_server
66
+ @thread.kill
67
+ end
68
+
69
+ def setup_connection
70
+ @connection = nil
71
+ end
72
+
73
+ def teardown_connection
74
+ @connection.close if @connection
75
+ end
76
+
77
+ def connect(options={})
78
+ default_options = {
79
+ :host => @address,
80
+ :port => @port,
81
+ }
82
+ Groonga::Client::Connection::HTTP.new(default_options.merge(options))
83
+ end
84
+
85
+ def test_connected?
86
+ @connection = connect
87
+ assert_false(@connection.connected?)
88
+ end
89
+
90
+ class TestClose < self
91
+ def test_twice
92
+ @connection = connect
93
+ assert_false(@connection.close)
94
+ assert_false(@connection.close)
95
+ end
96
+ end
97
+ end
@@ -1,4 +1,8 @@
1
1
  module TestResponseHelper
2
+ def parse_raw_response(command_name, raw_response)
3
+ make_command(command_name).send(:parse_raw_response, raw_response)
4
+ end
5
+
2
6
  def make_command(command_name, parameters = {})
3
7
  command_class = Groonga::Command.find(command_name)
4
8
  command = command_class.new(command_name, parameters)
@@ -1,5 +1,3 @@
1
- require "test/unit/rr"
2
-
3
1
  require "response/helper"
4
2
 
5
3
  class TestResponseColumnList < Test::Unit::TestCase
@@ -9,16 +7,9 @@ class TestResponseColumnList < Test::Unit::TestCase
9
7
  header = [0,1372430096.70991,0.000522851943969727]
10
8
  body = [[["id","UInt32"],["name","ShortText"],["path","ShortText"],["type","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["source","ShortText"]],
11
9
  [256,"Text","/tmp/test.db.0000100","var","COLUMN_SCALAR|PERSISTENT","TestTable","ShortText",[]]]
10
+ raw_response = [header, body].to_json
12
11
 
13
- connection = Object.new
14
- stub(connection).send.with_any_args.yields([header, body].to_json) do
15
- request = Object.new
16
- stub(request).wait do
17
- true
18
- end
19
- end
20
-
21
- response = make_command("column_list").execute(connection)
12
+ response = parse_raw_response("column_list", raw_response)
22
13
  assert_equal(Groonga::Client::Response::ColumnList, response.class)
23
14
  end
24
15
  end
@@ -1,23 +1,138 @@
1
- require "test/unit/rr"
1
+ # Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
2
+ # Copyright (C) 2013 Kosuke Asami
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2
17
 
3
18
  require "response/helper"
4
19
 
5
20
  class TestResponseSelect < Test::Unit::TestCase
6
- include TestResponseHelper
21
+ class TestParseRawResponse < self
22
+ include TestResponseHelper
7
23
 
8
- def test_select
9
- header = [0,1372430096.70991,0.000522851943969727]
10
- body = [[[1], [["_id", "UInt32"]], [1]]]
24
+ def test_select
25
+ header = [0,1372430096.70991,0.000522851943969727]
26
+ body = [[[1], [["_id", "UInt32"]], [1]]]
27
+ raw_response = [header, body].to_json
11
28
 
12
- connection = Object.new
13
- stub(connection).send.with_any_args.yields([header, body].to_json) do
14
- request = Object.new
15
- stub(request).wait do
16
- true
29
+ response = parse_raw_response("select", raw_response)
30
+ assert_equal(Groonga::Client::Response::Select, response.class)
31
+ end
32
+ end
33
+
34
+ class TestBody < self
35
+ def setup
36
+ @command = Groonga::Command::Select.new("select", {})
37
+ end
38
+
39
+ def test_n_hits
40
+ response = create_response([[[29], [["_id", "UInt32"]]]])
41
+ assert_equal(29, response.n_hits)
42
+ end
43
+
44
+ private
45
+ def create_response(body)
46
+ header = [0, 1372430096.70991, 0.000522851943969727]
47
+ Groonga::Client::Response::Select.new(@command, header, body)
48
+ end
49
+
50
+ class TestRecords < self
51
+ def test_time
52
+ updated_at = 1379040474
53
+ assert_equal([{"updated_at" => Time.at(updated_at)}],
54
+ records([[[1], [["updated_at", "Time"]], [updated_at]]]))
55
+ end
56
+
57
+ private
58
+ def records(body)
59
+ create_response(body).records
17
60
  end
18
61
  end
19
62
 
20
- response = make_command("select").execute(connection)
21
- assert_equal(Groonga::Client::Response::Select, response.class)
63
+ class TestDrilldowns < self
64
+ def setup
65
+ pair_arguments = {
66
+ "drilldown" => "_key",
67
+ "drilldown_output_columns" => "_key,_nsubrecs",
68
+ }
69
+ @command = Groonga::Command::Select.new("select", pair_arguments)
70
+ end
71
+
72
+ def test_key
73
+ body = [
74
+ [[0], []],
75
+ [
76
+ [29],
77
+ [
78
+ ["_key", "ShortText"],
79
+ ["_nsubrecs", "Int32"],
80
+ ],
81
+ ["groonga", 29],
82
+ ["Ruby", 19],
83
+ ["rroonga", 9],
84
+ ],
85
+ ]
86
+ assert_equal(["_key"],
87
+ drilldowns(body).collect(&:key))
88
+ end
89
+
90
+ def test_n_hits
91
+ body = [
92
+ [[0], []],
93
+ [
94
+ [29],
95
+ [
96
+ ["_key", "ShortText"],
97
+ ["_nsubrecs", "Int32"],
98
+ ],
99
+ ["groonga", 29],
100
+ ["Ruby", 19],
101
+ ["rroonga", 9],
102
+ ],
103
+ ]
104
+ assert_equal([29],
105
+ drilldowns(body).collect(&:n_hits))
106
+ end
107
+
108
+ def test_items
109
+ body = [
110
+ [[0], []],
111
+ [
112
+ [29],
113
+ [
114
+ ["_key", "ShortText"],
115
+ ["_nsubrecs", "Int32"],
116
+ ],
117
+ ["groonga", 29],
118
+ ["Ruby", 19],
119
+ ["rroonga", 9],
120
+ ],
121
+ ]
122
+ assert_equal([
123
+ [
124
+ {"_key" => "groonga", "_nsubrecs" => 29},
125
+ {"_key" => "Ruby", "_nsubrecs" => 19},
126
+ {"_key" => "rroonga", "_nsubrecs" => 9},
127
+ ],
128
+ ],
129
+ drilldowns(body).collect(&:items))
130
+ end
131
+
132
+ private
133
+ def drilldowns(body)
134
+ create_response(body).drilldowns
135
+ end
136
+ end
22
137
  end
23
138
  end