tire 0.4.3 → 0.5.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.
- data/.gitignore +1 -1
- data/.yardopts +1 -0
- data/README.markdown +2 -2
- data/examples/rails-application-template.rb +20 -6
- data/lib/tire.rb +2 -0
- data/lib/tire/alias.rb +1 -1
- data/lib/tire/configuration.rb +8 -0
- data/lib/tire/dsl.rb +69 -2
- data/lib/tire/index.rb +33 -20
- data/lib/tire/model/indexing.rb +7 -1
- data/lib/tire/model/persistence.rb +7 -4
- data/lib/tire/model/persistence/attributes.rb +1 -1
- data/lib/tire/model/persistence/finders.rb +4 -16
- data/lib/tire/model/search.rb +21 -8
- data/lib/tire/multi_search.rb +263 -0
- data/lib/tire/results/collection.rb +78 -49
- data/lib/tire/results/item.rb +6 -3
- data/lib/tire/results/pagination.rb +15 -1
- data/lib/tire/rubyext/ruby_1_8.rb +1 -7
- data/lib/tire/rubyext/uri_escape.rb +74 -0
- data/lib/tire/search.rb +33 -11
- data/lib/tire/search/facet.rb +8 -3
- data/lib/tire/search/filter.rb +1 -1
- data/lib/tire/search/highlight.rb +1 -1
- data/lib/tire/search/queries/match.rb +40 -0
- data/lib/tire/search/query.rb +42 -6
- data/lib/tire/search/scan.rb +1 -1
- data/lib/tire/search/script_field.rb +1 -1
- data/lib/tire/search/sort.rb +1 -1
- data/lib/tire/tasks.rb +17 -14
- data/lib/tire/version.rb +26 -8
- data/test/integration/active_record_searchable_test.rb +248 -129
- data/test/integration/boosting_queries_test.rb +32 -0
- data/test/integration/custom_score_queries_test.rb +1 -0
- data/test/integration/dsl_search_test.rb +9 -1
- data/test/integration/facets_test.rb +19 -6
- data/test/integration/match_query_test.rb +79 -0
- data/test/integration/multi_search_test.rb +114 -0
- data/test/integration/persistent_model_test.rb +58 -0
- data/test/models/article.rb +1 -1
- data/test/models/persistent_article_in_index.rb +16 -0
- data/test/models/persistent_article_with_defaults.rb +4 -3
- data/test/test_helper.rb +3 -1
- data/test/unit/configuration_test.rb +10 -0
- data/test/unit/index_test.rb +69 -27
- data/test/unit/model_initialization_test.rb +31 -0
- data/test/unit/model_persistence_test.rb +21 -7
- data/test/unit/model_search_test.rb +56 -5
- data/test/unit/multi_search_test.rb +304 -0
- data/test/unit/results_collection_test.rb +42 -2
- data/test/unit/results_item_test.rb +4 -0
- data/test/unit/search_facet_test.rb +35 -11
- data/test/unit/search_query_test.rb +96 -0
- data/test/unit/search_test.rb +60 -3
- data/test/unit/tire_test.rb +14 -0
- data/tire.gemspec +0 -1
- metadata +75 -44
data/test/unit/index_test.rb
CHANGED
@@ -126,21 +126,26 @@ module Tire
|
|
126
126
|
assert_equal 1, response['tokens'].size
|
127
127
|
end
|
128
128
|
|
129
|
-
should "properly encode parameters" do
|
129
|
+
should "properly encode parameters for analyzer" do
|
130
130
|
Configuration.client.expects(:get).with do |url, payload|
|
131
|
-
|
131
|
+
assert_equal "#{@index.url}/_analyze?analyzer=whitespace&pretty=true", url
|
132
132
|
end.returns(mock_response(@mock_analyze_response))
|
133
133
|
|
134
134
|
@index.analyze("foo bar", :analyzer => 'whitespace')
|
135
135
|
|
136
|
+
end
|
137
|
+
|
138
|
+
should "properly encode parameters for field" do
|
136
139
|
Configuration.client.expects(:get).with do |url, payload|
|
137
|
-
|
140
|
+
assert_equal "#{@index.url}/_analyze?field=title&pretty=true", url
|
138
141
|
end.returns(mock_response(@mock_analyze_response))
|
139
142
|
|
140
143
|
@index.analyze("foo bar", :field => 'title')
|
144
|
+
end
|
141
145
|
|
146
|
+
should "properly encode format parameter" do
|
142
147
|
Configuration.client.expects(:get).with do |url, payload|
|
143
|
-
|
148
|
+
assert_equal "#{@index.url}/_analyze?analyzer=keyword&format=text&pretty=true", url
|
144
149
|
end.returns(mock_response(@mock_analyze_response))
|
145
150
|
|
146
151
|
@index.analyze("foo bar", :analyzer => 'keyword', :format => 'text')
|
@@ -210,21 +215,21 @@ module Tire
|
|
210
215
|
|
211
216
|
should "set type from Hash :type property" do
|
212
217
|
Configuration.client.expects(:post).with do |url,document|
|
213
|
-
|
218
|
+
assert_equal "#{@index.url}/article/", url
|
214
219
|
end.returns(mock_response('{"ok":true,"_id":"test"}'))
|
215
220
|
@index.store :type => 'article', :title => 'Test'
|
216
221
|
end
|
217
222
|
|
218
223
|
should "set type from Hash :_type property" do
|
219
224
|
Configuration.client.expects(:post).with do |url,document|
|
220
|
-
|
225
|
+
assert_equal "#{@index.url}/article/", url
|
221
226
|
end.returns(mock_response('{"ok":true,"_id":"test"}'))
|
222
227
|
@index.store :_type => 'article', :title => 'Test'
|
223
228
|
end
|
224
229
|
|
225
230
|
should "set type from Object _type method" do
|
226
231
|
Configuration.client.expects(:post).with do |url,document|
|
227
|
-
|
232
|
+
assert_equal "#{@index.url}/article/", url
|
228
233
|
end.returns(mock_response('{"ok":true,"_id":"test"}'))
|
229
234
|
|
230
235
|
article = Class.new do
|
@@ -236,7 +241,7 @@ module Tire
|
|
236
241
|
|
237
242
|
should "set type from Object type method" do
|
238
243
|
Configuration.client.expects(:post).with do |url,document|
|
239
|
-
|
244
|
+
assert_equal "#{@index.url}/article/", url
|
240
245
|
end.returns(mock_response('{"ok":true,"_id":"test"}'))
|
241
246
|
|
242
247
|
article = Class.new do
|
@@ -248,7 +253,7 @@ module Tire
|
|
248
253
|
|
249
254
|
should "properly encode namespaced document types" do
|
250
255
|
Configuration.client.expects(:post).with do |url,document|
|
251
|
-
|
256
|
+
assert_equal "#{@index.url}/my_namespace%2Fmy_model/", url
|
252
257
|
end.returns(mock_response('{"ok":true,"_id":"123"}'))
|
253
258
|
|
254
259
|
module MyNamespace
|
@@ -363,6 +368,29 @@ module Tire
|
|
363
368
|
article = @index.retrieve 'my_namespace/my_model', 'id-1'
|
364
369
|
end
|
365
370
|
|
371
|
+
should "allow to set routing" do
|
372
|
+
Configuration.client.expects(:get).with("#{@index.url}/article/id-1?routing=foo").
|
373
|
+
returns(mock_response('{"_id":"id-1"'))
|
374
|
+
article = @index.retrieve :article, 'id-1', :routing => 'foo'
|
375
|
+
end
|
376
|
+
|
377
|
+
should "allow to set routing and fields" do
|
378
|
+
Configuration.client.expects(:get).with do |url|
|
379
|
+
assert url.include?('routing=foo'), url
|
380
|
+
assert url.include?('fields=name'), url
|
381
|
+
end.returns(mock_response('{"_id":"id-1"'))
|
382
|
+
|
383
|
+
article = @index.retrieve :article, 'id-1', :routing => 'foo', :fields => 'name'
|
384
|
+
end
|
385
|
+
|
386
|
+
should "allow to set preference" do
|
387
|
+
Configuration.client.expects(:get).with do |url|
|
388
|
+
assert url.include?('preference=foo'), url
|
389
|
+
end.returns(mock_response('{"_id":"id-1"'))
|
390
|
+
|
391
|
+
article = @index.retrieve :article, 'id-1', :preference => 'foo'
|
392
|
+
end
|
393
|
+
|
366
394
|
end
|
367
395
|
|
368
396
|
context "when removing" do
|
@@ -694,8 +722,9 @@ module Tire
|
|
694
722
|
query = { :query => { :query_string => { :query => 'foo' } } }
|
695
723
|
Configuration.client.expects(:put).with do |url, payload|
|
696
724
|
payload = MultiJson.decode(payload)
|
697
|
-
|
698
|
-
|
725
|
+
assert_equal "#{Configuration.url}/_percolator/dummy/my-query",
|
726
|
+
url
|
727
|
+
assert_equal 'foo', payload['query']['query_string']['query']
|
699
728
|
end.
|
700
729
|
returns(mock_response('{
|
701
730
|
"ok" : true,
|
@@ -711,8 +740,9 @@ module Tire
|
|
711
740
|
should "register percolator query as a block" do
|
712
741
|
Configuration.client.expects(:put).with do |url, payload|
|
713
742
|
payload = MultiJson.decode(payload)
|
714
|
-
|
715
|
-
|
743
|
+
assert_equal "#{Configuration.url}/_percolator/dummy/my-query",
|
744
|
+
url
|
745
|
+
assert_equal 'foo', payload['query']['query_string']['query']
|
716
746
|
end.
|
717
747
|
returns(mock_response('{
|
718
748
|
"ok" : true,
|
@@ -733,9 +763,10 @@ module Tire
|
|
733
763
|
|
734
764
|
Configuration.client.expects(:put).with do |url, payload|
|
735
765
|
payload = MultiJson.decode(payload)
|
736
|
-
|
737
|
-
|
738
|
-
payload['
|
766
|
+
assert_equal "#{Configuration.url}/_percolator/dummy/my-query",
|
767
|
+
url
|
768
|
+
assert_equal 'foo', payload['query']['query_string']['query']
|
769
|
+
assert_equal ['alert'], payload['tags']
|
739
770
|
end.
|
740
771
|
returns(mock_response('{
|
741
772
|
"ok" : true,
|
@@ -757,8 +788,8 @@ module Tire
|
|
757
788
|
should "percolate document against all registered queries" do
|
758
789
|
Configuration.client.expects(:get).with do |url,payload|
|
759
790
|
payload = MultiJson.decode(payload)
|
760
|
-
|
761
|
-
payload['doc']['title']
|
791
|
+
assert_equal "#{@index.url}/document/_percolate", url
|
792
|
+
assert_equal 'Test', payload['doc']['title']
|
762
793
|
end.
|
763
794
|
returns(mock_response('{"ok":true,"_id":"test","matches":["alerts"]}'))
|
764
795
|
|
@@ -769,8 +800,8 @@ module Tire
|
|
769
800
|
should "percolate a typed document against all registered queries" do
|
770
801
|
Configuration.client.expects(:get).with do |url,payload|
|
771
802
|
payload = MultiJson.decode(payload)
|
772
|
-
|
773
|
-
payload['doc']['title']
|
803
|
+
assert_equal "#{@index.url}/article/_percolate", url
|
804
|
+
assert_equal 'Test', payload['doc']['title']
|
774
805
|
end.
|
775
806
|
returns(mock_response('{"ok":true,"_id":"test","matches":["alerts"]}'))
|
776
807
|
|
@@ -782,9 +813,9 @@ module Tire
|
|
782
813
|
Configuration.client.expects(:get).with do |url,payload|
|
783
814
|
payload = MultiJson.decode(payload)
|
784
815
|
# p [url, payload]
|
785
|
-
|
786
|
-
payload['doc']['title']
|
787
|
-
payload['query']['query_string']['query']
|
816
|
+
assert_equal "#{@index.url}/document/_percolate", url
|
817
|
+
assert_equal 'Test', payload['doc']['title']
|
818
|
+
assert_equal 'tag:alerts', payload['query']['query_string']['query']
|
788
819
|
end.
|
789
820
|
returns(mock_response('{"ok":true,"_id":"test","matches":["alerts"]}'))
|
790
821
|
|
@@ -797,8 +828,7 @@ module Tire
|
|
797
828
|
should "percolate document against all registered queries" do
|
798
829
|
Configuration.client.expects(:post).
|
799
830
|
with do |url, payload|
|
800
|
-
|
801
|
-
payload =~ /"title":"Test"/
|
831
|
+
assert_equal "#{@index.url}/article/?percolate=%2A", url
|
802
832
|
end.
|
803
833
|
returns(mock_response('{"ok":true,"_id":"test","matches":["alerts"]}'))
|
804
834
|
@index.store( {:type => 'article', :title => 'Test'}, {:percolate => true} )
|
@@ -807,8 +837,7 @@ module Tire
|
|
807
837
|
should "percolate document against specific queries" do
|
808
838
|
Configuration.client.expects(:post).
|
809
839
|
with do |url, payload|
|
810
|
-
|
811
|
-
payload =~ /"title":"Test"/
|
840
|
+
assert_equal "#{@index.url}/article/?percolate=tag%3Aalerts", url
|
812
841
|
end.
|
813
842
|
returns(mock_response('{"ok":true,"_id":"test","matches":["alerts"]}'))
|
814
843
|
response = @index.store( {:type => 'article', :title => 'Test'}, {:percolate => 'tag:alerts'} )
|
@@ -819,6 +848,19 @@ module Tire
|
|
819
848
|
|
820
849
|
end
|
821
850
|
|
851
|
+
context "when passing parent document ID" do
|
852
|
+
|
853
|
+
should "set the :parent option in the request parameters" do
|
854
|
+
Configuration.client.expects(:post).
|
855
|
+
with do |url, payload|
|
856
|
+
assert_equal "#{Configuration.url}/dummy/document/?parent=1234", url
|
857
|
+
end.
|
858
|
+
returns(mock_response('{"ok":true,"_id":"test"}'))
|
859
|
+
|
860
|
+
@index.store({:title => 'Test'}, {:parent => 1234})
|
861
|
+
end
|
862
|
+
end
|
863
|
+
|
822
864
|
context "reindexing" do
|
823
865
|
setup do
|
824
866
|
@results = {
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ModelWithIncorrectMapping
|
4
|
+
extend ActiveModel::Naming
|
5
|
+
include Tire::Model::Search
|
6
|
+
include Tire::Model::Callbacks
|
7
|
+
|
8
|
+
tire do
|
9
|
+
mapping do
|
10
|
+
indexes :title, :type => 'boo'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Tire
|
16
|
+
module Model
|
17
|
+
|
18
|
+
class ModelInitializationTest < Test::Unit::TestCase
|
19
|
+
|
20
|
+
context "Model initialization" do
|
21
|
+
|
22
|
+
should "display a warning when creating the index fails" do
|
23
|
+
STDERR.expects(:puts)
|
24
|
+
result = ModelWithIncorrectMapping.create_elasticsearch_index
|
25
|
+
assert ! result, result.inspect
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -24,16 +24,16 @@ module Tire
|
|
24
24
|
setup do
|
25
25
|
Model::Search.index_prefix 'prefix'
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
teardown do
|
29
29
|
Model::Search.index_prefix nil
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
should "have configured prefix in index_name" do
|
33
33
|
assert_equal 'prefix_persistent_articles', PersistentArticle.index_name
|
34
34
|
assert_equal 'prefix_persistent_articles', PersistentArticle.new(:title => 'Test').index_name
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
end
|
38
38
|
|
39
39
|
should "have document_type" do
|
@@ -125,8 +125,13 @@ module Tire
|
|
125
125
|
assert_equal ids.size, documents.count
|
126
126
|
end
|
127
127
|
|
128
|
-
should "find all documents" do
|
129
|
-
Configuration.client.
|
128
|
+
should "find all documents with correct type" do
|
129
|
+
Configuration.client.expects(:get).
|
130
|
+
with do |url,payload|
|
131
|
+
assert_equal "#{Configuration.url}/persistent_articles/persistent_article/_search", url
|
132
|
+
end.
|
133
|
+
times(3).
|
134
|
+
returns(mock_response(@find_all.to_json))
|
130
135
|
documents = PersistentArticle.all
|
131
136
|
|
132
137
|
assert_equal 3, documents.count
|
@@ -134,8 +139,12 @@ module Tire
|
|
134
139
|
assert_equal PersistentArticle.find(:all).map { |e| e.id }, PersistentArticle.all.map { |e| e.id }
|
135
140
|
end
|
136
141
|
|
137
|
-
should "find first document" do
|
138
|
-
Configuration.client.expects(:get).
|
142
|
+
should "find first document with correct type" do
|
143
|
+
Configuration.client.expects(:get).
|
144
|
+
with do |url,payload|
|
145
|
+
assert_equal "#{Configuration.url}/persistent_articles/persistent_article/_search?size=1", url
|
146
|
+
end.
|
147
|
+
returns(mock_response(@find_first.to_json))
|
139
148
|
document = PersistentArticle.first
|
140
149
|
|
141
150
|
assert_equal 'First', document.attributes['title']
|
@@ -201,6 +210,11 @@ module Tire
|
|
201
210
|
assert_equal false, article.hidden
|
202
211
|
end
|
203
212
|
|
213
|
+
should "evaluate lambdas as default values" do
|
214
|
+
article = PersistentArticleWithDefaults.new
|
215
|
+
assert_equal Time.now.year, article.created_at.year
|
216
|
+
end
|
217
|
+
|
204
218
|
should "not affect default value" do
|
205
219
|
article = PersistentArticleWithDefaults.new :title => 'Test'
|
206
220
|
article.tags << "ruby"
|
@@ -19,7 +19,7 @@ module Tire
|
|
19
19
|
context "Model::Search" do
|
20
20
|
|
21
21
|
setup do
|
22
|
-
@stub = stub('search') { stubs(:query).returns(self); stubs(:perform).returns(self); stubs(:results).returns([]) }
|
22
|
+
@stub = stub('search') { stubs(:query).returns(self); stubs(:perform).returns(self); stubs(:results).returns([]); stubs(:size).returns(true) }
|
23
23
|
Tire::Index.any_instance.stubs(:exists?).returns(false)
|
24
24
|
end
|
25
25
|
|
@@ -39,7 +39,7 @@ module Tire
|
|
39
39
|
should "limit searching in index for documents matching the model 'document_type'" do
|
40
40
|
Tire::Search::Search.
|
41
41
|
expects(:new).
|
42
|
-
with(
|
42
|
+
with('active_model_articles', { :type => 'active_model_article' }).
|
43
43
|
returns(@stub).
|
44
44
|
twice
|
45
45
|
|
@@ -121,6 +121,16 @@ module Tire
|
|
121
121
|
assert_equal 'Article', document.title
|
122
122
|
end
|
123
123
|
|
124
|
+
should "not pass the search option as URL parameter" do
|
125
|
+
Configuration.client.
|
126
|
+
expects(:get).with do |url, payload|
|
127
|
+
assert ! url.include?('sort')
|
128
|
+
end.
|
129
|
+
returns( mock_response({ 'hits' => { 'hits' => [] } }.to_json) )
|
130
|
+
|
131
|
+
ActiveModelArticle.search(@q, :sort => 'title:DESC').results
|
132
|
+
end
|
133
|
+
|
124
134
|
context "searching with a block" do
|
125
135
|
setup do
|
126
136
|
Tire::Search::Search.any_instance.expects(:perform).returns(@stub)
|
@@ -191,14 +201,14 @@ module Tire
|
|
191
201
|
should "allow to specify sort direction" do
|
192
202
|
Tire::Search::Sort.any_instance.expects(:by).with('title', 'DESC')
|
193
203
|
|
194
|
-
ActiveModelArticle.search @q, :order => 'title
|
204
|
+
ActiveModelArticle.search @q, :order => 'title:DESC'
|
195
205
|
end
|
196
206
|
|
197
207
|
should "allow to specify more fields to sort on" do
|
198
208
|
Tire::Search::Sort.any_instance.expects(:by).with('title', 'DESC')
|
199
209
|
Tire::Search::Sort.any_instance.expects(:by).with('author.name', nil)
|
200
210
|
|
201
|
-
ActiveModelArticle.search @q, :order => ['title
|
211
|
+
ActiveModelArticle.search @q, :order => ['title:DESC', 'author.name']
|
202
212
|
end
|
203
213
|
|
204
214
|
should "allow to specify number of results per page" do
|
@@ -237,6 +247,25 @@ module Tire
|
|
237
247
|
|
238
248
|
end
|
239
249
|
|
250
|
+
context "multi search" do
|
251
|
+
|
252
|
+
should "perform search request within corresponding index and type" do
|
253
|
+
Tire::Search::Multi::Search.
|
254
|
+
expects(:new).
|
255
|
+
with do |index, options, block|
|
256
|
+
assert_equal 'active_model_articles', index
|
257
|
+
assert_equal 'active_model_article', options[:type]
|
258
|
+
end.
|
259
|
+
returns( mock(:results => []) )
|
260
|
+
|
261
|
+
ActiveModelArticle.multi_search do
|
262
|
+
search 'foo'
|
263
|
+
search 'xoo'
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
|
240
269
|
should "not set callback when hooks are missing" do
|
241
270
|
@model = ActiveModelArticle.new
|
242
271
|
@model.expects(:update_elasticsearch_index).never
|
@@ -610,7 +639,7 @@ module Tire
|
|
610
639
|
|
611
640
|
end
|
612
641
|
|
613
|
-
should "
|
642
|
+
should "evaluate :as mapping options passed as strings or procs" do
|
614
643
|
class ::ModelWithMappingProcs
|
615
644
|
extend ActiveModel::Naming
|
616
645
|
extend ActiveModel::Callbacks
|
@@ -646,6 +675,28 @@ module Tire
|
|
646
675
|
assert_equal 3, document['three']
|
647
676
|
end
|
648
677
|
|
678
|
+
should "index :as mapping options passed as arbitrary objects" do
|
679
|
+
class ::ModelWithMappingOptionAsObject
|
680
|
+
extend ActiveModel::Naming
|
681
|
+
extend ActiveModel::Callbacks
|
682
|
+
include ActiveModel::Serialization
|
683
|
+
include Tire::Model::Search
|
684
|
+
|
685
|
+
mapping do
|
686
|
+
indexes :one, :as => [1, 2, 3]
|
687
|
+
end
|
688
|
+
|
689
|
+
attr_reader :attributes
|
690
|
+
|
691
|
+
def initialize(attributes = {}); @attributes = attributes; end
|
692
|
+
end
|
693
|
+
|
694
|
+
model = ::ModelWithMappingOptionAsObject.new
|
695
|
+
document = MultiJson.decode(model.to_indexed_json)
|
696
|
+
|
697
|
+
assert_equal [1, 2, 3], document['one']
|
698
|
+
end
|
699
|
+
|
649
700
|
end
|
650
701
|
|
651
702
|
context "with percolation" do
|
@@ -0,0 +1,304 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
class MultiSearchTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context "Multi::Search" do
|
7
|
+
setup { Configuration.reset }
|
8
|
+
|
9
|
+
should "be initialized with index" do
|
10
|
+
@search = Tire::Search::Multi::Search.new 'foo'
|
11
|
+
assert_equal ['foo'], @search.indices
|
12
|
+
end
|
13
|
+
|
14
|
+
context "search definition" do
|
15
|
+
setup do
|
16
|
+
@search_definitions = Tire::Search::Multi::SearchDefinitions.new
|
17
|
+
end
|
18
|
+
|
19
|
+
should "be enumerable" do
|
20
|
+
assert_respond_to @search_definitions, :each
|
21
|
+
assert_respond_to @search_definitions, :size
|
22
|
+
end
|
23
|
+
|
24
|
+
should "allow to add definition" do
|
25
|
+
@search_definitions << { :name => 'foo', :search => { 'query' => 'bar' } }
|
26
|
+
assert_equal 1, @search_definitions.size
|
27
|
+
end
|
28
|
+
|
29
|
+
should "return definition" do
|
30
|
+
@search_definitions << { :name => 'foo', :search => { 'query' => 'bar' } }
|
31
|
+
assert_equal 'bar', @search_definitions['foo']['query']
|
32
|
+
end
|
33
|
+
|
34
|
+
should "have names" do
|
35
|
+
@search_definitions << { :name => 'foo', :search => { 'query' => 'bar' } }
|
36
|
+
assert_equal ['foo'], @search_definitions.names
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "search results" do
|
41
|
+
setup do
|
42
|
+
@search_definitions = Tire::Search::Multi::SearchDefinitions.new
|
43
|
+
@search_definitions << { :name => 'foo', :search => Tire::Search::Search.new }
|
44
|
+
@responses = [{ 'hits' => { 'hits' => [{'_id' => 1},
|
45
|
+
{'_id' => 2},
|
46
|
+
{'_id' => 3}] }
|
47
|
+
}]
|
48
|
+
|
49
|
+
@results = Tire::Search::Multi::Results.new @search_definitions, @responses
|
50
|
+
end
|
51
|
+
|
52
|
+
should "be enumerable" do
|
53
|
+
assert_respond_to @results, :each
|
54
|
+
assert_respond_to @results, :each_pair
|
55
|
+
assert_respond_to @results, :each_with_index
|
56
|
+
assert_respond_to @results, :size
|
57
|
+
end
|
58
|
+
|
59
|
+
should "return named results" do
|
60
|
+
assert_instance_of Tire::Results::Collection, @results['foo']
|
61
|
+
assert_equal 1, @results['foo'].first.id
|
62
|
+
end
|
63
|
+
|
64
|
+
should "return nil for incorrect index" do
|
65
|
+
assert_nil @results['moo']
|
66
|
+
assert_nil @results[999]
|
67
|
+
end
|
68
|
+
|
69
|
+
should "iterate over results" do
|
70
|
+
@results.each do |results|
|
71
|
+
assert_instance_of Tire::Results::Collection, results
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
should "iterate over named results" do
|
76
|
+
@results.each_pair do |name, results|
|
77
|
+
assert_equal 'foo', name
|
78
|
+
assert_instance_of Tire::Results::Collection, results
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
should "be serializable to Hash" do
|
83
|
+
assert_instance_of Tire::Results::Collection, @results.to_hash['foo']
|
84
|
+
end
|
85
|
+
|
86
|
+
should "pass search options to collection" do
|
87
|
+
@search_definitions = Tire::Search::Multi::SearchDefinitions.new
|
88
|
+
@search_definitions << { :name => 'foo', :search => Tire::Search::Search.new(nil, :foo => 'bar') }
|
89
|
+
@responses = [{ 'hits' => { 'hits' => [{'_id' => 1}] } }]
|
90
|
+
|
91
|
+
@results = Tire::Search::Multi::Results.new @search_definitions, @responses
|
92
|
+
|
93
|
+
assert_equal 'bar', @results['foo'].options[:foo]
|
94
|
+
end
|
95
|
+
|
96
|
+
context "error responses" do
|
97
|
+
setup do
|
98
|
+
@search_definitions = Tire::Search::Multi::SearchDefinitions.new
|
99
|
+
@search_definitions << { :name => 'foo', :search => Tire::Search::Search.new }
|
100
|
+
@search_definitions << { :name => 'xoo', :search => Tire::Search::Search.new }
|
101
|
+
@responses = [{ 'hits' => { 'hits' => [{'_id' => 1},
|
102
|
+
{'_id' => 2},
|
103
|
+
{'_id' => 3}] }
|
104
|
+
},
|
105
|
+
{'error' => 'SearchPhaseExecutionException ...'}
|
106
|
+
]
|
107
|
+
|
108
|
+
@results = Tire::Search::Multi::Results.new @search_definitions, @responses
|
109
|
+
end
|
110
|
+
|
111
|
+
should "return success/failure state" do
|
112
|
+
assert_equal true, @results['foo'].success?
|
113
|
+
assert_equal 3, @results['foo'].size
|
114
|
+
assert_equal true, @results['xoo'].failure?
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "URL" do
|
120
|
+
|
121
|
+
should "have no index and type by default" do
|
122
|
+
@search = Tire::Search::Multi::Search.new
|
123
|
+
assert_equal '/_msearch', @search.path
|
124
|
+
end
|
125
|
+
|
126
|
+
should "have an index" do
|
127
|
+
@search = Tire::Search::Multi::Search.new 'foo'
|
128
|
+
assert_equal '/foo/_msearch', @search.path
|
129
|
+
end
|
130
|
+
|
131
|
+
should "have multiple indices" do
|
132
|
+
@search = Tire::Search::Multi::Search.new ['foo', 'bar']
|
133
|
+
assert_equal '/foo,bar/_msearch', @search.path
|
134
|
+
end
|
135
|
+
|
136
|
+
should "have index and type" do
|
137
|
+
@search = Tire::Search::Multi::Search.new 'foo', :type => 'bar'
|
138
|
+
assert_equal '/foo/bar/_msearch', @search.path
|
139
|
+
end
|
140
|
+
|
141
|
+
should "have index and multiple types" do
|
142
|
+
@search = Tire::Search::Multi::Search.new 'foo', :type => ['bar', 'bam']
|
143
|
+
assert_equal '/foo/bar,bam/_msearch', @search.path
|
144
|
+
end
|
145
|
+
|
146
|
+
should "contain host" do
|
147
|
+
@search = Tire::Search::Multi::Search.new
|
148
|
+
assert_equal 'http://localhost:9200/_msearch', @search.url
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
context "URL params" do
|
154
|
+
|
155
|
+
should "be empty when no params passed" do
|
156
|
+
@search = Tire::Search::Multi::Search.new 'foo'
|
157
|
+
assert_equal '', @search.params
|
158
|
+
end
|
159
|
+
|
160
|
+
should "serialize parameters" do
|
161
|
+
@search = Tire::Search::Multi::Search.new 'foo', :search_type => 'count'
|
162
|
+
assert_equal '?search_type=count', @search.params
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
context "search request" do
|
168
|
+
setup do
|
169
|
+
@search = Tire::Search::Multi::Search.new
|
170
|
+
end
|
171
|
+
|
172
|
+
should "have a collection of searches" do
|
173
|
+
@search.search :one
|
174
|
+
assert_instance_of Tire::Search::Multi::SearchDefinitions, @search.searches
|
175
|
+
end
|
176
|
+
|
177
|
+
should "be initialized with name" do
|
178
|
+
@search.search :one
|
179
|
+
assert_instance_of Tire::Search::Search, @search.searches[:one]
|
180
|
+
end
|
181
|
+
|
182
|
+
should "be initialized with options" do
|
183
|
+
@search.search :foo => 'bar'
|
184
|
+
assert_equal 'bar', @search.searches[0].options[:foo]
|
185
|
+
end
|
186
|
+
|
187
|
+
should "be initialized with name and options" do
|
188
|
+
@search.search :one, :foo => 'bar'
|
189
|
+
assert_instance_of Tire::Search::Search, @search.searches[:one]
|
190
|
+
assert_equal 'bar', @search.searches[:one].options[:foo]
|
191
|
+
assert_equal 'bar', @search.searches(:one).options[:foo]
|
192
|
+
end
|
193
|
+
|
194
|
+
should "pass the index name and options to the search object" do
|
195
|
+
@search.search :index => 'foo', :type => 'bar'
|
196
|
+
assert_equal ['foo'], @search.searches[0].indices
|
197
|
+
assert_equal ['bar'], @search.searches[0].types
|
198
|
+
assert_equal ['foo'], @search.searches(0).indices
|
199
|
+
end
|
200
|
+
|
201
|
+
should "pass options to Search object" do
|
202
|
+
@search.search :search_type => 'count'
|
203
|
+
assert_equal 'count', @search.searches[0].options[:search_type]
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
context "payload" do
|
209
|
+
|
210
|
+
should "serialize search payload header and body as Array" do
|
211
|
+
@search = Tire::Search::Multi::Search.new do
|
212
|
+
search :index => 'foo' do
|
213
|
+
query { all }
|
214
|
+
size 100
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
assert_equal 1, @search.searches.size
|
219
|
+
assert_equal 2, @search.to_array.size
|
220
|
+
|
221
|
+
assert_equal( 'foo', @search.to_array[0][:index] )
|
222
|
+
assert_equal( {:match_all => {}}, @search.to_array[1][:query] )
|
223
|
+
assert_equal( 100, @search.to_array[1][:size] )
|
224
|
+
end
|
225
|
+
|
226
|
+
should "serialize search payload header and body for multiple searches" do
|
227
|
+
@search = Tire::Search::Multi::Search.new do
|
228
|
+
search(:index => 'foo') { query { all } }
|
229
|
+
search(:index => 'ooo') { query { term :foo, 'bar' } }
|
230
|
+
end
|
231
|
+
|
232
|
+
assert_equal 2, @search.searches.size
|
233
|
+
assert_equal 4, @search.to_array.size
|
234
|
+
|
235
|
+
assert_equal 'foo', @search.to_array[0][:index]
|
236
|
+
assert_equal 'ooo', @search.to_array[2][:index]
|
237
|
+
assert_equal 'match_all', @search.to_array[1][:query].keys.first.to_s
|
238
|
+
assert_equal 'term', @search.to_array[3][:query].keys.first.to_s
|
239
|
+
end
|
240
|
+
|
241
|
+
should "serialize search parameters" do
|
242
|
+
@search = Tire::Search::Multi::Search.new do
|
243
|
+
search(:search_type => 'count') { query { all } }
|
244
|
+
end
|
245
|
+
|
246
|
+
assert_equal 'count', @search.to_array[0][:search_type]
|
247
|
+
end
|
248
|
+
|
249
|
+
should "serialize search payload as a string" do
|
250
|
+
@search = Tire::Search::Multi::Search.new do
|
251
|
+
search(:index => 'foo') { query { all } }
|
252
|
+
end
|
253
|
+
|
254
|
+
assert_equal 2, @search.to_payload.split("\n").size
|
255
|
+
end
|
256
|
+
|
257
|
+
should "end with a new line" do
|
258
|
+
@search = Tire::Search::Multi::Search.new { search(:index => 'foo') { query { all } } }
|
259
|
+
assert_match /.*\n$/, @search.to_payload
|
260
|
+
end
|
261
|
+
|
262
|
+
should "leave header empty when no index is passed" do
|
263
|
+
@search = Tire::Search::Multi::Search.new do
|
264
|
+
search() { query { all } }
|
265
|
+
end
|
266
|
+
|
267
|
+
assert_equal( {}, @search.to_array.first )
|
268
|
+
end
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
context "perform" do
|
273
|
+
setup do
|
274
|
+
@search = Tire::Search::Multi::Search.new do
|
275
|
+
search(:index => 'foo') do
|
276
|
+
query { all }
|
277
|
+
size 100
|
278
|
+
end
|
279
|
+
end
|
280
|
+
@response = mock_response '{ "responses" : [{"took":1,"hits":{"total":0,"hits":[]}}] }', 200
|
281
|
+
end
|
282
|
+
|
283
|
+
should "perform the request" do
|
284
|
+
Configuration.client.expects(:get).
|
285
|
+
with do |url, payload|
|
286
|
+
assert_equal 'http://localhost:9200/_msearch', url
|
287
|
+
assert payload.include?('match_all')
|
288
|
+
end.
|
289
|
+
returns(@response)
|
290
|
+
@search.perform
|
291
|
+
end
|
292
|
+
|
293
|
+
should "log the request" do
|
294
|
+
Configuration.client.expects(:get).returns(@response)
|
295
|
+
@search.expects(:logged)
|
296
|
+
@search.perform
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
end
|