fluent-plugin-droonga 0.0.2 → 0.7.0

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.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.yardopts +7 -0
  4. data/Gemfile +14 -2
  5. data/LICENSE.txt +1 -1
  6. data/README.md +1 -1
  7. data/Rakefile +27 -5
  8. data/benchmark/benchmark.rb +1 -1
  9. data/benchmark/utils.rb +9 -6
  10. data/benchmark/watch/benchmark-notify.rb +2 -2
  11. data/benchmark/watch/benchmark-publish.rb +1 -1
  12. data/benchmark/watch/benchmark-scan.rb +1 -1
  13. data/benchmark/watch/catalog.json +1 -1
  14. data/bin/grn2jsons +1 -1
  15. data/fluent-plugin-droonga.gemspec +5 -3
  16. data/lib/droonga/adapter.rb +13 -130
  17. data/lib/droonga/adapter_plugin.rb +51 -0
  18. data/lib/droonga/catalog.rb +2 -2
  19. data/lib/droonga/collector.rb +107 -0
  20. data/lib/droonga/collector_plugin.rb +82 -0
  21. data/lib/droonga/command_mapper.rb +1 -1
  22. data/lib/droonga/{proxy.rb → dispatcher.rb} +116 -151
  23. data/lib/droonga/distributor.rb +51 -0
  24. data/lib/droonga/distributor_plugin.rb +59 -0
  25. data/lib/droonga/engine.rb +9 -50
  26. data/lib/droonga/farm.rb +47 -0
  27. data/lib/droonga/forwarder.rb +125 -0
  28. data/lib/droonga/handler.rb +69 -60
  29. data/lib/droonga/handler_plugin.rb +22 -11
  30. data/lib/droonga/input_message.rb +51 -0
  31. data/lib/droonga/job_queue.rb +5 -1
  32. data/lib/droonga/job_queue_schema.rb +1 -1
  33. data/lib/droonga/logger.rb +1 -1
  34. data/lib/droonga/partition.rb +76 -0
  35. data/lib/droonga/pluggable.rb +62 -0
  36. data/lib/droonga/plugin.rb +18 -16
  37. data/lib/droonga/plugin/{adapter_groonga.rb → adapter/groonga.rb} +10 -10
  38. data/lib/droonga/plugin/adapter/groonga/select.rb +13 -4
  39. data/lib/droonga/plugin/collector/basic.rb +142 -0
  40. data/lib/droonga/plugin/distributor/crud.rb +43 -0
  41. data/lib/droonga/plugin/distributor/groonga.rb +37 -0
  42. data/lib/droonga/plugin/distributor/search.rb +273 -0
  43. data/lib/droonga/plugin/distributor/watch.rb +39 -0
  44. data/lib/droonga/plugin/{handler_add.rb → handler/add.rb} +6 -6
  45. data/lib/droonga/plugin/{handler_forward.rb → handler/forward.rb} +9 -4
  46. data/lib/droonga/plugin/{handler_groonga.rb → handler/groonga.rb} +36 -4
  47. data/lib/droonga/plugin/handler/groonga/column_create.rb +5 -9
  48. data/lib/droonga/plugin/handler/groonga/table_create.rb +9 -18
  49. data/lib/droonga/plugin/{handler_search.rb → handler/search.rb} +4 -4
  50. data/lib/droonga/plugin/{handler_watch.rb → handler/watch.rb} +4 -4
  51. data/lib/droonga/plugin_loader.rb +45 -0
  52. data/lib/droonga/plugin_registerable.rb +51 -0
  53. data/lib/droonga/plugin_repository.rb +56 -0
  54. data/lib/droonga/processor.rb +64 -0
  55. data/lib/droonga/searcher.rb +16 -7
  56. data/lib/droonga/server.rb +5 -9
  57. data/lib/droonga/sweeper.rb +1 -1
  58. data/lib/droonga/watch_schema.rb +1 -1
  59. data/lib/droonga/watcher.rb +1 -1
  60. data/lib/droonga/worker.rb +21 -9
  61. data/lib/fluent/plugin/out_droonga.rb +33 -15
  62. data/lib/groonga_command_converter.rb +1 -1
  63. data/sample/cluster/fluentd.conf +0 -1
  64. data/test/command/config/default/catalog.json +43 -0
  65. data/test/command/config/default/fluentd.conf +11 -0
  66. data/test/command/fixture/documents.jsons +208 -0
  67. data/test/command/fixture/user-table-array.jsons +38 -0
  68. data/test/command/fixture/user-table.jsons +38 -0
  69. data/test/command/run-test.rb +35 -0
  70. data/test/command/suite/add/minimum.expected +12 -0
  71. data/test/command/suite/add/minimum.test +11 -0
  72. data/test/command/suite/add/with-values.expected +12 -0
  73. data/test/command/suite/add/with-values.test +17 -0
  74. data/test/command/suite/add/without-key.expected +12 -0
  75. data/test/command/suite/add/without-key.test +16 -0
  76. data/test/command/suite/groonga/column_create/scalar.expected +34 -0
  77. data/test/command/suite/groonga/column_create/scalar.test +17 -0
  78. data/test/command/suite/groonga/column_create/vector.expected +34 -0
  79. data/test/command/suite/groonga/column_create/vector.test +18 -0
  80. data/test/command/suite/groonga/select/minimum.expected +26 -0
  81. data/test/command/suite/groonga/select/minimum.test +8 -0
  82. data/test/command/suite/groonga/table_create/array.expected +17 -0
  83. data/test/command/suite/groonga/table_create/array.test +8 -0
  84. data/test/command/suite/groonga/table_create/hash.expected +17 -0
  85. data/test/command/suite/groonga/table_create/hash.test +8 -0
  86. data/test/command/suite/search/array-attribute-label.expected +25 -0
  87. data/test/command/suite/search/array-attribute-label.test +30 -0
  88. data/test/command/suite/search/chained-queries.expected +45 -0
  89. data/test/command/suite/search/chained-queries.test +43 -0
  90. data/test/command/suite/search/complex.expected +52 -0
  91. data/test/command/suite/search/complex.test +25 -0
  92. data/test/command/suite/search/condition-nested.expected +19 -0
  93. data/test/command/suite/search/condition-nested.test +29 -0
  94. data/test/command/suite/search/condition-query.expected +28 -0
  95. data/test/command/suite/search/condition-query.test +25 -0
  96. data/test/command/suite/search/condition-script.expected +28 -0
  97. data/test/command/suite/search/condition-script.test +28 -0
  98. data/test/command/suite/search/hash-attribute-label.expected +34 -0
  99. data/test/command/suite/search/hash-attribute-label.test +38 -0
  100. data/test/command/suite/search/minimum.expected +13 -0
  101. data/test/command/suite/search/minimum.test +16 -0
  102. data/test/command/suite/search/multiple-queries.expected +39 -0
  103. data/test/command/suite/search/multiple-queries.test +39 -0
  104. data/test/command/suite/search/output-range.expected +28 -0
  105. data/test/command/suite/search/output-range.test +25 -0
  106. data/test/command/suite/search/simple.expected +52 -0
  107. data/test/command/suite/search/simple.test +24 -0
  108. data/test/command/suite/search/sort-and-output-range.expected +25 -0
  109. data/test/command/suite/search/sort-and-output-range.test +29 -0
  110. data/test/command/suite/search/sort-range.expected +28 -0
  111. data/test/command/suite/search/sort-range.test +28 -0
  112. data/test/command/suite/search/sort-with-invisible-column.expected +28 -0
  113. data/test/command/suite/search/sort-with-invisible-column.test +28 -0
  114. data/test/unit/fixtures/array.grn +18 -0
  115. data/test/{fixtures → unit/fixtures}/catalog.json +0 -0
  116. data/test/{fixtures → unit/fixtures}/document.grn +20 -9
  117. data/test/unit/fixtures/reference/array.grn +11 -0
  118. data/test/unit/fixtures/reference/hash.grn +7 -0
  119. data/test/{helper.rb → unit/helper.rb} +2 -1
  120. data/test/{helper → unit/helper}/fixture.rb +1 -1
  121. data/test/unit/helper/plugin_helper.rb +38 -0
  122. data/test/{helper → unit/helper}/sandbox.rb +19 -6
  123. data/test/{helper → unit/helper}/stub_worker.rb +1 -1
  124. data/test/{helper → unit/helper}/watch_helper.rb +1 -13
  125. data/test/{plugin → unit/plugin}/adapter/groonga/test_select.rb +108 -4
  126. data/test/unit/plugin/collector/test_basic.rb +558 -0
  127. data/test/unit/plugin/distributor/test_search.rb +914 -0
  128. data/test/{plugin → unit/plugin}/handler/groonga/test_column_create.rb +18 -14
  129. data/test/{plugin → unit/plugin}/handler/groonga/test_table_create.rb +13 -11
  130. data/test/{plugin/handler/test_handler_add.rb → unit/plugin/handler/test_add.rb} +2 -14
  131. data/test/{plugin/handler/test_handler_groonga.rb → unit/plugin/handler/test_groonga.rb} +6 -26
  132. data/test/unit/plugin/handler/test_search.rb +601 -0
  133. data/test/{plugin/handler/test_handler_watch.rb → unit/plugin/handler/test_watch.rb} +2 -2
  134. data/test/{run-test.rb → unit/run-test.rb} +3 -3
  135. data/test/{test_adapter.rb → unit/test_adapter.rb} +17 -14
  136. data/test/{test_catalog.rb → unit/test_catalog.rb} +4 -4
  137. data/test/{test_command_mapper.rb → unit/test_command_mapper.rb} +1 -1
  138. data/test/{test_groonga_command_converter.rb → unit/test_groonga_command_converter.rb} +3 -3
  139. data/test/{test_job_queue_schema.rb → unit/test_job_queue_schema.rb} +1 -1
  140. data/test/{test_output.rb → unit/test_output.rb} +9 -9
  141. data/test/{test_handler.rb → unit/test_plugin.rb} +19 -22
  142. data/test/unit/test_plugin_repository.rb +89 -0
  143. data/test/{test_sweeper.rb → unit/test_sweeper.rb} +1 -1
  144. data/test/{test_watch_schema.rb → unit/test_watch_schema.rb} +1 -1
  145. data/test/{test_watcher.rb → unit/test_watcher.rb} +1 -1
  146. metadata +226 -66
  147. data/lib/droonga/executor.rb +0 -289
  148. data/lib/droonga/plugin/handler_proxy.rb +0 -82
  149. data/test/plugin/handler/test_handler_search.rb +0 -512
  150. data/test/test_worker.rb +0 -144
@@ -1,289 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2013 droonga project
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 version 2.1 as published by the Free Software Foundation.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
-
18
- require "fluent-logger"
19
- require "groonga"
20
-
21
- require "droonga/job_queue"
22
- require "droonga/handler_plugin"
23
- require "droonga/plugin"
24
- require "droonga/proxy"
25
-
26
- module Droonga
27
- class Executor
28
- attr_reader :context, :envelope, :name
29
-
30
- def initialize(options={})
31
- @handlers = []
32
- @outputs = {}
33
- @options = options
34
- @name = options[:name]
35
- @database_name = options[:database]
36
- @queue_name = options[:queue_name]
37
- @handler_names = options[:handlers]
38
- @pool_size = options[:n_workers]
39
- # load_handlers
40
- Droonga::Plugin.load_all
41
- prepare
42
- end
43
-
44
- def shutdown
45
- $log.trace("#{log_tag}: shutdown: start")
46
- @handlers.each do |handler|
47
- handler.shutdown
48
- end
49
- @outputs.each do |dest, output|
50
- output[:logger].close if output[:logger]
51
- end
52
- if @database
53
- @database.close
54
- @context.close
55
- @database = @context = nil
56
- end
57
- if @job_queue
58
- @job_queue.close
59
- @job_queue = nil
60
- end
61
- $log.trace("#{log_tag}: shutdown: done")
62
- end
63
-
64
- def add_handler(name)
65
- plugin = HandlerPlugin.new(name)
66
- @handlers << plugin.instantiate(self)
67
- end
68
-
69
- def add_route(route)
70
- envelope["via"].push(route)
71
- end
72
-
73
- def dispatch(tag, time, record, synchronous=nil)
74
- $log.trace("#{log_tag}: dispatch: start")
75
- message = [tag, time, record]
76
- body, type, arguments = parse_message([tag, time, record])
77
- reply_to = envelope["replyTo"]
78
- if reply_to.is_a? String
79
- envelope["replyTo"] = {
80
- "type" => type + ".result",
81
- "to" => reply_to
82
- }
83
- end
84
- post_or_push(message, body,
85
- "type" => type,
86
- "arguments" => arguments,
87
- "synchronous" => synchronous)
88
- $log.trace("#{log_tag}: dispatch: done")
89
- end
90
-
91
- def execute_one
92
- $log.trace("#{log_tag}: execute_one: start")
93
- message = @job_queue.pull_message
94
- unless message
95
- $log.trace("#{log_tag}: execute_one: abort: no message")
96
- return
97
- end
98
- body, command, arguments = parse_message(message)
99
- handler = find_handler(command)
100
- if handler
101
- $log.trace("#{log_tag}: execute_one: handle: start",
102
- :hander => handler.class)
103
- handler.handle(command, body, *arguments)
104
- $log.trace("#{log_tag}: execute_one: handle: done",
105
- :hander => handler.class)
106
- end
107
- $log.trace("#{log_tag}: execute_one: done")
108
- end
109
-
110
- def post(body, destination=nil)
111
- $log.trace("#{log_tag}: post: start")
112
- post_or_push(nil, body, destination)
113
- $log.trace("#{log_tag}: post: done")
114
- end
115
-
116
- private
117
- def post_or_push(message, body, destination)
118
- route = nil
119
- unless is_route?(destination)
120
- route = envelope["via"].pop
121
- destination = route
122
- end
123
- unless is_route?(destination)
124
- destination = envelope["replyTo"]
125
- end
126
- command = nil
127
- receiver = nil
128
- arguments = nil
129
- synchronous = nil
130
- case destination
131
- when String
132
- command = destination
133
- when Hash
134
- command = destination["type"]
135
- receiver = destination["to"]
136
- arguments = destination["arguments"]
137
- synchronous = destination["synchronous"]
138
- end
139
- if receiver
140
- output(receiver, body, command, arguments)
141
- else
142
- handler = find_handler(command)
143
- if handler
144
- if synchronous.nil?
145
- synchronous = handler.prefer_synchronous?(command)
146
- end
147
- if route || @pool_size.zero? || synchronous
148
- $log.trace("#{log_tag}: post_or_push: handle: start")
149
- handler.handle(command, body, *arguments)
150
- $log.trace("#{log_tag}: post_or_push: handle: done")
151
- else
152
- unless message
153
- envelope["body"] = body
154
- envelope["type"] = command
155
- envelope["arguments"] = arguments
156
- message = ['', Time.now.to_f, envelope]
157
- end
158
- @job_queue.push_message(message)
159
- end
160
- end
161
- end
162
- add_route(route) if route
163
- end
164
-
165
- def is_route?(route)
166
- route.is_a?(String) || route.is_a?(Hash)
167
- end
168
-
169
- def output(receiver, body, command, arguments)
170
- $log.trace("#{log_tag}: output: start")
171
- unless receiver.is_a?(String) && command.is_a?(String)
172
- $log.trace("#{log_tag}: output: abort: invalid argument",
173
- :receiver => receiver,
174
- :command => command)
175
- return
176
- end
177
- unless receiver =~ /\A(.*):(\d+)\/(.*?)(\?.+)?\z/
178
- raise "format: hostname:port/tag(?params)"
179
- end
180
- host = $1
181
- port = $2
182
- tag = $3
183
- params = $4
184
- output = get_output(host, port, params)
185
- unless output
186
- $log.trace("#{log_tag}: output: abort: no output",
187
- :host => host,
188
- :port => port,
189
- :params => params)
190
- return
191
- end
192
- if command =~ /\.result$/
193
- message = {
194
- inReplyTo: envelope["id"],
195
- statusCode: 200,
196
- type: command,
197
- body: body
198
- }
199
- else
200
- message = envelope.merge(
201
- body: body,
202
- type: command,
203
- arguments: arguments
204
- )
205
- end
206
- output_tag = "#{tag}.message"
207
- $log.trace("#{log_tag}: output: post: start: <#{output_tag}>")
208
- output.post(output_tag, message)
209
- $log.trace("#{log_tag}: output: post: done: <#{output_tag}>")
210
- $log.trace("#{log_tag}: output: done")
211
- end
212
-
213
- def parse_message(message)
214
- tag, time, record = message
215
- prefix, type, *arguments = tag.split(/\./)
216
- if type.nil? || type.empty? || type == 'message'
217
- @envelope = record
218
- else
219
- @envelope = {
220
- "type" => type,
221
- "arguments" => arguments,
222
- "body" => record
223
- }
224
- end
225
- envelope["via"] ||= []
226
- [envelope["body"], envelope["type"], envelope["arguments"]]
227
- end
228
-
229
- def load_handlers
230
- @handler_names.each do |handler_name|
231
- plugin = Droonga::Plugin.new("handler", handler_name)
232
- plugin.load
233
- end
234
- end
235
-
236
- def prepare
237
- if @database_name && !@database_name.empty?
238
- @context = Groonga::Context.new
239
- @database = @context.open_database(@database_name)
240
- @job_queue = JobQueue.open(@database_name, @queue_name)
241
- end
242
- @handler_names.each do |handler_name|
243
- add_handler(handler_name)
244
- end
245
- add_handler("proxy_message") if @options[:proxy]
246
- end
247
-
248
- def find_handler(command)
249
- @handlers.find do |handler|
250
- handler.handlable?(command)
251
- end
252
- end
253
-
254
- def get_output(host, port, params)
255
- host_port = "#{host}:#{port}"
256
- @outputs[host_port] ||= {}
257
- output = @outputs[host_port]
258
-
259
- has_connection_id = (not params.nil? \
260
- and params =~ /[\?&;]connection_id=([^&;]+)/)
261
- if output[:logger].nil? or has_connection_id
262
- connection_id = $1
263
- if not has_connection_id or output[:connection_id] != connection_id
264
- output[:connection_id] = connection_id
265
- logger = create_logger(:host => host, :port => port.to_i)
266
- # output[:logger] should be closed if it exists beforehand?
267
- output[:logger] = logger
268
- end
269
- end
270
-
271
- has_client_session_id = (not params.nil? \
272
- and params =~ /[\?&;]client_session_id=([^&;]+)/)
273
- if has_client_session_id
274
- client_session_id = $1
275
- # some generic way to handle client_session_id is expected
276
- end
277
-
278
- output[:logger]
279
- end
280
-
281
- def create_logger(options)
282
- Fluent::Logger::FluentLogger.new(nil, options)
283
- end
284
-
285
- def log_tag
286
- "[#{Process.ppid}][#{Process.pid}] executor"
287
- end
288
- end
289
- end
@@ -1,82 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2013 droonga project
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 version 2.1 as published by the Free Software Foundation.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
-
18
- require "droonga/handler"
19
- require "droonga/searcher"
20
-
21
- module Droonga
22
- class BasicProxyHandler < Droonga::ProxyHandler
23
- Droonga::HandlerPlugin.register("proxy", self)
24
-
25
- command :proxy_gather
26
- def proxy_gather(request)
27
- output = body ? body[input_name] : input_name
28
- emit(request, output)
29
- end
30
-
31
- command :proxy_reduce
32
- def proxy_reduce(request)
33
- return unless request
34
- body[input_name].each do |output, elements|
35
- value = request
36
- old_value = output_values[output]
37
- value = reduce(elements, old_value, request) if old_value
38
- emit(value, output)
39
- end
40
- end
41
-
42
- def reduce(elements, *values)
43
- result = {}
44
- elements.each do |key, deal|
45
- func, *args = deal
46
- case func
47
- when "sum"
48
- result[key] = values[0][key] + values[1][key]
49
- when "sort"
50
- result[key] = merge(values[0][key], values[1][key], args)
51
- end
52
- end
53
- return result
54
- end
55
-
56
- def merge(x, y, order)
57
- index = 0
58
- y.each do |_y|
59
- loop do
60
- _x = x[index]
61
- break unless _x
62
- break if compare(_y, _x, order)
63
- index += 1
64
- end
65
- x.insert(index, _y)
66
- index += 1
67
- end
68
- return x
69
- end
70
-
71
- def compare(x, y, operators)
72
- for index in 0..x.size-1 do
73
- _x = x[index]
74
- _y = y[index]
75
- operator = operators[index]
76
- break unless operator
77
- return true if _x.__send__(operator, _y)
78
- end
79
- return false
80
- end
81
- end
82
- end
@@ -1,512 +0,0 @@
1
- # Copyright (C) 2013 droonga project
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 version 2.1 as published by the Free Software Foundation.
6
- #
7
- # This library is distributed in the hope that it will be useful,
8
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
- # Lesser General Public License for more details.
11
- #
12
- # You should have received a copy of the GNU Lesser General Public
13
- # License along with this library; if not, write to the Free Software
14
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
-
16
- require "droonga/plugin/handler_search"
17
-
18
- class SearchHandlerTest < Test::Unit::TestCase
19
- def setup
20
- setup_database
21
- setup_handler
22
- end
23
-
24
- def teardown
25
- teardown_handler
26
- teardown_database
27
- end
28
-
29
- private
30
- def setup_database
31
- restore(fixture_data("document.grn"))
32
- @database = Groonga::Database.open(@database_path.to_s)
33
- end
34
-
35
- def teardown_database
36
- @database.close
37
- @database = nil
38
- end
39
-
40
- def setup_handler
41
- @worker = StubWorker.new
42
- @handler = Droonga::SearchHandler.new(@worker)
43
- end
44
-
45
- def teardown_handler
46
- @handler = nil
47
- end
48
-
49
- def search(request)
50
- @handler.search(request)
51
- normalize_result_set(@worker.body)
52
- end
53
-
54
- def normalize_result_set(result_set)
55
- result_set.each do |name, result|
56
- result["startTime"] = start_time if result["startTime"]
57
- result["elapsedTime"] = elapsed_time if result["elapsedTime"]
58
- end
59
- result_set
60
- end
61
-
62
- def start_time
63
- "2013-01-31T14:34:47+09:00"
64
- end
65
-
66
- def elapsed_time
67
- 0.01
68
- end
69
-
70
- def assert_search(expected, request)
71
- assert_equal(expected, search(request))
72
- end
73
-
74
- class NoParameterTest < self
75
- def test_empty
76
- assert_search({}, {})
77
- end
78
- end
79
-
80
- class QueriesTest < self
81
- def test_empty
82
- assert_search({}, {"queries" => {}})
83
- end
84
- end
85
-
86
- class HashQueryTest < self
87
- def test_string_matchTo
88
- request = base_request
89
- request["queries"]["sections-result"]["condition"] = {
90
- "query" => "Groonga",
91
- "matchTo" => "title"
92
- }
93
- assert_search({
94
- "sections-result" => {
95
- "records" => [
96
- { "title" => "Groonga overview" },
97
- ],
98
- },
99
- },
100
- request)
101
- end
102
-
103
- def test_array_matchTo
104
- request = base_request
105
- request["queries"]["sections-result"]["condition"] = {
106
- "query" => "Groonga",
107
- "matchTo" => ["title"]
108
- }
109
- assert_search({
110
- "sections-result" => {
111
- "records" => [
112
- { "title" => "Groonga overview" },
113
- ],
114
- },
115
- },
116
- request)
117
- end
118
-
119
- def base_request
120
- {
121
- "queries" => {
122
- "sections-result" => {
123
- "source" => "Sections",
124
- "output" => {
125
- "elements" => [
126
- "records",
127
- ],
128
- "format" => "complex",
129
- "limit" => 1,
130
- "attributes" => ["title"],
131
- },
132
- },
133
- },
134
- }
135
- end
136
- end
137
-
138
- class SourceTest < self
139
- def test_non_existent
140
- assert_raise(Droonga::Searcher::UndefinedSourceError) do
141
- search({
142
- "queries" => {
143
- "non-existent-result" => {
144
- "source" => "non-existent",
145
- },
146
- },
147
- })
148
- end
149
- end
150
-
151
- def test_existent
152
- assert_search({
153
- "sections-result" => {},
154
- },
155
- {
156
- "queries" => {
157
- "sections-result" => {
158
- "source" => "Sections",
159
- "output" => {},
160
- },
161
- },
162
- })
163
- end
164
- end
165
-
166
- class OutputTest < self
167
- def test_count
168
- assert_search({
169
- "sections-result" => {
170
- "count" => 9,
171
- },
172
- },
173
- {
174
- "queries" => {
175
- "sections-result" => {
176
- "source" => "Sections",
177
- "output" => {
178
- "elements" => [
179
- "count",
180
- ],
181
- },
182
- },
183
- },
184
- })
185
- end
186
-
187
- def test_elapsed_time
188
- assert_search({
189
- "sections-result" => {
190
- "startTime" => start_time,
191
- "elapsedTime" => elapsed_time,
192
- },
193
- },
194
- {
195
- "queries" => {
196
- "sections-result" => {
197
- "source" => "Sections",
198
- "output" => {
199
- "elements" => [
200
- "startTime",
201
- "elapsedTime",
202
- ],
203
- },
204
- },
205
- },
206
- })
207
- end
208
-
209
- class AttributesTest < self
210
- def test_source_only
211
- expected = {
212
- "sections-result" => {
213
- "records" => [
214
- {
215
- "_key" => "1.1",
216
- "title" => "Groonga overview",
217
- },
218
- {
219
- "_key" => "1.2",
220
- "title" => "Full text search and Instant update",
221
- },
222
- {
223
- "_key" => "1.3",
224
- "title" => "Column store and aggregate query",
225
- },
226
- ],
227
- },
228
- }
229
- request = {
230
- "queries" => {
231
- "sections-result" => {
232
- "source" => "Sections",
233
- "output" => {
234
- "elements" => [
235
- "records",
236
- ],
237
- "format" => "complex",
238
- "limit" => 3,
239
- "attributes" => ["_key", "title"],
240
- },
241
- },
242
- },
243
- }
244
- assert_search(expected, request)
245
- end
246
-
247
- def test_label
248
- expected = {
249
- "sections-result" => {
250
- "records" => [
251
- {
252
- "key" => "1.1",
253
- "title" => "Groonga overview",
254
- },
255
- {
256
- "key" => "1.2",
257
- "title" => "Full text search and Instant update",
258
- },
259
- {
260
- "key" => "1.3",
261
- "title" => "Column store and aggregate query",
262
- },
263
- ],
264
- },
265
- }
266
- request = {
267
- "queries" => {
268
- "sections-result" => {
269
- "source" => "Sections",
270
- "output" => {
271
- "elements" => [
272
- "records",
273
- ],
274
- "format" => "complex",
275
- "limit" => 3,
276
- "attributes" => [
277
- {
278
- "label" => "key",
279
- "source" => "_key",
280
- },
281
- "title",
282
- ],
283
- },
284
- },
285
- },
286
- }
287
- assert_search(expected, request)
288
- end
289
-
290
- def test_static_value
291
- expected = {
292
- "sections-result" => {
293
- "records" => [
294
- {
295
- "single_quote_string" => "string value",
296
- "double_quote_string" => "string value",
297
- "integer" => 29,
298
- "complex_negative_number" => -29.29,
299
- },
300
- {
301
- "single_quote_string" => "string value",
302
- "double_quote_string" => "string value",
303
- "integer" => 29,
304
- "complex_negative_number" => -29.29,
305
- },
306
- ],
307
- },
308
- }
309
- request = {
310
- "queries" => {
311
- "sections-result" => {
312
- "source" => "Sections",
313
- "output" => {
314
- "elements" => [
315
- "records",
316
- ],
317
- "format" => "complex",
318
- "limit" => 2,
319
- "attributes" => [
320
- {
321
- "label" => "single_quote_string",
322
- "source" => "'string value'",
323
- },
324
- {
325
- "label" => "double_quote_string",
326
- "source" => '"string value"',
327
- },
328
- {
329
- "label" => "integer",
330
- "source" => "29",
331
- },
332
- {
333
- "label" => "complex_negative_number",
334
- "source" => "-29.29",
335
- },
336
- ],
337
- },
338
- },
339
- },
340
- }
341
- assert_search(expected, request)
342
- end
343
-
344
- def test_expression
345
- expected = {
346
- "sections-result" => {
347
- "records" => [
348
- {
349
- "formatted title" => "<Groonga overview>",
350
- "title" => "Groonga overview",
351
- },
352
- ],
353
- },
354
- }
355
- request = {
356
- "queries" => {
357
- "sections-result" => {
358
- "source" => "Sections",
359
- "output" => {
360
- "elements" => [
361
- "records",
362
- ],
363
- "format" => "complex",
364
- "limit" => 1,
365
- "attributes" => [
366
- "title",
367
- {
368
- "label" => "formatted title",
369
- "source" => "'<' + title + '>'",
370
- },
371
- ],
372
- },
373
- },
374
- },
375
- }
376
- assert_search(expected, request)
377
- end
378
-
379
- def test_snippet_html
380
- expected = {
381
- "sections-result" => {
382
- "records" => [
383
- {
384
- "title" => "Groonga overview",
385
- "snippet" => [
386
- "<span class=\"keyword\">Groonga</span> overview",
387
- ],
388
- },
389
- ],
390
- },
391
- }
392
- request = {
393
- "queries" => {
394
- "sections-result" => {
395
- "source" => "Sections",
396
- "condition" => {
397
- "query" => "Groonga",
398
- "matchTo" => ["title"],
399
- },
400
- "output" => {
401
- "elements" => [
402
- "records",
403
- ],
404
- "format" => "complex",
405
- "limit" => 1,
406
- "attributes" => [
407
- "title",
408
- {
409
- "label" => "snippet",
410
- "source" => "snippet_html(title)",
411
- },
412
- ],
413
- },
414
- },
415
- },
416
- }
417
- assert_search(expected, request)
418
- end
419
- end
420
-
421
- class FormatTest < self
422
- def test_complex
423
- request = {
424
- "queries" => {
425
- "sections-result" => {
426
- "source" => "Sections",
427
- "output" => {
428
- "elements" => [
429
- "records",
430
- ],
431
- "format" => "complex",
432
- "limit" => 3,
433
- "attributes" => ["_key", "title"],
434
- },
435
- },
436
- },
437
- }
438
- assert_search(complex_result, request)
439
- end
440
-
441
- def test_simple
442
- request = {
443
- "queries" => {
444
- "sections-result" => {
445
- "source" => "Sections",
446
- "output" => {
447
- "elements" => [
448
- "records",
449
- ],
450
- "format" => "simple",
451
- "limit" => 3,
452
- "attributes" => ["_key", "title"],
453
- },
454
- },
455
- },
456
- }
457
- assert_search(simple_result, request)
458
- end
459
-
460
- def test_default
461
- request = {
462
- "queries" => {
463
- "sections-result" => {
464
- "source" => "Sections",
465
- "output" => {
466
- "elements" => [
467
- "records",
468
- ],
469
- "limit" => 3,
470
- "attributes" => ["_key", "title"],
471
- },
472
- },
473
- },
474
- }
475
- assert_search(simple_result, request)
476
- end
477
-
478
- def complex_result
479
- {
480
- "sections-result" => {
481
- "records" => [
482
- {
483
- "_key" => "1.1",
484
- "title" => "Groonga overview",
485
- },
486
- {
487
- "_key" => "1.2",
488
- "title" => "Full text search and Instant update",
489
- },
490
- {
491
- "_key" => "1.3",
492
- "title" => "Column store and aggregate query",
493
- },
494
- ],
495
- },
496
- }
497
- end
498
-
499
- def simple_result
500
- {
501
- "sections-result" => {
502
- "records" => [
503
- ["1.1", "Groonga overview"],
504
- ["1.2", "Full text search and Instant update"],
505
- ["1.3", "Column store and aggregate query"],
506
- ],
507
- },
508
- }
509
- end
510
- end
511
- end
512
- end