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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/Appraisals +7 -0
- data/Gemfile +0 -2
- data/History.txt +10 -0
- data/lib/sunspot.rb +55 -17
- data/lib/sunspot/adapters.rb +68 -18
- data/lib/sunspot/batcher.rb +1 -1
- data/lib/sunspot/configuration.rb +4 -2
- data/lib/sunspot/data_extractor.rb +36 -6
- data/lib/sunspot/dsl.rb +4 -3
- data/lib/sunspot/dsl/adjustable.rb +2 -2
- data/lib/sunspot/dsl/field_query.rb +69 -16
- data/lib/sunspot/dsl/field_stats.rb +25 -0
- data/lib/sunspot/dsl/fields.rb +28 -8
- data/lib/sunspot/dsl/fulltext.rb +9 -1
- data/lib/sunspot/dsl/group.rb +118 -0
- data/lib/sunspot/dsl/paginatable.rb +4 -1
- data/lib/sunspot/dsl/scope.rb +19 -10
- data/lib/sunspot/dsl/search.rb +1 -1
- data/lib/sunspot/dsl/spellcheckable.rb +14 -0
- data/lib/sunspot/dsl/standard_query.rb +63 -35
- data/lib/sunspot/field.rb +76 -4
- data/lib/sunspot/field_factory.rb +60 -11
- data/lib/sunspot/indexer.rb +70 -18
- data/lib/sunspot/query.rb +5 -4
- data/lib/sunspot/query/abstract_field_facet.rb +0 -2
- data/lib/sunspot/query/abstract_fulltext.rb +76 -0
- data/lib/sunspot/query/abstract_json_field_facet.rb +70 -0
- data/lib/sunspot/query/bbox.rb +5 -1
- data/lib/sunspot/query/common_query.rb +31 -6
- data/lib/sunspot/query/composite_fulltext.rb +58 -8
- data/lib/sunspot/query/date_field_json_facet.rb +25 -0
- data/lib/sunspot/query/dismax.rb +25 -71
- data/lib/sunspot/query/field_json_facet.rb +19 -0
- data/lib/sunspot/query/field_list.rb +15 -0
- data/lib/sunspot/query/field_stats.rb +61 -0
- data/lib/sunspot/query/function_query.rb +1 -2
- data/lib/sunspot/query/geo.rb +1 -1
- data/lib/sunspot/query/geofilt.rb +8 -3
- data/lib/sunspot/query/group.rb +46 -0
- data/lib/sunspot/query/group_query.rb +17 -0
- data/lib/sunspot/query/join.rb +88 -0
- data/lib/sunspot/query/more_like_this.rb +1 -1
- data/lib/sunspot/query/pagination.rb +12 -4
- data/lib/sunspot/query/range_json_facet.rb +28 -0
- data/lib/sunspot/query/restriction.rb +99 -13
- data/lib/sunspot/query/sort.rb +41 -0
- data/lib/sunspot/query/sort_composite.rb +7 -0
- data/lib/sunspot/query/spellcheck.rb +19 -0
- data/lib/sunspot/query/standard_query.rb +24 -2
- data/lib/sunspot/query/text_field_boost.rb +1 -3
- data/lib/sunspot/schema.rb +12 -3
- data/lib/sunspot/search.rb +4 -2
- data/lib/sunspot/search/abstract_search.rb +93 -43
- data/lib/sunspot/search/cursor_paginated_collection.rb +32 -0
- data/lib/sunspot/search/field_facet.rb +4 -4
- data/lib/sunspot/search/field_json_facet.rb +33 -0
- data/lib/sunspot/search/field_stats.rb +21 -0
- data/lib/sunspot/search/hit.rb +6 -1
- data/lib/sunspot/search/hit_enumerable.rb +4 -1
- data/lib/sunspot/search/json_facet_row.rb +40 -0
- data/lib/sunspot/search/json_facet_stats.rb +23 -0
- data/lib/sunspot/search/paginated_collection.rb +1 -0
- data/lib/sunspot/search/query_group.rb +74 -0
- data/lib/sunspot/search/standard_search.rb +70 -3
- data/lib/sunspot/search/stats_facet.rb +25 -0
- data/lib/sunspot/search/stats_json_row.rb +82 -0
- data/lib/sunspot/search/stats_row.rb +68 -0
- data/lib/sunspot/session.rb +62 -37
- data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +6 -4
- data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +16 -8
- data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +2 -2
- data/lib/sunspot/session_proxy/retry_5xx_session_proxy.rb +1 -1
- data/lib/sunspot/session_proxy/sharding_session_proxy.rb +4 -2
- data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +1 -1
- data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +6 -4
- data/lib/sunspot/setup.rb +42 -0
- data/lib/sunspot/type.rb +20 -0
- data/lib/sunspot/util.rb +78 -14
- data/lib/sunspot/version.rb +1 -1
- data/spec/api/adapters_spec.rb +40 -15
- data/spec/api/batcher_spec.rb +15 -15
- data/spec/api/binding_spec.rb +3 -3
- data/spec/api/class_set_spec.rb +6 -6
- data/spec/api/data_extractor_spec.rb +39 -0
- data/spec/api/hit_enumerable_spec.rb +32 -9
- data/spec/api/indexer/attributes_spec.rb +35 -30
- data/spec/api/indexer/batch_spec.rb +8 -7
- data/spec/api/indexer/dynamic_fields_spec.rb +8 -8
- data/spec/api/indexer/fixed_fields_spec.rb +16 -11
- data/spec/api/indexer/fulltext_spec.rb +8 -8
- data/spec/api/indexer/removal_spec.rb +24 -14
- data/spec/api/indexer_spec.rb +2 -2
- data/spec/api/query/advanced_manipulation_examples.rb +3 -3
- data/spec/api/query/connectives_examples.rb +26 -14
- data/spec/api/query/dsl_spec.rb +24 -6
- data/spec/api/query/dynamic_fields_examples.rb +18 -18
- data/spec/api/query/faceting_examples.rb +80 -61
- data/spec/api/query/fulltext_examples.rb +194 -40
- data/spec/api/query/function_spec.rb +116 -13
- data/spec/api/query/geo_examples.rb +8 -12
- data/spec/api/query/group_spec.rb +27 -5
- data/spec/api/query/highlighting_examples.rb +26 -26
- data/spec/api/query/join_spec.rb +19 -0
- data/spec/api/query/more_like_this_spec.rb +40 -27
- data/spec/api/query/ordering_pagination_examples.rb +37 -23
- data/spec/api/query/scope_examples.rb +39 -39
- data/spec/api/query/spatial_examples.rb +3 -3
- data/spec/api/query/spellcheck_examples.rb +20 -0
- data/spec/api/query/standard_spec.rb +3 -1
- data/spec/api/query/stats_examples.rb +66 -0
- data/spec/api/query/text_field_scoping_examples.rb +5 -5
- data/spec/api/query/types_spec.rb +4 -4
- data/spec/api/search/cursor_paginated_collection_spec.rb +35 -0
- data/spec/api/search/dynamic_fields_spec.rb +4 -4
- data/spec/api/search/faceting_spec.rb +55 -52
- data/spec/api/search/highlighting_spec.rb +7 -7
- data/spec/api/search/hits_spec.rb +43 -29
- data/spec/api/search/paginated_collection_spec.rb +19 -18
- data/spec/api/search/results_spec.rb +13 -13
- data/spec/api/search/search_spec.rb +3 -3
- data/spec/api/search/stats_spec.rb +94 -0
- data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +23 -16
- data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +16 -4
- data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +10 -6
- data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +11 -11
- data/spec/api/session_proxy/sharding_session_proxy_spec.rb +15 -14
- data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +3 -3
- data/spec/api/session_proxy/spec_helper.rb +1 -1
- data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +40 -26
- data/spec/api/session_spec.rb +78 -38
- data/spec/api/sunspot_spec.rb +7 -4
- data/spec/helpers/integration_helper.rb +11 -1
- data/spec/helpers/query_helper.rb +1 -1
- data/spec/helpers/search_helper.rb +30 -0
- data/spec/integration/atomic_updates_spec.rb +58 -0
- data/spec/integration/dynamic_fields_spec.rb +31 -20
- data/spec/integration/faceting_spec.rb +252 -39
- data/spec/integration/field_grouping_spec.rb +47 -15
- data/spec/integration/field_lists_spec.rb +57 -0
- data/spec/integration/geospatial_spec.rb +34 -8
- data/spec/integration/highlighting_spec.rb +8 -8
- data/spec/integration/indexing_spec.rb +7 -6
- data/spec/integration/join_spec.rb +45 -0
- data/spec/integration/keyword_search_spec.rb +68 -38
- data/spec/integration/local_search_spec.rb +4 -4
- data/spec/integration/more_like_this_spec.rb +7 -7
- data/spec/integration/scoped_search_spec.rb +193 -74
- data/spec/integration/spellcheck_spec.rb +119 -0
- data/spec/integration/stats_spec.rb +88 -0
- data/spec/integration/stored_fields_spec.rb +1 -1
- data/spec/integration/test_pagination.rb +4 -4
- data/spec/integration/unicode_spec.rb +1 -1
- data/spec/mocks/adapters.rb +36 -0
- data/spec/mocks/connection.rb +5 -3
- data/spec/mocks/photo.rb +32 -1
- data/spec/mocks/post.rb +18 -3
- data/spec/spec_helper.rb +13 -8
- data/sunspot.gemspec +6 -4
- data/tasks/rdoc.rake +22 -14
- metadata +101 -44
- data/lib/sunspot/dsl/field_group.rb +0 -57
- 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.
|
|
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.
|
|
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.
|
|
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).
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
53
|
-
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.
|
|
63
|
-
result.
|
|
64
|
-
index.
|
|
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.
|
|
88
|
+
expect(MockAdapter::DataAccessor).not_to receive(message)
|
|
75
89
|
end
|
|
76
|
-
search.hits.last.instance.
|
|
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 }.
|
|
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 }.
|
|
93
|
-
search.hits.map { |hit| hit.instance }.
|
|
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.
|
|
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).
|
|
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).
|
|
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).
|
|
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).
|
|
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).
|
|
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).
|
|
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).
|
|
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).
|
|
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).
|
|
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.
|
|
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) }.
|
|
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).
|
|
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.
|
|
22
|
-
it { subject.total_pages.
|
|
23
|
-
it { subject.current_page.
|
|
24
|
-
it { subject.per_page.
|
|
25
|
-
it { subject.previous_page.
|
|
26
|
-
it { subject.
|
|
27
|
-
it { subject.
|
|
28
|
-
it { subject.
|
|
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.
|
|
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.
|
|
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.
|
|
43
|
-
it { subject.num_pages.
|
|
44
|
-
it { subject.limit_value.
|
|
45
|
-
it { subject.first_page
|
|
46
|
-
it { subject.last_page
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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).
|
|
68
|
+
expect(data_accessor_for(Post)).to receive(:load_all).once.and_return([])
|
|
69
69
|
end
|
|
70
|
-
search.results.
|
|
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.
|
|
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.
|
|
17
|
+
expect(search.results).to eq([post_1])
|
|
18
18
|
|
|
19
19
|
stub_results(post_2)
|
|
20
20
|
search.execute!
|
|
21
|
-
search.results.
|
|
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
|