elasticsearch-persistence-queryable 0.1.8

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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/CHANGELOG.md +16 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +13 -0
  6. data/README.md +678 -0
  7. data/Rakefile +57 -0
  8. data/elasticsearch-persistence.gemspec +57 -0
  9. data/examples/music/album.rb +34 -0
  10. data/examples/music/artist.rb +50 -0
  11. data/examples/music/artists/_form.html.erb +8 -0
  12. data/examples/music/artists/artists_controller.rb +67 -0
  13. data/examples/music/artists/artists_controller_test.rb +53 -0
  14. data/examples/music/artists/index.html.erb +57 -0
  15. data/examples/music/artists/show.html.erb +51 -0
  16. data/examples/music/assets/application.css +226 -0
  17. data/examples/music/assets/autocomplete.css +48 -0
  18. data/examples/music/assets/blank_cover.png +0 -0
  19. data/examples/music/assets/form.css +113 -0
  20. data/examples/music/index_manager.rb +60 -0
  21. data/examples/music/search/index.html.erb +93 -0
  22. data/examples/music/search/search_controller.rb +41 -0
  23. data/examples/music/search/search_controller_test.rb +9 -0
  24. data/examples/music/search/search_helper.rb +15 -0
  25. data/examples/music/suggester.rb +45 -0
  26. data/examples/music/template.rb +392 -0
  27. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.css +7 -0
  28. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.js +6 -0
  29. data/examples/notes/.gitignore +7 -0
  30. data/examples/notes/Gemfile +28 -0
  31. data/examples/notes/README.markdown +36 -0
  32. data/examples/notes/application.rb +238 -0
  33. data/examples/notes/config.ru +7 -0
  34. data/examples/notes/test.rb +118 -0
  35. data/lib/elasticsearch/per_thread_registry.rb +53 -0
  36. data/lib/elasticsearch/persistence/client.rb +51 -0
  37. data/lib/elasticsearch/persistence/inheritence.rb +9 -0
  38. data/lib/elasticsearch/persistence/model/base.rb +95 -0
  39. data/lib/elasticsearch/persistence/model/callbacks.rb +37 -0
  40. data/lib/elasticsearch/persistence/model/errors.rb +9 -0
  41. data/lib/elasticsearch/persistence/model/find.rb +155 -0
  42. data/lib/elasticsearch/persistence/model/gateway_delegation.rb +23 -0
  43. data/lib/elasticsearch/persistence/model/hash_wrapper.rb +17 -0
  44. data/lib/elasticsearch/persistence/model/rails.rb +39 -0
  45. data/lib/elasticsearch/persistence/model/store.rb +271 -0
  46. data/lib/elasticsearch/persistence/model.rb +148 -0
  47. data/lib/elasticsearch/persistence/null_relation.rb +56 -0
  48. data/lib/elasticsearch/persistence/query_cache.rb +68 -0
  49. data/lib/elasticsearch/persistence/querying.rb +21 -0
  50. data/lib/elasticsearch/persistence/relation/delegation.rb +130 -0
  51. data/lib/elasticsearch/persistence/relation/finder_methods.rb +39 -0
  52. data/lib/elasticsearch/persistence/relation/merger.rb +179 -0
  53. data/lib/elasticsearch/persistence/relation/query_builder.rb +279 -0
  54. data/lib/elasticsearch/persistence/relation/query_methods.rb +362 -0
  55. data/lib/elasticsearch/persistence/relation/search_option_methods.rb +44 -0
  56. data/lib/elasticsearch/persistence/relation/spawn_methods.rb +61 -0
  57. data/lib/elasticsearch/persistence/relation.rb +110 -0
  58. data/lib/elasticsearch/persistence/repository/class.rb +71 -0
  59. data/lib/elasticsearch/persistence/repository/find.rb +73 -0
  60. data/lib/elasticsearch/persistence/repository/naming.rb +115 -0
  61. data/lib/elasticsearch/persistence/repository/response/results.rb +105 -0
  62. data/lib/elasticsearch/persistence/repository/search.rb +156 -0
  63. data/lib/elasticsearch/persistence/repository/serialize.rb +31 -0
  64. data/lib/elasticsearch/persistence/repository/store.rb +94 -0
  65. data/lib/elasticsearch/persistence/repository.rb +77 -0
  66. data/lib/elasticsearch/persistence/scoping/default.rb +137 -0
  67. data/lib/elasticsearch/persistence/scoping/named.rb +70 -0
  68. data/lib/elasticsearch/persistence/scoping.rb +52 -0
  69. data/lib/elasticsearch/persistence/version.rb +5 -0
  70. data/lib/elasticsearch/persistence.rb +157 -0
  71. data/lib/elasticsearch/rails_compatibility.rb +17 -0
  72. data/lib/rails/generators/elasticsearch/model/model_generator.rb +21 -0
  73. data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +9 -0
  74. data/lib/rails/generators/elasticsearch_generator.rb +2 -0
  75. data/lib/rails/instrumentation/railtie.rb +31 -0
  76. data/lib/rails/instrumentation.rb +10 -0
  77. data/test/integration/model/model_basic_test.rb +157 -0
  78. data/test/integration/repository/custom_class_test.rb +85 -0
  79. data/test/integration/repository/customized_class_test.rb +82 -0
  80. data/test/integration/repository/default_class_test.rb +114 -0
  81. data/test/integration/repository/virtus_model_test.rb +114 -0
  82. data/test/test_helper.rb +53 -0
  83. data/test/unit/model_base_test.rb +48 -0
  84. data/test/unit/model_find_test.rb +148 -0
  85. data/test/unit/model_gateway_test.rb +99 -0
  86. data/test/unit/model_rails_test.rb +88 -0
  87. data/test/unit/model_store_test.rb +514 -0
  88. data/test/unit/persistence_test.rb +32 -0
  89. data/test/unit/repository_class_test.rb +51 -0
  90. data/test/unit/repository_client_test.rb +32 -0
  91. data/test/unit/repository_find_test.rb +388 -0
  92. data/test/unit/repository_indexing_test.rb +37 -0
  93. data/test/unit/repository_module_test.rb +146 -0
  94. data/test/unit/repository_naming_test.rb +146 -0
  95. data/test/unit/repository_response_results_test.rb +98 -0
  96. data/test/unit/repository_search_test.rb +117 -0
  97. data/test/unit/repository_serialize_test.rb +57 -0
  98. data/test/unit/repository_store_test.rb +303 -0
  99. metadata +487 -0
@@ -0,0 +1,279 @@
1
+ module Elasticsearch
2
+ module Persistence
3
+ class QueryBuilder
4
+
5
+ attr_reader :structure, :values
6
+
7
+ def initialize(values)
8
+ @values = values
9
+ end
10
+
11
+ def aggregations
12
+ values[:aggregation]
13
+ end
14
+
15
+ def filters
16
+ values[:filter]
17
+ end
18
+
19
+ def or_filters
20
+ values[:or_filter]
21
+ end
22
+
23
+ def query
24
+ @query ||= compact_where(values[:where])
25
+ end
26
+
27
+ def query_strings
28
+ @query_string ||= compact_where(values[:query_string], bool: false)
29
+ end
30
+
31
+ def must_nots
32
+ @must_nots ||= compact_where(values[:must_not])
33
+ end
34
+
35
+ def shoulds
36
+ @shoulds ||= compact_where(values[:should])
37
+ end
38
+
39
+ def fields
40
+ values[:field]
41
+ end
42
+
43
+ def source
44
+ values[:source]
45
+ end
46
+
47
+ def highlights
48
+ values[:highlight]
49
+ end
50
+
51
+ def size
52
+ values[:size]
53
+ end
54
+
55
+ def sort
56
+ values[:order]
57
+ end
58
+
59
+ def query_filters
60
+ values[:filter]
61
+ end
62
+
63
+ def search_options
64
+ build_search_options
65
+ end
66
+
67
+ def query_string_options
68
+ @query_string_options || {}
69
+ end
70
+
71
+ def count?
72
+ values[:count]
73
+ end
74
+
75
+ def to_elastic
76
+ @structure = Jbuilder.new ignore_nil: true
77
+ build_query
78
+ build_sort unless sort.blank?
79
+ build_highlights unless highlights.blank?
80
+ build_fields unless fields.blank?
81
+ build_source unless source.blank?
82
+ build_aggregations unless aggregations.blank?
83
+ structure.attributes!
84
+ end
85
+
86
+ private
87
+
88
+ def missing_bool_query?
89
+ query.nil? && must_nots.nil? && shoulds.nil?
90
+ end
91
+
92
+ def missing_query_string?
93
+ query_strings.nil?
94
+ end
95
+
96
+ def missing_query_filter?
97
+ query_filters.nil? && or_filters.nil?
98
+ end
99
+
100
+ def build_query
101
+ return if missing_bool_query? && missing_query_string? && missing_query_filter?
102
+ structure.query do
103
+ structure.bool do
104
+ structure.must query unless missing_bool_query?
105
+ structure.must_not must_nots unless must_nots.nil?
106
+ structure.should shoulds unless shoulds.nil?
107
+
108
+ build_filtered_query if query_filters || or_filters
109
+
110
+ end unless missing_bool_query? && missing_query_filter?
111
+
112
+
113
+ structure.query_string do
114
+ structure.extract! query_string_options, *query_string_options.keys
115
+ structure.query query_strings
116
+ end unless query_strings.nil?
117
+ end
118
+ end
119
+
120
+ def build_filtered_query
121
+ structure.filter do
122
+ structure.or do
123
+ or_filters.each do |f|
124
+ structure.child! do
125
+ structure.set! f[:name], extract_filters(f[:name], f[:args])
126
+ end
127
+ end
128
+ end unless or_filters.blank?
129
+
130
+ structure.bool do
131
+ structure.must do
132
+ query_filters.each do |f|
133
+ structure.child! do
134
+ structure.set! f[:name], extract_filters(f[:name], f[:args])
135
+ end
136
+ end
137
+ end
138
+ end unless query_filters.blank?
139
+ end
140
+ end
141
+
142
+ def build_source
143
+ if [true,false].include? source.first
144
+ structure._source source.first
145
+ else
146
+ structure._source do
147
+ structure.include source.first.delete(:include) if source.first.has_key? :include
148
+ structure.exclude source.first.delete(:exclude) if source.first.has_key? :exclude
149
+ end
150
+ end
151
+ end
152
+
153
+ def build_sort
154
+ structure.sort sort.flatten.inject(Hash.new) { |h,v| h.merge(v) }
155
+ end
156
+
157
+ def build_highlights
158
+ structure.highlight do
159
+ structure.fields do
160
+ highlights.each do |highlight|
161
+ structure.set! highlight, extract_highlighter(highlight)
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ def build_filters
168
+ filters.each do |f|
169
+ structure.filter extract_filters(f[:name], f[:args])
170
+ end
171
+ end
172
+
173
+ def build_or_filters
174
+ or_filters.each do |f|
175
+ structure.filter extract_filters(f[:name], f[:args])
176
+ end
177
+ end
178
+
179
+ def build_aggregations
180
+ structure.aggregations do
181
+ aggregations.each do |agg|
182
+ structure.set! agg[:name], aggregation(agg[:name], agg[:args])
183
+ end
184
+ end
185
+ end
186
+
187
+ def build_fields
188
+ structure.fields do
189
+ structure.array! fields.flatten
190
+ end
191
+ end
192
+
193
+ def build_search_options
194
+ values[:search_option] ||= []
195
+
196
+ opts = extra_search_options
197
+ (values[:search_option] + [opts]).compact.inject(Hash.new) { |h,k,v| h.merge(k) }
198
+ end
199
+
200
+ def extra_search_options
201
+ [:size].inject(Hash.new) { |h,k| h[k] = self.send(k) unless self.send(k).nil?; h}
202
+ end
203
+
204
+ def compact_where(q, opts = {bool:true})
205
+ return if q.nil?
206
+ if opts.delete(:bool)
207
+ as_must(q)
208
+ else
209
+ as_query_string(q.flatten)
210
+ end
211
+ end
212
+
213
+ def as_must(q)
214
+ _must = []
215
+ q.each do |arg|
216
+ arg.each_pair { |k,v| _must << (v.is_a?(Array) ? {terms: Hash[k,v]} : {term: Hash[k,v]}) } if arg.class == Hash
217
+ _must << {term: Hash[[arg.split(/:/).collect(&:strip)]]} if arg.class == String
218
+ _must << arg.first if arg.class == Array
219
+ end
220
+ _must.length == 1 ? _must.first : _must
221
+ end
222
+
223
+ def as_query_string(q)
224
+ _and = []
225
+
226
+ @query_string_options = q.pop if q.length > 1
227
+
228
+ q.each do |arg|
229
+ arg.each_pair { |k,v| _and << "(#{k}:#{v})" } if arg.class == Hash
230
+ _and << "(#{arg})" if arg.class == String
231
+ end
232
+ _and.join(" AND ")
233
+ end
234
+
235
+
236
+
237
+ def extract_highlighter(highlighter)
238
+ Jbuilder.new do |highlight|
239
+ highlight.extract! highlighter
240
+ end
241
+ end
242
+
243
+ def extract_filters(name,opts = {})
244
+ Jbuilder.new do |filter|
245
+ case
246
+ when opts.is_a?(Hash)
247
+ filter.extract! opts, *opts.keys
248
+ when opts.is_a?(Array)
249
+ extract_filter_arguments_from_array(filter, opts)
250
+ else
251
+ raise "#filter only accepts Hash or Array"
252
+ end
253
+ end
254
+ end
255
+
256
+ def aggregation(name, opts = {})
257
+ Jbuilder.new do |agg|
258
+ case
259
+ when opts.is_a?(Hash)
260
+ agg.extract! opts, *opts.keys
261
+ when opts.is_a?(Array)
262
+ extract_filter_arguments_from_array(agg, opts)
263
+ else
264
+ raise "#aggregation only accepts Hash or Array"
265
+ end
266
+ end
267
+ end
268
+
269
+ def extract_filter_arguments_from_array(element, opts)
270
+ opts.each do |opt|
271
+ element.child! do
272
+ element.extract! opt , *opt.keys
273
+ end
274
+ end
275
+ end
276
+
277
+ end
278
+ end
279
+ end
@@ -0,0 +1,362 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+
3
+ module Elasticsearch
4
+ module Persistence
5
+ module QueryMethods
6
+ extend ActiveSupport::Concern
7
+
8
+
9
+ MULTI_VALUE_METHODS = [:where, :order, :field, :highlight, :source,
10
+ :must_not, :should, :query_string,
11
+ :aggregation, :search_option,
12
+ :filter, :or_filter, :extending, :skip_callbacks]
13
+ SINGLE_VALUE_METHODS = [:size]
14
+
15
+ class WhereChain
16
+ def initialize(scope)
17
+ @scope = scope
18
+ end
19
+ end
20
+
21
+
22
+ MULTI_VALUE_METHODS.each do |name|
23
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
24
+ def #{name}_values # def select_values
25
+ @values[:#{name}] || [] # @values[:select] || []
26
+ end # end
27
+ #
28
+ def #{name}_values=(values) # def select_values=(values)
29
+ raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
30
+ @values[:#{name}] = values # @values[:select] = values
31
+ end # end
32
+ CODE
33
+ end
34
+
35
+ SINGLE_VALUE_METHODS.each do |name|
36
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
37
+ def #{name}_value # def readonly_value
38
+ @values[:#{name}] # @values[:readonly]
39
+ end # end
40
+ CODE
41
+ end
42
+
43
+ SINGLE_VALUE_METHODS.each do |name|
44
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
45
+ def #{name}_value=(value) # def readonly_value=(value)
46
+ raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
47
+ @values[:#{name}] = value # @values[:readonly] = value
48
+ end # end
49
+ CODE
50
+ end
51
+
52
+
53
+
54
+ def order(*args)
55
+ check_if_method_has_arguments!(:order, args)
56
+ spawn.order!(*args)
57
+ end
58
+
59
+ def order!(*args)
60
+ self.order_values += [preprocess_order_args(args)]
61
+ self
62
+ end
63
+
64
+ alias :sort :order
65
+
66
+
67
+ def skip_callbacks(*args)
68
+ spawn.skip_callbacks!(*args)
69
+ end
70
+
71
+ def skip_callbacks!(*args)
72
+ self.skip_callbacks_values += args
73
+ self
74
+ end
75
+
76
+ alias :sort :order
77
+
78
+
79
+ def size(args)
80
+ spawn.size!(args)
81
+ end
82
+
83
+ def size!(args)
84
+ self.size_value = args
85
+ self
86
+ end
87
+
88
+ alias :limit :size
89
+
90
+
91
+
92
+
93
+ def where(opts = :chain, *rest)
94
+ if opts == :chain
95
+ WhereChain.new(spawn)
96
+ elsif opts.blank?
97
+ self
98
+ else
99
+ spawn.where!(opts, *rest)
100
+ end
101
+ end
102
+
103
+ alias :must :where
104
+
105
+ def where!(opts, *rest) # :nodoc:
106
+ if opts == :chain
107
+ WhereChain.new(self)
108
+ else
109
+ #if Hash === opts
110
+ #opts = sanitize_forbidden_attributes(opts)
111
+ #end
112
+
113
+ self.where_values += build_where(opts, rest)
114
+ self
115
+ end
116
+ end
117
+
118
+
119
+
120
+
121
+ def query_string(opts = :chain, *rest)
122
+ if opts == :chain
123
+ WhereChain.new(spawn)
124
+ elsif opts.blank?
125
+ self
126
+ else
127
+ spawn.query_string!(opts, *rest)
128
+ end
129
+ end
130
+
131
+ def query_string!(opts, *rest) # :nodoc:
132
+ if opts == :chain
133
+ WhereChain.new(self)
134
+ else
135
+ self.query_string_values += build_where(opts, rest)
136
+ self
137
+ end
138
+ end
139
+
140
+
141
+
142
+
143
+ def must_not(opts = :chain, *rest)
144
+ if opts == :chain
145
+ WhereChain.new(spawn)
146
+ elsif opts.blank?
147
+ self
148
+ else
149
+ spawn.must_not!(opts, *rest)
150
+ end
151
+ end
152
+
153
+ alias :where_not :must_not
154
+
155
+ def must_not!(opts, *rest)
156
+ if opts == :chain
157
+ WhereChain.new(self)
158
+ else
159
+ self.must_not_values += build_where(opts, rest)
160
+ self
161
+ end
162
+ end
163
+
164
+
165
+
166
+
167
+ def should(opts = :chain, *rest)
168
+ if opts == :chain
169
+ WhereChain.new(spawn)
170
+ elsif opts.blank?
171
+ self
172
+ else
173
+ spawn.should!(opts, *rest)
174
+ end
175
+ end
176
+
177
+ def should!(opts, *rest)
178
+ if opts == :chain
179
+ WhereChain.new(self)
180
+ else
181
+ self.should_values += build_where(opts, rest)
182
+ self
183
+ end
184
+ end
185
+
186
+
187
+ def or_filter(name, options = {}, &block)
188
+ spawn.or_filter!(name, options, &block)
189
+ end
190
+
191
+ def or_filter!(name, options = {}, &block)
192
+ self.or_filter_values += [{name: name, args: options}]
193
+ self
194
+ end
195
+
196
+
197
+
198
+ def filter(name, options = {}, &block)
199
+ spawn.filter!(name, options, &block)
200
+ end
201
+
202
+ def filter!(name, options = {}, &block)
203
+ self.filter_values += [{name: name, args: options}]
204
+ self
205
+ end
206
+
207
+
208
+
209
+
210
+ def aggregation(name, options = {}, &block)
211
+ spawn.aggregation!(name, options, &block)
212
+ end
213
+
214
+ def aggregation!(name, options = {}, &block)
215
+ self.aggregation_values += [{name: name, args: options}]
216
+ self
217
+ end
218
+
219
+
220
+
221
+
222
+ def field(*args)
223
+ spawn.field!(*args)
224
+ end
225
+ alias :fields :field
226
+
227
+ def field!(*args)
228
+ self.field_values += args
229
+ self
230
+ end
231
+
232
+
233
+
234
+
235
+ def source(*args)
236
+ spawn.source!(*args)
237
+ end
238
+
239
+ def source!(*args)
240
+ self.source_values += args
241
+ self
242
+ end
243
+
244
+
245
+
246
+
247
+ def has_field?(field)
248
+ spawn.filter(:exists, {field: field})
249
+ end
250
+
251
+
252
+
253
+
254
+ def bind(value)
255
+ spawn.bind!(value)
256
+ end
257
+
258
+ def bind!(value) # :nodoc:
259
+ self.bind_values += [value]
260
+ self
261
+ end
262
+
263
+ def build_where(opts, other = [])
264
+ case opts
265
+ when String, Array
266
+ #TODO: Remove duplication with: /activerecord/lib/active_record/sanitization.rb:113
267
+ values = Hash === other.first ? other.first.values : other
268
+
269
+ values.grep(Elasticsearch::Persistence::Relation) do |rel|
270
+ self.bind_values += rel.bind_values
271
+ end
272
+
273
+ [other.empty? ? opts : ([opts] + other)]
274
+ when Hash
275
+ [other.empty? ? opts : ([opts] + other)]
276
+ else
277
+ [opts]
278
+ end
279
+ end
280
+
281
+ def highlight(*args)
282
+ spawn.highlight!(*args)
283
+ end
284
+
285
+ def highlight!(*args)
286
+ self.highlight_values += args
287
+ self
288
+ end
289
+
290
+
291
+ # Returns a chainable relation with zero records.
292
+ #
293
+ #
294
+ def none
295
+ extending(NullRelation)
296
+ end
297
+
298
+ def none! # :nodoc:
299
+ extending!(NullRelation)
300
+ end
301
+
302
+
303
+ def extending(*modules, &block)
304
+ if modules.any? || block
305
+ spawn.extending!(*modules, &block)
306
+ else
307
+ self
308
+ end
309
+ end
310
+
311
+ def extending!(*modules, &block) # :nodoc:
312
+ modules << Module.new(&block) if block
313
+ modules.flatten!
314
+
315
+ self.extending_values += modules
316
+ extend(*extending_values) if extending_values.any?
317
+
318
+ self
319
+ end
320
+
321
+ private
322
+
323
+ def check_if_method_has_arguments!(method_name, args)
324
+ if args.blank?
325
+ raise ArgumentError, "The method .#{method_name}() must contain arguments."
326
+ end
327
+ end
328
+
329
+ VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
330
+ 'asc', 'desc', 'ASC', 'DESC'] # :nodoc:
331
+
332
+ def validate_order_args(args)
333
+ args.each do |arg|
334
+ next unless arg.is_a?(Hash)
335
+ arg.each do |_key, value|
336
+ raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
337
+ "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
338
+ end
339
+ end
340
+ end
341
+
342
+ def preprocess_order_args(order_args)
343
+ args = order_args.reject{ |arg| arg.is_a?(Hash) }.take(2)
344
+ return [Hash[[args]]] if args.length == 2
345
+ order_args.select { |arg| arg.is_a?(Hash)}.flatten
346
+ end
347
+
348
+ def add_relations_to_bind_values(attributes)
349
+ if attributes.is_a?(Hash)
350
+ attributes.each_value do |value|
351
+ if value.is_a?(ActiveRecord::Relation)
352
+ self.bind_values += value.bind_values
353
+ else
354
+ add_relations_to_bind_values(value)
355
+ end
356
+ end
357
+ end
358
+ end
359
+ end
360
+
361
+ end
362
+ end
@@ -0,0 +1,44 @@
1
+ module Elasticsearch
2
+ module Persistence
3
+
4
+ module SearchOptionMethods
5
+ extend ActiveSupport::Concern
6
+
7
+ def routing(args)
8
+ check_if_method_has_arguments!(:routing, args)
9
+ spawn.routing!(args)
10
+ end
11
+
12
+ def routing!(args)
13
+ merge_search_option_values(:routing, args)
14
+ self
15
+ end
16
+
17
+ def search_type(args)
18
+ check_if_method_has_arguments!(:search_type, args)
19
+ spawn.search_type!(args)
20
+ end
21
+
22
+ def search_type!(args)
23
+ merge_search_option_values(:search_type, args)
24
+ self
25
+ end
26
+
27
+ def search_options(*args)
28
+ spawn.search_options!(*args)
29
+ end
30
+
31
+ def search_options!(*args)
32
+ self.search_option_values += args
33
+ self
34
+ end
35
+
36
+ private
37
+
38
+ def merge_search_option_values(key, value)
39
+ self.search_option_values += [Hash[key,value]]
40
+ end
41
+
42
+ end
43
+ end
44
+ end