sunspot 2.2.7 → 2.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rspec +2 -0
  4. data/Appraisals +7 -0
  5. data/Gemfile +0 -8
  6. data/gemfiles/.gitkeep +0 -0
  7. data/lib/sunspot/dsl/scope.rb +6 -1
  8. data/lib/sunspot/field.rb +11 -0
  9. data/lib/sunspot/field_factory.rb +6 -2
  10. data/lib/sunspot/query/bbox.rb +5 -1
  11. data/lib/sunspot/query/restriction.rb +11 -0
  12. data/lib/sunspot/search/hit_enumerable.rb +4 -1
  13. data/lib/sunspot/search/standard_search.rb +2 -3
  14. data/lib/sunspot/version.rb +1 -1
  15. data/spec/api/adapters_spec.rb +19 -19
  16. data/spec/api/batcher_spec.rb +15 -15
  17. data/spec/api/binding_spec.rb +3 -3
  18. data/spec/api/class_set_spec.rb +3 -3
  19. data/spec/api/hit_enumerable_spec.rb +32 -9
  20. data/spec/api/indexer/attributes_spec.rb +31 -31
  21. data/spec/api/indexer/batch_spec.rb +8 -7
  22. data/spec/api/indexer/dynamic_fields_spec.rb +8 -8
  23. data/spec/api/indexer/fixed_fields_spec.rb +12 -12
  24. data/spec/api/indexer/fulltext_spec.rb +8 -8
  25. data/spec/api/indexer/removal_spec.rb +14 -14
  26. data/spec/api/indexer_spec.rb +2 -2
  27. data/spec/api/query/advanced_manipulation_examples.rb +3 -3
  28. data/spec/api/query/connectives_examples.rb +26 -14
  29. data/spec/api/query/dsl_spec.rb +17 -9
  30. data/spec/api/query/dynamic_fields_examples.rb +18 -18
  31. data/spec/api/query/faceting_examples.rb +62 -62
  32. data/spec/api/query/fulltext_examples.rb +56 -55
  33. data/spec/api/query/function_spec.rb +26 -26
  34. data/spec/api/query/geo_examples.rb +6 -6
  35. data/spec/api/query/group_spec.rb +6 -6
  36. data/spec/api/query/highlighting_examples.rb +26 -26
  37. data/spec/api/query/join_spec.rb +2 -2
  38. data/spec/api/query/more_like_this_spec.rb +29 -29
  39. data/spec/api/query/ordering_pagination_examples.rb +25 -25
  40. data/spec/api/query/scope_examples.rb +39 -39
  41. data/spec/api/query/spatial_examples.rb +3 -3
  42. data/spec/api/query/spellcheck_examples.rb +3 -3
  43. data/spec/api/query/standard_spec.rb +1 -1
  44. data/spec/api/query/stats_examples.rb +8 -8
  45. data/spec/api/query/text_field_scoping_examples.rb +5 -5
  46. data/spec/api/query/types_spec.rb +4 -4
  47. data/spec/api/search/cursor_paginated_collection_spec.rb +12 -12
  48. data/spec/api/search/dynamic_fields_spec.rb +4 -4
  49. data/spec/api/search/faceting_spec.rb +55 -52
  50. data/spec/api/search/highlighting_spec.rb +7 -7
  51. data/spec/api/search/hits_spec.rb +29 -29
  52. data/spec/api/search/paginated_collection_spec.rb +18 -18
  53. data/spec/api/search/results_spec.rb +13 -13
  54. data/spec/api/search/search_spec.rb +3 -3
  55. data/spec/api/search/stats_spec.rb +10 -10
  56. data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +19 -18
  57. data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +9 -9
  58. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +10 -6
  59. data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +10 -10
  60. data/spec/api/session_proxy/sharding_session_proxy_spec.rb +14 -13
  61. data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +2 -2
  62. data/spec/api/session_proxy/spec_helper.rb +1 -1
  63. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +9 -5
  64. data/spec/api/session_spec.rb +42 -42
  65. data/spec/api/sunspot_spec.rb +4 -4
  66. data/spec/integration/atomic_updates_spec.rb +25 -11
  67. data/spec/integration/dynamic_fields_spec.rb +10 -10
  68. data/spec/integration/faceting_spec.rb +39 -39
  69. data/spec/integration/field_grouping_spec.rb +16 -16
  70. data/spec/integration/field_lists_spec.rb +41 -0
  71. data/spec/integration/geospatial_spec.rb +19 -8
  72. data/spec/integration/highlighting_spec.rb +5 -5
  73. data/spec/integration/indexing_spec.rb +5 -5
  74. data/spec/integration/keyword_search_spec.rb +47 -45
  75. data/spec/integration/local_search_spec.rb +4 -4
  76. data/spec/integration/more_like_this_spec.rb +7 -7
  77. data/spec/integration/scoped_search_spec.rb +107 -107
  78. data/spec/integration/spellcheck_spec.rb +52 -7
  79. data/spec/integration/stats_spec.rb +10 -10
  80. data/spec/integration/stored_fields_spec.rb +1 -1
  81. data/spec/integration/test_pagination.rb +4 -4
  82. data/spec/integration/unicode_spec.rb +1 -1
  83. data/spec/mocks/post.rb +5 -1
  84. data/spec/spec_helper.rb +11 -6
  85. data/sunspot.gemspec +3 -1
  86. metadata +40 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4bdef6ed9f0c2c63ec693c6db3fe71149987c50d
4
- data.tar.gz: c7451cff132715d22bff11d90bed4ba62bf516e2
3
+ metadata.gz: 97232f93d9d1c5ce704e6249cd1afcec04f7f231
4
+ data.tar.gz: 9eb35de3e65284cdec3eb299d6085cc32e662590
5
5
  SHA512:
6
- metadata.gz: 71b60a64a69d3397a7d81c01282f8ab80e8c7b662bdb4196e91c84b9c06787d8787a2f37ba80e163f653ac0635ecf6edf682b2fec27a0dbef8ecfb79e9fd62c0
7
- data.tar.gz: bdb4c1d76331b386db7a487b3161afbf4f10c7f5c3a74f0d45e1d1876d348f84ba7fa7dfc750d45a2342f0d73d8cf51b72567dae3972ffd5ac08549cd8bf5ec6
6
+ metadata.gz: 5bd0d81960ded04f07fdfa72811ddf959c5c97b0339e58246761469d3f9b4d9a82bf71ec69e8ee222b05ff9c07b5ff406f2702ef1ab8caeacbb1d219415b0044
7
+ data.tar.gz: b8adf8fc509ea65e460139687084832f8353e81e6ad1fd50f976db0a721545934761894ca42281962b19ce64b179a69b607dd3bb05b735b5fc53603aff0685a5
data/.gitignore CHANGED
@@ -11,3 +11,4 @@ pkg
11
11
  README.rdoc
12
12
  .bundle
13
13
  Gemfile.lock
14
+ gemfiles/*.gemfile*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,7 @@
1
+ appraise 'rsolr-1.1.x' do
2
+ gem 'rsolr', '~> 1.1.0'
3
+ end
4
+
5
+ appraise 'rsolr-2.1.x' do
6
+ gem 'rsolr', '~> 2.1.0'
7
+ end
data/Gemfile CHANGED
@@ -1,11 +1,3 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem 'sunspot_solr', :path => File.expand_path('../../sunspot_solr', __FILE__)
4
-
5
3
  gemspec
6
-
7
- group :development do
8
- gem 'rake'
9
- end
10
-
11
- gem 'rsolr', ENV['RSOLR'] if ENV['RSOLR']
File without changes
@@ -14,7 +14,12 @@ module Sunspot
14
14
 
15
15
  # Build a restriction to return only fields of the type in the results.
16
16
  def field_list(*args)
17
- @query.add_field_list(Sunspot::Query::FieldList.new(args.flatten))
17
+ list = args.flatten.map { |field| @setup.field(field.to_sym).indexed_name.to_sym }
18
+ @query.add_field_list(Sunspot::Query::FieldList.new([:id] + list)) unless list.empty?
19
+ end
20
+
21
+ def without_stored_fields
22
+ @query.add_field_list(Sunspot::Query::FieldList.new([:id]))
18
23
  end
19
24
 
20
25
  #
@@ -93,6 +93,17 @@ module Sunspot
93
93
  !!@joined
94
94
  end
95
95
 
96
+ #
97
+ # Whether the field is stored or not.
98
+ #
99
+ # ==== Returns
100
+ #
101
+ # Boolean:: True if this field is a stored field
102
+ #
103
+ def stored?
104
+ !!@stored
105
+ end
106
+
96
107
  def hash
97
108
  indexed_name.hash
98
109
  end
@@ -72,11 +72,15 @@ module Sunspot
72
72
  # into the Solr document for indexing.
73
73
  #
74
74
  def populate_document(document, model, options = {}) #:nodoc:
75
+ atomic_operation = options[:update] == :set
75
76
  value = extract_value(model, options)
76
- unless value.nil?
77
- Util.Array(@field.to_indexed(value)).each do |scalar_value|
77
+ if value != nil || atomic_operation
78
+ indexed_values = Util.Array(@field.to_indexed(value))
79
+ indexed_values = [nil] if indexed_values.empty? && atomic_operation
80
+ indexed_values.each do |scalar_value|
78
81
  field_options = {}
79
82
  field_options[:boost] = @field.boost if @field.boost
83
+ field_options[:null] = true if scalar_value.nil? && atomic_operation
80
84
  document.add_field(
81
85
  @field.indexed_name.to_sym,
82
86
  scalar_value,
@@ -5,8 +5,12 @@ module Sunspot
5
5
  @field, @first_corner, @second_corner = field, first_corner, second_corner
6
6
  end
7
7
 
8
+ def to_solr_conditional
9
+ "[#{@first_corner.join(",")} TO #{@second_corner.join(",")}]"
10
+ end
11
+
8
12
  def to_params
9
- filter = "#{@field.indexed_name}:[#{@first_corner.join(",")} TO #{@second_corner.join(",")}]"
13
+ filter = "#{@field.indexed_name}:#{to_solr_conditional}"
10
14
 
11
15
  {:fq => filter}
12
16
  end
@@ -169,6 +169,17 @@ module Sunspot
169
169
  end
170
170
  end
171
171
 
172
+ class InBoundingBox < Base
173
+ def initialize(negated, field, first_corner, second_corner)
174
+ @bbox = Sunspot::Query::Bbox.new(field, first_corner, second_corner)
175
+ super negated, field, [first_corner, second_corner]
176
+ end
177
+
178
+ def to_solr_conditional
179
+ @bbox.to_solr_conditional
180
+ end
181
+ end
182
+
172
183
  #
173
184
  # Results must have field with value equal to given value. If the value
174
185
  # is nil, results must have no value for the given field.
@@ -11,6 +11,9 @@ module Sunspot
11
11
  end
12
12
  end
13
13
 
14
+ #
15
+ # Returns all of the hits that have a result
16
+ #
14
17
  def verified_hits
15
18
  hits.select { |h| h.result }
16
19
  end
@@ -31,7 +34,7 @@ module Sunspot
31
34
  hits_for_class = id_hit_hash[class_name]
32
35
  data_accessor.load_all(ids).each do |result|
33
36
  hit = hits_for_class.delete(Adapters::InstanceAdapter.adapt(result).id.to_s)
34
- hit.result = result
37
+ hit.result = result if hit
35
38
  end
36
39
  hits_for_class.values.each { |hit| hit.result = nil }
37
40
  end
@@ -49,12 +49,11 @@ module Sunspot
49
49
  # the index. Otherwise return Solr's suggested collation.
50
50
  #
51
51
  # Solr's suggested collation is more liberal, replacing even terms that
52
- # are present in the index. This may not be useful if only one term is
53
- # misspelled and preventing useful results.
52
+ # are present in the index.
54
53
  #
55
54
  # Mix and match in your views for a blend of strict and liberal collations.
56
55
  def spellcheck_collation(*terms)
57
- if solr_spellcheck['suggestions'] && solr_spellcheck['suggestions'].length > 2
56
+ if solr_spellcheck['suggestions'] && solr_spellcheck['suggestions'].length > 0
58
57
  collation = terms.join(" ").dup if terms
59
58
 
60
59
  # If we are given a query string, tokenize it and strictly replace
@@ -1,3 +1,3 @@
1
1
  module Sunspot
2
- VERSION = '2.2.7'
2
+ VERSION = '2.2.8'
3
3
  end
@@ -2,45 +2,45 @@ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
2
 
3
3
  describe Sunspot::Adapters::InstanceAdapter do
4
4
  it "finds adapter by superclass" do
5
- Sunspot::Adapters::InstanceAdapter::for(Model).should be(AbstractModelInstanceAdapter)
5
+ expect(Sunspot::Adapters::InstanceAdapter::for(Model)).to be(AbstractModelInstanceAdapter)
6
6
  end
7
7
 
8
8
  it "finds adapter by mixin" do
9
- Sunspot::Adapters::InstanceAdapter::for(MixModel).should be(MixInModelInstanceAdapter)
9
+ expect(Sunspot::Adapters::InstanceAdapter::for(MixModel)).to be(MixInModelInstanceAdapter)
10
10
  end
11
11
 
12
12
  it 'throws NoAdapterError if anonymous module passed in' do
13
- lambda do
13
+ expect do
14
14
  Sunspot::Adapters::InstanceAdapter::for(Module.new)
15
- end.should raise_error(Sunspot::NoAdapterError)
15
+ end.to raise_error(Sunspot::NoAdapterError)
16
16
  end
17
17
 
18
18
  it "registers adapters found by ancestor lookup with the descendant class" do
19
- Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel).should be(nil)
19
+ expect(Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel)).to be(nil)
20
20
  Sunspot::Adapters::InstanceAdapter::for(UnseenModel)
21
- Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel).should be(AbstractModelInstanceAdapter)
21
+ expect(Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel)).to be(AbstractModelInstanceAdapter)
22
22
  end
23
23
  end
24
24
 
25
25
  describe Sunspot::Adapters::DataAccessor do
26
26
  it "finds adapter by superclass" do
27
- Sunspot::Adapters::DataAccessor::for(Model).should be(AbstractModelDataAccessor)
27
+ expect(Sunspot::Adapters::DataAccessor::for(Model)).to be(AbstractModelDataAccessor)
28
28
  end
29
29
 
30
30
  it "finds adapter by mixin" do
31
- Sunspot::Adapters::DataAccessor::for(MixModel).should be(MixInModelDataAccessor)
31
+ expect(Sunspot::Adapters::DataAccessor::for(MixModel)).to be(MixInModelDataAccessor)
32
32
  end
33
33
 
34
34
  it 'throws NoAdapterError if anonymous module passed in' do
35
- lambda do
35
+ expect do
36
36
  Sunspot::Adapters::DataAccessor::for(Module.new)
37
- end.should raise_error(Sunspot::NoAdapterError)
37
+ end.to raise_error(Sunspot::NoAdapterError)
38
38
  end
39
39
 
40
40
  it "registers adapters found by ancestor lookup with the descendant class" do
41
- Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel).should be(nil)
41
+ expect(Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel)).to be(nil)
42
42
  Sunspot::Adapters::DataAccessor::for(UnseenModel)
43
- Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel).should be(AbstractModelDataAccessor)
43
+ expect(Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel)).to be(AbstractModelDataAccessor)
44
44
  end
45
45
  end
46
46
 
@@ -51,30 +51,30 @@ describe Sunspot::Adapters::Registry do
51
51
  let(:mixin_accessor){ Sunspot::Adapters::DataAccessor::for(MixModel) }
52
52
 
53
53
  it "registers and retrieves a data accessor for abstractclass" do
54
- registry.retrieve(AbstractModel).should be_a(abstractclass_accessor)
54
+ expect(registry.retrieve(AbstractModel)).to be_a(abstractclass_accessor)
55
55
  end
56
56
 
57
57
  it "registers and retrieves a data accessor for superclass" do
58
- registry.retrieve(Model).should be_a(superclass_accessor)
58
+ expect(registry.retrieve(Model)).to be_a(superclass_accessor)
59
59
  end
60
60
 
61
61
  it "registers and retrieves a data accessor for mixin" do
62
- registry.retrieve(MixModel).should be_a(mixin_accessor)
62
+ expect(registry.retrieve(MixModel)).to be_a(mixin_accessor)
63
63
  end
64
64
 
65
65
  it "injects inherited attributes" do
66
- AbstractModelDataAccessor.any_instance.stub(:inherited_attributes).and_return([:to_be_injected])
66
+ allow_any_instance_of(AbstractModelDataAccessor).to receive(:inherited_attributes).and_return([:to_be_injected])
67
67
  in_registry_data_accessor = registry.retrieve(AbstractModel)
68
68
  in_registry_data_accessor.to_be_injected = "value"
69
- registry.retrieve(Model).to_be_injected.should == "value"
69
+ expect(registry.retrieve(Model).to_be_injected).to eq("value")
70
70
  end
71
71
 
72
72
  it "not overrides inherited attributes" do
73
- AbstractModelDataAccessor.any_instance.stub(:inherited_attributes).and_return([:to_be_injected])
73
+ allow_any_instance_of(AbstractModelDataAccessor).to receive(:inherited_attributes).and_return([:to_be_injected])
74
74
  parent_data_accessor = registry.retrieve(AbstractModel)
75
75
  current_data_accessor = registry.retrieve(Model)
76
76
  parent_data_accessor.to_be_injected = "value"
77
77
  current_data_accessor.to_be_injected = "safe-value"
78
- registry.retrieve(Model).to_be_injected.should == "safe-value"
78
+ expect(registry.retrieve(Model).to_be_injected).to eq("safe-value")
79
79
  end
80
80
  end
@@ -2,12 +2,12 @@ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
2
 
3
3
  describe Sunspot::Batcher do
4
4
  it "includes Enumerable" do
5
- described_class.should include Enumerable
5
+ expect(described_class).to include Enumerable
6
6
  end
7
7
 
8
8
  describe "#each" do
9
9
  let(:current) { [:foo, :bar] }
10
- before { subject.stub(:current).and_return current }
10
+ before { allow(subject).to receive(:current).and_return current }
11
11
 
12
12
  it "iterates over current" do
13
13
  yielded_values = []
@@ -16,25 +16,25 @@ describe Sunspot::Batcher do
16
16
  yielded_values << value
17
17
  end
18
18
 
19
- yielded_values.should eq current
19
+ expect(yielded_values).to eq current
20
20
  end
21
21
  end
22
22
 
23
23
  describe "adding to current batch" do
24
24
  it "#push pushes to current" do
25
25
  subject.push :foo
26
- subject.current.should include :foo
26
+ expect(subject.current).to include :foo
27
27
  end
28
28
 
29
29
  it "#<< pushes to current" do
30
30
  subject.push :foo
31
- subject.current.should include :foo
31
+ expect(subject.current).to include :foo
32
32
  end
33
33
 
34
34
  it "#concat concatinates on current batch" do
35
35
  subject << :foo
36
36
  subject.concat [:bar, :mix]
37
- should include :foo, :bar, :mix
37
+ is_expected.to include :foo, :bar, :mix
38
38
  end
39
39
  end
40
40
 
@@ -46,7 +46,7 @@ describe Sunspot::Batcher do
46
46
  end
47
47
 
48
48
  it "is empty by default" do
49
- subject.current.should be_empty
49
+ expect(subject.current).to be_empty
50
50
  end
51
51
  end
52
52
 
@@ -58,7 +58,7 @@ describe Sunspot::Batcher do
58
58
  end
59
59
 
60
60
  it "returns the same as last time" do
61
- subject.current.should eq subject.current
61
+ expect(subject.current).to eq subject.current
62
62
  end
63
63
  end
64
64
  end
@@ -71,7 +71,7 @@ describe Sunspot::Batcher do
71
71
  it "changes current" do
72
72
  subject << :foo
73
73
  subject.start_new
74
- should_not include :foo
74
+ is_expected.not_to include :foo
75
75
  end
76
76
  end
77
77
 
@@ -88,25 +88,25 @@ describe Sunspot::Batcher do
88
88
  it "changes current" do
89
89
  subject << :foo
90
90
  subject.end_current
91
- should_not include :foo
91
+ is_expected.not_to include :foo
92
92
  end
93
93
 
94
94
  it "returns current" do
95
95
  subject << :foo
96
- subject.end_current.should include :foo
96
+ expect(subject.end_current).to include :foo
97
97
  end
98
98
  end
99
99
  end
100
100
 
101
101
  describe "#batching?" do
102
102
  it "is false when depth is 0" do
103
- subject.should_receive(:depth).and_return 0
104
- should_not be_batching
103
+ expect(subject).to receive(:depth).and_return 0
104
+ is_expected.not_to be_batching
105
105
  end
106
106
 
107
107
  it "is true when depth is more than 0" do
108
- subject.should_receive(:depth).and_return 1
109
- should be_batching
108
+ expect(subject).to receive(:depth).and_return 1
109
+ is_expected.to be_batching
110
110
  end
111
111
  end
112
112
  end
@@ -6,7 +6,7 @@ describe "DSL bindings" do
6
6
  session.search(Post) do
7
7
  value = test_method
8
8
  end
9
- value.should == 'value'
9
+ expect(value).to eq('value')
10
10
  end
11
11
 
12
12
  it 'should give access to calling context\'s id method in search DSL' do
@@ -14,7 +14,7 @@ describe "DSL bindings" do
14
14
  session.search(Post) do
15
15
  value = id
16
16
  end
17
- value.should == 16
17
+ expect(value).to eq(16)
18
18
  end
19
19
 
20
20
  it 'should give access to calling context\'s methods in nested DSL block' do
@@ -24,7 +24,7 @@ describe "DSL bindings" do
24
24
  value = test_method
25
25
  end
26
26
  end
27
- value.should == 'value'
27
+ expect(value).to eq('value')
28
28
  end
29
29
 
30
30
  it 'should give access to calling context\'s methods in double-nested DSL block' do
@@ -7,7 +7,7 @@ describe Sunspot::ClassSet do
7
7
  set = described_class.new
8
8
  set << class1 << class2
9
9
 
10
- set.to_a.should =~ [class1, class2]
10
+ expect(set.to_a).to match_array([class1, class2])
11
11
  end
12
12
 
13
13
  it "replaces classes with the same name" do
@@ -15,10 +15,10 @@ describe Sunspot::ClassSet do
15
15
 
16
16
  class1 = double(:name => "Class1")
17
17
  set << class1
18
- set.to_a.should == [class1]
18
+ expect(set.to_a).to eq([class1])
19
19
 
20
20
  class1_dup = double(:name => "Class1")
21
21
  set << class1_dup
22
- set.to_a.should == [class1_dup]
22
+ expect(set.to_a).to eq([class1_dup])
23
23
  end
24
24
  end
@@ -9,37 +9,60 @@ describe Sunspot::Search::HitEnumerable do
9
9
 
10
10
  describe "#hits" do
11
11
  before do
12
- subject.stub(:solr_docs).and_return([{"id" => "Post 1", "score" => 3.14}])
13
- subject.stub(:highlights_for)
12
+ allow(subject).to receive(:solr_docs).and_return([{"id" => "Post 1", "score" => 3.14}])
13
+ allow(subject).to receive(:highlights_for)
14
14
  end
15
15
 
16
16
  it "retrieves the raw Solr response from #solr_docs and constructs Hit objects" do
17
- Sunspot::Search::Hit.should_receive(:new).
17
+ expect(Sunspot::Search::Hit).to receive(:new).
18
18
  with({"id" => "Post 1", "score" => 3.14}, anything, anything)
19
19
 
20
20
  subject.hits
21
21
  end
22
22
 
23
23
  it "constructs Hit objects with highlights" do
24
- subject.should_receive(:highlights_for).with({"id" => "Post 1", "score" => 3.14})
24
+ expect(subject).to receive(:highlights_for).with({"id" => "Post 1", "score" => 3.14})
25
25
 
26
26
  subject.hits
27
27
  end
28
28
 
29
29
  it "returns only verified hits if :verify => true is passed" do
30
- Sunspot::Search::Hit.any_instance.stub(:result).and_return(nil)
30
+ allow_any_instance_of(Sunspot::Search::Hit).to receive(:result).and_return(nil)
31
31
 
32
- subject.hits(:verify => true).should be_empty
32
+ expect(subject.hits(:verify => true)).to be_empty
33
33
  end
34
34
 
35
35
  it "returns an empty array if no results are available from Solr" do
36
- subject.stub(:solr_docs).and_return(nil)
36
+ allow(subject).to receive(:solr_docs).and_return(nil)
37
37
 
38
- subject.hits.should == []
38
+ expect(subject.hits).to eq([])
39
39
  end
40
40
 
41
41
  it "provides #populate_hits so that querying for one hit result will eager load the rest" do
42
- Sunspot::Search::Hit.any_instance.should_receive(:result=)
42
+ expect_any_instance_of(Sunspot::Search::Hit).to receive(:result=)
43
+
44
+ subject.populate_hits
45
+ end
46
+ end
47
+
48
+ describe "#populate_hits" do
49
+ let(:post_1) { Post.new(id: "1", title: "Title 1") }
50
+
51
+ before do
52
+ allow(subject).to receive(:solr_docs).and_return([{ "id" => "Post 1", "score" => 3.14 }])
53
+ allow(subject).to receive(:highlights_for)
54
+ end
55
+
56
+ it "populates the hit object with the result from the data accessor" do
57
+ allow_any_instance_of(MockAdapter::DataAccessor).to receive(:load_all).and_return([post_1])
58
+ expect_any_instance_of(Sunspot::Search::Hit).to receive(:result=).with(post_1)
59
+
60
+ subject.populate_hits
61
+ end
62
+
63
+ it "populates the hit object only once if there are duplicate entries in the database (ex: db missing unique constraints)" do
64
+ allow_any_instance_of(MockAdapter::DataAccessor).to receive(:load_all).and_return([post_1, post_1])
65
+ expect_any_instance_of(Sunspot::Search::Hit).to receive(:result=).with(post_1)
43
66
 
44
67
  subject.populate_hits
45
68
  end