groonga-client 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/doc/text/news.md +13 -0
- data/lib/groonga/client.rb +1 -1
- data/lib/groonga/client/request.rb +22 -0
- data/lib/groonga/client/request/base.rb +174 -0
- data/lib/groonga/client/request/error.rb +39 -0
- data/lib/groonga/client/request/select.rb +292 -0
- data/lib/groonga/client/response/schema.rb +25 -9
- data/lib/groonga/client/response/select.rb +64 -2
- data/lib/groonga/client/spec-helper.rb +37 -0
- data/lib/groonga/client/test-helper.rb +37 -0
- data/lib/groonga/client/test/fixture.rb +35 -0
- data/lib/groonga/client/test/groonga-server-runner.rb +158 -0
- data/lib/groonga/client/version.rb +1 -1
- data/test/request/select/test-filter-parameter.rb +97 -0
- data/test/request/select/test-output-columns-parameter.rb +75 -0
- data/test/request/select/test-sort-keys-columns-parameter.rb +74 -0
- data/test/request/select/test-values-parameter.rb +58 -0
- data/test/request/test-base.rb +50 -0
- data/test/request/test-select.rb +131 -0
- data/test/response/test-schema.rb +342 -0
- data/test/response/test-select-command-version1.rb +68 -0
- data/test/response/test-select-command-version3.rb +70 -0
- data/test/run-test.rb +1 -0
- metadata +36 -16
@@ -102,31 +102,31 @@ module Groonga
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
-
class Type < Hash
|
105
|
+
class Type < ::Hash
|
106
106
|
include Hashie::Extensions::MethodAccess
|
107
107
|
end
|
108
108
|
|
109
|
-
class Tokenizer < Hash
|
109
|
+
class Tokenizer < ::Hash
|
110
110
|
include Hashie::Extensions::MethodAccess
|
111
111
|
end
|
112
112
|
|
113
|
-
class Normalizer < Hash
|
113
|
+
class Normalizer < ::Hash
|
114
114
|
include Hashie::Extensions::MethodAccess
|
115
115
|
end
|
116
116
|
|
117
|
-
class TokenFilter < Hash
|
117
|
+
class TokenFilter < ::Hash
|
118
118
|
include Hashie::Extensions::MethodAccess
|
119
119
|
end
|
120
120
|
|
121
|
-
class KeyType < Hash
|
121
|
+
class KeyType < ::Hash
|
122
122
|
include Hashie::Extensions::MethodAccess
|
123
123
|
end
|
124
124
|
|
125
|
-
class ValueType < Hash
|
125
|
+
class ValueType < ::Hash
|
126
126
|
include Hashie::Extensions::MethodAccess
|
127
127
|
end
|
128
128
|
|
129
|
-
class Index < Hash
|
129
|
+
class Index < ::Hash
|
130
130
|
include Hashie::Extensions::MethodAccess
|
131
131
|
|
132
132
|
def initialize(schema, raw_index)
|
@@ -155,13 +155,17 @@ module Groonga
|
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
158
|
+
def full_text_searchable?
|
159
|
+
table.tokenizer and column.position
|
160
|
+
end
|
161
|
+
|
158
162
|
private
|
159
163
|
def coerce_table(table_name)
|
160
164
|
@schema.tables[table_name]
|
161
165
|
end
|
162
166
|
end
|
163
167
|
|
164
|
-
class Column < Hash
|
168
|
+
class Column < ::Hash
|
165
169
|
include Hashie::Extensions::MethodAccess
|
166
170
|
|
167
171
|
def initialize(schema, raw_column)
|
@@ -181,6 +185,12 @@ module Groonga
|
|
181
185
|
end
|
182
186
|
end
|
183
187
|
|
188
|
+
def have_full_text_search_index?
|
189
|
+
indexes.any? do |index|
|
190
|
+
index.full_text_searchable?
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
184
194
|
private
|
185
195
|
def coerce_indexes(raw_indexes)
|
186
196
|
raw_indexes.collect do |raw_index|
|
@@ -189,7 +199,7 @@ module Groonga
|
|
189
199
|
end
|
190
200
|
end
|
191
201
|
|
192
|
-
class Table < Hash
|
202
|
+
class Table < ::Hash
|
193
203
|
include Hashie::Extensions::MethodAccess
|
194
204
|
|
195
205
|
def initialize(schema)
|
@@ -214,6 +224,12 @@ module Groonga
|
|
214
224
|
end
|
215
225
|
end
|
216
226
|
|
227
|
+
def have_full_text_search_index?
|
228
|
+
indexes.any? do |index|
|
229
|
+
index.full_text_searchable?
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
217
233
|
private
|
218
234
|
def coerce_key_type(raw_key_type)
|
219
235
|
if raw_key_type.nil?
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# Copyright (C) 2013-2016 Kouhei Sutou <kou@clear-code.com>
|
2
2
|
# Copyright (C) 2013 Kosuke Asami
|
3
|
+
# Copyright (C) 2016 Masafumi Yokoyama <yokoyama@clear-code.com>
|
3
4
|
#
|
4
5
|
# This library is free software; you can redistribute it and/or
|
5
6
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -23,9 +24,13 @@ module Groonga
|
|
23
24
|
class Select < Base
|
24
25
|
Response.register("select", self)
|
25
26
|
|
27
|
+
include Enumerable
|
28
|
+
|
26
29
|
# @return [Integer] The number of records that match againt
|
27
30
|
# a search condition.
|
28
31
|
attr_accessor :n_hits
|
32
|
+
# For Kaminari
|
33
|
+
alias_method :total_count, :n_hits
|
29
34
|
attr_accessor :records
|
30
35
|
|
31
36
|
# @return [::Array<Groonga::Client::Response::Select::Drilldown>,
|
@@ -37,19 +42,51 @@ module Groonga
|
|
37
42
|
# Otherwise, `[drilldown1, drilldown2]` is returned.
|
38
43
|
attr_accessor :drilldowns
|
39
44
|
|
45
|
+
# @return [::Hash<String, Groonga::Client::Response::Select::Slice>]
|
46
|
+
#
|
47
|
+
# @since 0.3.4
|
48
|
+
attr_accessor :slices
|
49
|
+
|
40
50
|
def body=(body)
|
41
51
|
super(body)
|
42
52
|
parse_body(body)
|
43
53
|
end
|
44
54
|
|
55
|
+
# For Kaminari
|
56
|
+
def limit_value
|
57
|
+
(@command[:limit] || 10).to_i
|
58
|
+
end
|
59
|
+
|
60
|
+
# For Kaminari
|
61
|
+
def offset_value
|
62
|
+
(@command[:offset] || 0).to_i
|
63
|
+
end
|
64
|
+
|
65
|
+
# For Kaminari
|
66
|
+
def size
|
67
|
+
records.size
|
68
|
+
end
|
69
|
+
|
70
|
+
def each(&block)
|
71
|
+
records.each(&block)
|
72
|
+
end
|
73
|
+
|
45
74
|
private
|
46
75
|
def parse_body(body)
|
47
76
|
if body.is_a?(::Array)
|
48
77
|
@n_hits, @records = parse_match_records_v1(body.first)
|
49
|
-
@
|
78
|
+
if @command.slices.empty?
|
79
|
+
raw_slices = nil
|
80
|
+
raw_drilldowns = body[1..-1]
|
81
|
+
else
|
82
|
+
raw_slices, *raw_drilldowns = body[1..-1]
|
83
|
+
end
|
84
|
+
@slices = parse_slices_v1(raw_slices)
|
85
|
+
@drilldowns = parse_drilldowns_v1(raw_drilldowns)
|
50
86
|
else
|
51
87
|
@n_hits, @records = parse_match_records_v3(body)
|
52
88
|
@drilldowns = parse_drilldowns_v3(body["drilldowns"])
|
89
|
+
@slices = parse_slices_v3(body["slices"])
|
53
90
|
end
|
54
91
|
body
|
55
92
|
end
|
@@ -74,7 +111,7 @@ module Groonga
|
|
74
111
|
end
|
75
112
|
|
76
113
|
(raw_records || []).collect do |raw_record|
|
77
|
-
record =
|
114
|
+
record = Record.new
|
78
115
|
columns.each_with_index do |(name, type), i|
|
79
116
|
record[name] = convert_value(raw_record[i], type)
|
80
117
|
end
|
@@ -139,10 +176,35 @@ module Groonga
|
|
139
176
|
drilldowns
|
140
177
|
end
|
141
178
|
|
179
|
+
def parse_slices_v1(raw_slices)
|
180
|
+
slices = {}
|
181
|
+
(raw_slices || {}).each do |key, raw_slice|
|
182
|
+
n_hits, records = parse_match_records_v1(raw_slice)
|
183
|
+
slices[key] = Slice.new(key, n_hits, records)
|
184
|
+
end
|
185
|
+
slices
|
186
|
+
end
|
187
|
+
|
188
|
+
def parse_slices_v3(raw_slices)
|
189
|
+
slices = {}
|
190
|
+
(raw_slices || {}).each do |key, raw_slice|
|
191
|
+
n_hits, records = parse_match_records_v3(raw_slice)
|
192
|
+
slices[key] = Slice.new(key, n_hits, records)
|
193
|
+
end
|
194
|
+
slices
|
195
|
+
end
|
196
|
+
|
197
|
+
class Record < ::Hash
|
198
|
+
include Hashie::Extensions::MethodAccess
|
199
|
+
end
|
200
|
+
|
142
201
|
class Drilldown < Struct.new(:key, :n_hits, :records)
|
143
202
|
# @deprecated since 0.2.6. Use {#records} instead.
|
144
203
|
alias_method :items, :records
|
145
204
|
end
|
205
|
+
|
206
|
+
class Slice < Struct.new(:key, :n_hits, :records)
|
207
|
+
end
|
146
208
|
end
|
147
209
|
end
|
148
210
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License as published by the Free Software Foundation; either
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this library; if not, write to the Free Software
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
16
|
+
|
17
|
+
require "groonga/client/test/fixture"
|
18
|
+
|
19
|
+
module Groonga
|
20
|
+
class Client
|
21
|
+
module SpecHelper
|
22
|
+
include Test::Fixture
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def included(target)
|
26
|
+
target.before(:each) do
|
27
|
+
setup_groonga
|
28
|
+
end
|
29
|
+
|
30
|
+
target.after(:each) do
|
31
|
+
teardown_groonga
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License as published by the Free Software Foundation; either
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this library; if not, write to the Free Software
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
16
|
+
|
17
|
+
require "groonga/client/test/fixture"
|
18
|
+
|
19
|
+
module Groonga
|
20
|
+
class Client
|
21
|
+
module TestHelper
|
22
|
+
include Test::Fixture
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def included(target)
|
26
|
+
target.setup do
|
27
|
+
setup_groonga
|
28
|
+
end
|
29
|
+
|
30
|
+
target.teardown do
|
31
|
+
teardown_groonga
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License as published by the Free Software Foundation; either
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this library; if not, write to the Free Software
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
16
|
+
|
17
|
+
require "groonga/client/test/groonga-server-runner"
|
18
|
+
|
19
|
+
module Groonga
|
20
|
+
class Client
|
21
|
+
module Test
|
22
|
+
module Fixture
|
23
|
+
def setup_groonga
|
24
|
+
@groonga_server_runner = GroongaServerRunner.new
|
25
|
+
@groonga_server_runner.run
|
26
|
+
end
|
27
|
+
|
28
|
+
def teardown_groonga
|
29
|
+
return if @groonga_server_runner.nil?
|
30
|
+
@groonga_server_runner.stop
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License as published by the Free Software Foundation; either
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this library; if not, write to the Free Software
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
16
|
+
|
17
|
+
require "rbconfig"
|
18
|
+
require "fileutils"
|
19
|
+
|
20
|
+
module Groonga
|
21
|
+
class Client
|
22
|
+
module Test
|
23
|
+
class GroongaServerRunner
|
24
|
+
def initialize
|
25
|
+
@pid = nil
|
26
|
+
@using_running_server = false
|
27
|
+
@url = build_url
|
28
|
+
@groonga = find_groonga
|
29
|
+
@tmp_dir = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def run
|
33
|
+
if groonga_server_running?
|
34
|
+
@using_running_server = true
|
35
|
+
else
|
36
|
+
return if @groonga.nil?
|
37
|
+
@tmp_dir = create_tmp_dir
|
38
|
+
db_path = @tmp_dir + "db"
|
39
|
+
@pid = spawn(@groonga,
|
40
|
+
"--port", @url.port.to_s,
|
41
|
+
"--log-path", (@tmp_dir + "groonga.log").to_s,
|
42
|
+
"--query-log-path", (@tmp_dir + "query.log").to_s,
|
43
|
+
"--protocol", "http",
|
44
|
+
"-s",
|
45
|
+
"-n", db_path.to_s)
|
46
|
+
wait_groonga_ready
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def stop
|
51
|
+
if @using_running_server
|
52
|
+
Groonga::Client.open(url: @url) do |client|
|
53
|
+
schema = client.schema
|
54
|
+
schema.tables.each do |name, _|
|
55
|
+
client.delete(table: name,
|
56
|
+
filter: "true")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
else
|
60
|
+
if @pid
|
61
|
+
Groonga::Client.open(url: @url) do |client|
|
62
|
+
client.shutdown
|
63
|
+
end
|
64
|
+
wait_groonga_shutdown
|
65
|
+
end
|
66
|
+
if @tmp_dir
|
67
|
+
FileUtils.rm_rf(@tmp_dir)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
def build_url
|
74
|
+
default_options = Groonga::Client.default_options
|
75
|
+
url = default_options[:url]
|
76
|
+
if url.nil?
|
77
|
+
host = default_options[:host] ||
|
78
|
+
default_options[:address] ||
|
79
|
+
"127.0.0.1"
|
80
|
+
port = default_options[:port] || 10041
|
81
|
+
path = default_options[:path]
|
82
|
+
url = URI("http://#{host}:#{port}#{path}")
|
83
|
+
end
|
84
|
+
url
|
85
|
+
end
|
86
|
+
|
87
|
+
def groonga_server_running?
|
88
|
+
begin
|
89
|
+
TCPSocket.open(@url.host, @url.port) do
|
90
|
+
end
|
91
|
+
rescue SystemCallError
|
92
|
+
false
|
93
|
+
else
|
94
|
+
true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def find_groonga
|
99
|
+
paths = ENV["PATH"].split(File::PATH_SEPARATOR)
|
100
|
+
exeext = RbConfig::CONFIG["EXEEXT"]
|
101
|
+
paths.each do |path|
|
102
|
+
groonga = File.join(path, "groonga#{exeext}")
|
103
|
+
return groonga if File.executable?(groonga)
|
104
|
+
end
|
105
|
+
nil
|
106
|
+
end
|
107
|
+
|
108
|
+
def create_tmp_dir
|
109
|
+
tmpfs_dir = "/dev/shm"
|
110
|
+
if File.directory?(tmpfs_dir)
|
111
|
+
base_tmp_dir = Pathname(tmpfs_dir)
|
112
|
+
else
|
113
|
+
base_tmp_dir = Pathname("tmp")
|
114
|
+
end
|
115
|
+
tmp_dir = base_tmp_dir + "groonga-client.#{Process.pid}"
|
116
|
+
FileUtils.rm_rf(tmp_dir)
|
117
|
+
FileUtils.mkdir_p(tmp_dir)
|
118
|
+
tmp_dir
|
119
|
+
end
|
120
|
+
|
121
|
+
def wait_groonga_ready
|
122
|
+
n_retried = 0
|
123
|
+
while n_retried <= 20
|
124
|
+
n_retried += 1
|
125
|
+
sleep(0.05)
|
126
|
+
if groonga_server_running?
|
127
|
+
break
|
128
|
+
else
|
129
|
+
begin
|
130
|
+
pid = Process.waitpid(@pid, Process::WNOHANG)
|
131
|
+
rescue SystemCallError
|
132
|
+
@pid = nil
|
133
|
+
break
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def wait_groonga_shutdown
|
140
|
+
# TODO: Remove me when Groonga 6.0.1 has been released.
|
141
|
+
# Workaround to shutdown as soon as possible.
|
142
|
+
groonga_server_running?
|
143
|
+
|
144
|
+
n_retried = 0
|
145
|
+
while n_retried <= 20
|
146
|
+
n_retried += 1
|
147
|
+
sleep(0.05)
|
148
|
+
pid = Process.waitpid(@pid, Process::WNOHANG)
|
149
|
+
return if pid
|
150
|
+
end
|
151
|
+
|
152
|
+
Process.kill(:KILL, @pid)
|
153
|
+
Process.waitpid(@pid)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|