sunspot 2.0.0 → 2.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.
Files changed (165) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +2 -0
  4. data/Appraisals +7 -0
  5. data/Gemfile +0 -2
  6. data/History.txt +10 -0
  7. data/lib/sunspot.rb +55 -17
  8. data/lib/sunspot/adapters.rb +68 -18
  9. data/lib/sunspot/batcher.rb +1 -1
  10. data/lib/sunspot/configuration.rb +4 -2
  11. data/lib/sunspot/data_extractor.rb +36 -6
  12. data/lib/sunspot/dsl.rb +4 -3
  13. data/lib/sunspot/dsl/adjustable.rb +2 -2
  14. data/lib/sunspot/dsl/field_query.rb +69 -16
  15. data/lib/sunspot/dsl/field_stats.rb +25 -0
  16. data/lib/sunspot/dsl/fields.rb +28 -8
  17. data/lib/sunspot/dsl/fulltext.rb +9 -1
  18. data/lib/sunspot/dsl/group.rb +118 -0
  19. data/lib/sunspot/dsl/paginatable.rb +4 -1
  20. data/lib/sunspot/dsl/scope.rb +19 -10
  21. data/lib/sunspot/dsl/search.rb +1 -1
  22. data/lib/sunspot/dsl/spellcheckable.rb +14 -0
  23. data/lib/sunspot/dsl/standard_query.rb +63 -35
  24. data/lib/sunspot/field.rb +76 -4
  25. data/lib/sunspot/field_factory.rb +60 -11
  26. data/lib/sunspot/indexer.rb +70 -18
  27. data/lib/sunspot/query.rb +5 -4
  28. data/lib/sunspot/query/abstract_field_facet.rb +0 -2
  29. data/lib/sunspot/query/abstract_fulltext.rb +76 -0
  30. data/lib/sunspot/query/abstract_json_field_facet.rb +70 -0
  31. data/lib/sunspot/query/bbox.rb +5 -1
  32. data/lib/sunspot/query/common_query.rb +31 -6
  33. data/lib/sunspot/query/composite_fulltext.rb +58 -8
  34. data/lib/sunspot/query/date_field_json_facet.rb +25 -0
  35. data/lib/sunspot/query/dismax.rb +25 -71
  36. data/lib/sunspot/query/field_json_facet.rb +19 -0
  37. data/lib/sunspot/query/field_list.rb +15 -0
  38. data/lib/sunspot/query/field_stats.rb +61 -0
  39. data/lib/sunspot/query/function_query.rb +1 -2
  40. data/lib/sunspot/query/geo.rb +1 -1
  41. data/lib/sunspot/query/geofilt.rb +8 -3
  42. data/lib/sunspot/query/group.rb +46 -0
  43. data/lib/sunspot/query/group_query.rb +17 -0
  44. data/lib/sunspot/query/join.rb +88 -0
  45. data/lib/sunspot/query/more_like_this.rb +1 -1
  46. data/lib/sunspot/query/pagination.rb +12 -4
  47. data/lib/sunspot/query/range_json_facet.rb +28 -0
  48. data/lib/sunspot/query/restriction.rb +99 -13
  49. data/lib/sunspot/query/sort.rb +41 -0
  50. data/lib/sunspot/query/sort_composite.rb +7 -0
  51. data/lib/sunspot/query/spellcheck.rb +19 -0
  52. data/lib/sunspot/query/standard_query.rb +24 -2
  53. data/lib/sunspot/query/text_field_boost.rb +1 -3
  54. data/lib/sunspot/schema.rb +12 -3
  55. data/lib/sunspot/search.rb +4 -2
  56. data/lib/sunspot/search/abstract_search.rb +93 -43
  57. data/lib/sunspot/search/cursor_paginated_collection.rb +32 -0
  58. data/lib/sunspot/search/field_facet.rb +4 -4
  59. data/lib/sunspot/search/field_json_facet.rb +33 -0
  60. data/lib/sunspot/search/field_stats.rb +21 -0
  61. data/lib/sunspot/search/hit.rb +6 -1
  62. data/lib/sunspot/search/hit_enumerable.rb +4 -1
  63. data/lib/sunspot/search/json_facet_row.rb +40 -0
  64. data/lib/sunspot/search/json_facet_stats.rb +23 -0
  65. data/lib/sunspot/search/paginated_collection.rb +1 -0
  66. data/lib/sunspot/search/query_group.rb +74 -0
  67. data/lib/sunspot/search/standard_search.rb +70 -3
  68. data/lib/sunspot/search/stats_facet.rb +25 -0
  69. data/lib/sunspot/search/stats_json_row.rb +82 -0
  70. data/lib/sunspot/search/stats_row.rb +68 -0
  71. data/lib/sunspot/session.rb +62 -37
  72. data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +6 -4
  73. data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +16 -8
  74. data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +2 -2
  75. data/lib/sunspot/session_proxy/retry_5xx_session_proxy.rb +1 -1
  76. data/lib/sunspot/session_proxy/sharding_session_proxy.rb +4 -2
  77. data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +1 -1
  78. data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +6 -4
  79. data/lib/sunspot/setup.rb +42 -0
  80. data/lib/sunspot/type.rb +20 -0
  81. data/lib/sunspot/util.rb +78 -14
  82. data/lib/sunspot/version.rb +1 -1
  83. data/spec/api/adapters_spec.rb +40 -15
  84. data/spec/api/batcher_spec.rb +15 -15
  85. data/spec/api/binding_spec.rb +3 -3
  86. data/spec/api/class_set_spec.rb +6 -6
  87. data/spec/api/data_extractor_spec.rb +39 -0
  88. data/spec/api/hit_enumerable_spec.rb +32 -9
  89. data/spec/api/indexer/attributes_spec.rb +35 -30
  90. data/spec/api/indexer/batch_spec.rb +8 -7
  91. data/spec/api/indexer/dynamic_fields_spec.rb +8 -8
  92. data/spec/api/indexer/fixed_fields_spec.rb +16 -11
  93. data/spec/api/indexer/fulltext_spec.rb +8 -8
  94. data/spec/api/indexer/removal_spec.rb +24 -14
  95. data/spec/api/indexer_spec.rb +2 -2
  96. data/spec/api/query/advanced_manipulation_examples.rb +3 -3
  97. data/spec/api/query/connectives_examples.rb +26 -14
  98. data/spec/api/query/dsl_spec.rb +24 -6
  99. data/spec/api/query/dynamic_fields_examples.rb +18 -18
  100. data/spec/api/query/faceting_examples.rb +80 -61
  101. data/spec/api/query/fulltext_examples.rb +194 -40
  102. data/spec/api/query/function_spec.rb +116 -13
  103. data/spec/api/query/geo_examples.rb +8 -12
  104. data/spec/api/query/group_spec.rb +27 -5
  105. data/spec/api/query/highlighting_examples.rb +26 -26
  106. data/spec/api/query/join_spec.rb +19 -0
  107. data/spec/api/query/more_like_this_spec.rb +40 -27
  108. data/spec/api/query/ordering_pagination_examples.rb +37 -23
  109. data/spec/api/query/scope_examples.rb +39 -39
  110. data/spec/api/query/spatial_examples.rb +3 -3
  111. data/spec/api/query/spellcheck_examples.rb +20 -0
  112. data/spec/api/query/standard_spec.rb +3 -1
  113. data/spec/api/query/stats_examples.rb +66 -0
  114. data/spec/api/query/text_field_scoping_examples.rb +5 -5
  115. data/spec/api/query/types_spec.rb +4 -4
  116. data/spec/api/search/cursor_paginated_collection_spec.rb +35 -0
  117. data/spec/api/search/dynamic_fields_spec.rb +4 -4
  118. data/spec/api/search/faceting_spec.rb +55 -52
  119. data/spec/api/search/highlighting_spec.rb +7 -7
  120. data/spec/api/search/hits_spec.rb +43 -29
  121. data/spec/api/search/paginated_collection_spec.rb +19 -18
  122. data/spec/api/search/results_spec.rb +13 -13
  123. data/spec/api/search/search_spec.rb +3 -3
  124. data/spec/api/search/stats_spec.rb +94 -0
  125. data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +23 -16
  126. data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +16 -4
  127. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +10 -6
  128. data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +11 -11
  129. data/spec/api/session_proxy/sharding_session_proxy_spec.rb +15 -14
  130. data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +3 -3
  131. data/spec/api/session_proxy/spec_helper.rb +1 -1
  132. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +40 -26
  133. data/spec/api/session_spec.rb +78 -38
  134. data/spec/api/sunspot_spec.rb +7 -4
  135. data/spec/helpers/integration_helper.rb +11 -1
  136. data/spec/helpers/query_helper.rb +1 -1
  137. data/spec/helpers/search_helper.rb +30 -0
  138. data/spec/integration/atomic_updates_spec.rb +58 -0
  139. data/spec/integration/dynamic_fields_spec.rb +31 -20
  140. data/spec/integration/faceting_spec.rb +252 -39
  141. data/spec/integration/field_grouping_spec.rb +47 -15
  142. data/spec/integration/field_lists_spec.rb +57 -0
  143. data/spec/integration/geospatial_spec.rb +34 -8
  144. data/spec/integration/highlighting_spec.rb +8 -8
  145. data/spec/integration/indexing_spec.rb +7 -6
  146. data/spec/integration/join_spec.rb +45 -0
  147. data/spec/integration/keyword_search_spec.rb +68 -38
  148. data/spec/integration/local_search_spec.rb +4 -4
  149. data/spec/integration/more_like_this_spec.rb +7 -7
  150. data/spec/integration/scoped_search_spec.rb +193 -74
  151. data/spec/integration/spellcheck_spec.rb +119 -0
  152. data/spec/integration/stats_spec.rb +88 -0
  153. data/spec/integration/stored_fields_spec.rb +1 -1
  154. data/spec/integration/test_pagination.rb +4 -4
  155. data/spec/integration/unicode_spec.rb +1 -1
  156. data/spec/mocks/adapters.rb +36 -0
  157. data/spec/mocks/connection.rb +5 -3
  158. data/spec/mocks/photo.rb +32 -1
  159. data/spec/mocks/post.rb +18 -3
  160. data/spec/spec_helper.rb +13 -8
  161. data/sunspot.gemspec +6 -4
  162. data/tasks/rdoc.rake +22 -14
  163. metadata +101 -44
  164. data/lib/sunspot/dsl/field_group.rb +0 -57
  165. data/lib/sunspot/query/field_group.rb +0 -37
@@ -19,8 +19,8 @@ describe "field grouping" do
19
19
  group :title
20
20
  end
21
21
 
22
- search.group(:title).groups.should include { |g| g.value == "Title1" }
23
- search.group(:title).groups.should include { |g| g.value == "Title2" }
22
+ expect(search.group(:title).groups).to include { |g| g.value == "Title1" }
23
+ expect(search.group(:title).groups).to include { |g| g.value == "Title2" }
24
24
  end
25
25
 
26
26
  it "returns the number of matches unique groups" do
@@ -28,7 +28,7 @@ describe "field grouping" do
28
28
  group :title
29
29
  end
30
30
 
31
- search.group(:title).total.should == 2
31
+ expect(search.group(:title).total).to eq(2)
32
32
  end
33
33
 
34
34
  it "provides access to the number of matches before grouping" do
@@ -36,7 +36,7 @@ describe "field grouping" do
36
36
  group :title
37
37
  end
38
38
 
39
- search.group(:title).matches.should == @posts.length
39
+ expect(search.group(:title).matches).to eq(@posts.length)
40
40
  end
41
41
 
42
42
  it "allows grouping by multiple fields" do
@@ -44,8 +44,8 @@ describe "field grouping" do
44
44
  group :title, :sort_title
45
45
  end
46
46
 
47
- search.group(:title).groups.should_not be_empty
48
- search.group(:sort_title).groups.should_not be_empty
47
+ expect(search.group(:title).groups).not_to be_empty
48
+ expect(search.group(:sort_title).groups).not_to be_empty
49
49
  end
50
50
 
51
51
  it "allows specification of the number of documents per group" do
@@ -56,7 +56,7 @@ describe "field grouping" do
56
56
  end
57
57
 
58
58
  title1_group = search.group(:title).groups.detect { |g| g.value == "Title1" }
59
- title1_group.hits.length.should == 2
59
+ expect(title1_group.hits.length).to eq(2)
60
60
  end
61
61
 
62
62
  it "allows specification of the sort within groups" do
@@ -69,7 +69,20 @@ describe "field grouping" do
69
69
  highest_ranked_post = @posts.sort_by { |p| -p.ratings_average }.first
70
70
 
71
71
  title1_group = search.group(:title).groups.detect { |g| g.value == "Title1" }
72
- title1_group.hits.first.primary_key.to_i.should == highest_ranked_post.id
72
+ expect(title1_group.hits.first.primary_key.to_i).to eq(highest_ranked_post.id)
73
+ end
74
+
75
+ it "allows specification of an ordering function within groups" do
76
+ search = Sunspot.search(Post) do
77
+ group :title do
78
+ order_by_function(:product, :average_rating, -2, :asc)
79
+ end
80
+ end
81
+
82
+ highest_ranked_post = @posts.sort_by { |p| -p.ratings_average }.first
83
+
84
+ title1_group = search.group(:title).groups.detect { |g| g.value == "Title1" }
85
+ expect(title1_group.hits.first.primary_key.to_i).to eq(highest_ranked_post.id)
73
86
  end
74
87
 
75
88
  it "allows pagination within groups" do
@@ -78,8 +91,27 @@ describe "field grouping" do
78
91
  paginate :per_page => 1, :page => 2
79
92
  end
80
93
 
81
- search.group(:title).groups.length.should eql(1)
82
- search.group(:title).groups.first.results.should == [ @posts.last ]
94
+ expect(search.group(:title).groups.length).to eql(1)
95
+ expect(search.group(:title).groups.first.results).to eq([ @posts.last ])
96
+ end
97
+
98
+ context "returns a not paginated collection" do
99
+ subject do
100
+ search = Sunspot.search(Post) do
101
+ group :title do
102
+ ngroups false
103
+ end
104
+ paginate :per_page => 1, :page => 2
105
+
106
+ end
107
+ search.group(:title).groups
108
+ end
109
+
110
+ it { expect(subject.per_page).to eql(1) }
111
+ it { expect(subject.total_pages).to eql(0) }
112
+ it { expect(subject.current_page).to eql(2) }
113
+ it { expect(subject.first_page?).to be(false) }
114
+ it { expect(subject.last_page?).to be(true) }
83
115
  end
84
116
 
85
117
  context "returns a paginated collection" do
@@ -91,10 +123,10 @@ describe "field grouping" do
91
123
  search.group(:title).groups
92
124
  end
93
125
 
94
- it { subject.per_page.should eql(1) }
95
- it { subject.total_pages.should eql(2) }
96
- it { subject.current_page.should eql(2) }
97
- it { subject.first_page?.should be_false }
98
- it { subject.last_page?.should be_true }
126
+ it { expect(subject.per_page).to eql(1) }
127
+ it { expect(subject.total_pages).to eql(2) }
128
+ it { expect(subject.current_page).to eql(2) }
129
+ it { expect(subject.first_page?).to be(false) }
130
+ it { expect(subject.last_page?).to be(true) }
99
131
  end
100
132
  end
@@ -0,0 +1,57 @@
1
+ require File.expand_path('../spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'fields lists' do
4
+ before :all do
5
+ Sunspot.remove_all
6
+ @post = Post.new(title: 'A Title', body: 'A Body', featured: true, tags: ['tag'])
7
+ Sunspot.index!(@post)
8
+ end
9
+
10
+ let(:stored_field_names) do
11
+ (Sunspot::Setup.for(Post).fields + Sunspot::Setup.for(Post).all_text_fields)
12
+ .select { |f| f.stored? }
13
+ .map { |f| f.name }
14
+ end
15
+
16
+ it 'loads all stored fields by dafault' do
17
+ hit = Sunspot.search(Post).hits.first
18
+
19
+ stored_field_names.each do |field|
20
+ expect(hit.stored(field)).not_to be_nil
21
+ end
22
+ end
23
+
24
+ it 'loads only filtered fields' do
25
+ hit = Sunspot.search(Post) { field_list(:title) }.hits.first
26
+
27
+ expect(hit.stored(:title)).to eq(@post.title)
28
+
29
+ (stored_field_names - [:title]).each do |field|
30
+ expect(hit.stored(field)).to be_nil
31
+ end
32
+ end
33
+
34
+ it 'does not raise Sunspot::UnrecognizedFieldError when listing existing text fields' do
35
+ expect do
36
+ Sunspot.search(Post) {
37
+ field_list(:body)
38
+ }
39
+ end.to_not raise_error
40
+ end
41
+
42
+ it 'does raise Sunspot::UnrecognizedFieldError when listing a non-existent text fields' do
43
+ expect do
44
+ Sunspot.search(Post) {
45
+ field_list(:bogus_body)
46
+ }
47
+ end.to raise_error(Sunspot::UnrecognizedFieldError)
48
+ end
49
+
50
+ it 'does not load any stored fields' do
51
+ hit = Sunspot.search(Post) { without_stored_fields }.hits.first
52
+
53
+ stored_field_names.each do |field|
54
+ expect(hit.stored(field)).to be_nil
55
+ end
56
+ end
57
+ end
@@ -15,7 +15,7 @@ describe "geospatial search" do
15
15
  with(:coordinates_new).in_radius(32, -68, 1)
16
16
  }.results
17
17
 
18
- results.should include(@post)
18
+ expect(results).to include(@post)
19
19
  end
20
20
 
21
21
  it "filters out posts not in the radius" do
@@ -23,18 +23,44 @@ describe "geospatial search" do
23
23
  with(:coordinates_new).in_radius(33, -68, 1)
24
24
  }.results
25
25
 
26
- results.should_not include(@post)
26
+ expect(results).not_to include(@post)
27
27
  end
28
28
 
29
- it "allows conjunction queries" do
29
+ it "filters out posts in the radius" do
30
+ results = Sunspot.search(Post) {
31
+ without(:coordinates_new).in_radius(32, -68, 1)
32
+ }.results
33
+
34
+ expect(results).not_to include(@post)
35
+ end
36
+
37
+ it "allows conjunction queries with radius" do
38
+ post = Post.new(:title => "Howdy",
39
+ :coordinates => Sunspot::Util::Coordinates.new(35, -68))
40
+
41
+ Sunspot.index!(post)
42
+
30
43
  results = Sunspot.search(Post) {
31
44
  any_of do
32
45
  with(:coordinates_new).in_radius(32, -68, 1)
33
46
  with(:coordinates_new).in_radius(35, 68, 1)
47
+ without(:coordinates_new).in_radius(35, -68, 1)
48
+ end
49
+ }.results
50
+
51
+ expect(results).to include(@post)
52
+ expect(results).not_to include(post)
53
+ end
54
+
55
+ it "allows conjunction queries with bounding box" do
56
+ results = Sunspot.search(Post) {
57
+ any_of do
58
+ with(:coordinates_new).in_bounding_box([31, -69], [33, -67])
59
+ with(:coordinates_new).in_bounding_box([35, 68], [36, 69])
34
60
  end
35
61
  }.results
36
62
 
37
- results.should include(@post)
63
+ expect(results).to include(@post)
38
64
  end
39
65
  end
40
66
 
@@ -52,7 +78,7 @@ describe "geospatial search" do
52
78
  with(:coordinates_new).in_bounding_box [31, -69], [33, -67]
53
79
  }.results
54
80
 
55
- results.should include(@post)
81
+ expect(results).to include(@post)
56
82
  end
57
83
 
58
84
  it "filters out posts not in the bounding box" do
@@ -60,7 +86,7 @@ describe "geospatial search" do
60
86
  with(:coordinates_new).in_bounding_box [20, -70], [21, -69]
61
87
  }.results
62
88
 
63
- results.should_not include(@post)
89
+ expect(results).not_to include(@post)
64
90
  end
65
91
  end
66
92
 
@@ -82,7 +108,7 @@ describe "geospatial search" do
82
108
  order_by_geodist(:coordinates_new, 32, -68)
83
109
  }.results
84
110
 
85
- results.should == @posts.reverse
111
+ expect(results).to eq(@posts.reverse)
86
112
  end
87
113
 
88
114
  it "orders posts by distance descending" do
@@ -90,7 +116,7 @@ describe "geospatial search" do
90
116
  order_by_geodist(:coordinates_new, 32, -68, :desc)
91
117
  }.results
92
118
 
93
- results.should == @posts
119
+ expect(results).to eq(@posts)
94
120
  end
95
121
  end
96
122
  end
@@ -11,22 +11,22 @@ describe 'keyword highlighting' do
11
11
  end
12
12
 
13
13
  it 'should include highlights in the results' do
14
- @search_result.hits.first.highlights.length.should == 1
14
+ expect(@search_result.hits.first.highlights.length).to eq(1)
15
15
  end
16
16
 
17
17
  it 'should return formatted highlight fragments' do
18
- @search_result.hits.first.highlights(:body).first.format.should == 'And the <em>fox</em> laughed'
18
+ expect(@search_result.hits.first.highlights(:body).first.format).to eq('And the <em>fox</em> laughed')
19
19
  end
20
20
 
21
21
  it 'should be empty for non-keyword searches' do
22
22
  search_result = Sunspot.search(Post){ with :blog_id, 1 }
23
- search_result.hits.first.highlights.should be_empty
23
+ expect(search_result.hits.first.highlights).to be_empty
24
24
  end
25
25
 
26
26
  it "should process multiple keyword request on different fields with highlights correctly" do
27
27
  search_results = nil
28
- lambda do
29
- search_results = Sunspot.search(Post) do
28
+ expect do
29
+ search_results = Sunspot.search(Post) do
30
30
  keywords 'Lorem ipsum', :fields => [:body] do
31
31
  highlight :body
32
32
  end
@@ -34,9 +34,9 @@ describe 'keyword highlighting' do
34
34
  highlight :title
35
35
  end
36
36
  end
37
- end.should_not raise_error(RSolr::Error::Http)
38
- search_results.results.length.should eq(1)
39
- search_results.results.first.should eq(@posts.last)
37
+ end.to_not raise_error
38
+ expect(search_results.results.length).to eq(1)
39
+ expect(search_results.results.first).to eq(@posts.last)
40
40
  # this one might be a Solr bug, therefore not related to Sunspot itself
41
41
  # search_results.hits.first.highlights.should_not be_empty
42
42
  end
@@ -2,33 +2,34 @@ require File.expand_path('../spec_helper', File.dirname(__FILE__))
2
2
 
3
3
  describe 'indexing' do
4
4
  it 'should index non-multivalued field with newlines' do
5
- lambda do
5
+ expect do
6
6
  Sunspot.index!(Post.new(:title => "A\nTitle"))
7
- end.should_not raise_error
7
+ end.not_to raise_error
8
8
  end
9
9
 
10
10
  it 'should correctly remove by model instance' do
11
11
  post = Post.new(:title => 'test post')
12
12
  Sunspot.index!(post)
13
13
  Sunspot.remove!(post)
14
- Sunspot.search(Post) { with(:title, 'test post') }.results.should be_empty
14
+ expect(Sunspot.search(Post) { with(:title, 'test post') }.results).to be_empty
15
15
  end
16
16
 
17
17
  it 'should correctly delete by ID' do
18
18
  post = Post.new(:title => 'test post')
19
19
  Sunspot.index!(post)
20
20
  Sunspot.remove_by_id!(Post, post.id)
21
- Sunspot.search(Post) { with(:title, 'test post') }.results.should be_empty
21
+ expect(Sunspot.search(Post) { with(:title, 'test post') }.results).to be_empty
22
22
  end
23
23
 
24
24
  it 'removes documents by query' do
25
25
  Sunspot.remove_all!
26
26
  posts = [Post.new(:title => 'birds'), Post.new(:title => 'monkeys')]
27
27
  Sunspot.index!(posts)
28
- Sunspot.remove! do
28
+
29
+ Sunspot.remove!(Post) do
29
30
  with(:title, 'birds')
30
31
  end
31
- Sunspot.search(Post).should have(2).results
32
+ expect(Sunspot.search(Post).results.size).to eq(1)
32
33
  end
33
34
 
34
35
 
@@ -0,0 +1,45 @@
1
+ require File.expand_path('../spec_helper', File.dirname(__FILE__))
2
+
3
+ describe "searching by joined fields" do
4
+ before :each do
5
+ Sunspot.remove_all!
6
+
7
+ @container1 = PhotoContainer.new(:id => 1)
8
+ @container2 = PhotoContainer.new(:id => 2).tap { |c| allow(c).to receive(:id).and_return(2) }
9
+ @container3 = PhotoContainer.new(:id => 3).tap { |c| allow(c).to receive(:id).and_return(3) }
10
+
11
+ @picture = Picture.new(:photo_container_id => @container1.id, :description => "one")
12
+ @photo1 = Photo.new(:photo_container_id => @container1.id, :description => "two")
13
+ @photo2 = Photo.new(:photo_container_id => @container2.id, :description => "three")
14
+
15
+ Sunspot.index!(@container1, @container2, @photo1, @photo2, @picture)
16
+ end
17
+
18
+ it "matches by joined fields" do
19
+ {
20
+ "one" => [],
21
+ "two" => [@container1],
22
+ "three" => [@container2]
23
+ }.each do |key, res|
24
+ results = Sunspot.search(PhotoContainer) {
25
+ fulltext(key, :fields => [:photo_description])
26
+ }.results
27
+
28
+ expect(results).to eq res
29
+ end
30
+ end
31
+
32
+ it "doesn't match by joined fields with the same name from other collections" do
33
+ {
34
+ "one" => [@container1],
35
+ "two" => [],
36
+ "three" => []
37
+ }.each do |key, res|
38
+ results = Sunspot.search(PhotoContainer) {
39
+ fulltext(key, :fields => [:picture_description])
40
+ }.results
41
+
42
+ expect(results).to eq res
43
+ end
44
+ end
45
+ end
@@ -16,36 +16,64 @@ describe 'keyword search' do
16
16
  Sunspot.index!(@comment)
17
17
  end
18
18
 
19
+ context 'edismax' do
20
+ it 'matches with wildcards' do
21
+ results = Sunspot.search(Post) { keywords '*oas*' }.results
22
+ [0,2].each { |i| expect(results).to include(@posts[i])}
23
+ [1].each { |i| expect(results).not_to include(@posts[i])}
24
+ end
25
+
26
+ it 'matches multiple keywords on different fields with wildcards using subqueries' do
27
+ results = Sunspot.search(Post) do
28
+ keywords 'insuffic*',:fields=>[:title]
29
+ keywords 'win*',:fields=>[:body]
30
+ end.results
31
+ [0].each {|i| expect(results).to include(@posts[i])}
32
+ [1,2].each {|i| expect(results).not_to include(@posts[i])}
33
+ end
34
+
35
+ it 'matches with proximity' do
36
+ results = Sunspot.search(Post) { keywords '"wind buffer"~4' }.results
37
+ [0,1].each {|i| expect(results).not_to include(@posts[i])}
38
+ [2].each {|i| expect(results).to include(@posts[i])}
39
+ end
40
+
41
+ it 'does not match if not within proximity' do
42
+ results = Sunspot.search(Post) { keywords '"wind buffer"~1' }.results
43
+ expect(results).to eq([])
44
+ end
45
+ end
46
+
19
47
  it 'matches a single keyword out of a single field' do
20
48
  results = Sunspot.search(Post) { keywords 'toast' }.results
21
- [0, 2].each { |i| results.should include(@posts[i]) }
22
- [1].each { |i| results.should_not include(@posts[i]) }
49
+ [0, 2].each { |i| expect(results).to include(@posts[i]) }
50
+ [1].each { |i| expect(results).not_to include(@posts[i]) }
23
51
  end
24
52
 
25
53
  it 'matches multiple words out of a single field' do
26
54
  results = Sunspot.search(Post) { keywords 'elects toast' }.results
27
- results.should == [@posts[0]]
55
+ expect(results).to eq([@posts[0]])
28
56
  end
29
57
 
30
58
  it 'matches multiple words in multiple fields' do
31
59
  results = Sunspot.search(Post) { keywords 'toast wind' }.results
32
- [0, 2].each { |i| results.should include(@posts[i]) }
33
- [1].each { |i| results.should_not include(@posts[i]) }
60
+ [0, 2].each { |i| expect(results).to include(@posts[i]) }
61
+ [1].each { |i| expect(results).not_to include(@posts[i]) }
34
62
  end
35
63
 
36
64
  it 'matches multiple types' do
37
65
  results = Sunspot.search(Post, Namespaced::Comment) do
38
66
  keywords 'toast'
39
67
  end.results
40
- [@posts[0], @posts[2], @comment].each { |obj| results.should include(obj) }
41
- results.should_not include(@posts[1])
68
+ [@posts[0], @posts[2], @comment].each { |obj| expect(results).to include(obj) }
69
+ expect(results).not_to include(@posts[1])
42
70
  end
43
71
 
44
72
  it 'matches keywords from only the fields specified' do
45
73
  results = Sunspot.search(Post) do
46
74
  keywords 'moron', :fields => [:title]
47
75
  end.results
48
- results.should == [@posts[1]]
76
+ expect(results).to eq([@posts[1]])
49
77
  end
50
78
 
51
79
  it 'matches multiple keywords on different fields using subqueries' do
@@ -53,13 +81,13 @@ describe 'keyword search' do
53
81
  keywords 'moron', :fields => [:title]
54
82
  keywords 'wind', :fields => [:body]
55
83
  end
56
- search.results.should == []
84
+ expect(search.results).to eq([])
57
85
 
58
86
  search = Sunspot.search(Post) do
59
87
  keywords 'moron', :fields => [:title]
60
88
  keywords 'buffer', :fields => [:body]
61
89
  end
62
- search.results.should == [@posts[1]]
90
+ expect(search.results).to eq([@posts[1]])
63
91
  end
64
92
 
65
93
  it 'matches multiple keywords with escaped characters' do
@@ -67,7 +95,7 @@ describe 'keyword search' do
67
95
  keywords 'spirit', :fields => [:title]
68
96
  keywords 'host\'s', :fields => [:body]
69
97
  end
70
- search.results.should == [@posts[2]]
98
+ expect(search.results).to eq([@posts[2]])
71
99
  end
72
100
 
73
101
  it 'matches multiple keywords with phrase-based search' do
@@ -76,7 +104,7 @@ describe 'keyword search' do
76
104
  keywords '"interpret the buffer"', :fields => [:body]
77
105
  keywords '"does the"', :fields => [:body]
78
106
  end
79
- search.results.should == [@posts[2]]
107
+ expect(search.results).to eq([@posts[2]])
80
108
  end
81
109
 
82
110
  it 'matches multiple keywords different options' do
@@ -84,7 +112,7 @@ describe 'keyword search' do
84
112
  keywords 'insufficient nonexistent', :fields => [:title], :minimum_match => 1
85
113
  keywords 'wind does', :fields => [:body], :minimum_match => 2
86
114
  end
87
- search.results.should == [@posts[0]]
115
+ expect(search.results).to eq([@posts[0]])
88
116
  end
89
117
  end
90
118
 
@@ -97,9 +125,10 @@ describe 'keyword search' do
97
125
 
98
126
  it 'should assign a higher score to the result matching the higher-boosted field' do
99
127
  search = Sunspot.search(Post) { keywords 'rhinoceros' }
100
- search.hits.map { |hit| hit.primary_key }.should ==
128
+ expect(search.hits.map { |hit| hit.primary_key }).to eq(
101
129
  @posts.map { |post| post.id.to_s }
102
- search.hits.first.score.should > search.hits.last.score
130
+ )
131
+ expect(search.hits.first.score).to be > search.hits.last.score
103
132
  end
104
133
  end
105
134
 
@@ -114,9 +143,10 @@ describe 'keyword search' do
114
143
 
115
144
  it 'should assign a higher score to the higher-boosted document' do
116
145
  search = Sunspot.search(Post) { keywords 'test' }
117
- search.hits.map { |hit| hit.primary_key }.should ==
146
+ expect(search.hits.map { |hit| hit.primary_key }).to eq(
118
147
  @posts.map { |post| post.id.to_s }
119
- search.hits.first.score.should > search.hits.last.score
148
+ )
149
+ expect(search.hits.first.score).to be > search.hits.last.score
120
150
  end
121
151
  end
122
152
 
@@ -136,8 +166,8 @@ describe 'keyword search' do
136
166
  phrase_fields :body => 2.0
137
167
  end
138
168
  end.hits
139
- hits.first.instance.should == @comments.first
140
- hits.first.score.should > hits.last.score
169
+ expect(hits.first.instance).to eq(@comments.first)
170
+ expect(hits.first.score).to be > hits.last.score
141
171
  end
142
172
 
143
173
  it 'assigns a higher score to documents in which the search terms appear in a boosted field' do
@@ -146,8 +176,8 @@ describe 'keyword search' do
146
176
  fields :body => 2.0, :author_name => 0.75
147
177
  end
148
178
  end.hits
149
- hits.first.instance.should == @comments.first
150
- hits.first.score.should > hits.last.score
179
+ expect(hits.first.instance).to eq(@comments.first)
180
+ expect(hits.first.score).to be > hits.last.score
151
181
  end
152
182
 
153
183
  it 'assigns a higher score to documents in which the search terms appear in a higher boosted phrase field' do
@@ -156,8 +186,8 @@ describe 'keyword search' do
156
186
  phrase_fields :body => 2.0, :author_name => 0.75
157
187
  end
158
188
  end.hits
159
- hits.first.instance.should == @comments.first
160
- hits.first.score.should > hits.last.score
189
+ expect(hits.first.instance).to eq(@comments.first)
190
+ expect(hits.first.score).to be > hits.last.score
161
191
  end
162
192
  end
163
193
 
@@ -182,8 +212,8 @@ describe 'keyword search' do
182
212
  end
183
213
  query.without(@posts[1])
184
214
  end
185
- search.results.should == [@posts[0], @posts[2]]
186
- search.hits[0].score.should > search.hits[1].score
215
+ expect(search.results).to eq([@posts[0], @posts[2]])
216
+ expect(search.hits[0].score).to be > search.hits[1].score
187
217
  end
188
218
 
189
219
  it 'should assign scores in order of multiple boost query match' do
@@ -193,9 +223,9 @@ describe 'keyword search' do
193
223
  boost(1.5) { with(:average_rating).greater_than(3.0) }
194
224
  end
195
225
  end
196
- search.results.should == @posts
197
- search.hits[0].score.should > search.hits[1].score
198
- search.hits[1].score.should > search.hits[2].score
226
+ expect(search.results).to eq(@posts)
227
+ expect(search.hits[0].score).to be > search.hits[1].score
228
+ expect(search.hits[1].score).to be > search.hits[2].score
199
229
  end
200
230
  end
201
231
 
@@ -213,11 +243,11 @@ describe 'keyword search' do
213
243
  end
214
244
 
215
245
  it 'should match documents that contain the minimum_match number of search terms' do
216
- @search.results.should include(@posts[0])
246
+ expect(@search.results).to include(@posts[0])
217
247
  end
218
248
 
219
249
  it 'should not match documents that do not contain the minimum_match number of search terms' do
220
- @search.results.should_not include(@posts[1])
250
+ expect(@search.results).not_to include(@posts[1])
221
251
  end
222
252
  end
223
253
 
@@ -236,15 +266,15 @@ describe 'keyword search' do
236
266
  end
237
267
 
238
268
  it 'should match exact phrase' do
239
- @search.results.should include(@posts[0])
269
+ expect(@search.results).to include(@posts[0])
240
270
  end
241
271
 
242
272
  it 'should match phrase divided by query phrase slop terms' do
243
- @search.results.should include(@posts[1])
273
+ expect(@search.results).to include(@posts[1])
244
274
  end
245
275
 
246
276
  it 'should not match phrase divided by more than query phrase slop terms' do
247
- @search.results.should_not include(@posts[2])
277
+ expect(@search.results).not_to include(@posts[2])
248
278
  end
249
279
  end
250
280
 
@@ -270,15 +300,15 @@ describe 'keyword search' do
270
300
  end
271
301
 
272
302
  it 'should give phrase field boost to exact match' do
273
- @sorted_hits[0].score.should > @sorted_hits[1].score
303
+ expect(@sorted_hits[0].score).to be > @sorted_hits[1].score
274
304
  end
275
305
 
276
306
  it 'should give phrase field boost to match within slop' do
277
- @sorted_hits[2].score.should > @sorted_hits[3].score
307
+ expect(@sorted_hits[2].score).to be > @sorted_hits[3].score
278
308
  end
279
309
 
280
310
  it 'should not give phrase field boost to match beyond slop' do
281
- @sorted_hits[4].score.should == @sorted_hits[5].score
311
+ expect(@sorted_hits[4].score).to eq(@sorted_hits[5].score)
282
312
  end
283
313
  end
284
314
 
@@ -288,8 +318,8 @@ describe 'keyword search' do
288
318
  end
289
319
 
290
320
  after :each do
291
- @search.results.should == @posts
292
- @search.hits.first.score.should > @search.hits.last.score
321
+ expect(@search.results).to eq(@posts)
322
+ expect(@search.hits.first.score).to be > @search.hits.last.score
293
323
  end
294
324
 
295
325
  it 'boosts via function query with float' do