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