sunspot 2.2.7 → 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 (117) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rspec +2 -0
  4. data/Appraisals +7 -0
  5. data/Gemfile +0 -8
  6. data/lib/sunspot/adapters.rb +4 -1
  7. data/lib/sunspot/configuration.rb +1 -0
  8. data/lib/sunspot/data_extractor.rb +36 -6
  9. data/lib/sunspot/dsl/field_query.rb +11 -0
  10. data/lib/sunspot/dsl/field_stats.rb +7 -0
  11. data/lib/sunspot/dsl/fields.rb +16 -0
  12. data/lib/sunspot/dsl/group.rb +10 -0
  13. data/lib/sunspot/dsl/scope.rb +23 -18
  14. data/lib/sunspot/field.rb +11 -0
  15. data/lib/sunspot/field_factory.rb +6 -2
  16. data/lib/sunspot/query/abstract_json_field_facet.rb +70 -0
  17. data/lib/sunspot/query/bbox.rb +5 -1
  18. data/lib/sunspot/query/date_field_json_facet.rb +25 -0
  19. data/lib/sunspot/query/field_json_facet.rb +19 -0
  20. data/lib/sunspot/query/field_stats.rb +35 -2
  21. data/lib/sunspot/query/group.rb +4 -5
  22. data/lib/sunspot/query/join.rb +2 -4
  23. data/lib/sunspot/query/range_json_facet.rb +28 -0
  24. data/lib/sunspot/query/restriction.rb +19 -4
  25. data/lib/sunspot/query.rb +3 -3
  26. data/lib/sunspot/schema.rb +10 -2
  27. data/lib/sunspot/search/abstract_search.rb +14 -1
  28. data/lib/sunspot/search/field_json_facet.rb +33 -0
  29. data/lib/sunspot/search/hit.rb +6 -1
  30. data/lib/sunspot/search/hit_enumerable.rb +4 -1
  31. data/lib/sunspot/search/json_facet_row.rb +40 -0
  32. data/lib/sunspot/search/json_facet_stats.rb +23 -0
  33. data/lib/sunspot/search/standard_search.rb +2 -3
  34. data/lib/sunspot/search/stats_json_row.rb +82 -0
  35. data/lib/sunspot/search/stats_row.rb +3 -1
  36. data/lib/sunspot/search.rb +4 -3
  37. data/lib/sunspot/session.rb +13 -5
  38. data/lib/sunspot/setup.rb +31 -0
  39. data/lib/sunspot/util.rb +23 -0
  40. data/lib/sunspot/version.rb +1 -1
  41. data/spec/api/adapters_spec.rb +32 -19
  42. data/spec/api/batcher_spec.rb +15 -15
  43. data/spec/api/binding_spec.rb +3 -3
  44. data/spec/api/class_set_spec.rb +3 -3
  45. data/spec/api/data_extractor_spec.rb +39 -0
  46. data/spec/api/hit_enumerable_spec.rb +32 -9
  47. data/spec/api/indexer/attributes_spec.rb +31 -31
  48. data/spec/api/indexer/batch_spec.rb +8 -7
  49. data/spec/api/indexer/dynamic_fields_spec.rb +8 -8
  50. data/spec/api/indexer/fixed_fields_spec.rb +12 -12
  51. data/spec/api/indexer/fulltext_spec.rb +8 -8
  52. data/spec/api/indexer/removal_spec.rb +14 -14
  53. data/spec/api/indexer_spec.rb +2 -2
  54. data/spec/api/query/advanced_manipulation_examples.rb +3 -3
  55. data/spec/api/query/connectives_examples.rb +26 -14
  56. data/spec/api/query/dsl_spec.rb +17 -9
  57. data/spec/api/query/dynamic_fields_examples.rb +18 -18
  58. data/spec/api/query/faceting_examples.rb +62 -62
  59. data/spec/api/query/fulltext_examples.rb +63 -58
  60. data/spec/api/query/function_spec.rb +26 -26
  61. data/spec/api/query/geo_examples.rb +6 -6
  62. data/spec/api/query/group_spec.rb +6 -6
  63. data/spec/api/query/highlighting_examples.rb +26 -26
  64. data/spec/api/query/join_spec.rb +2 -2
  65. data/spec/api/query/more_like_this_spec.rb +29 -29
  66. data/spec/api/query/ordering_pagination_examples.rb +25 -25
  67. data/spec/api/query/scope_examples.rb +39 -39
  68. data/spec/api/query/spatial_examples.rb +3 -3
  69. data/spec/api/query/spellcheck_examples.rb +3 -3
  70. data/spec/api/query/standard_spec.rb +1 -1
  71. data/spec/api/query/stats_examples.rb +8 -8
  72. data/spec/api/query/text_field_scoping_examples.rb +5 -5
  73. data/spec/api/query/types_spec.rb +4 -4
  74. data/spec/api/search/cursor_paginated_collection_spec.rb +12 -12
  75. data/spec/api/search/dynamic_fields_spec.rb +4 -4
  76. data/spec/api/search/faceting_spec.rb +55 -52
  77. data/spec/api/search/highlighting_spec.rb +7 -7
  78. data/spec/api/search/hits_spec.rb +43 -29
  79. data/spec/api/search/paginated_collection_spec.rb +18 -18
  80. data/spec/api/search/results_spec.rb +13 -13
  81. data/spec/api/search/search_spec.rb +3 -3
  82. data/spec/api/search/stats_spec.rb +10 -10
  83. data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +19 -18
  84. data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +9 -9
  85. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +10 -6
  86. data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +10 -10
  87. data/spec/api/session_proxy/sharding_session_proxy_spec.rb +14 -13
  88. data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +2 -2
  89. data/spec/api/session_proxy/spec_helper.rb +1 -1
  90. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +9 -5
  91. data/spec/api/session_spec.rb +42 -42
  92. data/spec/api/sunspot_spec.rb +7 -4
  93. data/spec/helpers/integration_helper.rb +1 -0
  94. data/spec/integration/atomic_updates_spec.rb +25 -11
  95. data/spec/integration/dynamic_fields_spec.rb +10 -10
  96. data/spec/integration/faceting_spec.rb +252 -39
  97. data/spec/integration/field_grouping_spec.rb +35 -16
  98. data/spec/integration/field_lists_spec.rb +57 -0
  99. data/spec/integration/geospatial_spec.rb +34 -8
  100. data/spec/integration/highlighting_spec.rb +5 -5
  101. data/spec/integration/indexing_spec.rb +5 -5
  102. data/spec/integration/join_spec.rb +45 -0
  103. data/spec/integration/keyword_search_spec.rb +47 -45
  104. data/spec/integration/local_search_spec.rb +4 -4
  105. data/spec/integration/more_like_this_spec.rb +7 -7
  106. data/spec/integration/scoped_search_spec.rb +108 -108
  107. data/spec/integration/spellcheck_spec.rb +52 -7
  108. data/spec/integration/stats_spec.rb +54 -13
  109. data/spec/integration/stored_fields_spec.rb +1 -1
  110. data/spec/integration/test_pagination.rb +4 -4
  111. data/spec/integration/unicode_spec.rb +1 -1
  112. data/spec/mocks/adapters.rb +33 -0
  113. data/spec/mocks/photo.rb +14 -4
  114. data/spec/mocks/post.rb +9 -1
  115. data/spec/spec_helper.rb +11 -10
  116. data/sunspot.gemspec +3 -1
  117. metadata +49 -6
@@ -27,14 +27,14 @@ describe 'search faceting' do
27
27
 
28
28
  it "should return value #{value1.inspect} with count 2" do
29
29
  row = @search.facet(field).rows[0]
30
- row.value.should == value1
31
- row.count.should == 2
30
+ expect(row.value).to eq(value1)
31
+ expect(row.count).to eq(2)
32
32
  end
33
33
 
34
34
  it "should return value #{value2.inspect} with count 1" do
35
35
  row = @search.facet(field).rows[1]
36
- row.value.should == value2
37
- row.count.should == 1
36
+ expect(row.value).to eq(value2)
37
+ expect(row.count).to eq(1)
38
38
  end
39
39
  end
40
40
  end
@@ -66,7 +66,7 @@ describe 'search faceting' do
66
66
  search = Sunspot.search(Post) do
67
67
  facet :title, :limit => 3
68
68
  end
69
- search.facet(:title).should have(3).rows
69
+ expect(search.facet(:title).rows.size).to eq(3)
70
70
  end
71
71
 
72
72
  it 'should not return zeros by default' do
@@ -74,7 +74,7 @@ describe 'search faceting' do
74
74
  with :blog_id, 1
75
75
  facet :title
76
76
  end
77
- search.facet(:title).rows.map { |row| row.value }.should_not include('zero')
77
+ expect(search.facet(:title).rows.map { |row| row.value }).not_to include('zero')
78
78
  end
79
79
 
80
80
  it 'should return zeros when specified' do
@@ -82,14 +82,14 @@ describe 'search faceting' do
82
82
  with :blog_id, 1
83
83
  facet :title, :zeros => true
84
84
  end
85
- search.facet(:title).rows.map { |row| row.value }.should include('zero')
85
+ expect(search.facet(:title).rows.map { |row| row.value }).to include('zero')
86
86
  end
87
87
 
88
88
  it 'should return facet rows from an offset' do
89
89
  search = Sunspot.search(Post) do
90
90
  facet :title, :offset => 3
91
91
  end
92
- search.facet(:title).rows.map { |row| row.value }.should == %w(one zero)
92
+ expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(one zero))
93
93
  end
94
94
 
95
95
  it 'should return a specified minimum count' do
@@ -97,7 +97,7 @@ describe 'search faceting' do
97
97
  with :blog_id, 1
98
98
  facet :title, :minimum_count => 2
99
99
  end
100
- search.facet(:title).rows.map { |row| row.value }.should == %w(four three two)
100
+ expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two))
101
101
  end
102
102
 
103
103
  it 'should order facets lexically' do
@@ -105,7 +105,7 @@ describe 'search faceting' do
105
105
  with :blog_id, 1
106
106
  facet :title, :sort => :index
107
107
  end
108
- search.facet(:title).rows.map { |row| row.value }.should == %w(four one three two)
108
+ expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four one three two))
109
109
  end
110
110
 
111
111
  it 'should order facets by count' do
@@ -113,7 +113,7 @@ describe 'search faceting' do
113
113
  with :blog_id, 1
114
114
  facet :title, :sort => :count
115
115
  end
116
- search.facet(:title).rows.map { |row| row.value }.should == %w(four three two one)
116
+ expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two one))
117
117
  end
118
118
 
119
119
  it 'should limit facet values by prefix' do
@@ -121,7 +121,7 @@ describe 'search faceting' do
121
121
  with :blog_id, 1
122
122
  facet :title, :prefix => 't'
123
123
  end
124
- search.facet(:title).rows.map { |row| row.value }.sort.should == %w(three two)
124
+ expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(%w(three two))
125
125
  end
126
126
 
127
127
  it 'should return :all facet' do
@@ -129,8 +129,8 @@ describe 'search faceting' do
129
129
  with :blog_id, 1
130
130
  facet :title, :extra => :any
131
131
  end
132
- search.facet(:title).rows.first.value.should == :any
133
- search.facet(:title).rows.first.count.should == 10
132
+ expect(search.facet(:title).rows.first.value).to eq(:any)
133
+ expect(search.facet(:title).rows.first.count).to eq(10)
134
134
  end
135
135
 
136
136
  it 'should return :none facet' do
@@ -138,8 +138,8 @@ describe 'search faceting' do
138
138
  with :blog_id, 1
139
139
  facet :title, :extra => :none
140
140
  end
141
- search.facet(:title).rows.first.value.should == :none
142
- search.facet(:title).rows.first.count.should == 1
141
+ expect(search.facet(:title).rows.first.value).to eq(:none)
142
+ expect(search.facet(:title).rows.first.count).to eq(1)
143
143
  end
144
144
 
145
145
  it 'gives correct facet count when group == true and truncate == true' do
@@ -152,10 +152,140 @@ describe 'search faceting' do
152
152
  end
153
153
 
154
154
  # Should be 5 instead of 11
155
- search.facet(:title).rows.first.count.should == 5
155
+ expect(search.facet(:title).rows.first.count).to eq(5)
156
156
  end
157
157
  end
158
158
 
159
+ context 'json facet options' do
160
+ before :all do
161
+ Sunspot.remove_all
162
+ facet_values = %w(zero one two three four)
163
+ facet_values.each_with_index do |value, i|
164
+ i.times { Sunspot.index(Post.new(:title => value, :blog_id => 1)) }
165
+ end
166
+ Sunspot.index(Post.new(:blog_id => 1))
167
+ Sunspot.index(Post.new(:title => 'zero', :blog_id => 2))
168
+ Sunspot.commit
169
+ end
170
+
171
+ it 'should return indexed elements' do
172
+ search = Sunspot.search(Post) do
173
+ json_facet(:title)
174
+ end
175
+ expect(search.facet(:title).rows.size).to eq(5)
176
+ end
177
+
178
+ it 'should limit the number of facet rows' do
179
+ search = Sunspot.search(Post) do
180
+ json_facet :title, :limit => 3
181
+ end
182
+ expect(search.facet(:title).rows.size).to eq(3)
183
+ end
184
+
185
+ it 'should not return zeros by default' do
186
+ search = Sunspot.search(Post) do
187
+ with :blog_id, 1
188
+ json_facet :title
189
+ end
190
+ expect(search.facet(:title).rows.map { |row| row.value }).not_to include('zero')
191
+ end
192
+
193
+ it 'should return a specified minimum count' do
194
+ search = Sunspot.search(Post) do
195
+ with :blog_id, 1
196
+ json_facet :title, :minimum_count => 2
197
+ end
198
+ expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two))
199
+ end
200
+
201
+ it 'should order facets lexically' do
202
+ search = Sunspot.search(Post) do
203
+ with :blog_id, 1
204
+ json_facet :title, :sort => :index
205
+ end
206
+ expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four one three two))
207
+ end
208
+
209
+ it 'should order facets by count' do
210
+ search = Sunspot.search(Post) do
211
+ with :blog_id, 1
212
+ json_facet :title, :sort => :count
213
+ end
214
+ expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two one))
215
+ end
216
+
217
+ it 'should limit facet values by prefix' do
218
+ search = Sunspot.search(Post) do
219
+ with :blog_id, 1
220
+ json_facet :title, :prefix => 't'
221
+ end
222
+ expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(%w(three two))
223
+ end
224
+
225
+ end
226
+
227
+ context 'nested json facet' do
228
+ before :all do
229
+ Sunspot.remove_all
230
+ facet_values = %w(zero one two three four)
231
+ nested_facet_values = %w(alfa bravo charlie delta)
232
+
233
+ facet_values.each do |value|
234
+ nested_facet_values.each do |v2|
235
+ Sunspot.index(Post.new(:title => value, :author_name => v2, :blog_id => 1))
236
+ end
237
+ end
238
+
239
+ 0.upto(9) { |i| Sunspot.index(Post.new(:title => 'zero', :author_name => "another#{i}", :blog_id => 1)) }
240
+
241
+ Sunspot.commit
242
+ end
243
+
244
+ it 'should get nested' do
245
+ search = Sunspot.search(Post) do
246
+ json_facet(:title, nested: { field: :author_name } )
247
+ end
248
+ expect(search.facet(:title).rows.first.nested.size).to eq(4)
249
+ end
250
+
251
+ it 'without limit take the first 10' do
252
+ search = Sunspot.search(Post) do
253
+ json_facet(:title, nested: { field: :author_name } )
254
+ end
255
+ expect(search.facet(:title).rows.last.nested.size).to eq(10)
256
+ end
257
+
258
+ it 'without limit' do
259
+ search = Sunspot.search(Post) do
260
+ json_facet(:title, nested: { field: :author_name, limit: -1 } )
261
+ end
262
+ expect(search.facet(:title).rows.last.nested.size).to eq(14)
263
+ end
264
+
265
+ it 'works with distinct' do
266
+ search = Sunspot.search(Post) do
267
+ json_facet(:title, nested: { field: :author_name, distinct: { strategy: :unique } } )
268
+ end
269
+ expect(search.facet(:title).rows.first.nested.map(&:count).uniq.size).to eq(1)
270
+ end
271
+
272
+ it 'should limit the nested facet' do
273
+ search = Sunspot.search(Post) do
274
+ json_facet(:title, nested: { field: :author_name, limit: 2 } )
275
+ end
276
+ expect(search.facet(:title).rows.first.nested.size).to eq(2)
277
+ end
278
+
279
+ it 'should work nested of nested' do
280
+ search = Sunspot.search(Post) do
281
+ json_facet(:title, nested: { field: :author_name, nested: { field: :title } } )
282
+ end
283
+ expect(search.facet(:title).rows.first.nested.first.nested.size).to eq(1)
284
+ expect(search.facet(:title).rows.first.nested.first.nested.first.nested).to eq(nil)
285
+ end
286
+
287
+ end
288
+
159
289
  context 'prefix escaping' do
160
290
  before do
161
291
  Sunspot.remove_all
@@ -170,7 +300,7 @@ describe 'search faceting' do
170
300
  with :blog_id, 1
171
301
  facet :title, :prefix => 'title '
172
302
  end
173
- search.facet(:title).rows.map { |row| row.value }.sort.should == ["title with spaces 1", "title with spaces 2"]
303
+ expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(["title with spaces 1", "title with spaces 2"])
174
304
  end
175
305
 
176
306
  it 'should limit facet values by a prefix with slashes' do
@@ -178,7 +308,7 @@ describe 'search faceting' do
178
308
  with :blog_id, 1
179
309
  facet :title, :prefix => 'title/'
180
310
  end
181
- search.facet(:title).rows.map { |row| row.value }.sort.should == ["title/with/slashes/1", "title/with/slashes/2"]
311
+ expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(["title/with/slashes/1", "title/with/slashes/2"])
182
312
  end
183
313
  end
184
314
 
@@ -199,7 +329,7 @@ describe 'search faceting' do
199
329
  category_filter = with(:category_ids, 1)
200
330
  facet(:category_ids, :exclude => category_filter)
201
331
  end
202
- search.facet(:category_ids).rows.map { |row| row.value }.to_set.should == Set[1, 2]
332
+ expect(search.facet(:category_ids).rows.map { |row| row.value }.to_set).to eq(Set[1, 2])
203
333
  end
204
334
 
205
335
  it 'should use facet keys to facet more than once with different exclusions' do
@@ -209,8 +339,8 @@ describe 'search faceting' do
209
339
  facet(:category_ids)
210
340
  facet(:category_ids, :exclude => category_filter, :name => :all_category_ids)
211
341
  end
212
- search.facet(:category_ids).rows.map { |row| row.value }.should == [1]
213
- search.facet(:all_category_ids).rows.map { |row| row.value }.to_set.should == Set[1, 2]
342
+ expect(search.facet(:category_ids).rows.map { |row| row.value }).to eq([1])
343
+ expect(search.facet(:all_category_ids).rows.map { |row| row.value }.to_set).to eq(Set[1, 2])
214
344
  end
215
345
  end
216
346
 
@@ -228,7 +358,7 @@ describe 'search faceting' do
228
358
  end
229
359
  end
230
360
  end
231
- search.facet(:category_ids).rows.map { |row| [row.value, row.count] }.to_set.should == Set[[:category_1, 1], [:category_2, 1]]
361
+ expect(search.facet(:category_ids).rows.map { |row| [row.value, row.count] }.to_set).to eq(Set[[:category_1, 1], [:category_2, 1]])
232
362
  end
233
363
 
234
364
  it 'should use facet keys to facet more than once with different exclusions' do
@@ -253,12 +383,63 @@ describe 'search faceting' do
253
383
  end
254
384
  end
255
385
  end
256
- search.facet(:category_ids).rows.map { |row| [row.value, row.count] }.to_set.should == Set[[:category_1, 1]]
257
- search.facet(:all_category_ids).rows.map { |row| [row.value, row.count] }.to_set.should == Set[[:category_1, 1], [:category_2, 1]]
386
+ expect(search.facet(:category_ids).rows.map { |row| [row.value, row.count] }.to_set).to eq(Set[[:category_1, 1]])
387
+ expect(search.facet(:all_category_ids).rows.map { |row| [row.value, row.count] }.to_set).to eq(Set[[:category_1, 1], [:category_2, 1]])
258
388
  end
259
389
  end
260
390
  end
261
391
 
392
+ context 'distinct field facets' do
393
+ before :all do
394
+ Sunspot.remove_all
395
+
396
+ Sunspot.index!(
397
+ (0..5).map { |i| Post.new(:blog_id => i, :title => 'title') }
398
+ )
399
+
400
+ 0.upto(3) { |i| Sunspot.index(Post.new(:blog_id => i, :title => 'title')) }
401
+
402
+ Sunspot.index!(Post.new(:blog_id => 4, :title => 'other title'))
403
+ Sunspot.index!(Post.new(:blog_id => 5, :title => 'other title'))
404
+
405
+ Sunspot.index!(Post.new(:blog_id => 40, :title => 'title'))
406
+ Sunspot.index!(Post.new(:blog_id => 40, :title => 'title'))
407
+
408
+ Sunspot.index!(Post.new(:blog_id => 40, :title => 'other title'))
409
+ Sunspot.index!(Post.new(:blog_id => 40, :title => 'other title'))
410
+ end
411
+
412
+ it 'should return unique indexed elements for a field' do
413
+ search = Sunspot.search(Post) do
414
+ json_facet(:blog_id, distinct: { strategy: :unique })
415
+ end
416
+
417
+ expect(search.facet(:blog_id).rows.size).to eq(7)
418
+ expect(search.facet(:blog_id).rows.map(&:count).uniq.size).to eq(1)
419
+ end
420
+
421
+ it 'should return unique indexed elements for a field and facet on a field' do
422
+ search = Sunspot.search(Post) do
423
+ json_facet(:blog_id, distinct: { group_by: :title, strategy: :unique })
424
+ end
425
+
426
+ expect(search.facet(:blog_id).rows.size).to eq(2)
427
+ expect(search.facet(:blog_id).rows[0].count).to eq(3)
428
+ expect(search.facet(:blog_id).rows[1].count).to eq(7)
429
+ end
430
+
431
+ it 'should return unique indexed elements for a field and facet on a field with hll' do
432
+ search = Sunspot.search(Post) do
433
+ json_facet(:blog_id, distinct: { group_by: :title, strategy: :hll })
434
+ end
435
+
436
+ expect(search.facet(:blog_id).rows.size).to eq(2)
437
+ expect(search.facet(:blog_id).rows[0].count).to eq(3)
438
+ expect(search.facet(:blog_id).rows[1].count).to eq(7)
439
+ end
440
+
441
+ end
442
+
262
443
  context 'date facets' do
263
444
  before :all do
264
445
  Sunspot.remove_all
@@ -273,11 +454,43 @@ describe 'search faceting' do
273
454
  search = Sunspot.search(Post) do
274
455
  facet :published_at, :time_range => time..(time + 60*60*24*2), :sort => :count
275
456
  end
276
- search.facet(:published_at).rows.first.value.should == (time..(time + 60*60*24))
277
- search.facet(:published_at).rows.first.count.should == 2
278
- search.facet(:published_at).rows.last.value.should == ((time + 60*60*24)..(time + 60*60*24*2))
279
- search.facet(:published_at).rows.last.count.should == 1
457
+ expect(search.facet(:published_at).rows.first.value).to eq(time..(time + 60*60*24))
458
+ expect(search.facet(:published_at).rows.first.count).to eq(2)
459
+ expect(search.facet(:published_at).rows.last.value).to eq((time + 60*60*24)..(time + 60*60*24*2))
460
+ expect(search.facet(:published_at).rows.last.count).to eq(1)
280
461
  end
462
+
463
+ it 'json facet should return time ranges' do
464
+ days_diff = 15
465
+ time_from = Time.utc(2009, 7, 8)
466
+ time_to = Time.utc(2009, 7, 8 + days_diff)
467
+ search = Sunspot.search(Post) do
468
+ json_facet(
469
+ :published_at,
470
+ :time_range => time_from..time_to
471
+ )
472
+ end
473
+
474
+ expect(search.facet(:published_at).rows.size).to eq(days_diff)
475
+ expect(search.facet(:published_at).rows[0].count).to eq(2)
476
+ expect(search.facet(:published_at).rows[1].count).to eq(1)
477
+ end
478
+
479
+ it 'json facet should return time ranges with custom gap' do
480
+ days_diff = 10
481
+ time_from = Time.utc(2009, 7, 8)
482
+ time_to = Time.utc(2009, 7, 8 + days_diff)
483
+ search = Sunspot.search(Post) do
484
+ json_facet(
485
+ :published_at,
486
+ :time_range => time_from..time_to,
487
+ gap: 60*60*24*2
488
+ )
489
+ end
490
+ expect(search.facet(:published_at).rows.size).to eq(days_diff / 2)
491
+ expect(search.facet(:published_at).rows[0].count).to eq(3)
492
+ end
493
+
281
494
  end
282
495
 
283
496
  context 'class facets' do
@@ -290,10 +503,10 @@ describe 'search faceting' do
290
503
  search = Sunspot.search(Post, Namespaced::Comment) do
291
504
  facet(:class, :sort => :count)
292
505
  end
293
- search.facet(:class).rows.first.value.should == Post
294
- search.facet(:class).rows.first.count.should == 2
295
- search.facet(:class).rows.last.value.should == Namespaced::Comment
296
- search.facet(:class).rows.last.count.should == 1
506
+ expect(search.facet(:class).rows.first.value).to eq(Post)
507
+ expect(search.facet(:class).rows.first.count).to eq(2)
508
+ expect(search.facet(:class).rows.last.value).to eq(Namespaced::Comment)
509
+ expect(search.facet(:class).rows.last.count).to eq(1)
297
510
  end
298
511
  end
299
512
 
@@ -319,12 +532,12 @@ describe 'search faceting' do
319
532
  end
320
533
  end
321
534
  facet = search.facet(:rating_range)
322
- facet.rows[0].value.should == (3.0..4.0)
323
- facet.rows[0].count.should == 3
324
- facet.rows[1].value.should == (1.0..2.0)
325
- facet.rows[1].count.should == 2
326
- facet.rows[2].value.should == (4.0..5.0)
327
- facet.rows[2].count.should == 1
535
+ expect(facet.rows[0].value).to eq(3.0..4.0)
536
+ expect(facet.rows[0].count).to eq(3)
537
+ expect(facet.rows[1].value).to eq(1.0..2.0)
538
+ expect(facet.rows[1].count).to eq(2)
539
+ expect(facet.rows[2].value).to eq(4.0..5.0)
540
+ expect(facet.rows[2].count).to eq(1)
328
541
  end
329
542
  end
330
543
  end
@@ -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,7 @@ 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
73
  end
74
74
 
75
75
  it "allows specification of an ordering function within groups" do
@@ -82,7 +82,7 @@ describe "field grouping" do
82
82
  highest_ranked_post = @posts.sort_by { |p| -p.ratings_average }.first
83
83
 
84
84
  title1_group = search.group(:title).groups.detect { |g| g.value == "Title1" }
85
- title1_group.hits.first.primary_key.to_i.should == highest_ranked_post.id
85
+ expect(title1_group.hits.first.primary_key.to_i).to eq(highest_ranked_post.id)
86
86
  end
87
87
 
88
88
  it "allows pagination within groups" do
@@ -91,8 +91,27 @@ describe "field grouping" do
91
91
  paginate :per_page => 1, :page => 2
92
92
  end
93
93
 
94
- search.group(:title).groups.length.should eql(1)
95
- 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) }
96
115
  end
97
116
 
98
117
  context "returns a paginated collection" do
@@ -104,10 +123,10 @@ describe "field grouping" do
104
123
  search.group(:title).groups
105
124
  end
106
125
 
107
- it { subject.per_page.should eql(1) }
108
- it { subject.total_pages.should eql(2) }
109
- it { subject.current_page.should eql(2) }
110
- it { subject.first_page?.should be_false }
111
- 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) }
112
131
  end
113
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