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.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -4
  3. data/benchmark/watch/benchmark-notify.rb +2 -2
  4. data/benchmark/watch/benchmark-scan.rb +3 -0
  5. data/benchmark/watch/fluentd.conf +0 -1
  6. data/fluent-plugin-droonga.gemspec +2 -3
  7. data/lib/droonga/catalog.rb +10 -124
  8. data/lib/droonga/catalog/base.rb +140 -0
  9. data/lib/droonga/catalog/version1.rb +23 -0
  10. data/lib/droonga/catalog_loader.rb +33 -0
  11. data/lib/droonga/collector.rb +2 -71
  12. data/lib/droonga/collector_plugin.rb +2 -34
  13. data/lib/droonga/dispatcher.rb +141 -196
  14. data/lib/droonga/distribution_planner.rb +76 -0
  15. data/lib/droonga/distributor.rb +5 -7
  16. data/lib/droonga/distributor_plugin.rb +23 -15
  17. data/lib/droonga/engine.rb +2 -2
  18. data/lib/droonga/event_loop.rb +46 -0
  19. data/lib/droonga/farm.rb +9 -5
  20. data/lib/droonga/fluent_message_sender.rb +84 -0
  21. data/lib/droonga/forwarder.rb +43 -53
  22. data/lib/droonga/handler.rb +20 -68
  23. data/lib/droonga/handler_message.rb +61 -0
  24. data/lib/droonga/handler_messenger.rb +92 -0
  25. data/lib/droonga/handler_plugin.rb +10 -12
  26. data/lib/droonga/input_adapter.rb +52 -0
  27. data/lib/droonga/{adapter.rb → input_adapter_plugin.rb} +7 -13
  28. data/lib/droonga/input_message.rb +11 -11
  29. data/lib/droonga/logger.rb +4 -3
  30. data/lib/droonga/message_pack_packer.rb +62 -0
  31. data/lib/droonga/message_processing_error.rb +54 -0
  32. data/lib/droonga/message_pusher.rb +60 -0
  33. data/lib/droonga/message_receiver.rb +61 -0
  34. data/lib/droonga/output_adapter.rb +53 -0
  35. data/lib/droonga/{adapter_plugin.rb → output_adapter_plugin.rb} +3 -21
  36. data/lib/droonga/output_message.rb +37 -0
  37. data/lib/droonga/partition.rb +27 -5
  38. data/lib/droonga/pluggable.rb +9 -4
  39. data/lib/droonga/plugin.rb +12 -3
  40. data/lib/droonga/plugin/collector/basic.rb +91 -18
  41. data/lib/droonga/plugin/distributor/crud.rb +9 -9
  42. data/lib/droonga/plugin/distributor/distributed_search_planner.rb +401 -0
  43. data/lib/droonga/plugin/distributor/groonga.rb +5 -5
  44. data/lib/droonga/plugin/distributor/search.rb +4 -246
  45. data/lib/droonga/plugin/distributor/watch.rb +11 -6
  46. data/lib/droonga/plugin/handler/add.rb +69 -7
  47. data/lib/droonga/plugin/handler/groonga.rb +6 -6
  48. data/lib/droonga/plugin/handler/search.rb +5 -3
  49. data/lib/droonga/plugin/handler/watch.rb +19 -13
  50. data/lib/droonga/plugin/{adapter → input_adapter}/groonga.rb +5 -11
  51. data/lib/droonga/plugin/{adapter → input_adapter}/groonga/select.rb +2 -36
  52. data/lib/droonga/plugin/output_adapter/groonga.rb +30 -0
  53. data/lib/droonga/plugin/output_adapter/groonga/select.rb +54 -0
  54. data/lib/droonga/plugin_loader.rb +2 -2
  55. data/lib/droonga/processor.rb +21 -23
  56. data/lib/droonga/replier.rb +40 -0
  57. data/lib/droonga/searcher.rb +298 -174
  58. data/lib/droonga/server.rb +0 -67
  59. data/lib/droonga/session.rb +85 -0
  60. data/lib/droonga/test.rb +21 -0
  61. data/lib/droonga/test/stub_distributor.rb +31 -0
  62. data/lib/droonga/test/stub_handler.rb +37 -0
  63. data/lib/droonga/test/stub_handler_message.rb +35 -0
  64. data/lib/droonga/test/stub_handler_messenger.rb +34 -0
  65. data/lib/droonga/time_formatter.rb +37 -0
  66. data/lib/droonga/watcher.rb +1 -0
  67. data/lib/droonga/worker.rb +16 -19
  68. data/lib/fluent/plugin/out_droonga.rb +9 -9
  69. data/lib/groonga_command_converter.rb +5 -5
  70. data/sample/cluster/catalog.json +1 -1
  71. data/test/command/config/default/catalog.json +19 -1
  72. data/test/command/fixture/event.jsons +41 -0
  73. data/test/command/fixture/user-table.jsons +9 -0
  74. data/test/command/run-test.rb +2 -2
  75. data/test/command/suite/add/error/invalid-integer.expected +20 -0
  76. data/test/command/suite/add/error/invalid-integer.test +12 -0
  77. data/test/command/suite/add/error/invalid-time.expected +20 -0
  78. data/test/command/suite/add/error/invalid-time.test +12 -0
  79. data/test/command/suite/add/error/missing-key.expected +13 -0
  80. data/test/command/suite/add/error/missing-key.test +16 -0
  81. data/test/command/suite/add/error/missing-table.expected +13 -0
  82. data/test/command/suite/add/error/missing-table.test +16 -0
  83. data/test/command/suite/add/error/unknown-column.expected +20 -0
  84. data/test/command/suite/add/error/unknown-column.test +12 -0
  85. data/test/command/suite/add/error/unknown-table.expected +13 -0
  86. data/test/command/suite/add/error/unknown-table.test +17 -0
  87. data/test/command/suite/add/minimum.expected +1 -3
  88. data/test/command/suite/add/with-values.expected +1 -3
  89. data/test/command/suite/add/without-key.expected +1 -3
  90. data/test/command/suite/message/error/missing-dataset.expected +13 -0
  91. data/test/command/suite/message/error/missing-dataset.test +5 -0
  92. data/test/command/suite/message/error/unknown-command.expected +13 -0
  93. data/test/command/suite/message/error/unknown-command.test +6 -0
  94. data/test/command/suite/message/error/unknown-dataset.expected +13 -0
  95. data/test/command/suite/message/error/unknown-dataset.test +6 -0
  96. data/test/command/suite/search/{array-attribute-label.expected → attributes/array.expected} +0 -0
  97. data/test/command/suite/search/{array-attribute-label.test → attributes/array.test} +0 -0
  98. data/test/command/suite/search/{hash-attribute-label.expected → attributes/hash.expected} +0 -0
  99. data/test/command/suite/search/{hash-attribute-label.test → attributes/hash.test} +0 -0
  100. data/test/command/suite/search/{condition-nested.expected → condition/nested.expected} +0 -0
  101. data/test/command/suite/search/{condition-nested.test → condition/nested.test} +0 -0
  102. data/test/command/suite/search/{condition-query.expected → condition/query.expected} +0 -0
  103. data/test/command/suite/search/{condition-query.test → condition/query.test} +0 -0
  104. data/test/command/suite/search/{condition-script.expected → condition/script.expected} +0 -0
  105. data/test/command/suite/search/{condition-script.test → condition/script.test} +0 -0
  106. data/test/command/suite/search/error/cyclic-source.expected +18 -0
  107. data/test/command/suite/search/error/cyclic-source.test +12 -0
  108. data/test/command/suite/search/error/deeply-cyclic-source.expected +21 -0
  109. data/test/command/suite/search/error/deeply-cyclic-source.test +15 -0
  110. data/test/command/suite/search/error/missing-source-parameter.expected +17 -0
  111. data/test/command/suite/search/error/missing-source-parameter.test +11 -0
  112. data/test/command/suite/search/error/unknown-source.expected +18 -0
  113. data/test/command/suite/search/error/unknown-source.test +12 -0
  114. data/test/command/suite/search/{minimum.expected → group/count.expected} +2 -1
  115. data/test/command/suite/search/{minimum.test → group/count.test} +5 -3
  116. data/test/command/suite/search/group/limit.expected +19 -0
  117. data/test/command/suite/search/group/limit.test +20 -0
  118. data/test/command/suite/search/group/string.expected +36 -0
  119. data/test/command/suite/search/group/string.test +44 -0
  120. data/test/command/suite/search/{chained-queries.expected → multiple/chained.expected} +0 -0
  121. data/test/command/suite/search/{chained-queries.test → multiple/chained.test} +0 -0
  122. data/test/command/suite/search/{multiple-queries.expected → multiple/parallel.expected} +0 -0
  123. data/test/command/suite/search/{multiple-queries.test → multiple/parallel.test} +0 -0
  124. data/test/command/suite/search/{output-range.expected → range/only-output.expected} +0 -0
  125. data/test/command/suite/search/{output-range.test → range/only-output.test} +0 -0
  126. data/test/command/suite/search/{sort-range.expected → range/only-sort.expected} +0 -0
  127. data/test/command/suite/search/{sort-range.test → range/only-sort.test} +0 -0
  128. data/test/command/suite/search/{sort-and-output-range.expected → range/sort-and-output.expected} +0 -0
  129. data/test/command/suite/search/{sort-and-output-range.test → range/sort-and-output.test} +0 -0
  130. data/test/command/suite/search/range/too-large-output-offset.expected +16 -0
  131. data/test/command/suite/search/range/too-large-output-offset.test +25 -0
  132. data/test/command/suite/search/range/too-large-sort-offset.expected +16 -0
  133. data/test/command/suite/search/range/too-large-sort-offset.test +28 -0
  134. data/test/command/suite/search/response/records/value/time.expected +24 -0
  135. data/test/command/suite/search/response/records/value/time.test +24 -0
  136. data/test/command/suite/search/sort/default-offset-limit.expected +43 -0
  137. data/test/command/suite/search/sort/default-offset-limit.test +26 -0
  138. data/test/command/suite/search/{sort-with-invisible-column.expected → sort/invisible-column.expected} +0 -0
  139. data/test/command/suite/search/{sort-with-invisible-column.test → sort/invisible-column.test} +0 -0
  140. data/test/command/suite/watch/subscribe.expected +12 -0
  141. data/test/command/suite/watch/subscribe.test +9 -0
  142. data/test/command/suite/watch/unsubscribe.expected +12 -0
  143. data/test/command/suite/watch/unsubscribe.test +9 -0
  144. data/test/unit/{test_catalog.rb → catalog/test_version1.rb} +12 -4
  145. data/test/unit/fixtures/{catalog.json → catalog/version1.json} +0 -0
  146. data/test/unit/helper.rb +2 -0
  147. data/test/unit/plugin/collector/test_basic.rb +289 -33
  148. data/test/unit/plugin/distributor/test_search.rb +176 -861
  149. data/test/unit/plugin/distributor/test_search_planner.rb +1102 -0
  150. data/test/unit/plugin/handler/groonga/test_column_create.rb +17 -13
  151. data/test/unit/plugin/handler/groonga/test_table_create.rb +10 -10
  152. data/test/unit/plugin/handler/test_add.rb +74 -11
  153. data/test/unit/plugin/handler/test_groonga.rb +15 -1
  154. data/test/unit/plugin/handler/test_search.rb +33 -17
  155. data/test/unit/plugin/handler/test_watch.rb +43 -27
  156. data/test/unit/run-test.rb +2 -0
  157. data/test/unit/test_message_pack_packer.rb +51 -0
  158. data/test/unit/test_time_formatter.rb +29 -0
  159. metadata +208 -110
  160. data/lib/droonga/job_queue.rb +0 -87
  161. data/lib/droonga/job_queue_schema.rb +0 -65
  162. data/test/unit/test_adapter.rb +0 -51
  163. 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(envelope)
26
- unless envelope["dataset"]
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(envelope)
29
+ broadcast_all(message)
30
30
  end
31
31
 
32
32
  command :column_create
33
- def column_create(envelope)
34
- broadcast_all(envelope)
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(envelope)
26
- message = []
27
- input_names = []
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(envelope)
26
- broadcast_all(envelope)
25
+ def feed(message)
26
+ broadcast_all(message)
27
27
  end
28
28
 
29
29
  command "watch.subscribe" => :subscribe
30
- def subscribe(envelope)
31
- broadcast_all(envelope)
30
+ def subscribe(message)
31
+ broadcast_all(message)
32
32
  end
33
33
 
34
34
  command "watch.unsubscribe" => :unsubscribe
35
- def unsubscribe(envelope)
36
- broadcast_all(envelope)
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(request)
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
- return [false] unless table
71
+ raise UnknownTable.new(request["table"]) unless table
72
+
36
73
  if table.support_key?
37
- table.add(request["key"], request["values"])
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(request["values"])
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(request)
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(request)
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(request)
26
+ def search(message, messenger)
27
27
  searcher = Droonga::Searcher.new(@context)
28
- searcher.search(request["queries"]).each do |output, value|
29
- emit(value, output)
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