groonga-client 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -0
- data/README.md +1 -0
- data/doc/text/news.md +16 -3
- data/groonga-client.gemspec +1 -1
- data/lib/groonga/client.rb +69 -7
- data/lib/groonga/client/command.rb +1 -2
- data/lib/groonga/client/connection/error.rb +31 -0
- data/lib/groonga/client/{protocol → connection}/gqtp.rb +41 -1
- data/lib/groonga/client/connection/http.rb +83 -0
- data/lib/groonga/client/{protocol/http.rb → connection/request.rb} +5 -18
- data/lib/groonga/client/response/base.rb +38 -8
- data/lib/groonga/client/response/column_list.rb +3 -2
- data/lib/groonga/client/response/select.rb +46 -14
- data/lib/groonga/client/response/table_create.rb +12 -0
- data/lib/groonga/client/response/table_list.rb +3 -2
- data/lib/groonga/client/version.rb +1 -1
- data/test/connection/test-gqtp.rb +105 -0
- data/test/connection/test-http.rb +97 -0
- data/test/response/helper.rb +4 -0
- data/test/response/test-column-list.rb +2 -11
- data/test/response/test-select.rb +127 -12
- data/test/response/test-table-list.rb +2 -11
- data/test/results/test-column-list.rb +2 -1
- data/test/results/test-table-list.rb +2 -1
- data/test/test-client.rb +43 -27
- data/test/test-command.rb +36 -3
- metadata +36 -31
- data/test/results/test-select.rb +0 -63
@@ -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
|
-
|
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
|
13
|
-
super(
|
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
|
-
@
|
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
|
-
|
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,
|
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
|
34
|
-
[
|
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
|
75
|
+
Drilldown.new(key, n_hits, items)
|
76
|
+
end
|
46
77
|
end
|
47
78
|
|
48
|
-
Drilldown
|
79
|
+
class Drilldown < Struct.new(:key, :n_hits, :items)
|
80
|
+
end
|
49
81
|
end
|
50
82
|
end
|
51
83
|
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
|
data/test/response/helper.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
21
|
+
class TestParseRawResponse < self
|
22
|
+
include TestResponseHelper
|
7
23
|
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
21
|
-
|
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
|