groonga-client 0.3.3 → 0.3.4

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.
@@ -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
- @drilldowns = parse_drilldowns_v1(body[1..-1])
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