fluent-plugin-droonga 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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