fluent-plugin-droonga 0.7.0 → 0.8.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -4
- data/benchmark/watch/benchmark-notify.rb +2 -2
- data/benchmark/watch/benchmark-scan.rb +3 -0
- data/benchmark/watch/fluentd.conf +0 -1
- data/fluent-plugin-droonga.gemspec +2 -3
- data/lib/droonga/catalog.rb +10 -124
- data/lib/droonga/catalog/base.rb +140 -0
- data/lib/droonga/catalog/version1.rb +23 -0
- data/lib/droonga/catalog_loader.rb +33 -0
- data/lib/droonga/collector.rb +2 -71
- data/lib/droonga/collector_plugin.rb +2 -34
- data/lib/droonga/dispatcher.rb +141 -196
- data/lib/droonga/distribution_planner.rb +76 -0
- data/lib/droonga/distributor.rb +5 -7
- data/lib/droonga/distributor_plugin.rb +23 -15
- data/lib/droonga/engine.rb +2 -2
- data/lib/droonga/event_loop.rb +46 -0
- data/lib/droonga/farm.rb +9 -5
- data/lib/droonga/fluent_message_sender.rb +84 -0
- data/lib/droonga/forwarder.rb +43 -53
- data/lib/droonga/handler.rb +20 -68
- data/lib/droonga/handler_message.rb +61 -0
- data/lib/droonga/handler_messenger.rb +92 -0
- data/lib/droonga/handler_plugin.rb +10 -12
- data/lib/droonga/input_adapter.rb +52 -0
- data/lib/droonga/{adapter.rb → input_adapter_plugin.rb} +7 -13
- data/lib/droonga/input_message.rb +11 -11
- data/lib/droonga/logger.rb +4 -3
- data/lib/droonga/message_pack_packer.rb +62 -0
- data/lib/droonga/message_processing_error.rb +54 -0
- data/lib/droonga/message_pusher.rb +60 -0
- data/lib/droonga/message_receiver.rb +61 -0
- data/lib/droonga/output_adapter.rb +53 -0
- data/lib/droonga/{adapter_plugin.rb → output_adapter_plugin.rb} +3 -21
- data/lib/droonga/output_message.rb +37 -0
- data/lib/droonga/partition.rb +27 -5
- data/lib/droonga/pluggable.rb +9 -4
- data/lib/droonga/plugin.rb +12 -3
- data/lib/droonga/plugin/collector/basic.rb +91 -18
- data/lib/droonga/plugin/distributor/crud.rb +9 -9
- data/lib/droonga/plugin/distributor/distributed_search_planner.rb +401 -0
- data/lib/droonga/plugin/distributor/groonga.rb +5 -5
- data/lib/droonga/plugin/distributor/search.rb +4 -246
- data/lib/droonga/plugin/distributor/watch.rb +11 -6
- data/lib/droonga/plugin/handler/add.rb +69 -7
- data/lib/droonga/plugin/handler/groonga.rb +6 -6
- data/lib/droonga/plugin/handler/search.rb +5 -3
- data/lib/droonga/plugin/handler/watch.rb +19 -13
- data/lib/droonga/plugin/{adapter → input_adapter}/groonga.rb +5 -11
- data/lib/droonga/plugin/{adapter → input_adapter}/groonga/select.rb +2 -36
- data/lib/droonga/plugin/output_adapter/groonga.rb +30 -0
- data/lib/droonga/plugin/output_adapter/groonga/select.rb +54 -0
- data/lib/droonga/plugin_loader.rb +2 -2
- data/lib/droonga/processor.rb +21 -23
- data/lib/droonga/replier.rb +40 -0
- data/lib/droonga/searcher.rb +298 -174
- data/lib/droonga/server.rb +0 -67
- data/lib/droonga/session.rb +85 -0
- data/lib/droonga/test.rb +21 -0
- data/lib/droonga/test/stub_distributor.rb +31 -0
- data/lib/droonga/test/stub_handler.rb +37 -0
- data/lib/droonga/test/stub_handler_message.rb +35 -0
- data/lib/droonga/test/stub_handler_messenger.rb +34 -0
- data/lib/droonga/time_formatter.rb +37 -0
- data/lib/droonga/watcher.rb +1 -0
- data/lib/droonga/worker.rb +16 -19
- data/lib/fluent/plugin/out_droonga.rb +9 -9
- data/lib/groonga_command_converter.rb +5 -5
- data/sample/cluster/catalog.json +1 -1
- data/test/command/config/default/catalog.json +19 -1
- data/test/command/fixture/event.jsons +41 -0
- data/test/command/fixture/user-table.jsons +9 -0
- data/test/command/run-test.rb +2 -2
- data/test/command/suite/add/error/invalid-integer.expected +20 -0
- data/test/command/suite/add/error/invalid-integer.test +12 -0
- data/test/command/suite/add/error/invalid-time.expected +20 -0
- data/test/command/suite/add/error/invalid-time.test +12 -0
- data/test/command/suite/add/error/missing-key.expected +13 -0
- data/test/command/suite/add/error/missing-key.test +16 -0
- data/test/command/suite/add/error/missing-table.expected +13 -0
- data/test/command/suite/add/error/missing-table.test +16 -0
- data/test/command/suite/add/error/unknown-column.expected +20 -0
- data/test/command/suite/add/error/unknown-column.test +12 -0
- data/test/command/suite/add/error/unknown-table.expected +13 -0
- data/test/command/suite/add/error/unknown-table.test +17 -0
- data/test/command/suite/add/minimum.expected +1 -3
- data/test/command/suite/add/with-values.expected +1 -3
- data/test/command/suite/add/without-key.expected +1 -3
- data/test/command/suite/message/error/missing-dataset.expected +13 -0
- data/test/command/suite/message/error/missing-dataset.test +5 -0
- data/test/command/suite/message/error/unknown-command.expected +13 -0
- data/test/command/suite/message/error/unknown-command.test +6 -0
- data/test/command/suite/message/error/unknown-dataset.expected +13 -0
- data/test/command/suite/message/error/unknown-dataset.test +6 -0
- data/test/command/suite/search/{array-attribute-label.expected → attributes/array.expected} +0 -0
- data/test/command/suite/search/{array-attribute-label.test → attributes/array.test} +0 -0
- data/test/command/suite/search/{hash-attribute-label.expected → attributes/hash.expected} +0 -0
- data/test/command/suite/search/{hash-attribute-label.test → attributes/hash.test} +0 -0
- data/test/command/suite/search/{condition-nested.expected → condition/nested.expected} +0 -0
- data/test/command/suite/search/{condition-nested.test → condition/nested.test} +0 -0
- data/test/command/suite/search/{condition-query.expected → condition/query.expected} +0 -0
- data/test/command/suite/search/{condition-query.test → condition/query.test} +0 -0
- data/test/command/suite/search/{condition-script.expected → condition/script.expected} +0 -0
- data/test/command/suite/search/{condition-script.test → condition/script.test} +0 -0
- data/test/command/suite/search/error/cyclic-source.expected +18 -0
- data/test/command/suite/search/error/cyclic-source.test +12 -0
- data/test/command/suite/search/error/deeply-cyclic-source.expected +21 -0
- data/test/command/suite/search/error/deeply-cyclic-source.test +15 -0
- data/test/command/suite/search/error/missing-source-parameter.expected +17 -0
- data/test/command/suite/search/error/missing-source-parameter.test +11 -0
- data/test/command/suite/search/error/unknown-source.expected +18 -0
- data/test/command/suite/search/error/unknown-source.test +12 -0
- data/test/command/suite/search/{minimum.expected → group/count.expected} +2 -1
- data/test/command/suite/search/{minimum.test → group/count.test} +5 -3
- data/test/command/suite/search/group/limit.expected +19 -0
- data/test/command/suite/search/group/limit.test +20 -0
- data/test/command/suite/search/group/string.expected +36 -0
- data/test/command/suite/search/group/string.test +44 -0
- data/test/command/suite/search/{chained-queries.expected → multiple/chained.expected} +0 -0
- data/test/command/suite/search/{chained-queries.test → multiple/chained.test} +0 -0
- data/test/command/suite/search/{multiple-queries.expected → multiple/parallel.expected} +0 -0
- data/test/command/suite/search/{multiple-queries.test → multiple/parallel.test} +0 -0
- data/test/command/suite/search/{output-range.expected → range/only-output.expected} +0 -0
- data/test/command/suite/search/{output-range.test → range/only-output.test} +0 -0
- data/test/command/suite/search/{sort-range.expected → range/only-sort.expected} +0 -0
- data/test/command/suite/search/{sort-range.test → range/only-sort.test} +0 -0
- data/test/command/suite/search/{sort-and-output-range.expected → range/sort-and-output.expected} +0 -0
- data/test/command/suite/search/{sort-and-output-range.test → range/sort-and-output.test} +0 -0
- data/test/command/suite/search/range/too-large-output-offset.expected +16 -0
- data/test/command/suite/search/range/too-large-output-offset.test +25 -0
- data/test/command/suite/search/range/too-large-sort-offset.expected +16 -0
- data/test/command/suite/search/range/too-large-sort-offset.test +28 -0
- data/test/command/suite/search/response/records/value/time.expected +24 -0
- data/test/command/suite/search/response/records/value/time.test +24 -0
- data/test/command/suite/search/sort/default-offset-limit.expected +43 -0
- data/test/command/suite/search/sort/default-offset-limit.test +26 -0
- data/test/command/suite/search/{sort-with-invisible-column.expected → sort/invisible-column.expected} +0 -0
- data/test/command/suite/search/{sort-with-invisible-column.test → sort/invisible-column.test} +0 -0
- data/test/command/suite/watch/subscribe.expected +12 -0
- data/test/command/suite/watch/subscribe.test +9 -0
- data/test/command/suite/watch/unsubscribe.expected +12 -0
- data/test/command/suite/watch/unsubscribe.test +9 -0
- data/test/unit/{test_catalog.rb → catalog/test_version1.rb} +12 -4
- data/test/unit/fixtures/{catalog.json → catalog/version1.json} +0 -0
- data/test/unit/helper.rb +2 -0
- data/test/unit/plugin/collector/test_basic.rb +289 -33
- data/test/unit/plugin/distributor/test_search.rb +176 -861
- data/test/unit/plugin/distributor/test_search_planner.rb +1102 -0
- data/test/unit/plugin/handler/groonga/test_column_create.rb +17 -13
- data/test/unit/plugin/handler/groonga/test_table_create.rb +10 -10
- data/test/unit/plugin/handler/test_add.rb +74 -11
- data/test/unit/plugin/handler/test_groonga.rb +15 -1
- data/test/unit/plugin/handler/test_search.rb +33 -17
- data/test/unit/plugin/handler/test_watch.rb +43 -27
- data/test/unit/run-test.rb +2 -0
- data/test/unit/test_message_pack_packer.rb +51 -0
- data/test/unit/test_time_formatter.rb +29 -0
- metadata +208 -110
- data/lib/droonga/job_queue.rb +0 -87
- data/lib/droonga/job_queue_schema.rb +0 -65
- data/test/unit/test_adapter.rb +0 -51
- data/test/unit/test_job_queue_schema.rb +0 -45
@@ -22,16 +22,16 @@ module Droonga
|
|
22
22
|
repository.register("groonga", self)
|
23
23
|
|
24
24
|
command :table_create
|
25
|
-
def table_create(
|
26
|
-
unless
|
25
|
+
def table_create(message)
|
26
|
+
unless message["dataset"]
|
27
27
|
raise "dataset must be set. FIXME: This error should return client."
|
28
28
|
end
|
29
|
-
broadcast_all(
|
29
|
+
broadcast_all(message)
|
30
30
|
end
|
31
31
|
|
32
32
|
command :column_create
|
33
|
-
def column_create(
|
34
|
-
broadcast_all(
|
33
|
+
def column_create(message)
|
34
|
+
broadcast_all(message)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -16,258 +16,16 @@
|
|
16
16
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
17
|
|
18
18
|
require "droonga/distributor_plugin"
|
19
|
+
require "droonga/plugin/distributor/distributed_search_planner"
|
19
20
|
|
20
21
|
module Droonga
|
21
22
|
class SearchDistributor < Droonga::DistributorPlugin
|
22
23
|
repository.register("search", self)
|
23
24
|
|
24
25
|
command :search
|
25
|
-
def search(
|
26
|
-
|
27
|
-
|
28
|
-
output_names = []
|
29
|
-
output_mapper = {}
|
30
|
-
|
31
|
-
request = envelope["body"]
|
32
|
-
request["queries"].each do |input_name, query|
|
33
|
-
output = query["output"]
|
34
|
-
# Skip reducing phase for a result with no output.
|
35
|
-
next unless output
|
36
|
-
|
37
|
-
input_names << input_name
|
38
|
-
output_name = input_name + "_reduced"
|
39
|
-
output_names << output_name
|
40
|
-
output_mapper[output_name] = {
|
41
|
-
"output" => input_name,
|
42
|
-
}
|
43
|
-
|
44
|
-
# The collector module supports only "simple" format search results.
|
45
|
-
# So we have to override the format and restore it on the gathering
|
46
|
-
# phase.
|
47
|
-
final_format = output["format"] || "simple"
|
48
|
-
output["format"] = "simple"
|
49
|
-
|
50
|
-
final_offset, final_limit = calculate_offset_and_limit!(query)
|
51
|
-
|
52
|
-
elements = {}
|
53
|
-
output["elements"].each do |element|
|
54
|
-
case element
|
55
|
-
when "count"
|
56
|
-
elements[element] = {
|
57
|
-
"type" => "sum",
|
58
|
-
}
|
59
|
-
when "records"
|
60
|
-
# Skip reducing phase for a result with no record output.
|
61
|
-
next if final_limit.zero?
|
62
|
-
|
63
|
-
# Append sort key attributes to the list of output attributes
|
64
|
-
# temporarily, for the reducing phase. After all extra columns
|
65
|
-
# are removed on the gathering phase.
|
66
|
-
final_attributes = collect_output_attributes(output["attributes"])
|
67
|
-
output["attributes"] = format_attributes_to_array_style(output["attributes"])
|
68
|
-
output["attributes"] += collect_sort_attributes(output["attributes"], query["sortBy"])
|
69
|
-
|
70
|
-
elements[element] = sort_reducer(output["attributes"], query["sortBy"])
|
71
|
-
# On the reducing phase, we apply only "limit". We cannot apply
|
72
|
-
# "offset" on this phase because the collecter merges a pair of
|
73
|
-
# results step by step even if there are three or more results.
|
74
|
-
# Instead, we apply "offset" on the gethering phase.
|
75
|
-
elements[element]["limit"] = output["limit"]
|
76
|
-
|
77
|
-
output_mapper[output_name]["element"] = element
|
78
|
-
output_mapper[output_name]["offset"] = final_offset
|
79
|
-
output_mapper[output_name]["limit"] = final_limit
|
80
|
-
output_mapper[output_name]["format"] = final_format
|
81
|
-
output_mapper[output_name]["attributes"] = final_attributes
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
reducer = {
|
86
|
-
"type" => "reduce",
|
87
|
-
"body" => {
|
88
|
-
input_name => {
|
89
|
-
output_name => elements,
|
90
|
-
},
|
91
|
-
},
|
92
|
-
"inputs" => [input_name], # XXX should be placed in the "body"?
|
93
|
-
"outputs" => [output_name], # XXX should be placed in the "body"?
|
94
|
-
}
|
95
|
-
message << reducer
|
96
|
-
end
|
97
|
-
gatherer = {
|
98
|
-
"type" => "gather",
|
99
|
-
"body" => output_mapper,
|
100
|
-
"inputs" => output_names, # XXX should be placed in the "body"?
|
101
|
-
"post" => true, # XXX should be placed in the "body"?
|
102
|
-
}
|
103
|
-
message << gatherer
|
104
|
-
searcher = {
|
105
|
-
"type" => "broadcast",
|
106
|
-
"command" => "search", # XXX should be placed in the "body"?
|
107
|
-
"dataset" => envelope["dataset"] || request["dataset"],
|
108
|
-
"body" => request,
|
109
|
-
"outputs" => input_names, # XXX should be placed in the "body"?
|
110
|
-
"replica" => "random", # XXX should be placed in the "body"?
|
111
|
-
}
|
112
|
-
message.push(searcher)
|
113
|
-
post(message)
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
UNLIMITED = -1
|
118
|
-
|
119
|
-
def calculate_offset_and_limit!(query)
|
120
|
-
rich_sort = query["sortBy"].is_a?(Hash)
|
121
|
-
|
122
|
-
have_records = false
|
123
|
-
if query["output"] &&
|
124
|
-
query["output"]["elements"].is_a?(Array) &&
|
125
|
-
query["output"]["elements"].include?("records")
|
126
|
-
have_records = true
|
127
|
-
end
|
128
|
-
|
129
|
-
# Offset for workers must be zero, because we have to apply "limit" and
|
130
|
-
# "offset" on the last gapthering phase instaed of each reducing phase.
|
131
|
-
sort_offset = 0
|
132
|
-
if rich_sort
|
133
|
-
sort_offset = query["sortBy"]["offset"] || 0
|
134
|
-
query["sortBy"]["offset"] = 0
|
135
|
-
end
|
136
|
-
|
137
|
-
output_offset = query["output"]["offset"] || 0
|
138
|
-
query["output"]["offset"] = 0 if have_records
|
139
|
-
|
140
|
-
final_offset = sort_offset + output_offset
|
141
|
-
|
142
|
-
# We have to calculate limit based on offset.
|
143
|
-
# <A, B = limited integer (0...MAXINT)>
|
144
|
-
# | sort limit | output limit | => | worker's sort limit | worker's output limit | final limit |
|
145
|
-
# ============================= ====================================================================
|
146
|
-
# | UNLIMITED | UNLIMITED | => | UNLIMITED | UNLIMITED | UNLIMITED |
|
147
|
-
# | UNLIMITED | B | => | final_offset + B | final_offset + B | B |
|
148
|
-
# | A | UNLIMITED | => | final_offset + A | final_offset + A | A |
|
149
|
-
# | A | B | => | final_offset + min(A, B) | final_offset + min(A, B)| min(A, B) |
|
150
|
-
sort_limit = UNLIMITED
|
151
|
-
if rich_sort
|
152
|
-
sort_limit = query["sortBy"]["limit"] || UNLIMITED
|
153
|
-
end
|
154
|
-
output_limit = query["output"]["limit"] || 0
|
155
|
-
|
156
|
-
final_limit = 0
|
157
|
-
if sort_limit == UNLIMITED && output_limit == UNLIMITED
|
158
|
-
final_limit = UNLIMITED
|
159
|
-
query["output"]["limit"] = UNLIMITED
|
160
|
-
else
|
161
|
-
if sort_limit == UNLIMITED
|
162
|
-
final_limit = output_limit
|
163
|
-
elsif output_limit == UNLIMITED
|
164
|
-
final_limit = sort_limit
|
165
|
-
else
|
166
|
-
final_limit = [sort_limit, output_limit].min
|
167
|
-
end
|
168
|
-
query["sortBy"]["limit"] = final_offset + final_limit if rich_sort
|
169
|
-
query["output"]["limit"] = final_offset + final_limit
|
170
|
-
end
|
171
|
-
|
172
|
-
[final_offset, final_limit]
|
173
|
-
end
|
174
|
-
|
175
|
-
def format_attributes_to_array_style(attributes)
|
176
|
-
attributes ||= []
|
177
|
-
if attributes.is_a?(Hash)
|
178
|
-
attributes.keys.collect do |key|
|
179
|
-
attribute = attributes[key]
|
180
|
-
case attribute
|
181
|
-
when String
|
182
|
-
{
|
183
|
-
"label" => key,
|
184
|
-
"source" => attribute,
|
185
|
-
}
|
186
|
-
when Hash
|
187
|
-
attribute["label"] = key
|
188
|
-
attribute
|
189
|
-
end
|
190
|
-
end
|
191
|
-
else
|
192
|
-
attributes
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def collect_output_attributes(attributes)
|
197
|
-
attributes ||= []
|
198
|
-
if attributes.is_a?(Hash)
|
199
|
-
attributes.keys
|
200
|
-
else
|
201
|
-
attributes.collect do |attribute|
|
202
|
-
if attribute.is_a?(Hash)
|
203
|
-
attribute["label"] || attribute["source"]
|
204
|
-
else
|
205
|
-
attribute
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def collect_source_column_names(attributes)
|
212
|
-
attributes ||= []
|
213
|
-
if attributes.is_a?(Hash)
|
214
|
-
attributes_hash = attributes
|
215
|
-
attributes = []
|
216
|
-
attributes_hash.each do |key, attribute|
|
217
|
-
attributes << attribute["source"] || key
|
218
|
-
end
|
219
|
-
attributes
|
220
|
-
else
|
221
|
-
attributes.collect do |attribute|
|
222
|
-
if attribute.is_a?(Hash)
|
223
|
-
attribute["source"] || attribute["label"]
|
224
|
-
else
|
225
|
-
attribute
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
def collect_sort_attributes(attributes, sort_keys)
|
232
|
-
sort_keys ||= []
|
233
|
-
sort_keys = sort_keys["keys"] || [] if sort_keys.is_a?(Hash)
|
234
|
-
|
235
|
-
attributes = collect_source_column_names(attributes)
|
236
|
-
|
237
|
-
sort_attributes = sort_keys.collect do |key|
|
238
|
-
key = key[1..-1] if key[0] == "-"
|
239
|
-
key
|
240
|
-
end
|
241
|
-
sort_attributes.reject! do |attribute|
|
242
|
-
attributes.include?(attribute)
|
243
|
-
end
|
244
|
-
sort_attributes
|
245
|
-
end
|
246
|
-
|
247
|
-
ASCENDING_OPERATOR = "<".freeze
|
248
|
-
DESCENDING_OPERATOR = ">".freeze
|
249
|
-
|
250
|
-
def sort_reducer(attributes, sort_keys)
|
251
|
-
attributes ||= []
|
252
|
-
sort_keys ||= []
|
253
|
-
sort_keys = sort_keys["keys"] || [] if sort_keys.is_a?(Hash)
|
254
|
-
|
255
|
-
operators = sort_keys.collect do |sort_key|
|
256
|
-
operator = ASCENDING_OPERATOR
|
257
|
-
if sort_key[0] == "-"
|
258
|
-
operator = DESCENDING_OPERATOR
|
259
|
-
sort_key = sort_key[1..-1]
|
260
|
-
end
|
261
|
-
{
|
262
|
-
"operator" => operator,
|
263
|
-
"column" => attributes.index(sort_key),
|
264
|
-
}
|
265
|
-
end
|
266
|
-
|
267
|
-
{
|
268
|
-
"type" => "sort",
|
269
|
-
"operators" => operators,
|
270
|
-
}
|
26
|
+
def search(message)
|
27
|
+
planner = DistributedSearchPlanner.new(message)
|
28
|
+
distribute(planner.messages)
|
271
29
|
end
|
272
30
|
end
|
273
31
|
end
|
@@ -22,18 +22,23 @@ module Droonga
|
|
22
22
|
repository.register("watch", self)
|
23
23
|
|
24
24
|
command "watch.feed" => :feed
|
25
|
-
def feed(
|
26
|
-
broadcast_all(
|
25
|
+
def feed(message)
|
26
|
+
broadcast_all(message)
|
27
27
|
end
|
28
28
|
|
29
29
|
command "watch.subscribe" => :subscribe
|
30
|
-
def subscribe(
|
31
|
-
broadcast_all(
|
30
|
+
def subscribe(message)
|
31
|
+
broadcast_all(message)
|
32
32
|
end
|
33
33
|
|
34
34
|
command "watch.unsubscribe" => :unsubscribe
|
35
|
-
def unsubscribe(
|
36
|
-
broadcast_all(
|
35
|
+
def unsubscribe(message)
|
36
|
+
broadcast_all(message)
|
37
|
+
end
|
38
|
+
|
39
|
+
command "watch.sweep" => :sweep
|
40
|
+
def sweep(message)
|
41
|
+
broadcast_all(message)
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
@@ -18,27 +18,89 @@
|
|
18
18
|
require "groonga"
|
19
19
|
|
20
20
|
require "droonga/handler_plugin"
|
21
|
+
require "droonga/message_processing_error"
|
21
22
|
|
22
23
|
module Droonga
|
23
24
|
class AddHandler < Droonga::HandlerPlugin
|
24
25
|
repository.register("add", self)
|
25
26
|
|
27
|
+
class MissingTableParameter < BadRequest
|
28
|
+
def initialize
|
29
|
+
super("\"table\" must be specified.")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class MissingPrimaryKeyParameter < BadRequest
|
34
|
+
def initialize(table_name)
|
35
|
+
super("\"key\" must be specified. " +
|
36
|
+
"The table #{table_name.inspect} requires a primary key for a new record.")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class UnknownTable < NotFound
|
41
|
+
def initialize(table_name)
|
42
|
+
super("The table #{table_name.inspect} does not exist in the dataset.")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class InvalidValue < BadRequest
|
47
|
+
def initialize(column, value, request)
|
48
|
+
super("The column #{column.inspect} cannot store the value #{value.inspect}.",
|
49
|
+
request)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class UnknownColumn < NotFound
|
54
|
+
def initialize(column, table, request)
|
55
|
+
super("The column #{column.inspect} does not exist in the table #{table.inspect}.",
|
56
|
+
request)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
26
60
|
command :add
|
27
|
-
def add(
|
28
|
-
outputs = process_add(request)
|
29
|
-
emit(outputs)
|
61
|
+
def add(message, messenger)
|
62
|
+
outputs = process_add(message.request)
|
63
|
+
messenger.emit(outputs)
|
30
64
|
end
|
31
65
|
|
32
66
|
private
|
33
67
|
def process_add(request)
|
68
|
+
raise MissingTableParameter.new unless request.include?("table")
|
69
|
+
|
34
70
|
table = @context[request["table"]]
|
35
|
-
|
71
|
+
raise UnknownTable.new(request["table"]) unless table
|
72
|
+
|
36
73
|
if table.support_key?
|
37
|
-
|
74
|
+
unless request.include?("key")
|
75
|
+
raise MissingPrimaryKeyParameter.new(request["table"])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
add_record(table, request)
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_record(table, request)
|
84
|
+
record = nil
|
85
|
+
if table.support_key?
|
86
|
+
record = table.add(request["key"])
|
38
87
|
else
|
39
|
-
table.add
|
88
|
+
record = table.add
|
89
|
+
end
|
90
|
+
(request["values"] || []).each do |column, value|
|
91
|
+
begin
|
92
|
+
record[column] = value
|
93
|
+
rescue Groonga::InvalidArgument => error
|
94
|
+
record.delete if record.added?
|
95
|
+
raise InvalidValue.new(column, value, request)
|
96
|
+
rescue ArgumentError => error
|
97
|
+
record.delete if record.added?
|
98
|
+
raise InvalidValue.new(column, value, request)
|
99
|
+
rescue Groonga::NoSuchColumn => error
|
100
|
+
record.delete if record.added?
|
101
|
+
raise UnknownColumn.new(column, request["table"], request)
|
102
|
+
end
|
40
103
|
end
|
41
|
-
[true]
|
42
104
|
end
|
43
105
|
end
|
44
106
|
end
|
@@ -24,17 +24,17 @@ module Droonga
|
|
24
24
|
repository.register("groonga", self)
|
25
25
|
|
26
26
|
command :table_create
|
27
|
-
def table_create(
|
27
|
+
def table_create(message, messenger)
|
28
28
|
command = TableCreate.new(@context)
|
29
|
-
outputs = command.execute(request)
|
30
|
-
emit(outputs)
|
29
|
+
outputs = command.execute(message.request)
|
30
|
+
messenger.emit(outputs)
|
31
31
|
end
|
32
32
|
|
33
33
|
command :column_create
|
34
|
-
def column_create(
|
34
|
+
def column_create(message, messenger)
|
35
35
|
command = ColumnCreate.new(@context)
|
36
|
-
outputs = command.execute(request)
|
37
|
-
emit(outputs)
|
36
|
+
outputs = command.execute(message.request)
|
37
|
+
messenger.emit(outputs)
|
38
38
|
end
|
39
39
|
|
40
40
|
def prefer_synchronous?(command)
|
@@ -23,11 +23,13 @@ module Droonga
|
|
23
23
|
repository.register("search", self)
|
24
24
|
|
25
25
|
command :search
|
26
|
-
def search(
|
26
|
+
def search(message, messenger)
|
27
27
|
searcher = Droonga::Searcher.new(@context)
|
28
|
-
|
29
|
-
|
28
|
+
values = {}
|
29
|
+
searcher.search(message.request["queries"]).each do |output, value|
|
30
|
+
values[output] = value
|
30
31
|
end
|
32
|
+
messenger.emit(values)
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|