load_balanced_tire 0.1

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 (121) hide show
  1. data/.gitignore +14 -0
  2. data/.travis.yml +29 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.markdown +760 -0
  6. data/Rakefile +78 -0
  7. data/examples/rails-application-template.rb +249 -0
  8. data/examples/tire-dsl.rb +876 -0
  9. data/lib/tire.rb +55 -0
  10. data/lib/tire/alias.rb +296 -0
  11. data/lib/tire/configuration.rb +30 -0
  12. data/lib/tire/dsl.rb +43 -0
  13. data/lib/tire/http/client.rb +62 -0
  14. data/lib/tire/http/clients/curb.rb +61 -0
  15. data/lib/tire/http/clients/faraday.rb +71 -0
  16. data/lib/tire/http/response.rb +27 -0
  17. data/lib/tire/index.rb +361 -0
  18. data/lib/tire/logger.rb +60 -0
  19. data/lib/tire/model/callbacks.rb +40 -0
  20. data/lib/tire/model/import.rb +26 -0
  21. data/lib/tire/model/indexing.rb +128 -0
  22. data/lib/tire/model/naming.rb +100 -0
  23. data/lib/tire/model/percolate.rb +99 -0
  24. data/lib/tire/model/persistence.rb +71 -0
  25. data/lib/tire/model/persistence/attributes.rb +143 -0
  26. data/lib/tire/model/persistence/finders.rb +66 -0
  27. data/lib/tire/model/persistence/storage.rb +69 -0
  28. data/lib/tire/model/search.rb +307 -0
  29. data/lib/tire/results/collection.rb +114 -0
  30. data/lib/tire/results/item.rb +86 -0
  31. data/lib/tire/results/pagination.rb +54 -0
  32. data/lib/tire/rubyext/hash.rb +8 -0
  33. data/lib/tire/rubyext/ruby_1_8.rb +7 -0
  34. data/lib/tire/rubyext/symbol.rb +11 -0
  35. data/lib/tire/search.rb +188 -0
  36. data/lib/tire/search/facet.rb +74 -0
  37. data/lib/tire/search/filter.rb +28 -0
  38. data/lib/tire/search/highlight.rb +37 -0
  39. data/lib/tire/search/query.rb +186 -0
  40. data/lib/tire/search/scan.rb +114 -0
  41. data/lib/tire/search/script_field.rb +23 -0
  42. data/lib/tire/search/sort.rb +25 -0
  43. data/lib/tire/tasks.rb +135 -0
  44. data/lib/tire/utils.rb +17 -0
  45. data/lib/tire/version.rb +22 -0
  46. data/test/fixtures/articles/1.json +1 -0
  47. data/test/fixtures/articles/2.json +1 -0
  48. data/test/fixtures/articles/3.json +1 -0
  49. data/test/fixtures/articles/4.json +1 -0
  50. data/test/fixtures/articles/5.json +1 -0
  51. data/test/integration/active_model_indexing_test.rb +51 -0
  52. data/test/integration/active_model_searchable_test.rb +114 -0
  53. data/test/integration/active_record_searchable_test.rb +446 -0
  54. data/test/integration/boolean_queries_test.rb +43 -0
  55. data/test/integration/count_test.rb +34 -0
  56. data/test/integration/custom_score_queries_test.rb +88 -0
  57. data/test/integration/dis_max_queries_test.rb +68 -0
  58. data/test/integration/dsl_search_test.rb +22 -0
  59. data/test/integration/explanation_test.rb +44 -0
  60. data/test/integration/facets_test.rb +259 -0
  61. data/test/integration/filtered_queries_test.rb +66 -0
  62. data/test/integration/filters_test.rb +63 -0
  63. data/test/integration/fuzzy_queries_test.rb +20 -0
  64. data/test/integration/highlight_test.rb +64 -0
  65. data/test/integration/index_aliases_test.rb +122 -0
  66. data/test/integration/index_mapping_test.rb +43 -0
  67. data/test/integration/index_store_test.rb +96 -0
  68. data/test/integration/index_update_document_test.rb +111 -0
  69. data/test/integration/mongoid_searchable_test.rb +309 -0
  70. data/test/integration/percolator_test.rb +111 -0
  71. data/test/integration/persistent_model_test.rb +130 -0
  72. data/test/integration/prefix_query_test.rb +43 -0
  73. data/test/integration/query_return_version_test.rb +70 -0
  74. data/test/integration/query_string_test.rb +52 -0
  75. data/test/integration/range_queries_test.rb +36 -0
  76. data/test/integration/reindex_test.rb +46 -0
  77. data/test/integration/results_test.rb +39 -0
  78. data/test/integration/scan_test.rb +56 -0
  79. data/test/integration/script_fields_test.rb +38 -0
  80. data/test/integration/sort_test.rb +36 -0
  81. data/test/integration/text_query_test.rb +39 -0
  82. data/test/models/active_model_article.rb +31 -0
  83. data/test/models/active_model_article_with_callbacks.rb +49 -0
  84. data/test/models/active_model_article_with_custom_document_type.rb +7 -0
  85. data/test/models/active_model_article_with_custom_index_name.rb +7 -0
  86. data/test/models/active_record_models.rb +122 -0
  87. data/test/models/article.rb +15 -0
  88. data/test/models/mongoid_models.rb +97 -0
  89. data/test/models/persistent_article.rb +11 -0
  90. data/test/models/persistent_article_in_namespace.rb +12 -0
  91. data/test/models/persistent_article_with_casting.rb +28 -0
  92. data/test/models/persistent_article_with_defaults.rb +11 -0
  93. data/test/models/persistent_articles_with_custom_index_name.rb +10 -0
  94. data/test/models/supermodel_article.rb +17 -0
  95. data/test/models/validated_model.rb +11 -0
  96. data/test/test_helper.rb +93 -0
  97. data/test/unit/active_model_lint_test.rb +17 -0
  98. data/test/unit/configuration_test.rb +74 -0
  99. data/test/unit/http_client_test.rb +76 -0
  100. data/test/unit/http_response_test.rb +49 -0
  101. data/test/unit/index_alias_test.rb +275 -0
  102. data/test/unit/index_test.rb +894 -0
  103. data/test/unit/logger_test.rb +125 -0
  104. data/test/unit/model_callbacks_test.rb +116 -0
  105. data/test/unit/model_import_test.rb +71 -0
  106. data/test/unit/model_persistence_test.rb +528 -0
  107. data/test/unit/model_search_test.rb +913 -0
  108. data/test/unit/results_collection_test.rb +281 -0
  109. data/test/unit/results_item_test.rb +162 -0
  110. data/test/unit/rubyext_test.rb +66 -0
  111. data/test/unit/search_facet_test.rb +153 -0
  112. data/test/unit/search_filter_test.rb +42 -0
  113. data/test/unit/search_highlight_test.rb +46 -0
  114. data/test/unit/search_query_test.rb +301 -0
  115. data/test/unit/search_scan_test.rb +113 -0
  116. data/test/unit/search_script_field_test.rb +26 -0
  117. data/test/unit/search_sort_test.rb +50 -0
  118. data/test/unit/search_test.rb +499 -0
  119. data/test/unit/tire_test.rb +126 -0
  120. data/tire.gemspec +90 -0
  121. metadata +549 -0
@@ -0,0 +1,113 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+ module Search
5
+ class ScanTest < Test::Unit::TestCase
6
+
7
+ context "Scan" do
8
+ setup do
9
+ Configuration.reset
10
+ @results = {
11
+ "_scroll_id" => "abc123",
12
+ "took" => 3,
13
+ "hits" => {
14
+ "total" => 10,
15
+ "hits" => [
16
+ { "_id" => "1", "_source" => { "title" => "Test" } }
17
+ ]
18
+ }
19
+ }
20
+ @empty_results = @results.merge('hits' => {'hits' => []})
21
+ @default_response = mock_response @results.to_json, 200
22
+ end
23
+
24
+ should "initialize the search object with the indices" do
25
+ s = Scan.new(['index1', 'index2'])
26
+ assert_instance_of Tire::Search::Search, s.search
27
+ end
28
+
29
+ should "fetch the initial scroll ID" do
30
+ s = Scan.new('index1')
31
+ s.search.expects(:perform).
32
+ returns(stub :json => { '_scroll_id' => 'abc123' })
33
+
34
+ assert_equal 'abc123', s.scroll_id
35
+ end
36
+
37
+ should "perform the request lazily" do
38
+ s = Scan.new('dummy')
39
+
40
+ s.expects(:scroll_id).
41
+ returns('abc123').
42
+ at_least_once
43
+
44
+ Configuration.client.expects(:get).
45
+ with { |url,id| url =~ %r|_search/scroll.*search_type=scan| && id == 'abc123' }.
46
+ returns(@default_response).
47
+ once
48
+
49
+ assert_not_nil s.results
50
+ assert_not_nil s.response
51
+ assert_not_nil s.json
52
+ end
53
+
54
+ should "set the total and seen variables" do
55
+ s = Scan.new('dummy')
56
+ s.expects(:scroll_id).returns('abc123').at_least_once
57
+ Configuration.client.expects(:get).returns(@default_response).at_least_once
58
+
59
+ assert_equal 10, s.total
60
+ assert_equal 1, s.seen
61
+ end
62
+
63
+ should "log the request and response" do
64
+ Tire.configure { logger STDERR }
65
+
66
+ s = Scan.new('dummy')
67
+ s.expects(:scroll_id).returns('abc123').at_least_once
68
+ Configuration.client.expects(:get).returns(@default_response).at_least_once
69
+
70
+ Configuration.logger.expects(:log_request).
71
+ with { |(endpoint, params, curl)| endpoint == 'scroll' }
72
+
73
+ Configuration.logger.expects(:log_response).
74
+ with { |code, took, body| code == 200 && took == 3 && body == '1/10 (10.0%)' }
75
+
76
+ s.__perform
77
+ end
78
+
79
+ context "results" do
80
+ setup do
81
+ @search = Scan.new('dummy')
82
+ @search.expects(:results).
83
+ returns(Results::Collection.new @results).
84
+ then.
85
+ returns(Results::Collection.new @empty_results).
86
+ at_least_once
87
+ @search.results
88
+ end
89
+
90
+ should "be iterable" do
91
+ assert_respond_to @search, :each
92
+ assert_respond_to @search, :size
93
+
94
+ assert_nothing_raised do
95
+ @search.each { |batch| p batch; assert_equal 'Test', batch.first.title }
96
+ end
97
+ end
98
+
99
+ should "be iterable by individual documents" do
100
+ assert_respond_to @search, :each_document
101
+
102
+ assert_nothing_raised do
103
+ @search.each_document { |item| assert_equal 'Test', item.title }
104
+ end
105
+ end
106
+
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ module Tire::Search
4
+
5
+ class ScriptFieldTest < Test::Unit::TestCase
6
+
7
+ context "ScriptField" do
8
+
9
+ should "be serialized to JSON" do
10
+ assert_respond_to ScriptField.new(:test1, {}), :to_json
11
+ end
12
+
13
+ should "encode simple declarations as JSON" do
14
+ assert_equal( { :test1 => { :script => "doc['my_field_name'].value * factor",
15
+ :params => { :factor => 2.2 }, :lang => :js } }.to_json,
16
+
17
+ ScriptField.new( :test1,
18
+ { :script => "doc['my_field_name'].value * factor",
19
+ :params => { :factor => 2.2 }, :lang => :js } ).to_json
20
+ )
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ require 'test_helper'
2
+
3
+ module Tire::Search
4
+
5
+ class SortTest < Test::Unit::TestCase
6
+
7
+ context "Sort" do
8
+
9
+ should "be serialized to JSON" do
10
+ assert_respond_to Sort.new, :to_json
11
+ end
12
+
13
+ should "encode simple strings" do
14
+ assert_equal [:foo].to_json, Sort.new.by(:foo).to_json
15
+ end
16
+
17
+ should "encode method arguments" do
18
+ assert_equal [:foo => 'desc'].to_json, Sort.new.by(:foo, 'desc').to_json
19
+ end
20
+
21
+ should "encode hash" do
22
+ assert_equal [ :foo => { :reverse => true } ].to_json, Sort.new.by(:foo, :reverse => true).to_json
23
+ end
24
+
25
+ should "encode multiple sort fields in chain" do
26
+ assert_equal [:foo, :bar].to_json, Sort.new.by(:foo).by(:bar).to_json
27
+ end
28
+
29
+ should "encode fields when passed as a block to constructor" do
30
+ s = Sort.new do
31
+ by :foo
32
+ by :bar, 'desc'
33
+ by :_score
34
+ end
35
+ assert_equal [ :foo, {:bar => 'desc'}, :_score ].to_json, s.to_json
36
+ end
37
+
38
+ should "encode fields deeper in json" do
39
+ s = Sort.new { by 'author.name' }
40
+ assert_equal [ 'author.name' ].to_json, s.to_json
41
+
42
+ s = Sort.new { by 'author.name', 'desc' }
43
+ assert_equal [ {'author.name' => 'desc'} ].to_json, s.to_json
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,499 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class SearchTest < Test::Unit::TestCase
6
+
7
+ context "Search" do
8
+ setup { Configuration.reset }
9
+
10
+ should "be initialized with single index" do
11
+ s = Search::Search.new('index') { query { string 'foo' } }
12
+ assert_match %r|/index/_search|, s.url
13
+ end
14
+
15
+ should "be initialized with multiple indices" do
16
+ s = Search::Search.new(['index1','index2']) { query { string 'foo' } }
17
+ assert_match %r|/index1,index2/_search|, s.url
18
+ end
19
+
20
+ should "be initialized with multiple indices with options" do
21
+ indices = {'index1' => {:boost => 1},'index2' => {:boost => 2}}
22
+ s = Search::Search.new(indices) { query { string 'foo' } }
23
+ assert_match /index1/, s.url
24
+ assert_match /index2/, s.url
25
+ assert_equal({'index1' => 1, 'index2' => 2}, s.to_hash[:indices_boost])
26
+ end
27
+
28
+ should "be initialized with multiple indices as string" do
29
+ s = Search::Search.new(['index1,index2,index3']) { query { string 'foo' } }
30
+ assert_match %r|/index1,index2,index3/_search|, s.url
31
+ end
32
+
33
+ should "allow to search all indices by leaving index empty" do
34
+ s = Search::Search.new { query { string 'foo' } }
35
+ assert_match %r|localhost:9200/_search|, s.url
36
+ end
37
+
38
+ should "allow to limit results with document type" do
39
+ s = Search::Search.new('index', :type => 'bar') do
40
+ query { string 'foo' }
41
+ end
42
+
43
+ assert_match %r|index/bar/_search|, s.url
44
+ end
45
+
46
+ should "allow to pass search parameters" do
47
+ s = Search::Search.new('index', :routing => 123, :timeout => 1) { query { string 'foo' } }
48
+
49
+ assert ! s.params.empty?
50
+
51
+ assert_match %r|routing=123|, s.params
52
+ assert_match %r|timeout=1|, s.params
53
+ end
54
+
55
+ should "encode search parameters in the request" do
56
+ Configuration.client.expects(:get).with do |url, payload|
57
+ url.include? 'routing=123&timeout=1'
58
+ end.returns mock_response( { 'hits' => { 'hits' => [ {:_id => 1} ] } }.to_json )
59
+
60
+ Search::Search.new('index', :routing => 123, :timeout => 1) { query { string 'foo' } }.perform
61
+ end
62
+
63
+ should "encode missing params as an empty string" do
64
+ Configuration.client.expects(:get).with do |url, payload|
65
+ (! url.include? '?') && (! url.include? '&')
66
+ end.returns mock_response( { 'hits' => { 'hits' => [ {:_id => 1} ] } }.to_json )
67
+
68
+ s = Search::Search.new('index') { query { string 'foo' } }
69
+ s.perform
70
+
71
+ assert_equal '', s.params
72
+ end
73
+
74
+ should "properly encode namespaced document type" do
75
+ Configuration.client.expects(:get).with do |url, payload|
76
+ url.match %r|index/my_application%2Farticle/_search|
77
+ end.returns mock_response( { 'hits' => { 'hits' => [ {:_id => 1} ] } }.to_json )
78
+
79
+ s = Search::Search.new('index', :type => 'my_application/article') do
80
+ query { string 'foo' }
81
+ end
82
+ s.perform
83
+
84
+ assert_match %r|index/my_application%2Farticle/_search|, s.url
85
+ assert_match %r|index/my_application%2Farticle/_search|, s.to_curl
86
+ end
87
+
88
+ should "allow to pass block to query" do
89
+ Search::Query.any_instance.expects(:instance_eval)
90
+
91
+ Search::Search.new('index') do
92
+ query { string 'foo' }
93
+ end
94
+ end
95
+
96
+ should "allow to pass block with argument to query (use variables from outer scope)" do
97
+ def foo; 'bar'; end
98
+
99
+ Search::Query.any_instance.expects(:instance_eval).never
100
+
101
+ Search::Search.new('index') do |search|
102
+ search.query do |query|
103
+ query.string foo
104
+ end
105
+ end
106
+ end
107
+
108
+ should "store indices as an array" do
109
+ s = Search::Search.new('index1') do;end
110
+ assert_equal ['index1'], s.indices
111
+
112
+ s = Search::Search.new(['index1', 'index2']) do;end
113
+ assert_equal ['index1', 'index2'], s.indices
114
+ end
115
+
116
+ should "return curl snippet for debugging" do
117
+ s = Search::Search.new('index') do
118
+ query { string 'title:foo' }
119
+ end
120
+ assert_equal %q|curl -X GET "http://localhost:9200/index/_search?pretty=true" -d | +
121
+ %q|'{"query":{"query_string":{"query":"title:foo"}}}'|,
122
+ s.to_curl
123
+ end
124
+
125
+ should "return curl snippet with multiple indices for debugging" do
126
+ s = Search::Search.new(['index_1', 'index_2']) do
127
+ query { string 'title:foo' }
128
+ end
129
+ assert_match /index_1,index_2/, s.to_curl
130
+ end
131
+
132
+ should "return itself as a Hash" do
133
+ s = Search::Search.new('index') do
134
+ query { string 'title:foo' }
135
+ end
136
+ assert_nothing_raised do
137
+ assert_instance_of Hash, s.to_hash
138
+ assert_equal "title:foo", s.to_hash[:query][:query_string][:query]
139
+ end
140
+ end
141
+
142
+ should "allow chaining" do
143
+ assert_nothing_raised do
144
+ Search::Search.new('index').query { }.
145
+ sort { by :title, 'desc' }.
146
+ size(5).
147
+ sort { by :name, 'asc' }.
148
+ from(1).
149
+ version(true)
150
+ end
151
+ end
152
+
153
+ should "perform the search lazily" do
154
+ response = mock_response '{"took":1,"hits":[]}', 200
155
+ Configuration.client.expects(:get).returns(response)
156
+ Results::Collection.expects(:new).returns([])
157
+
158
+ s = Search::Search.new('index')
159
+ assert_not_nil s.results
160
+ assert_not_nil s.response
161
+ assert_not_nil s.json
162
+ end
163
+
164
+ should "allow the search criteria to be chained" do
165
+ s = Search::Search.new('index').query { string 'foo' }
166
+ assert_nil s.filters, "Should NOT have filters"
167
+
168
+ s.expects(:perform).once
169
+ s.filter :term, :other_field => 'bar'
170
+ assert s.filters.size == 1, "Should have filters"
171
+ s.results
172
+ end
173
+
174
+ should "print debugging information on exception and return false" do
175
+ ::RestClient::Request.any_instance.
176
+ expects(:execute).
177
+ raises(::RestClient::InternalServerError)
178
+ STDERR.expects(:puts)
179
+
180
+ s = Search::Search.new('index')
181
+ assert_raise Search::SearchRequestFailed do
182
+ s.perform
183
+ end
184
+ end
185
+
186
+ should "log request, but not response, when logger is set" do
187
+ Configuration.logger STDERR
188
+
189
+ Configuration.client.expects(:get).returns(mock_response( '{"took":1,"hits":[]}', 200 ))
190
+
191
+ Results::Collection.expects(:new).returns([])
192
+ Configuration.logger.expects(:log_request).returns(true)
193
+ Configuration.logger.expects(:log_response).with(200, 1, '')
194
+
195
+ Search::Search.new('index').perform
196
+ end
197
+
198
+ should "log the original exception on failed request" do
199
+ Configuration.logger STDERR
200
+
201
+ Configuration.client.expects(:get).raises(Errno::ECONNREFUSED)
202
+ Configuration.logger.expects(:log_response).with('N/A', 'N/A', '')
203
+
204
+ assert_raise Errno::ECONNREFUSED do
205
+ Search::Search.new('index').perform
206
+ end
207
+ end
208
+
209
+ should "allow to set the server url" do
210
+ search = Search::Search.new('indexA')
211
+ Configuration.url 'http://es1.example.com'
212
+
213
+ Configuration.client.
214
+ expects(:get).
215
+ with do |url, payload|
216
+ url == 'http://es1.example.com/indexA/_search'
217
+ end.
218
+ returns(mock_response( '{"took":1,"hits":{"total": 0, "hits" : []}}', 200 ))
219
+
220
+ search.perform
221
+ end
222
+
223
+ context "sort" do
224
+
225
+ should "allow sorting by multiple fields" do
226
+ s = Search::Search.new('index') do
227
+ sort do
228
+ by :title, 'desc'
229
+ by :_score
230
+ end
231
+ end
232
+ hash = MultiJson.decode( s.to_json )
233
+ assert_equal [{'title' => 'desc'}, '_score'], hash['sort']
234
+ end
235
+
236
+ end
237
+
238
+ context "facets" do
239
+
240
+ should "retrieve terms facets" do
241
+ s = Search::Search.new('index') do
242
+ facet('foo1') { terms :bar, :global => true }
243
+ facet('foo2', :global => true) { terms :bar }
244
+ facet('foo3') { terms :baz }
245
+ end
246
+ assert_equal 3, s.facets.keys.size
247
+ assert_not_nil s.facets['foo1']
248
+ assert_not_nil s.facets['foo2']
249
+ assert_not_nil s.facets['foo3']
250
+ end
251
+
252
+ should "retrieve date histogram facets" do
253
+ s = Search::Search.new('index') do
254
+ facet('date') { date :published_on }
255
+ end
256
+ assert_equal 1, s.facets.keys.size
257
+ assert_not_nil s.facets['date']
258
+ end
259
+
260
+ end
261
+
262
+ context "filter" do
263
+
264
+ should "allow to specify filter" do
265
+ s = Search::Search.new('index') do
266
+ filter :terms, :tags => ['foo']
267
+ end
268
+
269
+ assert_equal 1, s.filters.size
270
+
271
+ assert_not_nil s.filters.first
272
+ assert_not_nil s.filters.first[:terms]
273
+
274
+ assert_equal( {:terms => {:tags => ['foo']}}.to_json,
275
+ s.to_hash[:filter].to_json )
276
+ end
277
+
278
+ should "allow to add multiple filters" do
279
+ s = Search::Search.new('index') do
280
+ filter :terms, :tags => ['foo']
281
+ filter :term, :words => 125
282
+ end
283
+
284
+ assert_equal 2, s.filters.size
285
+
286
+ assert_not_nil s.filters.first[:terms]
287
+ assert_not_nil s.filters.last[:term]
288
+
289
+ assert_equal( { :and => [ {:terms => {:tags => ['foo']}}, {:term => {:words => 125}} ] }.to_json,
290
+ s.to_hash[:filter].to_json )
291
+ end
292
+
293
+ end
294
+
295
+ context "highlight" do
296
+
297
+ should "allow to specify highlight for single field" do
298
+ s = Search::Search.new('index') do
299
+ highlight :body
300
+ end
301
+
302
+ assert_not_nil s.highlight
303
+ assert_instance_of Tire::Search::Highlight, s.highlight
304
+ end
305
+
306
+ should "allow to specify highlight for more fields" do
307
+ s = Search::Search.new('index') do
308
+ highlight :body, :title
309
+ end
310
+
311
+ assert_not_nil s.highlight
312
+ assert_instance_of Tire::Search::Highlight, s.highlight
313
+ end
314
+
315
+ should "allow to specify highlight with for more fields with options" do
316
+ s = Search::Search.new('index') do
317
+ highlight :body, :title => { :fragment_size => 150, :number_of_fragments => 3 }
318
+ end
319
+
320
+ assert_not_nil s.highlight
321
+ assert_instance_of Tire::Search::Highlight, s.highlight
322
+ end
323
+
324
+ end
325
+
326
+ context "with version" do
327
+
328
+ should "set the version" do
329
+ s = Search::Search.new('index') do
330
+ version true
331
+ end
332
+ hash = MultiJson.decode( s.to_json )
333
+ assert_equal true, hash['version']
334
+ end
335
+
336
+ end
337
+
338
+ context "with from/size" do
339
+
340
+ should "set the values in request" do
341
+ s = Search::Search.new('index') do
342
+ size 5
343
+ from 3
344
+ end
345
+ hash = MultiJson.decode( s.to_json )
346
+ assert_equal 5, hash['size']
347
+ assert_equal 3, hash['from']
348
+ end
349
+
350
+ should "set the size value in options" do
351
+ Results::Collection.any_instance.stubs(:total).returns(50)
352
+ s = Search::Search.new('index') do
353
+ size 5
354
+ end
355
+
356
+ assert_equal 5, s.options[:size]
357
+ end
358
+
359
+ should "set the from value in options" do
360
+ Results::Collection.any_instance.stubs(:total).returns(50)
361
+ s = Search::Search.new('index') do
362
+ from 5
363
+ end
364
+
365
+ assert_equal 5, s.options[:from]
366
+ end
367
+
368
+ end
369
+
370
+ context "when limiting returned fields" do
371
+
372
+ should "set the fields limit in request" do
373
+ s = Search::Search.new('index') do
374
+ fields :title
375
+ end
376
+ hash = MultiJson.decode( s.to_json )
377
+ assert_equal ['title'], hash['fields']
378
+ end
379
+
380
+ should "take multiple fields as an Array" do
381
+ s = Search::Search.new('index') do
382
+ fields [:title, :tags]
383
+ end
384
+ hash = MultiJson.decode( s.to_json )
385
+ assert_equal ['title', 'tags'], hash['fields']
386
+ end
387
+
388
+ should "take multiple fields as splat argument" do
389
+ s = Search::Search.new('index') do
390
+ fields :title, :tags
391
+ end
392
+ hash = MultiJson.decode( s.to_json )
393
+ assert_equal ['title', 'tags'], hash['fields']
394
+ end
395
+
396
+ end
397
+
398
+ context "explain" do
399
+
400
+ should "default to false" do
401
+ s = Search::Search.new('index') do
402
+ end
403
+ hash = MultiJson.decode( s.to_json )
404
+ assert_nil hash['explain']
405
+ end
406
+
407
+ should "set the explain field in the request when true" do
408
+ s = Search::Search.new('index') do
409
+ explain true
410
+ end
411
+ hash = MultiJson.decode( s.to_json )
412
+ assert_equal true, hash['explain']
413
+ end
414
+
415
+ should "not set the explain field when false" do
416
+ s = Search::Search.new('index') do
417
+ explain false
418
+ end
419
+ hash = MultiJson.decode( s.to_json )
420
+ assert_nil hash['explain']
421
+ end
422
+
423
+ end
424
+
425
+ context "boolean queries" do
426
+
427
+ should "wrap other queries" do
428
+ # TODO: Try to get rid of the `boolean` method
429
+ #
430
+ # TODO: Try to get rid of multiple `should`, `must`, invocations, and wrap queries like this:
431
+ # boolean do
432
+ # should do
433
+ # string 'foo'
434
+ # string 'bar'
435
+ # end
436
+ # end
437
+ s = Search::Search.new('index') do
438
+ query do
439
+ boolean do
440
+ should { string 'foo' }
441
+ should { string 'moo' }
442
+ must { string 'title:bar' }
443
+ must { terms :tags, ['baz'] }
444
+ end
445
+ end
446
+ end
447
+
448
+ hash = MultiJson.decode(s.to_json)
449
+ query = hash['query']['bool']
450
+ # p hash
451
+
452
+ assert_equal 2, query['should'].size
453
+ assert_equal 2, query['must'].size
454
+
455
+ assert_equal( { 'query_string' => { 'query' => 'foo' } }, query['should'].first)
456
+ assert_equal( { 'terms' => { 'tags' => ['baz'] } }, query['must'].last)
457
+ end
458
+
459
+ end
460
+
461
+ end
462
+
463
+ context "script field" do
464
+
465
+ should "allow to specify script field" do
466
+ s = Search::Search.new('index') do
467
+ script_field :test1, :script => "doc['my_field_name'].value * 2"
468
+ end
469
+
470
+ assert_equal 1, s.script_fields.size
471
+
472
+ assert_not_nil s.script_fields
473
+ assert_not_nil s.script_fields[:test1]
474
+
475
+ assert_equal( {:test1 => { :script => "doc['my_field_name'].value * 2" }}.to_json,
476
+ s.to_hash[:script_fields].to_json )
477
+ end
478
+
479
+ should "allow to add multiple script fields" do
480
+ s = Search::Search.new('index') do
481
+ script_field :field1, :script => "doc['my_field_name'].value * 2"
482
+ script_field :field2, :script => "doc['other_field_name'].value * 3"
483
+ end
484
+
485
+ assert_equal 2, s.script_fields.size
486
+
487
+ assert_not_nil s.script_fields[:field1]
488
+ assert_not_nil s.script_fields[:field2]
489
+
490
+ assert_equal( { :field1 => { :script => "doc['my_field_name'].value * 2" }, :field2 => { :script => "doc['other_field_name'].value * 3" } }.to_json,
491
+ s.to_hash[:script_fields].to_json )
492
+ end
493
+
494
+ end
495
+
496
+
497
+ end
498
+
499
+ end