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
@@ -14,38 +14,38 @@ describe 'search with highlighting results', :type => :search do
14
14
  end
15
15
 
16
16
  it 'returns all highlights' do
17
- @search.hits.last.should have(3).highlights
17
+ expect(@search.hits.last.highlights.size).to eq(3)
18
18
  end
19
19
 
20
20
  it 'returns all highlights for a specified field' do
21
- @search.hits.last.should have(2).highlights(:body)
21
+ expect(@search.hits.last.highlights(:body).size).to eq(2)
22
22
  end
23
23
 
24
24
  it 'returns first highlight for a specified field' do
25
- @search.hits.first.highlight(:title).format.should == 'one <em>two</em> three'
25
+ expect(@search.hits.first.highlight(:title).format).to eq('one <em>two</em> three')
26
26
  end
27
27
 
28
28
  it 'returns an empty array if a given field does not have a highlight' do
29
- @search.hits.first.highlights(:body).should == []
29
+ expect(@search.hits.first.highlights(:body)).to eq([])
30
30
  end
31
31
 
32
32
  it 'formats hits with <em> by default' do
33
33
  highlight = @search.hits.first.highlights(:title).first.formatted
34
- highlight.should == 'one <em>two</em> three'
34
+ expect(highlight).to eq('one <em>two</em> three')
35
35
  end
36
36
 
37
37
  it 'formats hits with provided block' do
38
38
  highlight = @search.hits.first.highlights(:title).first.format do |word|
39
39
  "<i>#{word}</i>"
40
40
  end
41
- highlight.should == 'one <i>two</i> three'
41
+ expect(highlight).to eq('one <i>two</i> three')
42
42
  end
43
43
 
44
44
  it 'handles multiple highlighted words' do
45
45
  highlight = @search.hits.last.highlights(:body).last.format do |word|
46
46
  "<b>#{word}</b>"
47
47
  end
48
- highlight.should == '<b>eight</b> nine <b>ten</b>'
48
+ expect(highlight).to eq('<b>eight</b> nine <b>ten</b>')
49
49
  end
50
50
 
51
51
  private
@@ -5,37 +5,51 @@ describe 'hits', :type => :search do
5
5
  post_1, post_2 = Array.new(2) { Post.new }
6
6
  stub_results(post_1, post_2)
7
7
  %w(load load_all).each do |message|
8
- MockAdapter::DataAccessor.should_not_receive(message)
8
+ expect(MockAdapter::DataAccessor).not_to receive(message)
9
9
  end
10
- session.search(Post).hits.map do |hit|
10
+ expect(session.search(Post).hits.map do |hit|
11
11
  [hit.class_name, hit.primary_key]
12
- end.should == [['Post', post_1.id.to_s], ['Post', post_2.id.to_s]]
12
+ end).to eq([['Post', post_1.id.to_s], ['Post', post_2.id.to_s]])
13
+ end
14
+
15
+ it "should return ID prefix when used with compositeId shard router" do
16
+ Sunspot.index!(ModelWithPrefixId.new)
17
+
18
+ expect(Sunspot.search(ModelWithPrefixId).
19
+ hits.map { |h| h.id_prefix }.uniq).to eq ["USERDATA!"]
20
+ end
21
+
22
+ it "should parse nested ID prefixes" do
23
+ Sunspot.index!(ModelWithNestedPrefixId.new)
24
+
25
+ expect(Sunspot.search(ModelWithNestedPrefixId).
26
+ hits.map { |h| h.id_prefix }.uniq).to eq ["USER!USERDATA!"]
13
27
  end
14
28
 
15
29
  it 'returns search total as attribute of hits' do
16
30
  stub_results(Post.new, 4)
17
- session.search(Post) do
31
+ expect(session.search(Post) do
18
32
  paginate(:page => 1)
19
- end.hits.total_entries.should == 4
33
+ end.hits.total_entries).to eq(4)
20
34
  end
21
35
 
22
36
  it 'returns search total as attribute of verified hits' do
23
37
  stub_results(Post.new, 4)
24
- session.search(Post) do
38
+ expect(session.search(Post) do
25
39
  paginate(:page => 1)
26
- end.hits(:verify => true).total_entries.should == 4
40
+ end.hits(:verify => true).total_entries).to eq(4)
27
41
  end
28
42
 
29
43
  it 'should return instance from hit' do
30
44
  posts = Array.new(2) { Post.new }
31
45
  stub_results(*posts)
32
- session.search(Post).hits.first.instance.should == posts.first
46
+ expect(session.search(Post).hits.first.instance).to eq(posts.first)
33
47
  end
34
48
 
35
49
  it 'should return the instance primary key when you use it as a param' do
36
50
  posts = Array.new(2) { Post.new }
37
51
  stub_results(*posts)
38
- session.search(Post).hits.first.to_param.should == posts.first.id.to_s
52
+ expect(session.search(Post).hits.first.to_param).to eq(posts.first.id.to_s)
39
53
  end
40
54
 
41
55
  it 'should provide iterator over hits with instances' do
@@ -49,8 +63,8 @@ describe 'hits', :type => :search do
49
63
  results << result
50
64
  end
51
65
 
52
- hits.should have(2).hits
53
- results.should have(2).results
66
+ expect(hits.size).to eq(2)
67
+ expect(results.size).to eq(2)
54
68
  end
55
69
 
56
70
  it 'should provide an Enumerator over hits with instances' do
@@ -59,9 +73,9 @@ describe 'hits', :type => :search do
59
73
  search = session.search(Post)
60
74
  hits, results = [], []
61
75
  search.each_hit_with_result.with_index do |(hit, result), index|
62
- hit.should be_kind_of(Sunspot::Search::Hit)
63
- result.should be_kind_of(Post)
64
- index.should be_kind_of(Integer)
76
+ expect(hit).to be_kind_of(Sunspot::Search::Hit)
77
+ expect(result).to be_kind_of(Post)
78
+ expect(index).to be_kind_of(Integer)
65
79
  end
66
80
  end
67
81
 
@@ -71,9 +85,9 @@ describe 'hits', :type => :search do
71
85
  search = session.search(Post)
72
86
  search.hits.first.instance
73
87
  %w(load load_all).each do |message|
74
- MockAdapter::DataAccessor.should_not_receive(message)
88
+ expect(MockAdapter::DataAccessor).not_to receive(message)
75
89
  end
76
- search.hits.last.instance.should == posts.last
90
+ expect(search.hits.last.instance).to eq(posts.last)
77
91
  end
78
92
 
79
93
  it 'should return only hits whose referenced object exists in the data store if :verify option passed' do
@@ -81,7 +95,7 @@ describe 'hits', :type => :search do
81
95
  posts.last.destroy
82
96
  stub_results(*posts)
83
97
  search = session.search(Post)
84
- search.hits(:verify => true).map { |hit| hit.instance }.should == posts[0..0]
98
+ expect(search.hits(:verify => true).map { |hit| hit.instance }).to eq(posts[0..0])
85
99
  end
86
100
 
87
101
  it 'should return verified and unverified hits from the same search' do
@@ -89,59 +103,59 @@ describe 'hits', :type => :search do
89
103
  posts.last.destroy
90
104
  stub_results(*posts)
91
105
  search = session.search(Post)
92
- search.hits(:verify => true).map { |hit| hit.instance }.should == posts[0..0]
93
- search.hits.map { |hit| hit.instance }.should == [posts.first, nil]
106
+ expect(search.hits(:verify => true).map { |hit| hit.instance }).to eq(posts[0..0])
107
+ expect(search.hits.map { |hit| hit.instance }).to eq([posts.first, nil])
94
108
  end
95
109
 
96
110
  it 'should attach score to hits' do
97
111
  stub_full_results('instance' => Post.new, 'score' => 1.23)
98
- session.search(Post).hits.first.score.should == 1.23
112
+ expect(session.search(Post).hits.first.score).to eq(1.23)
99
113
  end
100
114
 
101
115
  it 'should return stored field values in hits' do
102
116
  stub_full_results('instance' => Post.new, 'title_ss' => 'Title')
103
- session.search(Post).hits.first.stored(:title).should == 'Title'
117
+ expect(session.search(Post).hits.first.stored(:title)).to eq('Title')
104
118
  end
105
119
 
106
120
  it 'should return stored field values for searches against multiple types' do
107
121
  stub_full_results('instance' => Post.new, 'title_ss' => 'Title')
108
- session.search(Post, Namespaced::Comment).hits.first.stored(:title).should == 'Title'
122
+ expect(session.search(Post, Namespaced::Comment).hits.first.stored(:title)).to eq('Title')
109
123
  end
110
124
 
111
125
  it 'should return stored field values for searches against base type when subtype matches' do
112
126
  class SubclassedPost < Post; end;
113
127
  stub_full_results('instance' => SubclassedPost.new, 'title_ss' => 'Title')
114
- session.search(Post).hits.first.stored(:title).should == 'Title'
128
+ expect(session.search(Post).hits.first.stored(:title)).to eq('Title')
115
129
  end
116
130
 
117
131
  it 'should return stored text fields' do
118
132
  stub_full_results('instance' => Post.new, 'body_textsv' => 'Body')
119
- session.search(Post, Namespaced::Comment).hits.first.stored(:body).should == 'Body'
133
+ expect(session.search(Post, Namespaced::Comment).hits.first.stored(:body)).to eq('Body')
120
134
  end
121
135
 
122
136
  it 'should return stored boolean fields' do
123
137
  stub_full_results('instance' => Post.new, 'featured_bs' => true)
124
- session.search(Post, Namespaced::Comment).hits.first.stored(:featured).should be_true
138
+ expect(session.search(Post, Namespaced::Comment).hits.first.stored(:featured)).to be(true)
125
139
  end
126
140
 
127
141
  it 'should return stored boolean fields that evaluate to false' do
128
142
  stub_full_results('instance' => Post.new, 'featured_bs' => false)
129
- session.search(Post, Namespaced::Comment).hits.first.stored(:featured).should == false
143
+ expect(session.search(Post, Namespaced::Comment).hits.first.stored(:featured)).to eq(false)
130
144
  end
131
145
 
132
146
  it 'should return stored dynamic fields' do
133
147
  stub_full_results('instance' => Post.new, 'custom_string:test_ss' => 'Custom')
134
- session.search(Post, Namespaced::Comment).hits.first.stored(:custom_string, :test).should == 'Custom'
148
+ expect(session.search(Post, Namespaced::Comment).hits.first.stored(:custom_string, :test)).to eq('Custom')
135
149
  end
136
150
 
137
151
  it 'should typecast stored field values in hits' do
138
152
  time = Time.utc(2008, 7, 8, 2, 45)
139
153
  stub_full_results('instance' => Post.new, 'last_indexed_at_ds' => time.xmlschema)
140
- session.search(Post).hits.first.stored(:last_indexed_at).should == time
154
+ expect(session.search(Post).hits.first.stored(:last_indexed_at)).to eq(time)
141
155
  end
142
156
 
143
157
  it 'should return stored values for multi-valued fields' do
144
158
  stub_full_results('instance' => User.new, 'role_ids_ims' => %w(1 4 5))
145
- session.search(User).hits.first.stored(:role_ids).should == [1, 4, 5]
159
+ expect(session.search(User).hits.first.stored(:role_ids)).to eq([1, 4, 5])
146
160
  end
147
161
  end
@@ -3,46 +3,47 @@ require File.expand_path('spec_helper', File.dirname(__FILE__))
3
3
  describe "PaginatedCollection" do
4
4
  subject { Sunspot::Search::PaginatedCollection.new [], 1, 10, 20 }
5
5
 
6
- it { subject.should be_an(Array) }
6
+ it { expect(subject).to be_an(Array) }
7
7
 
8
8
  describe "#send" do
9
9
  it 'should allow send' do
10
- expect { subject.send(:current_page) }.not_to raise_error(NoMethodError)
10
+ expect { subject.send(:current_page) }.to_not raise_error
11
11
  end
12
12
  end
13
13
 
14
14
  describe "#respond_to?" do
15
15
  it 'should return true for current_page' do
16
- subject.respond_to?(:current_page).should be_true
16
+ expect(subject.respond_to?(:current_page)).to be(true)
17
17
  end
18
18
  end
19
19
 
20
20
  context "behaves like a WillPaginate::Collection" do
21
- it { subject.total_entries.should eql(20) }
22
- it { subject.total_pages.should eql(2) }
23
- it { subject.current_page.should eql(1) }
24
- it { subject.per_page.should eql(10) }
25
- it { subject.previous_page.should be_nil }
26
- it { subject.next_page.should eql(2) }
27
- it { subject.out_of_bounds?.should_not be_true }
28
- it { subject.offset.should eql(0) }
21
+ it { expect(subject.total_entries).to eql(20) }
22
+ it { expect(subject.total_pages).to eql(2) }
23
+ it { expect(subject.current_page).to eql(1) }
24
+ it { expect(subject.per_page).to eql(10) }
25
+ it { expect(subject.previous_page).to be_nil }
26
+ it { expect(subject.prev_page).to be_nil }
27
+ it { expect(subject.next_page).to eql(2) }
28
+ it { expect(subject.out_of_bounds?).not_to be(true) }
29
+ it { expect(subject.offset).to eql(0) }
29
30
 
30
31
  it 'should allow setting total_count' do
31
32
  subject.total_count = 1
32
- subject.total_count.should eql(1)
33
+ expect(subject.total_count).to eql(1)
33
34
  end
34
35
 
35
36
  it 'should allow setting total_entries' do
36
37
  subject.total_entries = 1
37
- subject.total_entries.should eql(1)
38
+ expect(subject.total_entries).to eql(1)
38
39
  end
39
40
  end
40
41
 
41
42
  context "behaves like Kaminari" do
42
- it { subject.total_count.should eql(20) }
43
- it { subject.num_pages.should eql(2) }
44
- it { subject.limit_value.should eql(10) }
45
- it { subject.first_page?.should be_true }
46
- it { subject.last_page?.should_not be_true }
43
+ it { expect(subject.total_count).to eql(20) }
44
+ it { expect(subject.num_pages).to eql(2) }
45
+ it { expect(subject.limit_value).to eql(10) }
46
+ it { expect(subject.first_page?).to be(true) }
47
+ it { expect(subject.last_page?).not_to be(true) }
47
48
  end
48
49
  end
@@ -4,15 +4,15 @@ describe 'search results', :type => :search do
4
4
  it 'loads single result' do
5
5
  post = Post.new
6
6
  stub_results(post)
7
- session.search(Post).results.should == [post]
7
+ expect(session.search(Post).results).to eq([post])
8
8
  end
9
9
 
10
10
  it 'loads multiple results in order' do
11
11
  post_1, post_2 = Post.new, Post.new
12
12
  stub_results(post_1, post_2)
13
- session.search(Post).results.should == [post_1, post_2]
13
+ expect(session.search(Post).results).to eq([post_1, post_2])
14
14
  stub_results(post_2, post_1)
15
- session.search(Post).results.should == [post_2, post_1]
15
+ expect(session.search(Post).results).to eq([post_2, post_1])
16
16
  end
17
17
 
18
18
  # This is a reduction of a crazy bug I found in production where some hits
@@ -22,42 +22,42 @@ describe 'search results', :type => :search do
22
22
  Namespaced::Comment.reset!
23
23
  results = [Post.new, Namespaced::Comment.new]
24
24
  stub_results(*results)
25
- session.search(Post, Namespaced::Comment).results.should == results
25
+ expect(session.search(Post, Namespaced::Comment).results).to eq(results)
26
26
  end
27
27
 
28
28
  it 'gracefully returns empty results when response is nil' do
29
29
  stub_nil_results
30
- session.search(Post).results.should == []
30
+ expect(session.search(Post).results).to eq([])
31
31
  end
32
32
 
33
33
  it 'returns search total as attribute of results' do
34
34
  stub_results(Post.new, 4)
35
- session.search(Post) do
35
+ expect(session.search(Post) do
36
36
  paginate(:page => 1)
37
- end.results.total_entries.should == 4
37
+ end.results.total_entries).to eq(4)
38
38
  end
39
39
 
40
40
  it 'returns total' do
41
41
  stub_results(Post.new, Post.new, 4)
42
- session.search(Post) { paginate(:page => 1) }.total.should == 4
42
+ expect(session.search(Post) { paginate(:page => 1) }.total).to eq(4)
43
43
  end
44
44
 
45
45
  it 'returns query time' do
46
46
  stub_nil_results
47
47
  connection.response['responseHeader'] = { 'QTime' => 42 }
48
- session.search(Post) { paginate(:page => 1) }.query_time.should == 42
48
+ expect(session.search(Post) { paginate(:page => 1) }.query_time).to eq(42)
49
49
  end
50
50
 
51
51
  it 'returns total for nil search' do
52
52
  stub_nil_results
53
- session.search(Post).total.should == 0
53
+ expect(session.search(Post).total).to eq(0)
54
54
  end
55
55
 
56
56
  it 'returns available results if some results are not available from data store' do
57
57
  posts = [Post.new, Post.new]
58
58
  posts.last.destroy
59
59
  stub_results(*posts)
60
- session.search(Post).results.should == posts[0..0]
60
+ expect(session.search(Post).results).to eq(posts[0..0])
61
61
  end
62
62
 
63
63
  it 'does not attempt to query the data store more than once when results are unavailable' do
@@ -65,8 +65,8 @@ describe 'search results', :type => :search do
65
65
  posts.each { |post| post.destroy }
66
66
  stub_results(*posts)
67
67
  search = session.search(Post) do
68
- data_accessor_for(Post).should_receive(:load_all).once.and_return([])
68
+ expect(data_accessor_for(Post)).to receive(:load_all).once.and_return([])
69
69
  end
70
- search.results.should == []
70
+ expect(search.results).to eq([])
71
71
  end
72
72
  end
@@ -6,7 +6,7 @@ describe Sunspot::Search do
6
6
  search = session.search Post do
7
7
  data_accessor_for(Post).custom_title = 'custom title'
8
8
  end
9
- search.results.first.title.should == 'custom title'
9
+ expect(search.results.first.title).to eq('custom title')
10
10
  end
11
11
 
12
12
  it 'should re-execute search' do
@@ -14,10 +14,10 @@ describe Sunspot::Search do
14
14
 
15
15
  stub_results(post_1)
16
16
  search = session.search Post
17
- search.results.should == [post_1]
17
+ expect(search.results).to eq([post_1])
18
18
 
19
19
  stub_results(post_2)
20
20
  search.execute!
21
- search.results.should == [post_2]
21
+ expect(search.results).to eq([post_2])
22
22
  end
23
23
  end
@@ -0,0 +1,94 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'stats', :type => :search do
4
+ it 'returns field name for stats field' do
5
+ stub_stats(:average_rating_ft, {})
6
+ result = session.search Post do
7
+ stats :average_rating
8
+ end
9
+ expect(result.stats(:average_rating).field_name).to eq(:average_rating)
10
+ end
11
+
12
+ it 'returns min for stats field' do
13
+ stub_stats(:average_rating_ft, { 'min' => 1.0 })
14
+ result = session.search Post do
15
+ stats :average_rating
16
+ end
17
+ expect(result.stats(:average_rating).min).to eq(1.0)
18
+ end
19
+
20
+ it 'returns max for stats field' do
21
+ stub_stats(:average_rating_ft, { 'max' => 5.0 })
22
+ result = session.search Post do
23
+ stats :average_rating
24
+ end
25
+ expect(result.stats(:average_rating).max).to eq(5.0)
26
+ end
27
+
28
+ it 'returns count for stats field' do
29
+ stub_stats(:average_rating_ft, { 'count' => 120 })
30
+ result = session.search Post do
31
+ stats :average_rating
32
+ end
33
+ expect(result.stats(:average_rating).count).to eq(120)
34
+ end
35
+
36
+ it 'returns sum for stats field' do
37
+ stub_stats(:average_rating_ft, { 'sum' => 2200.0 })
38
+ result = session.search Post do
39
+ stats :average_rating
40
+ end
41
+ expect(result.stats(:average_rating).sum).to eq(2200.0)
42
+ end
43
+
44
+ it 'returns facet rows for stats field' do
45
+ stub_stats_facets(:average_rating_ft, 'featured_bs' => {
46
+ 'false' => {},
47
+ 'true' => {}
48
+ })
49
+ result = session.search Post do
50
+ stats :average_rating do
51
+ facet :featured
52
+ end
53
+ end
54
+ expect(stats_facet_values(result, :average_rating, :featured)).to eq([false, true])
55
+ end
56
+
57
+ it 'returns facet stats for stats field' do
58
+ stub_stats_facets(:average_rating_ft, 'featured_bs' => {
59
+ 'true' => { 'min' => 2.0, 'max' => 4.0 }
60
+ })
61
+ result = session.search Post do
62
+ stats :average_rating do
63
+ facet :featured
64
+ end
65
+ end
66
+ expect(stats_facet_stats(result, :average_rating, :featured, true).min).to eq(2.0)
67
+ expect(stats_facet_stats(result, :average_rating, :featured, true).max).to eq(4.0)
68
+ end
69
+
70
+ it 'returns instantiated stats facet values' do
71
+ blogs = 2.times.map { Blog.new }
72
+ stub_stats_facets(:average_rating_ft, 'blog_id_i' => {
73
+ blogs[0].id.to_s => {}, blogs[1].id.to_s => {} })
74
+ search = session.search(Post) do
75
+ stats :average_rating do
76
+ facet :blog_id
77
+ end
78
+ end
79
+ expect(search.stats(:average_rating).facet(:blog_id).rows.map { |row| row.instance }).to eq(blogs)
80
+ end
81
+
82
+ it 'only returns verified instances when requested' do
83
+ blog = Blog.new
84
+ stub_stats_facets(:average_rating_ft, 'blog_id_i' => {
85
+ blog.id.to_s => {}, '0' => {} })
86
+
87
+ search = session.search(Post) do
88
+ stats :average_rating do
89
+ facet :blog_id
90
+ end
91
+ end
92
+ expect(search.stats(:average_rating).facet(:blog_id).rows(:verified => true).map { |row| row.instance }).to eq([blog])
93
+ end
94
+ end