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
@@ -25,13 +25,13 @@ describe 'local search' do
25
25
  end
26
26
 
27
27
  it 'should return results in geo order' do
28
- @search.results.should == @posts
28
+ expect(@search.results).to eq(@posts)
29
29
  end
30
30
 
31
31
  it 'should asssign higher score to closer locations' do
32
32
  hits = @search.hits
33
33
  hits[1..-1].each_with_index do |hit, i|
34
- hit.score.should < hits[i].score
34
+ expect(hit.score).to be < hits[i].score
35
35
  end
36
36
  end
37
37
  end
@@ -51,13 +51,13 @@ describe 'local search' do
51
51
  end
52
52
 
53
53
  it 'should take both fulltext and distance into account in ordering' do
54
- @search.results.should == @posts
54
+ expect(@search.results).to eq(@posts)
55
55
  end
56
56
 
57
57
  it 'should take both fulltext and distance into account in scoring' do
58
58
  hits = @search.hits
59
59
  hits[1..-1].each_with_index do |hit, i|
60
- hit.score.should < hits[i].score
60
+ expect(hit.score).to be < hits[i].score
61
61
  end
62
62
  end
63
63
  end
@@ -14,30 +14,30 @@ describe 'more_like_this' do
14
14
  end
15
15
 
16
16
  it 'should return results for all MLT fields' do
17
- Sunspot.more_like_this(@posts.first).results.to_set.should == @posts[1..3].to_set
17
+ expect(Sunspot.more_like_this(@posts.first).results.to_set).to eq(@posts[1..3].to_set)
18
18
  end
19
19
 
20
20
  it 'should return results for specified text field' do
21
- Sunspot.more_like_this(@posts.first) do
21
+ expect(Sunspot.more_like_this(@posts.first) do
22
22
  fields :body
23
- end.results.to_set.should == @posts[2..3].to_set
23
+ end.results.to_set).to eq(@posts[2..3].to_set)
24
24
  end
25
25
 
26
26
  it 'should return empty result set if no results' do
27
- Sunspot.more_like_this(@posts.last) do
27
+ expect(Sunspot.more_like_this(@posts.last) do
28
28
  with(:title, 'bogus')
29
- end.results.should == []
29
+ end.results).to eq([])
30
30
  end
31
31
 
32
32
  describe 'when non-indexed object searched' do
33
33
  before(:each) { @mlt = Sunspot.more_like_this(Post.new) }
34
34
 
35
35
  it 'should return empty result set' do
36
- @mlt.results.should == []
36
+ expect(@mlt.results).to eq([])
37
37
  end
38
38
 
39
39
  it 'shoult return a total of 0' do
40
- @mlt.total.should == 0
40
+ expect(@mlt.total).to eq(0)
41
41
  end
42
42
  end
43
43
  end
@@ -22,95 +22,95 @@ describe 'scoped_search' do
22
22
  end
23
23
 
24
24
  it 'should filter by exact match' do
25
- Sunspot.search(clazz) { with(field, values[2]) }.results.should == [@objects[2]]
25
+ expect(Sunspot.search(clazz) { with(field, values[2]) }.results).to eq([@objects[2]])
26
26
  end
27
27
 
28
28
  it 'should reject by inexact match' do
29
29
  results = Sunspot.search(clazz) { without(field, values[2]) }.results
30
- [0, 1, 3, 4].each { |i| results.should include(@objects[i]) }
31
- results.should_not include(@objects[2])
30
+ [0, 1, 3, 4].each { |i| expect(results).to include(@objects[i]) }
31
+ expect(results).not_to include(@objects[2])
32
32
  end
33
33
 
34
34
  it 'should filter by less than' do
35
35
  results = Sunspot.search(clazz) { with(field).less_than values[2] }.results
36
- (0..1).each { |i| results.should include(@objects[i]) }
37
- (2..4).each { |i| results.should_not include(@objects[i]) }
36
+ (0..1).each { |i| expect(results).to include(@objects[i]) }
37
+ (2..4).each { |i| expect(results).not_to include(@objects[i]) }
38
38
  end
39
39
 
40
40
  it 'should reject by less than' do
41
41
  results = Sunspot.search(clazz) { without(field).less_than values[2] }.results
42
- (0..1).each { |i| results.should_not include(@objects[i]) }
43
- (2..4).each { |i| results.should include(@objects[i]) }
42
+ (0..1).each { |i| expect(results).not_to include(@objects[i]) }
43
+ (2..4).each { |i| expect(results).to include(@objects[i]) }
44
44
  end
45
45
 
46
46
  it 'should filter by less than or equal to' do
47
47
  results = Sunspot.search(clazz) { with(field).less_than_or_equal_to values[2] }.results
48
- (0..2).each { |i| results.should include(@objects[i]) }
49
- (3..4).each { |i| results.should_not include(@objects[i]) }
48
+ (0..2).each { |i| expect(results).to include(@objects[i]) }
49
+ (3..4).each { |i| expect(results).not_to include(@objects[i]) }
50
50
  end
51
51
 
52
52
  it 'should reject by less than or equal to' do
53
53
  results = Sunspot.search(clazz) { without(field).less_than_or_equal_to values[2] }.results
54
- (0..2).each { |i| results.should_not include(@objects[i]) }
55
- (3..4).each { |i| results.should include(@objects[i]) }
54
+ (0..2).each { |i| expect(results).not_to include(@objects[i]) }
55
+ (3..4).each { |i| expect(results).to include(@objects[i]) }
56
56
  end
57
57
 
58
58
  it 'should filter by greater than' do
59
59
  results = Sunspot.search(clazz) { with(field).greater_than values[2] }.results
60
- (3..4).each { |i| results.should include(@objects[i]) }
61
- (0..2).each { |i| results.should_not include(@objects[i]) }
60
+ (3..4).each { |i| expect(results).to include(@objects[i]) }
61
+ (0..2).each { |i| expect(results).not_to include(@objects[i]) }
62
62
  end
63
63
 
64
64
  it 'should reject by greater than' do
65
65
  results = Sunspot.search(clazz) { without(field).greater_than values[2] }.results
66
- (3..4).each { |i| results.should_not include(@objects[i]) }
67
- (0..2).each { |i| results.should include(@objects[i]) }
66
+ (3..4).each { |i| expect(results).not_to include(@objects[i]) }
67
+ (0..2).each { |i| expect(results).to include(@objects[i]) }
68
68
  end
69
69
 
70
70
  it 'should filter by greater than or equal to' do
71
71
  results = Sunspot.search(clazz) { with(field).greater_than_or_equal_to values[2] }.results
72
- (2..4).each { |i| results.should include(@objects[i]) }
73
- (0..1).each { |i| results.should_not include(@objects[i]) }
72
+ (2..4).each { |i| expect(results).to include(@objects[i]) }
73
+ (0..1).each { |i| expect(results).not_to include(@objects[i]) }
74
74
  end
75
75
 
76
76
  it 'should reject by greater than' do
77
77
  results = Sunspot.search(clazz) { without(field).greater_than_or_equal_to values[2] }.results
78
- (2..4).each { |i| results.should_not include(@objects[i]) }
79
- (0..1).each { |i| results.should include(@objects[i]) }
78
+ (2..4).each { |i| expect(results).not_to include(@objects[i]) }
79
+ (0..1).each { |i| expect(results).to include(@objects[i]) }
80
80
  end
81
81
 
82
82
  it 'should filter by between' do
83
83
  results = Sunspot.search(clazz) { with(field).between(values[1]..values[3]) }.results
84
- (1..3).each { |i| results.should include(@objects[i]) }
85
- [0, 4].each { |i| results.should_not include(@objects[i]) }
84
+ (1..3).each { |i| expect(results).to include(@objects[i]) }
85
+ [0, 4].each { |i| expect(results).not_to include(@objects[i]) }
86
86
  end
87
87
 
88
88
  it 'should reject by between' do
89
89
  results = Sunspot.search(clazz) { without(field).between(values[1]..values[3]) }.results
90
- (1..3).each { |i| results.should_not include(@objects[i]) }
91
- [0, 4].each { |i| results.should include(@objects[i]) }
90
+ (1..3).each { |i| expect(results).not_to include(@objects[i]) }
91
+ [0, 4].each { |i| expect(results).to include(@objects[i]) }
92
92
  end
93
93
 
94
94
  it 'should filter by any of' do
95
95
  results = Sunspot.search(clazz) { with(field).any_of(values.values_at(1, 3)) }.results
96
- [1, 3].each { |i| results.should include(@objects[i]) }
97
- [0, 2, 4].each { |i| results.should_not include(@objects[i]) }
96
+ [1, 3].each { |i| expect(results).to include(@objects[i]) }
97
+ [0, 2, 4].each { |i| expect(results).not_to include(@objects[i]) }
98
98
  end
99
99
 
100
100
  it 'should reject by any of' do
101
101
  results = Sunspot.search(clazz) { without(field).any_of(values.values_at(1, 3)) }.results
102
- [1, 3].each { |i| results.should_not include(@objects[i]) }
103
- [0, 2, 4].each { |i| results.should include(@objects[i]) }
102
+ [1, 3].each { |i| expect(results).not_to include(@objects[i]) }
103
+ [0, 2, 4].each { |i| expect(results).to include(@objects[i]) }
104
104
  end
105
105
 
106
106
  it 'should order by field ascending' do
107
107
  results = Sunspot.search(clazz) { order_by field, :asc }.results
108
- results.should == @objects
108
+ expect(results).to eq(@objects)
109
109
  end
110
110
 
111
111
  it 'should order by field descending' do
112
112
  results = Sunspot.search(clazz) { order_by field, :desc }.results
113
- results.should == @objects.reverse
113
+ expect(results).to eq(@objects.reverse)
114
114
  end
115
115
  end
116
116
  end
@@ -126,6 +126,56 @@ describe 'scoped_search' do
126
126
  test_field_type 'Trie Float', :average_rating, :average_rating, Photo, -2.5, 0.0, 3.2, 3.5, 16.0
127
127
  test_field_type 'Trie Time', :created_at, :created_at, Photo, *(['1970-01-01 00:00:00 UTC', '1983-07-08 04:00:00 UTC', '1983-07-08 02:00:00 -0500',
128
128
  '2005-11-05 10:00:00 UTC', Time.now.to_s].map { |t| Time.parse(t) })
129
+ describe 'Date range field type' do
130
+ let(:date_ranges) do
131
+ {
132
+ 'December and January' => Date.new(2014,12,25)..Date.new(2015,1,10),
133
+ 'January only' => Date.new(2015,1,5)..Date.new(2015,1,20),
134
+ 'January and February' => Date.new(2015,1,25)..Date.new(2015,2,10),
135
+ 'February only' => Date.new(2015,2,5)..Date.new(2015,2,20),
136
+ 'December to February' => Date.new(2014,12,25)..Date.new(2015,2,10),
137
+ 'January to March' => Date.new(2015,1,25)..Date.new(2015,3,10),
138
+ 'December to March' => Date.new(2014,12,25)..Date.new(2015,3,20)
139
+ }
140
+ end
141
+
142
+ before :all do
143
+ january = Date.new(2015,1,1)..Date.new(2015,1,31)
144
+ february = Date.new(2015,2,1)..Date.new(2015,2,28)
145
+ Sunspot.remove_all
146
+ @posts = [Post.new(featured_for: january), Post.new(featured_for: february), Post.new]
147
+ Sunspot.index!(@posts)
148
+ end
149
+
150
+ it 'should filter by Contains' do
151
+ expect(featured_for_posts(:containing, Date.new(2015,1,15) )).to eq([@posts[0]])
152
+ expect(featured_for_posts(:containing, 'December and January')).to be_empty
153
+ expect(featured_for_posts(:containing, 'January only')).to eq([@posts[0]])
154
+ expect(featured_for_posts(:containing, 'January only', negated = true)).to eq(@posts[1..-1])
155
+ end
156
+
157
+ it 'should filter by Intersects' do
158
+ expect(featured_for_posts(:intersecting, Date.new(2015,1,15) )).to eq([@posts[0]])
159
+ expect(featured_for_posts(:intersecting, 'January only')).to eq([@posts[0]])
160
+ expect(featured_for_posts(:intersecting, 'January and February')).to eq(@posts[0..1])
161
+ expect(featured_for_posts(:intersecting, 'January and February', negated = true)).to eq([@posts[2]])
162
+ expect(featured_for_posts(:intersecting, 'February only')).to eq([@posts[1]])
163
+ expect(featured_for_posts(:intersecting, 'February only', negated = true)).to eq([@posts[0], @posts[2]])
164
+ end
165
+
166
+ it 'should filter by Within' do
167
+ expect(featured_for_posts(:within, Date.new(2015,1,15) )).to be_empty
168
+ (date_ranges.keys - date_ranges.keys.grep(/ to /)).each do |key|
169
+ expect(featured_for_posts(:within, key)).to be_empty
170
+ end
171
+ expect(featured_for_posts(:within, 'December to February')).to eq([@posts[0]])
172
+ expect(featured_for_posts(:within, 'December to February', negated = true)).to eq(@posts[1..-1])
173
+ expect(featured_for_posts(:within, 'January to March')).to eq([@posts[1]])
174
+ expect(featured_for_posts(:within, 'January to March', negated = true)).to eq([@posts[0], @posts[2]])
175
+ expect(featured_for_posts(:within, 'December to March')).to eq(@posts[0..1])
176
+ expect(featured_for_posts(:within, 'December to March', negated = true)).to eq([@posts[2]])
177
+ end
178
+ end
129
179
 
130
180
  describe 'Boolean field type' do
131
181
  before :all do
@@ -135,11 +185,11 @@ describe 'scoped_search' do
135
185
  end
136
186
 
137
187
  it 'should filter by exact match for true' do
138
- Sunspot.search(Post) { with(:featured, true) }.results.should == [@posts[0]]
188
+ expect(Sunspot.search(Post) { with(:featured, true) }.results).to eq([@posts[0]])
139
189
  end
140
190
 
141
191
  it 'should filter for exact match for false' do
142
- Sunspot.search(Post) { with(:featured, false) }.results.should == [@posts[1]]
192
+ expect(Sunspot.search(Post) { with(:featured, false) }.results).to eq([@posts[1]])
143
193
  end
144
194
  end
145
195
 
@@ -147,7 +197,7 @@ describe 'scoped_search' do
147
197
  it "allows for using symbols in defining static field names" do
148
198
  Sunspot.remove_all
149
199
  Sunspot.index!(legacy = Post.new(:title => "foo"))
150
- Sunspot.search(Post) { with(:legacy, "legacy foo") }.results.should == [legacy]
200
+ expect(Sunspot.search(Post) { with(:legacy, "legacy foo") }.results).to eq([legacy])
151
201
  end
152
202
  end
153
203
 
@@ -155,7 +205,7 @@ describe 'scoped_search' do
155
205
  %w(AND OR NOT TO).each do |word|
156
206
  it "should successfully search for #{word.inspect}" do
157
207
  Sunspot.index!(post = Post.new(:title => word))
158
- Sunspot.search(Post) { with(:title, word) }.results.should == [post]
208
+ expect(Sunspot.search(Post) { with(:title, word) }.results).to eq([post])
159
209
  end
160
210
  end
161
211
  end
@@ -168,11 +218,11 @@ describe 'scoped_search' do
168
218
  end
169
219
 
170
220
  it 'should filter results without value for field' do
171
- Sunspot.search(Post) { with(:title, nil) }.results.should == [@posts[1]]
221
+ expect(Sunspot.search(Post) { with(:title, nil) }.results).to eq([@posts[1]])
172
222
  end
173
223
 
174
224
  it 'should exclude results without value for field' do
175
- Sunspot.search(Post) { without(:title, nil) }.results.should == [@posts[0]]
225
+ expect(Sunspot.search(Post) { without(:title, nil) }.results).to eq([@posts[0]])
176
226
  end
177
227
  end
178
228
 
@@ -186,12 +236,13 @@ describe 'scoped_search' do
186
236
  end
187
237
 
188
238
  it 'should return results whose prefix matches' do
189
- Sunspot.search(Post) { with(:title).starting_with('test') }.results.should == @posts[0..1]
239
+ expect(Sunspot.search(Post) { with(:title).starting_with('test') }.results).to eq(@posts[0..1])
190
240
  end
191
241
  end
192
242
 
193
243
  describe 'inclusion by identity' do
194
244
  before do
245
+ Sunspot.remove_all
195
246
  @posts = (1..5).map do |i|
196
247
  post = Post.new
197
248
  Sunspot.index(post)
@@ -202,26 +253,27 @@ describe 'scoped_search' do
202
253
 
203
254
  it 'should only return included object' do
204
255
  included_post = @posts.shift
205
- Sunspot.search(Post) { with(included_post) }.results.should include(included_post)
256
+ expect(Sunspot.search(Post) { with(included_post) }.results).to include(included_post)
206
257
  end
207
258
 
208
259
  it 'should not return objects not included' do
209
260
  included_post = @posts.shift
210
261
  for excluded_post in @posts
211
- Sunspot.search(Post) { with(included_post) }.results.should_not include(excluded_post)
262
+ expect(Sunspot.search(Post) { with(included_post) }.results).not_to include(excluded_post)
212
263
  end
213
264
  end
214
265
 
215
266
  it 'should return included objects' do
216
267
  included_posts = [@posts.shift, @posts.shift]
217
268
  for included_post in included_posts
218
- Sunspot.search(Post) { with(included_posts) }.results.should include(included_post)
269
+ expect(Sunspot.search(Post) { with(included_posts) }.results).to include(included_post)
219
270
  end
220
271
  end
221
272
  end
222
273
 
223
274
  describe 'exclusion by identity' do
224
275
  before do
276
+ Sunspot.remove_all
225
277
  @posts = (1..5).map do |i|
226
278
  post = Post.new
227
279
  Sunspot.index(post)
@@ -232,20 +284,20 @@ describe 'scoped_search' do
232
284
 
233
285
  it 'should not return excluded object' do
234
286
  excluded_post = @posts.shift
235
- Sunspot.search(Post) { without(excluded_post) }.results.should_not include(excluded_post)
287
+ expect(Sunspot.search(Post) { without(excluded_post) }.results).not_to include(excluded_post)
236
288
  end
237
289
 
238
290
  it 'should return objects not excluded' do
239
291
  excluded_post = @posts.shift
240
292
  for included_post in @posts
241
- Sunspot.search(Post) { without(excluded_post) }.results.should include(included_post)
293
+ expect(Sunspot.search(Post) { without(excluded_post) }.results).to include(included_post)
242
294
  end
243
295
  end
244
296
 
245
297
  it 'should not return excluded objects' do
246
298
  excluded_posts = [@posts.shift, @posts.shift]
247
299
  for excluded_post in excluded_posts
248
- Sunspot.search(Post) { without(excluded_posts) }.results.should_not include(excluded_post)
300
+ expect(Sunspot.search(Post) { without(excluded_posts) }.results).not_to include(excluded_post)
249
301
  end
250
302
  end
251
303
  end
@@ -258,12 +310,50 @@ describe 'scoped_search' do
258
310
  it 'should return results that match any restriction in a disjunction' do
259
311
  posts = (1..3).map { |i| Post.new(:blog_id => i)}
260
312
  Sunspot.index!(posts)
261
- Sunspot.search(Post) do
313
+ expect(Sunspot.search(Post) do
262
314
  any_of do
263
315
  with(:blog_id, 1)
264
316
  with(:blog_id, 2)
265
317
  end
266
- end.results.should == posts[0..1]
318
+ end.results).to eq(posts[0..1])
319
+ end
320
+
321
+ it 'should return results, ignoring any restriction in a disjunction that has been passed an empty array' do
322
+ posts = (1..3).map { |i| Post.new(:blog_id => i)}
323
+ Sunspot.index!(posts)
324
+ expect(Sunspot.search(Post) do
325
+ with(:blog_id, [])
326
+ end.results).to eq(posts)
327
+ end
328
+
329
+ it 'should return results, ignoring any restriction in a negative disjunction that has been passed an empty array' do
330
+ posts = (1..3).map { |i| Post.new(:blog_id => i)}
331
+ Sunspot.index!(posts)
332
+ expect(Sunspot.search(Post) do
333
+ without(:blog_id, [])
334
+ end.results).to eq(posts)
335
+ end
336
+
337
+ it 'should return results, ignoring any restriction in a conjunction that has been passed an empty array' do
338
+ posts = (1..3).map { |i| Post.new(:blog_id => i)}
339
+ Sunspot.index!(posts)
340
+ expect(Sunspot.search(Post) do
341
+ all_of do
342
+ with(:blog_id, 1)
343
+ with(:blog_id, [])
344
+ end
345
+ end.results).to eq(posts[0..0])
346
+ end
347
+
348
+ it 'should return results, ignoring any restriction in a negative conjunction that has been passed an empty array' do
349
+ posts = (1..3).map { |i| Post.new(:blog_id => i)}
350
+ Sunspot.index!(posts)
351
+ expect(Sunspot.search(Post) do
352
+ all_of do
353
+ with(:blog_id, 1)
354
+ without(:blog_id, [])
355
+ end
356
+ end.results).to eq(posts[0..0])
267
357
  end
268
358
 
269
359
  it 'should return results that match a nested conjunction in a disjunction' do
@@ -274,7 +364,7 @@ describe 'scoped_search' do
274
364
  Post.new(:title => 'No', :blog_id => 2)
275
365
  ]
276
366
  Sunspot.index!(posts)
277
- Sunspot.search(Post) do
367
+ expect(Sunspot.search(Post) do
278
368
  any_of do
279
369
  with(:blog_id, 1)
280
370
  all_of do
@@ -282,7 +372,7 @@ describe 'scoped_search' do
282
372
  with(:title, 'Yes')
283
373
  end
284
374
  end
285
- end.results.should == posts[0..1]
375
+ end.results).to eq(posts[0..1])
286
376
  end
287
377
 
288
378
  it 'should return results that match a conjunction with a negated restriction' do
@@ -298,7 +388,7 @@ describe 'scoped_search' do
298
388
  without(:title, 'No')
299
389
  end
300
390
  end
301
- search.results.should == posts[0..1]
391
+ expect(search.results).to eq(posts[0..1])
302
392
  end
303
393
 
304
394
  it 'should return results that match a conjunction with a disjunction with a conjunction with a negated restriction' do
@@ -322,7 +412,7 @@ describe 'scoped_search' do
322
412
  end
323
413
  end
324
414
  end
325
- search.results.should == posts[0..2]
415
+ expect(search.results).to eq(posts[0..2])
326
416
  end
327
417
 
328
418
  it 'should return results that match a disjunction with a negated restriction and a nested disjunction in a conjunction with a negated restriction' do
@@ -347,7 +437,7 @@ describe 'scoped_search' do
347
437
  end
348
438
  end
349
439
  end
350
- search.results.should == posts[0..2]
440
+ expect(search.results).to eq(posts[0..2])
351
441
  end
352
442
  end
353
443
 
@@ -367,7 +457,7 @@ describe 'scoped_search' do
367
457
  order_by :average_rating, :desc
368
458
  order_by :sort_title, :asc
369
459
  end
370
- search.results.should == @posts
460
+ expect(search.results).to eq(@posts)
371
461
  end
372
462
  end
373
463
 
@@ -377,46 +467,75 @@ describe 'scoped_search' do
377
467
  Sunspot.index!(Array.new(100) { Post.new })
378
468
  end
379
469
 
380
- it 'should order randomly (run this test again if it fails)' do
381
- result_sets = Array.new(2) do
382
- Sunspot.search(Post) { order_by_random }.results.map do |result|
383
- result.id
384
- end
470
+ def search_ordered_by_random(direction = nil)
471
+ Sunspot.search(Post) do
472
+ order_by(:random, direction)
473
+ paginate(:page => 1, :per_page => 100)
385
474
  end
386
- result_sets[0].should_not == result_sets[1]
387
475
  end
388
476
 
389
- # This could fail if the random set returned just happens to be the same as the last random set (the nature of randomness)
477
+ it 'should order randomly' do
478
+ result_sets = Array.new(5) do
479
+ search_ordered_by_random.results.map { |result| result.id }
480
+ end
481
+ expect(result_sets.uniq.size).to be > 1
482
+ end
483
+
390
484
  it 'should order randomly using the order_by function and passing a direction' do
391
- result_sets = Array.new(2) do
392
- Sunspot.search(Post) { order_by(:random, :desc) }.results.map do |result|
393
- result.id
394
- end
485
+ result_sets = Array.new(5) do
486
+ search_ordered_by_random(:desc).results.map { |result| result.id }
395
487
  end
396
- result_sets[0].should_not == result_sets[1]
488
+ expect(result_sets.uniq.size).to be > 1
397
489
  end
398
490
 
399
491
  context 'when providing a custom seed value' do
400
492
  before do
401
- @first_results = Sunspot.search(Post) do
402
- order_by(:random, :seed => 12345)
403
- end.results.map { |result| result.id }
493
+ @first_results = search_ordered_by_random(:seed => 12345).results.map { |result| result.id }
404
494
  end
405
495
 
406
- # This could fail if the random set returned just happens to be the same as the last random set (the nature of randomness)
407
496
  it 'should return different results when passing a different seed value' do
408
- next_results = Sunspot.search(Post) do
409
- order_by(:random, :seed => 54321)
410
- end.results.map { |result| result.id }
411
- next_results.should_not == @first_results
497
+ next_results = search_ordered_by_random(:seed => 54321).results.map { |result| result.id }
498
+ expect(next_results).not_to eq(@first_results)
412
499
  end
413
500
 
414
501
  it 'should return the same results when passing the same seed value' do
415
- next_results = Sunspot.search(Post) do
416
- order_by(:random, :seed => 12345)
417
- end.results.map { |result| result.id }
418
- next_results.should == @first_results
502
+ next_results = search_ordered_by_random(:seed => 12345).results.map { |result| result.id }
503
+ expect(next_results).to eq(@first_results)
419
504
  end
420
505
  end
421
506
  end
507
+
508
+ describe 'ordering by function' do
509
+ before :all do
510
+ Sunspot.remove_all
511
+ @p1 = Post.new(:blog_id => 1, :category_ids => [3])
512
+ @p2 = Post.new(:blog_id => 2, :category_ids => [1])
513
+ Sunspot.index([@p1,@p2])
514
+ Sunspot.commit
515
+ end
516
+
517
+ it 'should order by sum' do
518
+ # 1+3 > 2+1
519
+ search = Sunspot.search(Post) {order_by_function :sum, :blog_id, :primary_category_id, :desc}
520
+ expect(search.results.first).to eq(@p1)
521
+ end
522
+
523
+ it 'should order by product and sum' do
524
+ # 1 * (1+3) < 2 * (2+1)
525
+ search = Sunspot.search(Post) { order_by_function :product, :blog_id, [:sum,:blog_id,:primary_category_id], :desc}
526
+ expect(search.results.first).to eq(@p2)
527
+ end
528
+
529
+ it 'should accept string literals' do
530
+ # (1 * -2) > (2 * -2)
531
+ search = Sunspot.search(Post) {order_by_function :product, :blog_id, '-2', :desc}
532
+ expect(search.results.first).to eq(@p1)
533
+ end
534
+
535
+ it 'should accept non-string literals' do
536
+ # (1 * -2) > (2 * -2)
537
+ search = Sunspot.search(Post) {order_by_function :product, :blog_id, -2, :desc}
538
+ expect(search.results.first).to eq(@p1)
539
+ end
540
+ end
422
541
  end