fluent-plugin-droonga 0.9.9 → 1.0.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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/.dir-locals.el +3 -0
  3. data/.travis.yml +6 -2
  4. data/README.md +6 -7
  5. data/Rakefile +23 -6
  6. data/fluent-plugin-droonga.gemspec +2 -2
  7. data/lib/droonga/adapter.rb +12 -3
  8. data/lib/droonga/adapter_runner.rb +28 -23
  9. data/lib/droonga/catalog/base.rb +7 -111
  10. data/lib/droonga/catalog/dataset.rb +13 -25
  11. data/lib/droonga/catalog/errors.rb +94 -0
  12. data/lib/droonga/catalog/schema.rb +277 -0
  13. data/lib/droonga/catalog/version1.rb +404 -0
  14. data/lib/droonga/catalog/version2.rb +160 -0
  15. data/lib/droonga/catalog_loader.rb +27 -4
  16. data/lib/droonga/catalog_observer.rb +44 -6
  17. data/lib/droonga/collector.rb +12 -10
  18. data/lib/droonga/{handler_plugin.rb → collector_message.rb} +47 -20
  19. data/lib/droonga/collector_runner.rb +64 -0
  20. data/lib/droonga/collectors.rb +18 -0
  21. data/lib/droonga/{catalog.rb → collectors/add.rb} +9 -7
  22. data/lib/droonga/{command_repository.rb → collectors/and.rb} +7 -14
  23. data/lib/droonga/collectors/sum.rb +26 -0
  24. data/lib/droonga/dispatcher.rb +74 -41
  25. data/lib/droonga/distributed_command_planner.rb +2 -2
  26. data/lib/droonga/engine.rb +13 -5
  27. data/lib/droonga/{message_processing_error.rb → error.rb} +33 -12
  28. data/lib/droonga/{plugin/planner/search.rb → error_messages.rb} +12 -10
  29. data/lib/droonga/farm.rb +15 -14
  30. data/lib/droonga/fluent_message_sender.rb +15 -11
  31. data/lib/droonga/forwarder.rb +22 -18
  32. data/lib/droonga/handler.rb +8 -2
  33. data/lib/droonga/handler_runner.rb +47 -26
  34. data/lib/droonga/input_message.rb +6 -6
  35. data/lib/droonga/{command.rb → loggable.rb} +7 -14
  36. data/lib/droonga/logger.rb +56 -15
  37. data/lib/droonga/message_matcher.rb +12 -7
  38. data/lib/droonga/message_pusher.rb +8 -4
  39. data/lib/droonga/message_receiver.rb +11 -9
  40. data/lib/droonga/output_message.rb +2 -0
  41. data/lib/droonga/planner.rb +21 -10
  42. data/lib/droonga/plugin.rb +15 -0
  43. data/lib/droonga/plugin/metadata/{adapter_message.rb → adapter_input_message.rb} +6 -14
  44. data/lib/droonga/plugin/metadata/adapter_output_message.rb +39 -0
  45. data/lib/droonga/plugin/metadata/collector_message.rb +39 -0
  46. data/lib/droonga/plugin/metadata/input_message.rb +15 -0
  47. data/lib/droonga/plugin_loader.rb +33 -25
  48. data/lib/droonga/plugin_registry.rb +9 -1
  49. data/lib/droonga/plugins/basic.rb +54 -0
  50. data/lib/droonga/plugins/crud.rb +36 -15
  51. data/lib/droonga/plugins/error.rb +5 -4
  52. data/lib/droonga/plugins/groonga.rb +9 -6
  53. data/lib/droonga/plugins/groonga/column_create.rb +10 -5
  54. data/lib/droonga/plugins/groonga/generic_command.rb +2 -8
  55. data/lib/droonga/plugins/groonga/generic_response.rb +2 -2
  56. data/lib/droonga/plugins/groonga/select.rb +2 -2
  57. data/lib/droonga/plugins/groonga/table_create.rb +9 -4
  58. data/lib/droonga/plugins/groonga/table_remove.rb +10 -5
  59. data/lib/droonga/plugins/search.rb +106 -5
  60. data/lib/droonga/plugins/search/distributed_search_planner.rb +398 -0
  61. data/lib/droonga/plugins/watch.rb +41 -20
  62. data/lib/droonga/processor.rb +12 -9
  63. data/lib/droonga/{plugin/collector/basic.rb → reducer.rb} +36 -50
  64. data/lib/droonga/replier.rb +7 -4
  65. data/lib/droonga/searcher.rb +40 -37
  66. data/lib/droonga/server.rb +8 -6
  67. data/lib/droonga/session.rb +17 -7
  68. data/lib/droonga/single_step.rb +53 -0
  69. data/lib/droonga/{plugin/planner/watch.rb → single_step_definition.rb} +27 -26
  70. data/lib/droonga/{partition.rb → slice.rb} +23 -12
  71. data/lib/droonga/status_code.rb +25 -0
  72. data/lib/droonga/step_runner.rb +63 -0
  73. data/lib/droonga/watch_schema.rb +7 -3
  74. data/lib/droonga/watcher.rb +4 -4
  75. data/lib/droonga/worker.rb +6 -6
  76. data/lib/fluent/plugin/out_droonga.rb +27 -2
  77. data/sample/cluster/catalog.json +33 -32
  78. data/test/command/config/default/catalog.json +72 -45
  79. data/test/command/config/version1/catalog.json +68 -0
  80. data/test/command/config/version1/fluentd.conf +11 -0
  81. data/test/command/suite/message/error/missing-dataset.expected +1 -1
  82. data/test/command/suite/message/error/unknown-dataset.expected +1 -1
  83. data/test/command/suite/message/error/unknown-type.expected +13 -0
  84. data/test/command/suite/message/error/{unknown-command.test → unknown-type.test} +1 -1
  85. data/test/command/suite/search/error/missing-source-parameter.expected +1 -1
  86. data/test/command/suite/search/error/unknown-source.expected +15 -3
  87. data/test/command/suite/watch/subscribe.expected +1 -3
  88. data/test/command/suite/watch/unsubscribe.expected +1 -3
  89. data/test/performance/watch/catalog.json +1 -0
  90. data/test/unit/catalog/test_dataset.rb +16 -358
  91. data/test/unit/catalog/test_schema.rb +285 -0
  92. data/test/unit/catalog/test_version1.rb +222 -28
  93. data/test/unit/catalog/test_version2.rb +155 -0
  94. data/test/unit/fixtures/catalog/version2.json +62 -0
  95. data/test/unit/helper/distributed_search_planner_helper.rb +2 -2
  96. data/test/unit/plugins/crud/test_add.rb +13 -13
  97. data/test/unit/plugins/groonga/test_column_create.rb +14 -11
  98. data/test/unit/plugins/groonga/test_table_create.rb +4 -9
  99. data/test/unit/plugins/groonga/test_table_remove.rb +4 -9
  100. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_basic.rb +0 -0
  101. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_group_by.rb +0 -0
  102. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_output.rb +0 -0
  103. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_sort_by.rb +0 -0
  104. data/test/unit/{plugin/collector/test_search.rb → plugins/search/test_collector.rb} +40 -39
  105. data/test/unit/plugins/{test_search.rb → search/test_handler.rb} +6 -5
  106. data/test/unit/{plugin/planner/test_search.rb → plugins/search/test_planner.rb} +3 -3
  107. data/test/unit/{plugin/collector → plugins}/test_basic.rb +68 -50
  108. data/test/unit/plugins/test_groonga.rb +2 -15
  109. data/test/unit/plugins/test_watch.rb +25 -22
  110. data/test/unit/test_message_matcher.rb +29 -6
  111. data/test/unit/test_output.rb +4 -0
  112. metadata +58 -50
  113. data/lib/droonga/collector_plugin.rb +0 -50
  114. data/lib/droonga/legacy_pluggable.rb +0 -66
  115. data/lib/droonga/legacy_plugin.rb +0 -57
  116. data/lib/droonga/legacy_plugin_repository.rb +0 -54
  117. data/lib/droonga/planner_plugin.rb +0 -54
  118. data/lib/droonga/plugin/collector/search.rb +0 -98
  119. data/lib/droonga/plugin/planner/crud.rb +0 -49
  120. data/lib/droonga/plugin/planner/distributed_search_planner.rb +0 -393
  121. data/lib/droonga/plugin/planner/groonga.rb +0 -54
  122. data/lib/droonga/plugin_registerable.rb +0 -75
  123. data/test/command/suite/message/error/unknown-command.expected +0 -13
  124. data/test/unit/test_command_repository.rb +0 -39
  125. data/test/unit/test_legacy_plugin.rb +0 -50
  126. data/test/unit/test_legacy_plugin_repository.rb +0 -89
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2013 Droonga Project
3
+ # Copyright (C) 2013-2014 Droonga Project
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -17,39 +17,47 @@
17
17
 
18
18
  require "pathname"
19
19
 
20
+ require "droonga/loggable"
21
+
20
22
  module Droonga
21
23
  class PluginLoader
24
+ include Loggable
25
+
22
26
  class << self
23
27
  def load_all
24
- $LOAD_PATH.each do |load_path|
25
- Dir.glob("#{load_path}/droonga/plugin/*") do |type_path|
26
- next unless File.directory?(type_path)
27
- type = File.basename(type_path)
28
- Dir.glob("#{type_path}/*.rb") do |path|
29
- name = File.basename(path, ".rb")
30
- loader = new(type, name)
31
- loader.load
32
- end
33
- end
34
-
35
- Pathname.glob("#{load_path}/droonga/plugins/*.rb") do |plugin_path|
36
- relative_plugin_path =
37
- plugin_path.relative_path_from(Pathname(load_path))
38
- require_path = relative_plugin_path.to_s.gsub(/\.rb\z/, "")
39
- require require_path
40
- end
41
- end
28
+ loader = new
29
+ loader.load_all
30
+ end
31
+ end
32
+
33
+ def initialize
34
+ end
35
+
36
+ def load(name)
37
+ logger.debug("loading...: <#{name}>")
38
+ path = "droonga/plugins/#{name}"
39
+ begin
40
+ require path
41
+ rescue StandardError, SyntaxError => error
42
+ logger.exception("failed to load: <#{path}>", error)
43
+ raise
42
44
  end
43
45
  end
44
46
 
45
- def initialize(type, name)
46
- @type = type
47
- @name = name
47
+ def load_all
48
+ $LOAD_PATH.each do |load_path|
49
+ search_pattern = "#{load_path}/droonga/plugins/*.rb"
50
+ logger.debug("searching...: <#{search_pattern}>")
51
+ Pathname.glob(search_pattern) do |plugin_path|
52
+ name = Pathname(plugin_path).basename(".rb").to_s
53
+ load(name)
54
+ end
55
+ end
48
56
  end
49
57
 
50
- def load
51
- return if @type == "metadata"
52
- require "droonga/plugin/#{@type}/#{@name}"
58
+ private
59
+ def log_tag
60
+ "plugin-loader"
53
61
  end
54
62
  end
55
63
  end
@@ -17,6 +17,12 @@ module Droonga
17
17
  class PluginRegistry
18
18
  include Enumerable
19
19
 
20
+ class UnknownPlugin < Error
21
+ def initialize(name, klass)
22
+ super("[#{klass}] Plugin not found: <#{name}>")
23
+ end
24
+ end
25
+
20
26
  def initialize
21
27
  @plugins = {}
22
28
  end
@@ -39,7 +45,9 @@ module Droonga
39
45
 
40
46
  def find_sub_classes(name, klass)
41
47
  plugin_module = self[name]
42
- return [] if plugin_module.nil?
48
+ if plugin_module.nil?
49
+ raise UnknownPlugin.new(name, klass)
50
+ end
43
51
  sub_classes = []
44
52
  collect_sub_classes_recursive(plugin_module, klass, sub_classes)
45
53
  sub_classes
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2014 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"
17
+ require "droonga/reducer"
18
+
19
+ module Droonga
20
+ module Plugins
21
+ module Basic
22
+ extend Plugin
23
+ register("basic")
24
+
25
+ class GatherCollector < Droonga::Collector
26
+ message.pattern = ["task.step.type", :equal, "gather"]
27
+
28
+ def collect(message)
29
+ output = message.input || message.name
30
+ if output.is_a?(Hash)
31
+ output_name = output["output"]
32
+ else
33
+ output_name = output
34
+ end
35
+ message.values[output_name] = message.value
36
+ end
37
+ end
38
+
39
+ class ReduceCollector < Droonga::Collector
40
+ message.pattern = ["task.step.type", :equal, "reduce"]
41
+
42
+ def collect(message)
43
+ message.input.each do |output_name, deal|
44
+ left_value = message.values[output_name]
45
+ right_value = message.value
46
+ reducer = Reducer.new(deal)
47
+ value = reducer.reduce(left_value, right_value)
48
+ message.values[output_name] = value
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -16,28 +16,40 @@
16
16
  require "groonga"
17
17
 
18
18
  require "droonga/plugin"
19
- require "droonga/message_processing_error"
19
+ require "droonga/error_messages"
20
20
 
21
21
  module Droonga
22
22
  module Plugins
23
23
  module CRUD
24
- Plugin.registry.register("crud", self)
24
+ extend Plugin
25
+ register("crud")
25
26
 
26
27
  class Adapter < Droonga::Adapter
27
- message.input_pattern = ["type", :equal, "add"]
28
- message.output_pattern = ["body.success", :exist?]
28
+ input_message.pattern = ["type", :equal, "add"]
29
+ output_message.pattern = ["body.success", :exist]
30
+
31
+ def adapt_input(input_message)
32
+ request = input_message.body
33
+ key = request["key"] || rand.to_s
34
+ values = request["values"] || {}
35
+ request["filter"] = values.merge("key" => key)
36
+ end
29
37
 
30
38
  def adapt_output(output_message)
31
- success = output_message.body["success"]
32
- unless success.nil?
33
- output_message.body = output_message.body["success"]
39
+ if output_message.errors
40
+ detail = output_message.body["detail"]
41
+ return if detail.nil?
42
+ detail.delete("filter")
43
+ output_message.errors.each do |path, error|
44
+ error["body"]["detail"].delete("filter")
45
+ end
46
+ else
47
+ output_message.body.delete("filter")
34
48
  end
35
49
  end
36
50
  end
37
51
 
38
52
  class Handler < Droonga::Handler
39
- message.type = "add"
40
-
41
53
  class MissingTableParameter < BadRequest
42
54
  def initialize
43
55
  super("\"table\" must be specified.")
@@ -71,12 +83,8 @@ module Droonga
71
83
  end
72
84
  end
73
85
 
74
- def handle(message, messenger)
75
- succeeded = process_add(message.request)
76
- outputs = {
77
- "success" => succeeded,
78
- }
79
- messenger.emit(outputs)
86
+ def handle(message)
87
+ process_add(message.request)
80
88
  end
81
89
 
82
90
  private
@@ -119,6 +127,19 @@ module Droonga
119
127
  end
120
128
  end
121
129
  end
130
+
131
+ define_single_step do |step|
132
+ step.name = "add"
133
+ step.inputs = {
134
+ "table" => {
135
+ :type => :table,
136
+ :filter => "filter",
137
+ },
138
+ }
139
+ step.write = true
140
+ step.handler = Handler
141
+ step.collector = Collectors::And
142
+ end
122
143
  end
123
144
  end
124
145
  end
@@ -18,14 +18,15 @@ require "droonga/plugin"
18
18
  module Droonga
19
19
  module Plugins
20
20
  module Error
21
- Plugin.registry.register("error", self)
21
+ extend Plugin
22
+ register("error")
22
23
 
23
24
  class Adapter < Droonga::Adapter
24
- message.output_pattern = ["body.errors", :exist?]
25
+ output_message.pattern = ["body.errors", :exist]
25
26
 
26
27
  def adapt_output(output_message)
27
28
  errors = output_message.body["errors"]
28
- if errors && !errors.empty?
29
+ if errors and !errors.empty?
29
30
  output_message.errors = errors
30
31
 
31
32
  status_codes = []
@@ -36,7 +37,7 @@ module Droonga
36
37
  if status_codes.size == 1
37
38
  output_message.status_code = status_codes.first
38
39
  else
39
- output_message.status_code = MessageProcessingError::STATUS_CODE
40
+ output_message.status_code = ErrorMessages::InternalServerError::STATUS_CODE
40
41
  end
41
42
 
42
43
  output_message.body = errors.values.first["body"]
@@ -14,16 +14,19 @@
14
14
  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
15
 
16
16
  require "droonga/plugin"
17
- require "droonga/plugins/groonga/generic_response"
18
- require "droonga/plugins/groonga/select"
19
- require "droonga/plugins/groonga/table_create"
20
- require "droonga/plugins/groonga/table_remove"
21
- require "droonga/plugins/groonga/column_create"
22
17
 
23
18
  module Droonga
24
19
  module Plugins
25
20
  module Groonga
26
- Plugin.registry.register("groonga", self)
21
+ extend Plugin
22
+ register("groonga")
27
23
  end
28
24
  end
29
25
  end
26
+
27
+ require "droonga/plugins/groonga/generic_response"
28
+ require "droonga/plugins/groonga/select"
29
+ require "droonga/plugins/groonga/table_create"
30
+ require "droonga/plugins/groonga/table_remove"
31
+ require "droonga/plugins/groonga/column_create"
32
+
@@ -28,7 +28,7 @@ module Droonga
28
28
  @command = command_class.new("column_create", request)
29
29
 
30
30
  table_name = @command["table"]
31
- if table_name.nil? || @context[table_name].nil?
31
+ if table_name.nil? or @context[table_name].nil?
32
32
  message = "table doesn't exist: <#{table_name.to_s}>"
33
33
  raise CommandError.new(:status => Status::INVALID_ARGUMENT,
34
34
  :message => message,
@@ -108,15 +108,20 @@ module Droonga
108
108
  end
109
109
 
110
110
  class Handler < Droonga::Handler
111
- message.type = "column_create"
112
111
  action.synchronous = true
113
112
 
114
- def handle(message, messenger)
113
+ def handle(message)
115
114
  command = Command.new(@context)
116
- outputs = command.execute(message.request)
117
- messenger.emit(outputs)
115
+ command.execute(message.request)
118
116
  end
119
117
  end
118
+
119
+ Groonga.define_single_step do |step|
120
+ step.name = "column_create"
121
+ step.write = true
122
+ step.handler = Handler
123
+ step.collector = Collectors::Add
124
+ end
120
125
  end
121
126
  end
122
127
  end
@@ -41,9 +41,9 @@ module Droonga
41
41
  def execute(request)
42
42
  @start_time = Time.now.to_f
43
43
  result = process_request(request)
44
- format(header(Status::SUCCESS), result)
44
+ [header(Status::SUCCESS), result]
45
45
  rescue CommandError => error
46
- format(header(error.status, error.message), error.result)
46
+ [header(error.status, error.message), error.result]
47
47
  end
48
48
 
49
49
  private
@@ -53,12 +53,6 @@ module Droonga
53
53
  header.push(error_message) unless error_message.empty?
54
54
  header
55
55
  end
56
-
57
- def format(header, body)
58
- {
59
- "result" => [header, body],
60
- }
61
- end
62
56
  end
63
57
  end
64
58
  end
@@ -25,8 +25,8 @@ module Droonga
25
25
  "table_remove",
26
26
  "column_create",
27
27
  ]
28
- message.input_pattern = ["type", :in, groonga_commands]
29
- message.output_pattern = ["body.result", :exist?]
28
+ input_message.pattern = ["type", :in, groonga_commands]
29
+ output_message.pattern = ["body.result", :exist]
30
30
 
31
31
  def adapt_output(output_message)
32
32
  output_message.body = output_message.body["result"]
@@ -101,13 +101,13 @@ module Droonga
101
101
  end
102
102
 
103
103
  class Adapter < Droonga::Adapter
104
- message.input_pattern = ["type", :equal, "select"]
104
+ input_message.pattern = ["type", :equal, "select"]
105
105
 
106
106
  def adapt_input(input_message)
107
107
  converter = RequestConverter.new
108
108
  select_request = input_message.body
109
109
  search_request = converter.convert(select_request)
110
- input_message.command = "search"
110
+ input_message.type = "search"
111
111
  input_message.body = search_request
112
112
  end
113
113
 
@@ -91,15 +91,20 @@ module Droonga
91
91
  end
92
92
 
93
93
  class Handler < Droonga::Handler
94
- message.type = "table_create"
95
94
  action.synchronous = true
96
95
 
97
- def handle(message, messenger)
96
+ def handle(message)
98
97
  command = Command.new(@context)
99
- outputs = command.execute(message.request)
100
- messenger.emit(outputs)
98
+ command.execute(message.request)
101
99
  end
102
100
  end
101
+
102
+ Groonga.define_single_step do |step|
103
+ step.name = "table_create"
104
+ step.write = true
105
+ step.handler = Handler
106
+ step.collector = Collectors::Add
107
+ end
103
108
  end
104
109
  end
105
110
  end
@@ -28,7 +28,7 @@ module Droonga
28
28
  @command = command_class.new("table_remove", request)
29
29
 
30
30
  name = @command["name"]
31
- if name.nil? || @context[name].nil?
31
+ if name.nil? or @context[name].nil?
32
32
  raise CommandError.new(:status => Status::INVALID_ARGUMENT,
33
33
  :message => "table not found",
34
34
  :result => false)
@@ -42,15 +42,20 @@ module Droonga
42
42
  end
43
43
 
44
44
  class Handler < Droonga::Handler
45
- message.type = "table_remove"
46
45
  action.synchronous = true
47
46
 
48
- def handle(message, messenger)
47
+ def handle(message)
49
48
  command = Command.new(@context)
50
- outputs = command.execute(message.request)
51
- messenger.emit(outputs)
49
+ command.execute(message.request)
52
50
  end
53
51
  end
52
+
53
+ Groonga.define_single_step do |step|
54
+ step.name = "table_remove"
55
+ step.write = true
56
+ step.handler = Handler
57
+ step.collector = Collectors::Add
58
+ end
54
59
  end
55
60
  end
56
61
  end
@@ -15,16 +15,23 @@
15
15
 
16
16
  require "droonga/plugin"
17
17
  require "droonga/searcher"
18
+ require "droonga/plugins/search/distributed_search_planner"
18
19
 
19
20
  module Droonga
20
21
  module Plugins
21
22
  module Search
22
- Plugin.registry.register("search", self)
23
+ extend Plugin
24
+ register("search")
23
25
 
24
- class Handler < Droonga::Handler
25
- message.type = "search"
26
+ class Planner < Droonga::Planner
27
+ def plan(message)
28
+ planner = DistributedSearchPlanner.new(message)
29
+ planner.plan
30
+ end
31
+ end
26
32
 
27
- def handle(message, messenger)
33
+ class Handler < Droonga::Handler
34
+ def handle(message)
28
35
  searcher = Droonga::Searcher.new(@context)
29
36
  values = {}
30
37
  request = message.request
@@ -32,9 +39,103 @@ module Droonga
32
39
  searcher.search(request["queries"]).each do |output, value|
33
40
  values[output] = value
34
41
  end
35
- messenger.emit(values)
42
+ values
43
+ end
44
+ end
45
+
46
+ class GatherCollector < Droonga::Collector
47
+ message.pattern = ["task.step.type", :equal, "search_gather"]
48
+
49
+ def collect(message)
50
+ output = message.input || message.name
51
+ if output.is_a?(Hash)
52
+ elements = output["elements"]
53
+ if elements and elements.is_a?(Hash)
54
+ # because "count" mapper requires all records,
55
+ # I have to apply it at first, before "limit" and "offset" are applied.
56
+ body = message.body
57
+ value = message.value
58
+ count_mapper = elements["count"]
59
+ if count_mapper
60
+ if count_mapper["no_output"]
61
+ value.delete("count")
62
+ else
63
+ value["count"] = value[count_mapper["target"]].size
64
+ end
65
+ end
66
+
67
+ records_mapper = elements["records"]
68
+ if records_mapper and value["records"]
69
+ if records_mapper["no_output"]
70
+ value.delete("records")
71
+ else
72
+ value["records"] = Reducer.apply_range(value["records"],
73
+ records_mapper)
74
+ value["records"] = apply_output_attributes_and_format(value["records"], records_mapper)
75
+ end
76
+ end
77
+ end
78
+ output_name = output["output"]
79
+ else
80
+ output_name = output
81
+ end
82
+ message.values[output_name] = message.value
83
+ end
84
+
85
+ private
86
+ def apply_output_attributes_and_format(items, output)
87
+ attributes = output["attributes"] || []
88
+ if output["format"] == "complex"
89
+ items.collect do |item|
90
+ complex_item = {}
91
+ attributes.each_with_index do |label, index|
92
+ complex_item[label] = item[index]
93
+ end
94
+ complex_item
95
+ end
96
+ else
97
+ items.collect do |item|
98
+ item[0...attributes.size]
99
+ end
100
+ end
36
101
  end
37
102
  end
103
+
104
+ class ReduceCollector < Droonga::Collector
105
+ message.pattern = ["task.step.type", :equal, "search_reduce"]
106
+
107
+ def collect(message)
108
+ #XXX This is just a workaround. Errors should be handled by the framework itself.
109
+ if message.name == "errors"
110
+ basic_reduce_collector = Basic::ReduceCollector.new
111
+ return basic_reduce_collector.collect(message)
112
+ end
113
+
114
+ message.input.each do |output_name, elements|
115
+ old_value = message.values[output_name]
116
+ if old_value
117
+ value = reduce_elements(elements, old_value, message.value)
118
+ else
119
+ value = message.value
120
+ end
121
+ message.values[output_name] = value
122
+ end
123
+ end
124
+
125
+ def reduce_elements(elements, left_values, right_values)
126
+ result = {}
127
+ elements.each do |key, deal|
128
+ reducer = Reducer.new(deal)
129
+ result[key] = reducer.reduce(left_values[key], right_values[key])
130
+ end
131
+ result
132
+ end
133
+ end
134
+
135
+ define_single_step do |step|
136
+ step.name = "search"
137
+ step.handler = Handler
138
+ end
38
139
  end
39
140
  end
40
141
  end