gojee-sunspot 2.0.2

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 (176) hide show
  1. data/.gitignore +12 -0
  2. data/Gemfile +5 -0
  3. data/History.txt +252 -0
  4. data/LICENSE +18 -0
  5. data/Rakefile +13 -0
  6. data/TODO +13 -0
  7. data/lib/light_config.rb +40 -0
  8. data/lib/sunspot.rb +579 -0
  9. data/lib/sunspot/adapters.rb +265 -0
  10. data/lib/sunspot/batcher.rb +62 -0
  11. data/lib/sunspot/class_set.rb +23 -0
  12. data/lib/sunspot/composite_setup.rb +202 -0
  13. data/lib/sunspot/configuration.rb +53 -0
  14. data/lib/sunspot/data_extractor.rb +50 -0
  15. data/lib/sunspot/dsl.rb +5 -0
  16. data/lib/sunspot/dsl/adjustable.rb +47 -0
  17. data/lib/sunspot/dsl/field_group.rb +57 -0
  18. data/lib/sunspot/dsl/field_query.rb +327 -0
  19. data/lib/sunspot/dsl/fields.rb +103 -0
  20. data/lib/sunspot/dsl/fulltext.rb +243 -0
  21. data/lib/sunspot/dsl/function.rb +27 -0
  22. data/lib/sunspot/dsl/functional.rb +44 -0
  23. data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
  24. data/lib/sunspot/dsl/paginatable.rb +32 -0
  25. data/lib/sunspot/dsl/query_facet.rb +36 -0
  26. data/lib/sunspot/dsl/restriction.rb +25 -0
  27. data/lib/sunspot/dsl/restriction_with_near.rb +160 -0
  28. data/lib/sunspot/dsl/scope.rb +217 -0
  29. data/lib/sunspot/dsl/search.rb +30 -0
  30. data/lib/sunspot/dsl/standard_query.rb +123 -0
  31. data/lib/sunspot/field.rb +193 -0
  32. data/lib/sunspot/field_factory.rb +129 -0
  33. data/lib/sunspot/indexer.rb +136 -0
  34. data/lib/sunspot/query.rb +11 -0
  35. data/lib/sunspot/query/abstract_field_facet.rb +52 -0
  36. data/lib/sunspot/query/bbox.rb +15 -0
  37. data/lib/sunspot/query/boost_query.rb +24 -0
  38. data/lib/sunspot/query/common_query.rb +96 -0
  39. data/lib/sunspot/query/composite_fulltext.rb +36 -0
  40. data/lib/sunspot/query/connective.rb +206 -0
  41. data/lib/sunspot/query/date_field_facet.rb +14 -0
  42. data/lib/sunspot/query/dismax.rb +132 -0
  43. data/lib/sunspot/query/field_facet.rb +41 -0
  44. data/lib/sunspot/query/field_group.rb +36 -0
  45. data/lib/sunspot/query/filter.rb +38 -0
  46. data/lib/sunspot/query/function_query.rb +52 -0
  47. data/lib/sunspot/query/geo.rb +53 -0
  48. data/lib/sunspot/query/geofilt.rb +16 -0
  49. data/lib/sunspot/query/highlighting.rb +62 -0
  50. data/lib/sunspot/query/more_like_this.rb +61 -0
  51. data/lib/sunspot/query/more_like_this_query.rb +12 -0
  52. data/lib/sunspot/query/pagination.rb +42 -0
  53. data/lib/sunspot/query/query_facet.rb +16 -0
  54. data/lib/sunspot/query/restriction.rb +262 -0
  55. data/lib/sunspot/query/scope.rb +9 -0
  56. data/lib/sunspot/query/sort.rb +109 -0
  57. data/lib/sunspot/query/sort_composite.rb +34 -0
  58. data/lib/sunspot/query/standard_query.rb +16 -0
  59. data/lib/sunspot/query/text_field_boost.rb +17 -0
  60. data/lib/sunspot/schema.rb +151 -0
  61. data/lib/sunspot/search.rb +9 -0
  62. data/lib/sunspot/search/abstract_search.rb +281 -0
  63. data/lib/sunspot/search/date_facet.rb +35 -0
  64. data/lib/sunspot/search/facet_row.rb +27 -0
  65. data/lib/sunspot/search/field_facet.rb +88 -0
  66. data/lib/sunspot/search/field_group.rb +32 -0
  67. data/lib/sunspot/search/group.rb +50 -0
  68. data/lib/sunspot/search/highlight.rb +38 -0
  69. data/lib/sunspot/search/hit.rb +150 -0
  70. data/lib/sunspot/search/hit_enumerable.rb +72 -0
  71. data/lib/sunspot/search/more_like_this_search.rb +31 -0
  72. data/lib/sunspot/search/paginated_collection.rb +57 -0
  73. data/lib/sunspot/search/query_facet.rb +67 -0
  74. data/lib/sunspot/search/standard_search.rb +21 -0
  75. data/lib/sunspot/session.rb +262 -0
  76. data/lib/sunspot/session_proxy.rb +95 -0
  77. data/lib/sunspot/session_proxy/abstract_session_proxy.rb +29 -0
  78. data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +66 -0
  79. data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +89 -0
  80. data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +43 -0
  81. data/lib/sunspot/session_proxy/multicore_session_proxy.rb +67 -0
  82. data/lib/sunspot/session_proxy/sharding_session_proxy.rb +222 -0
  83. data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +42 -0
  84. data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +37 -0
  85. data/lib/sunspot/setup.rb +350 -0
  86. data/lib/sunspot/text_field_setup.rb +29 -0
  87. data/lib/sunspot/type.rb +393 -0
  88. data/lib/sunspot/util.rb +252 -0
  89. data/lib/sunspot/version.rb +3 -0
  90. data/script/console +10 -0
  91. data/spec/api/adapters_spec.rb +33 -0
  92. data/spec/api/batcher_spec.rb +112 -0
  93. data/spec/api/binding_spec.rb +50 -0
  94. data/spec/api/class_set_spec.rb +24 -0
  95. data/spec/api/hit_enumerable_spec.rb +47 -0
  96. data/spec/api/indexer/attributes_spec.rb +149 -0
  97. data/spec/api/indexer/batch_spec.rb +72 -0
  98. data/spec/api/indexer/dynamic_fields_spec.rb +42 -0
  99. data/spec/api/indexer/fixed_fields_spec.rb +57 -0
  100. data/spec/api/indexer/fulltext_spec.rb +43 -0
  101. data/spec/api/indexer/removal_spec.rb +53 -0
  102. data/spec/api/indexer/spec_helper.rb +1 -0
  103. data/spec/api/indexer_spec.rb +14 -0
  104. data/spec/api/query/advanced_manipulation_examples.rb +35 -0
  105. data/spec/api/query/connectives_examples.rb +189 -0
  106. data/spec/api/query/dsl_spec.rb +18 -0
  107. data/spec/api/query/dynamic_fields_examples.rb +165 -0
  108. data/spec/api/query/faceting_examples.rb +397 -0
  109. data/spec/api/query/fulltext_examples.rb +313 -0
  110. data/spec/api/query/function_spec.rb +79 -0
  111. data/spec/api/query/geo_examples.rb +68 -0
  112. data/spec/api/query/group_spec.rb +32 -0
  113. data/spec/api/query/highlighting_examples.rb +245 -0
  114. data/spec/api/query/more_like_this_spec.rb +140 -0
  115. data/spec/api/query/ordering_pagination_examples.rb +116 -0
  116. data/spec/api/query/scope_examples.rb +275 -0
  117. data/spec/api/query/spatial_examples.rb +27 -0
  118. data/spec/api/query/spec_helper.rb +1 -0
  119. data/spec/api/query/standard_spec.rb +29 -0
  120. data/spec/api/query/text_field_scoping_examples.rb +30 -0
  121. data/spec/api/query/types_spec.rb +20 -0
  122. data/spec/api/search/dynamic_fields_spec.rb +33 -0
  123. data/spec/api/search/faceting_spec.rb +360 -0
  124. data/spec/api/search/highlighting_spec.rb +69 -0
  125. data/spec/api/search/hits_spec.rb +131 -0
  126. data/spec/api/search/paginated_collection_spec.rb +36 -0
  127. data/spec/api/search/results_spec.rb +72 -0
  128. data/spec/api/search/search_spec.rb +23 -0
  129. data/spec/api/search/spec_helper.rb +1 -0
  130. data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +85 -0
  131. data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +30 -0
  132. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +41 -0
  133. data/spec/api/session_proxy/sharding_session_proxy_spec.rb +77 -0
  134. data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +24 -0
  135. data/spec/api/session_proxy/spec_helper.rb +9 -0
  136. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +39 -0
  137. data/spec/api/session_spec.rb +232 -0
  138. data/spec/api/spec_helper.rb +3 -0
  139. data/spec/api/sunspot_spec.rb +29 -0
  140. data/spec/ext.rb +11 -0
  141. data/spec/helpers/indexer_helper.rb +17 -0
  142. data/spec/helpers/integration_helper.rb +8 -0
  143. data/spec/helpers/mock_session_helper.rb +13 -0
  144. data/spec/helpers/query_helper.rb +26 -0
  145. data/spec/helpers/search_helper.rb +68 -0
  146. data/spec/integration/dynamic_fields_spec.rb +57 -0
  147. data/spec/integration/faceting_spec.rb +251 -0
  148. data/spec/integration/field_grouping_spec.rb +66 -0
  149. data/spec/integration/geospatial_spec.rb +85 -0
  150. data/spec/integration/highlighting_spec.rb +44 -0
  151. data/spec/integration/indexing_spec.rb +55 -0
  152. data/spec/integration/keyword_search_spec.rb +317 -0
  153. data/spec/integration/local_search_spec.rb +64 -0
  154. data/spec/integration/more_like_this_spec.rb +43 -0
  155. data/spec/integration/scoped_search_spec.rb +354 -0
  156. data/spec/integration/stored_fields_spec.rb +12 -0
  157. data/spec/integration/test_pagination.rb +43 -0
  158. data/spec/integration/unicode_spec.rb +15 -0
  159. data/spec/mocks/adapters.rb +32 -0
  160. data/spec/mocks/blog.rb +3 -0
  161. data/spec/mocks/comment.rb +21 -0
  162. data/spec/mocks/connection.rb +126 -0
  163. data/spec/mocks/mock_adapter.rb +30 -0
  164. data/spec/mocks/mock_class_sharding_session_proxy.rb +24 -0
  165. data/spec/mocks/mock_record.rb +52 -0
  166. data/spec/mocks/mock_sharding_session_proxy.rb +15 -0
  167. data/spec/mocks/photo.rb +11 -0
  168. data/spec/mocks/post.rb +86 -0
  169. data/spec/mocks/super_class.rb +2 -0
  170. data/spec/mocks/user.rb +13 -0
  171. data/spec/spec_helper.rb +40 -0
  172. data/sunspot.gemspec +42 -0
  173. data/tasks/rdoc.rake +27 -0
  174. data/tasks/schema.rake +19 -0
  175. data/tasks/todo.rake +4 -0
  176. metadata +409 -0
@@ -0,0 +1,69 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'search with highlighting results', :type => :search do
4
+ before :each do
5
+ @posts = Array.new(2) { Post.new }
6
+ stub_results_with_highlighting(
7
+ @posts[0],
8
+ { 'title_text' => ['one @@@hl@@@two@@@endhl@@@ three'] },
9
+ @posts[1],
10
+ { 'title_text' => ['three four @@@hl@@@five@@@endhl@@@'],
11
+ 'body_text' => ['@@@hl@@@five@@@ six seven', '@@@hl@@@eight@@@endhl@@@ nine @@@hl@@@ten@@@endhl@@@'] }
12
+ )
13
+ @search = session.search(Post)
14
+ end
15
+
16
+ it 'returns all highlights' do
17
+ @search.hits.last.should have(3).highlights
18
+ end
19
+
20
+ it 'returns all highlights for a specified field' do
21
+ @search.hits.last.should have(2).highlights(:body)
22
+ end
23
+
24
+ it 'returns first highlight for a specified field' do
25
+ @search.hits.first.highlight(:title).format.should == 'one <em>two</em> three'
26
+ end
27
+
28
+ it 'returns an empty array if a given field does not have a highlight' do
29
+ @search.hits.first.highlights(:body).should == []
30
+ end
31
+
32
+ it 'formats hits with <em> by default' do
33
+ highlight = @search.hits.first.highlights(:title).first.formatted
34
+ highlight.should == 'one <em>two</em> three'
35
+ end
36
+
37
+ it 'formats hits with provided block' do
38
+ highlight = @search.hits.first.highlights(:title).first.format do |word|
39
+ "<i>#{word}</i>"
40
+ end
41
+ highlight.should == 'one <i>two</i> three'
42
+ end
43
+
44
+ it 'handles multiple highlighted words' do
45
+ highlight = @search.hits.last.highlights(:body).last.format do |word|
46
+ "<b>#{word}</b>"
47
+ end
48
+ highlight.should == '<b>eight</b> nine <b>ten</b>'
49
+ end
50
+
51
+ private
52
+
53
+ def stub_results_with_highlighting(*instances_and_highlights)
54
+ docs, highlights = [], []
55
+ instances_and_highlights.each_slice(2) do |doc, highlight|
56
+ docs << doc
57
+ highlights << highlight
58
+ end
59
+ response = stub_full_results(*docs.map { |doc| { 'instance' => doc }})
60
+ highlighting = response['highlighting'] = {}
61
+ highlights.each_with_index do |highlight, i|
62
+ if highlight
63
+ instance = docs[i]
64
+ highlighting["#{instance.class.name} #{instance.id}"] = highlight
65
+ end
66
+ end
67
+ response
68
+ end
69
+ end
@@ -0,0 +1,131 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'hits', :type => :search do
4
+ it 'should return hits without loading instances' do
5
+ post_1, post_2 = Array.new(2) { Post.new }
6
+ stub_results(post_1, post_2)
7
+ %w(load load_all).each do |message|
8
+ MockAdapter::DataAccessor.should_not_receive(message)
9
+ end
10
+ session.search(Post).hits.map do |hit|
11
+ [hit.class_name, hit.primary_key]
12
+ end.should == [['Post', post_1.id.to_s], ['Post', post_2.id.to_s]]
13
+ end
14
+
15
+ it 'returns search total as attribute of hits' do
16
+ stub_results(Post.new, 4)
17
+ session.search(Post) do
18
+ paginate(:page => 1)
19
+ end.hits.total_entries.should == 4
20
+ end
21
+
22
+ it 'returns search total as attribute of verified hits' do
23
+ stub_results(Post.new, 4)
24
+ session.search(Post) do
25
+ paginate(:page => 1)
26
+ end.hits(:verify => true).total_entries.should == 4
27
+ end
28
+
29
+ it 'should return instance from hit' do
30
+ posts = Array.new(2) { Post.new }
31
+ stub_results(*posts)
32
+ session.search(Post).hits.first.instance.should == posts.first
33
+ end
34
+
35
+ it 'should return the instance primary key when you use it as a param' do
36
+ posts = Array.new(2) { Post.new }
37
+ stub_results(*posts)
38
+ session.search(Post).hits.first.to_param.should == posts.first.id.to_s
39
+ end
40
+
41
+ it 'should provide iterator over hits with instances' do
42
+ posts = Array.new(2) { Post.new }
43
+ stub_results(*posts)
44
+ search = session.search(Post)
45
+ hits, results = [], []
46
+ search.each_hit_with_result do |hit, result|
47
+ hits << hit
48
+ results << result
49
+ end
50
+ end
51
+
52
+ it 'should hydrate all hits when an instance is requested from a hit' do
53
+ posts = Array.new(2) { Post.new }
54
+ stub_results(*posts)
55
+ search = session.search(Post)
56
+ search.hits.first.instance
57
+ %w(load load_all).each do |message|
58
+ MockAdapter::DataAccessor.should_not_receive(message)
59
+ end
60
+ search.hits.last.instance.should == posts.last
61
+ end
62
+
63
+ it 'should return only hits whose referenced object exists in the data store if :verify option passed' do
64
+ posts = Array.new(2) { Post.new }
65
+ posts.last.destroy
66
+ stub_results(*posts)
67
+ search = session.search(Post)
68
+ search.hits(:verify => true).map { |hit| hit.instance }.should == posts[0..0]
69
+ end
70
+
71
+ it 'should return verified and unverified hits from the same search' do
72
+ posts = Array.new(2) { Post.new }
73
+ posts.last.destroy
74
+ stub_results(*posts)
75
+ search = session.search(Post)
76
+ search.hits(:verify => true).map { |hit| hit.instance }.should == posts[0..0]
77
+ search.hits.map { |hit| hit.instance }.should == [posts.first, nil]
78
+ end
79
+
80
+ it 'should attach score to hits' do
81
+ stub_full_results('instance' => Post.new, 'score' => 1.23)
82
+ session.search(Post).hits.first.score.should == 1.23
83
+ end
84
+
85
+ it 'should return stored field values in hits' do
86
+ stub_full_results('instance' => Post.new, 'title_ss' => 'Title')
87
+ session.search(Post).hits.first.stored(:title).should == 'Title'
88
+ end
89
+
90
+ it 'should return stored field values for searches against multiple types' do
91
+ stub_full_results('instance' => Post.new, 'title_ss' => 'Title')
92
+ session.search(Post, Namespaced::Comment).hits.first.stored(:title).should == 'Title'
93
+ end
94
+
95
+ it 'should return stored field values for searches against base type when subtype matches' do
96
+ class SubclassedPost < Post; end;
97
+ stub_full_results('instance' => SubclassedPost.new, 'title_ss' => 'Title')
98
+ session.search(Post).hits.first.stored(:title).should == 'Title'
99
+ end
100
+
101
+ it 'should return stored text fields' do
102
+ stub_full_results('instance' => Post.new, 'body_textsv' => 'Body')
103
+ session.search(Post, Namespaced::Comment).hits.first.stored(:body).should == 'Body'
104
+ end
105
+
106
+ it 'should return stored boolean fields' do
107
+ stub_full_results('instance' => Post.new, 'featured_bs' => true)
108
+ session.search(Post, Namespaced::Comment).hits.first.stored(:featured).should be_true
109
+ end
110
+
111
+ it 'should return stored boolean fields that evaluate to false' do
112
+ stub_full_results('instance' => Post.new, 'featured_bs' => false)
113
+ session.search(Post, Namespaced::Comment).hits.first.stored(:featured).should == false
114
+ end
115
+
116
+ it 'should return stored dynamic fields' do
117
+ stub_full_results('instance' => Post.new, 'custom_string:test_ss' => 'Custom')
118
+ session.search(Post, Namespaced::Comment).hits.first.stored(:custom_string, :test).should == 'Custom'
119
+ end
120
+
121
+ it 'should typecast stored field values in hits' do
122
+ time = Time.utc(2008, 7, 8, 2, 45)
123
+ stub_full_results('instance' => Post.new, 'last_indexed_at_ds' => time.xmlschema)
124
+ session.search(Post).hits.first.stored(:last_indexed_at).should == time
125
+ end
126
+
127
+ it 'should return stored values for multi-valued fields' do
128
+ stub_full_results('instance' => User.new, 'role_ids_ims' => %w(1 4 5))
129
+ session.search(User).hits.first.stored(:role_ids).should == [1, 4, 5]
130
+ end
131
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe "PaginatedCollection" do
4
+ subject { Sunspot::Search::PaginatedCollection.new [], 1, 10, 20 }
5
+
6
+ it { subject.should be_an(Array) }
7
+
8
+ context "behaves like a WillPaginate::Collection" do
9
+ it { subject.total_entries.should eql(20) }
10
+ it { subject.total_pages.should eql(2) }
11
+ it { subject.current_page.should eql(1) }
12
+ it { subject.per_page.should eql(10) }
13
+ it { subject.previous_page.should be_nil }
14
+ it { subject.next_page.should eql(2) }
15
+ it { subject.out_of_bounds?.should_not be_true }
16
+ it { subject.offset.should eql(0) }
17
+
18
+ it 'should allow setting total_count' do
19
+ subject.total_count = 1
20
+ subject.total_count.should eql(1)
21
+ end
22
+
23
+ it 'should allow setting total_entries' do
24
+ subject.total_entries = 1
25
+ subject.total_entries.should eql(1)
26
+ end
27
+ end
28
+
29
+ context "behaves like Kaminari" do
30
+ it { subject.total_count.should eql(20) }
31
+ it { subject.num_pages.should eql(2) }
32
+ it { subject.limit_value.should eql(10) }
33
+ it { subject.first_page?.should be_true }
34
+ it { subject.last_page?.should_not be_true }
35
+ end
36
+ end
@@ -0,0 +1,72 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'search results', :type => :search do
4
+ it 'loads single result' do
5
+ post = Post.new
6
+ stub_results(post)
7
+ session.search(Post).results.should == [post]
8
+ end
9
+
10
+ it 'loads multiple results in order' do
11
+ post_1, post_2 = Post.new, Post.new
12
+ stub_results(post_1, post_2)
13
+ session.search(Post).results.should == [post_1, post_2]
14
+ stub_results(post_2, post_1)
15
+ session.search(Post).results.should == [post_2, post_1]
16
+ end
17
+
18
+ # This is a reduction of a crazy bug I found in production where some hits
19
+ # were inexplicably not being populated.
20
+ it 'properly loads results of multiple classes that have the same primary key' do
21
+ Post.reset!
22
+ Namespaced::Comment.reset!
23
+ results = [Post.new, Namespaced::Comment.new]
24
+ stub_results(*results)
25
+ session.search(Post, Namespaced::Comment).results.should == results
26
+ end
27
+
28
+ it 'gracefully returns empty results when response is nil' do
29
+ stub_nil_results
30
+ session.search(Post).results.should == []
31
+ end
32
+
33
+ it 'returns search total as attribute of results' do
34
+ stub_results(Post.new, 4)
35
+ session.search(Post) do
36
+ paginate(:page => 1)
37
+ end.results.total_entries.should == 4
38
+ end
39
+
40
+ it 'returns total' do
41
+ stub_results(Post.new, Post.new, 4)
42
+ session.search(Post) { paginate(:page => 1) }.total.should == 4
43
+ end
44
+
45
+ it 'returns query time' do
46
+ stub_nil_results
47
+ connection.response['responseHeader'] = { 'QTime' => 42 }
48
+ session.search(Post) { paginate(:page => 1) }.query_time.should == 42
49
+ end
50
+
51
+ it 'returns total for nil search' do
52
+ stub_nil_results
53
+ session.search(Post).total.should == 0
54
+ end
55
+
56
+ it 'returns available results if some results are not available from data store' do
57
+ posts = [Post.new, Post.new]
58
+ posts.last.destroy
59
+ stub_results(*posts)
60
+ session.search(Post).results.should == posts[0..0]
61
+ end
62
+
63
+ it 'does not attempt to query the data store more than once when results are unavailable' do
64
+ posts = [Post.new, Post.new]
65
+ posts.each { |post| post.destroy }
66
+ stub_results(*posts)
67
+ search = session.search(Post) do
68
+ data_accessor_for(Post).should_receive(:load_all).once.and_return([])
69
+ end
70
+ search.results.should == []
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Sunspot::Search do
4
+ it 'should allow access to the data accessor' do
5
+ stub_results(posts = Post.new)
6
+ search = session.search Post do
7
+ data_accessor_for(Post).custom_title = 'custom title'
8
+ end
9
+ search.results.first.title.should == 'custom title'
10
+ end
11
+
12
+ it 'should re-execute search' do
13
+ post_1, post_2 = Post.new, Post.new
14
+
15
+ stub_results(post_1)
16
+ search = session.search Post
17
+ search.results.should == [post_1]
18
+
19
+ stub_results(post_2)
20
+ search.execute!
21
+ search.results.should == [post_2]
22
+ end
23
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path('spec_helper', File.join(File.dirname(__FILE__), '..'))
@@ -0,0 +1,85 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Sunspot::SessionProxy::ClassShardingSessionProxy do
4
+ before do
5
+ @proxy = MockClassShardingSessionProxy.new(session)
6
+ end
7
+
8
+ [:index, :index!, :remove, :remove!].each do |method|
9
+ it "should delegate #{method} to appropriate shard" do
10
+ post = Post.new
11
+ photo = Photo.new
12
+ @proxy.post_session.should_receive(method).with([post])
13
+ @proxy.photo_session.should_receive(method).with([photo])
14
+ @proxy.send(method, post)
15
+ @proxy.send(method, photo)
16
+ end
17
+ end
18
+
19
+ [:remove_by_id, :remove_by_id!].each do |method|
20
+ it "should delegate #{method} to appropriate shard" do
21
+ @proxy.post_session.should_receive(method).with(Post, 1)
22
+ @proxy.photo_session.should_receive(method).with(Photo, 1)
23
+ @proxy.send(method, Post, 1)
24
+ @proxy.send(method, Photo, 1)
25
+ end
26
+ end
27
+
28
+ [:remove_all, :remove_all!].each do |method|
29
+ it "should delegate #{method} with argument to appropriate shard" do
30
+ @proxy.post_session.should_receive(method).with(Post)
31
+ @proxy.photo_session.should_receive(method).with(Photo)
32
+ @proxy.send(method, Post)
33
+ @proxy.send(method, Photo)
34
+ end
35
+
36
+ it "should delegate #{method} without argument to all shards" do
37
+ @proxy.post_session.should_receive(method)
38
+ @proxy.photo_session.should_receive(method)
39
+ @proxy.send(method)
40
+ end
41
+ end
42
+
43
+ [:commit, :commit_if_dirty, :commit_if_delete_dirty, :optimize].each do |method|
44
+ it "should delegate #{method} to all sessions" do
45
+ [@proxy.post_session, @proxy.photo_session].each do |session|
46
+ session.should_receive(method)
47
+ end
48
+ @proxy.send(method)
49
+ end
50
+ end
51
+
52
+ it "should not support the :batch method" do
53
+ lambda { @proxy.batch }.should raise_error(Sunspot::SessionProxy::NotSupportedError)
54
+ end
55
+
56
+ it "should delegate new_search to search session, adding in shards parameter" do
57
+ search = @proxy.new_search(Post)
58
+ search.query[:shards].should ==
59
+ 'http://photos.solr.local/solr,http://posts.solr.local/solr'
60
+ end
61
+
62
+ it "should delegate search to search session, adding in shards parameter" do
63
+ @proxy.search(Post)
64
+ connection.should have_last_search_with(
65
+ :shards => 'http://photos.solr.local/solr,http://posts.solr.local/solr'
66
+ )
67
+ end
68
+
69
+ [:dirty, :delete_dirty].each do |method|
70
+ it "should be dirty if any of the sessions are dirty" do
71
+ @proxy.post_session.stub!(:"#{method}?").and_return(true)
72
+ @proxy.should send("be_#{method}")
73
+ end
74
+
75
+ it "should not be dirty if none of the sessions are dirty" do
76
+ @proxy.should_not send("be_#{method}")
77
+ end
78
+ end
79
+
80
+ it "should raise a NotSupportedError when :config is called" do
81
+ lambda { @proxy.config }.should raise_error(Sunspot::SessionProxy::NotSupportedError)
82
+ end
83
+
84
+ it_should_behave_like 'session proxy'
85
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Sunspot::SessionProxy::ShardingSessionProxy do
4
+ before do
5
+ search_session = Sunspot::Session.new
6
+ @sessions = Array.new(2) { Sunspot::Session.new }
7
+ @proxy = Sunspot::SessionProxy::IdShardingSessionProxy.new(search_session, @sessions)
8
+ end
9
+
10
+ [:index, :index!, :remove, :remove!].each do |method|
11
+ it "should delegate #{method} to appropriate shard" do
12
+ posts = [Post.new(:id => 2), Post.new(:id => 1)]
13
+ @proxy.sessions[0].should_receive(method).with([posts[0]])
14
+ @proxy.sessions[1].should_receive(method).with([posts[1]])
15
+ @proxy.send(method, posts[0])
16
+ @proxy.send(method, posts[1])
17
+ end
18
+ end
19
+
20
+ [:remove_by_id, :remove_by_id!].each do |method|
21
+ it "should delegate #{method} to appropriate session" do
22
+ @proxy.sessions[0].should_receive(method).with(Post, 2)
23
+ @proxy.sessions[1].should_receive(method).with(Post, 1)
24
+ @proxy.send(method, Post, 1)
25
+ @proxy.send(method, Post, 2)
26
+ end
27
+ end
28
+
29
+ it_should_behave_like 'session proxy'
30
+ end