gojee-sunspot 2.0.3 → 2.0.4
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.
- data/.gitignore +12 -0
- data/Gemfile +5 -0
- data/History.txt +252 -0
- data/LICENSE +18 -0
- data/Rakefile +13 -0
- data/TODO +13 -0
- data/lib/light_config.rb +40 -0
- data/lib/sunspot/adapters.rb +265 -0
- data/lib/sunspot/batcher.rb +62 -0
- data/lib/sunspot/class_set.rb +23 -0
- data/lib/sunspot/composite_setup.rb +202 -0
- data/lib/sunspot/configuration.rb +53 -0
- data/lib/sunspot/data_extractor.rb +50 -0
- data/lib/sunspot/dsl/adjustable.rb +47 -0
- data/lib/sunspot/dsl/field_group.rb +57 -0
- data/lib/sunspot/dsl/field_query.rb +327 -0
- data/lib/sunspot/dsl/fields.rb +103 -0
- data/lib/sunspot/dsl/fulltext.rb +243 -0
- data/lib/sunspot/dsl/function.rb +27 -0
- data/lib/sunspot/dsl/functional.rb +44 -0
- data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
- data/lib/sunspot/dsl/paginatable.rb +32 -0
- data/lib/sunspot/dsl/query_facet.rb +36 -0
- data/lib/sunspot/dsl/restriction.rb +25 -0
- data/lib/sunspot/dsl/restriction_with_near.rb +160 -0
- data/lib/sunspot/dsl/scope.rb +217 -0
- data/lib/sunspot/dsl/search.rb +30 -0
- data/lib/sunspot/dsl/standard_query.rb +123 -0
- data/lib/sunspot/dsl.rb +5 -0
- data/lib/sunspot/field.rb +193 -0
- data/lib/sunspot/field_factory.rb +129 -0
- data/lib/sunspot/indexer.rb +136 -0
- data/lib/sunspot/query/abstract_field_facet.rb +52 -0
- data/lib/sunspot/query/bbox.rb +15 -0
- data/lib/sunspot/query/boost_query.rb +24 -0
- data/lib/sunspot/query/common_query.rb +96 -0
- data/lib/sunspot/query/composite_fulltext.rb +36 -0
- data/lib/sunspot/query/connective.rb +206 -0
- data/lib/sunspot/query/date_field_facet.rb +14 -0
- data/lib/sunspot/query/dismax.rb +132 -0
- data/lib/sunspot/query/field_facet.rb +41 -0
- data/lib/sunspot/query/field_group.rb +36 -0
- data/lib/sunspot/query/filter.rb +38 -0
- data/lib/sunspot/query/function_query.rb +52 -0
- data/lib/sunspot/query/geo.rb +53 -0
- data/lib/sunspot/query/geofilt.rb +16 -0
- data/lib/sunspot/query/highlighting.rb +62 -0
- data/lib/sunspot/query/more_like_this.rb +61 -0
- data/lib/sunspot/query/more_like_this_query.rb +12 -0
- data/lib/sunspot/query/pagination.rb +42 -0
- data/lib/sunspot/query/query_facet.rb +16 -0
- data/lib/sunspot/query/restriction.rb +262 -0
- data/lib/sunspot/query/scope.rb +9 -0
- data/lib/sunspot/query/sort.rb +109 -0
- data/lib/sunspot/query/sort_composite.rb +34 -0
- data/lib/sunspot/query/standard_query.rb +16 -0
- data/lib/sunspot/query/text_field_boost.rb +17 -0
- data/lib/sunspot/query.rb +11 -0
- data/lib/sunspot/schema.rb +151 -0
- data/lib/sunspot/search/abstract_search.rb +281 -0
- data/lib/sunspot/search/date_facet.rb +35 -0
- data/lib/sunspot/search/facet_row.rb +27 -0
- data/lib/sunspot/search/field_facet.rb +88 -0
- data/lib/sunspot/search/field_group.rb +32 -0
- data/lib/sunspot/search/group.rb +50 -0
- data/lib/sunspot/search/highlight.rb +38 -0
- data/lib/sunspot/search/hit.rb +150 -0
- data/lib/sunspot/search/hit_enumerable.rb +72 -0
- data/lib/sunspot/search/more_like_this_search.rb +31 -0
- data/lib/sunspot/search/paginated_collection.rb +57 -0
- data/lib/sunspot/search/query_facet.rb +67 -0
- data/lib/sunspot/search/standard_search.rb +21 -0
- data/lib/sunspot/search.rb +9 -0
- data/lib/sunspot/session.rb +262 -0
- data/lib/sunspot/session_proxy/abstract_session_proxy.rb +29 -0
- data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +66 -0
- data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +89 -0
- data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +43 -0
- data/lib/sunspot/session_proxy/multicore_session_proxy.rb +67 -0
- data/lib/sunspot/session_proxy/sharding_session_proxy.rb +222 -0
- data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +42 -0
- data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +37 -0
- data/lib/sunspot/session_proxy.rb +95 -0
- data/lib/sunspot/setup.rb +350 -0
- data/lib/sunspot/text_field_setup.rb +29 -0
- data/lib/sunspot/type.rb +393 -0
- data/lib/sunspot/util.rb +252 -0
- data/lib/sunspot/version.rb +3 -0
- data/lib/sunspot.rb +579 -0
- data/log/.gitignore +1 -0
- data/pkg/.gitignore +1 -0
- data/script/console +10 -0
- data/spec/api/adapters_spec.rb +33 -0
- data/spec/api/batcher_spec.rb +112 -0
- data/spec/api/binding_spec.rb +50 -0
- data/spec/api/class_set_spec.rb +24 -0
- data/spec/api/hit_enumerable_spec.rb +47 -0
- data/spec/api/indexer/attributes_spec.rb +149 -0
- data/spec/api/indexer/batch_spec.rb +72 -0
- data/spec/api/indexer/dynamic_fields_spec.rb +42 -0
- data/spec/api/indexer/fixed_fields_spec.rb +57 -0
- data/spec/api/indexer/fulltext_spec.rb +43 -0
- data/spec/api/indexer/removal_spec.rb +53 -0
- data/spec/api/indexer/spec_helper.rb +1 -0
- data/spec/api/indexer_spec.rb +14 -0
- data/spec/api/query/advanced_manipulation_examples.rb +35 -0
- data/spec/api/query/connectives_examples.rb +189 -0
- data/spec/api/query/dsl_spec.rb +18 -0
- data/spec/api/query/dynamic_fields_examples.rb +165 -0
- data/spec/api/query/faceting_examples.rb +397 -0
- data/spec/api/query/fulltext_examples.rb +313 -0
- data/spec/api/query/function_spec.rb +79 -0
- data/spec/api/query/geo_examples.rb +68 -0
- data/spec/api/query/group_spec.rb +32 -0
- data/spec/api/query/highlighting_examples.rb +245 -0
- data/spec/api/query/more_like_this_spec.rb +140 -0
- data/spec/api/query/ordering_pagination_examples.rb +116 -0
- data/spec/api/query/scope_examples.rb +275 -0
- data/spec/api/query/spatial_examples.rb +27 -0
- data/spec/api/query/spec_helper.rb +1 -0
- data/spec/api/query/standard_spec.rb +29 -0
- data/spec/api/query/text_field_scoping_examples.rb +30 -0
- data/spec/api/query/types_spec.rb +20 -0
- data/spec/api/search/dynamic_fields_spec.rb +33 -0
- data/spec/api/search/faceting_spec.rb +360 -0
- data/spec/api/search/highlighting_spec.rb +69 -0
- data/spec/api/search/hits_spec.rb +131 -0
- data/spec/api/search/paginated_collection_spec.rb +36 -0
- data/spec/api/search/results_spec.rb +72 -0
- data/spec/api/search/search_spec.rb +23 -0
- data/spec/api/search/spec_helper.rb +1 -0
- data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +85 -0
- data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +30 -0
- data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +41 -0
- data/spec/api/session_proxy/sharding_session_proxy_spec.rb +77 -0
- data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +24 -0
- data/spec/api/session_proxy/spec_helper.rb +9 -0
- data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +39 -0
- data/spec/api/session_spec.rb +232 -0
- data/spec/api/spec_helper.rb +3 -0
- data/spec/api/sunspot_spec.rb +29 -0
- data/spec/ext.rb +11 -0
- data/spec/helpers/indexer_helper.rb +17 -0
- data/spec/helpers/integration_helper.rb +8 -0
- data/spec/helpers/mock_session_helper.rb +13 -0
- data/spec/helpers/query_helper.rb +26 -0
- data/spec/helpers/search_helper.rb +68 -0
- data/spec/integration/dynamic_fields_spec.rb +57 -0
- data/spec/integration/faceting_spec.rb +251 -0
- data/spec/integration/field_grouping_spec.rb +66 -0
- data/spec/integration/geospatial_spec.rb +85 -0
- data/spec/integration/highlighting_spec.rb +44 -0
- data/spec/integration/indexing_spec.rb +55 -0
- data/spec/integration/keyword_search_spec.rb +317 -0
- data/spec/integration/local_search_spec.rb +64 -0
- data/spec/integration/more_like_this_spec.rb +43 -0
- data/spec/integration/scoped_search_spec.rb +354 -0
- data/spec/integration/stored_fields_spec.rb +12 -0
- data/spec/integration/test_pagination.rb +43 -0
- data/spec/integration/unicode_spec.rb +15 -0
- data/spec/mocks/adapters.rb +32 -0
- data/spec/mocks/blog.rb +3 -0
- data/spec/mocks/comment.rb +21 -0
- data/spec/mocks/connection.rb +126 -0
- data/spec/mocks/mock_adapter.rb +30 -0
- data/spec/mocks/mock_class_sharding_session_proxy.rb +24 -0
- data/spec/mocks/mock_record.rb +52 -0
- data/spec/mocks/mock_sharding_session_proxy.rb +15 -0
- data/spec/mocks/photo.rb +11 -0
- data/spec/mocks/post.rb +86 -0
- data/spec/mocks/super_class.rb +2 -0
- data/spec/mocks/user.rb +13 -0
- data/spec/spec_helper.rb +40 -0
- data/sunspot.gemspec +42 -0
- data/tasks/rdoc.rake +27 -0
- data/tasks/schema.rake +19 -0
- data/tasks/todo.rake +4 -0
- metadata +261 -3
@@ -0,0 +1,112 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Sunspot::Batcher do
|
4
|
+
it "includes Enumerable" do
|
5
|
+
described_class.should include Enumerable
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#each" do
|
9
|
+
let(:current) { [:foo, :bar] }
|
10
|
+
before { subject.stub(:current).and_return current }
|
11
|
+
|
12
|
+
it "iterates over current" do
|
13
|
+
yielded_values = []
|
14
|
+
|
15
|
+
subject.each do |value|
|
16
|
+
yielded_values << value
|
17
|
+
end
|
18
|
+
|
19
|
+
yielded_values.should eq current
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "adding to current batch" do
|
24
|
+
it "#push pushes to current" do
|
25
|
+
subject.push :foo
|
26
|
+
subject.current.should include :foo
|
27
|
+
end
|
28
|
+
|
29
|
+
it "#<< pushes to current" do
|
30
|
+
subject.push :foo
|
31
|
+
subject.current.should include :foo
|
32
|
+
end
|
33
|
+
|
34
|
+
it "#concat concatinates on current batch" do
|
35
|
+
subject << :foo
|
36
|
+
subject.concat [:bar, :mix]
|
37
|
+
should include :foo, :bar, :mix
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
describe "#current" do
|
43
|
+
context "no current" do
|
44
|
+
it "starts a new" do
|
45
|
+
expect { subject.current }.to change(subject, :depth).by 1
|
46
|
+
end
|
47
|
+
|
48
|
+
it "is empty by default" do
|
49
|
+
subject.current.should be_empty
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "with a current" do
|
54
|
+
before { subject.start_new }
|
55
|
+
|
56
|
+
it "does not start a new" do
|
57
|
+
expect { subject.current }.to_not change(subject, :depth)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "returns the same as last time" do
|
61
|
+
subject.current.should eq subject.current
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#start_new" do
|
67
|
+
it "creates a new batches" do
|
68
|
+
expect { 2.times { subject.start_new } }.to change(subject, :depth).by 2
|
69
|
+
end
|
70
|
+
|
71
|
+
it "changes current" do
|
72
|
+
subject << :foo
|
73
|
+
subject.start_new
|
74
|
+
should_not include :foo
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#end_current" do
|
79
|
+
context "no current batch" do
|
80
|
+
it "fails" do
|
81
|
+
expect { subject.end_current }.to raise_error Sunspot::Batcher::NoCurrentBatchError
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "with current batch" do
|
86
|
+
before { subject.start_new }
|
87
|
+
|
88
|
+
it "changes current" do
|
89
|
+
subject << :foo
|
90
|
+
subject.end_current
|
91
|
+
should_not include :foo
|
92
|
+
end
|
93
|
+
|
94
|
+
it "returns current" do
|
95
|
+
subject << :foo
|
96
|
+
subject.end_current.should include :foo
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#batching?" do
|
102
|
+
it "is false when depth is 0" do
|
103
|
+
subject.should_receive(:depth).and_return 0
|
104
|
+
should_not be_batching
|
105
|
+
end
|
106
|
+
|
107
|
+
it "is true when depth is more than 0" do
|
108
|
+
subject.should_receive(:depth).and_return 1
|
109
|
+
should be_batching
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "DSL bindings" do
|
4
|
+
it 'should give access to calling context\'s methods in search DSL' do
|
5
|
+
value = nil
|
6
|
+
session.search(Post) do
|
7
|
+
value = test_method
|
8
|
+
end
|
9
|
+
value.should == 'value'
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should give access to calling context\'s id method in search DSL' do
|
13
|
+
value = nil
|
14
|
+
session.search(Post) do
|
15
|
+
value = id
|
16
|
+
end
|
17
|
+
value.should == 16
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should give access to calling context\'s methods in nested DSL block' do
|
21
|
+
value = nil
|
22
|
+
session.search(Post) do
|
23
|
+
any_of do
|
24
|
+
value = test_method
|
25
|
+
end
|
26
|
+
end
|
27
|
+
value.should == 'value'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should give access to calling context\'s methods in double-nested DSL block' do
|
31
|
+
value = nil
|
32
|
+
session.search(Post) do
|
33
|
+
any_of do
|
34
|
+
all_of do
|
35
|
+
value = test_method
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def test_method
|
44
|
+
'value'
|
45
|
+
end
|
46
|
+
|
47
|
+
def id
|
48
|
+
16
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Sunspot::ClassSet do
|
4
|
+
it "is enumerable" do
|
5
|
+
class1, class2 = stub(:name => "Class1"), stub(:name => "Class2")
|
6
|
+
|
7
|
+
set = described_class.new
|
8
|
+
set << class1 << class2
|
9
|
+
|
10
|
+
set.to_a.should =~ [class1, class2]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "replaces classes with the same name" do
|
14
|
+
set = described_class.new
|
15
|
+
|
16
|
+
class1 = stub(:name => "Class1")
|
17
|
+
set << class1
|
18
|
+
set.to_a.should == [class1]
|
19
|
+
|
20
|
+
class1_dup = stub(:name => "Class1")
|
21
|
+
set << class1_dup
|
22
|
+
set.to_a.should == [class1_dup]
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Sunspot::Search::HitEnumerable do
|
4
|
+
subject do
|
5
|
+
Class.new do
|
6
|
+
include Sunspot::Search::HitEnumerable
|
7
|
+
end.new
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#hits" do
|
11
|
+
before do
|
12
|
+
subject.stub(:solr_docs).and_return([{"id" => "Post 1", "score" => 3.14}])
|
13
|
+
subject.stub(:highlights_for)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "retrieves the raw Solr response from #solr_docs and constructs Hit objects" do
|
17
|
+
Sunspot::Search::Hit.should_receive(:new).
|
18
|
+
with({"id" => "Post 1", "score" => 3.14}, anything, anything)
|
19
|
+
|
20
|
+
subject.hits
|
21
|
+
end
|
22
|
+
|
23
|
+
it "constructs Hit objects with highlights" do
|
24
|
+
subject.should_receive(:highlights_for).with({"id" => "Post 1", "score" => 3.14})
|
25
|
+
|
26
|
+
subject.hits
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns only verified hits if :verify => true is passed" do
|
30
|
+
Sunspot::Search::Hit.any_instance.stub(:result).and_return(nil)
|
31
|
+
|
32
|
+
subject.hits(:verify => true).should be_empty
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns an empty array if no results are available from Solr" do
|
36
|
+
subject.stub(:solr_docs).and_return(nil)
|
37
|
+
|
38
|
+
subject.hits.should == []
|
39
|
+
end
|
40
|
+
|
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=)
|
43
|
+
|
44
|
+
subject.populate_hits
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
require 'bigdecimal'
|
3
|
+
|
4
|
+
describe 'indexing attribute fields', :type => :indexer do
|
5
|
+
it 'should correctly index a stored string attribute field' do
|
6
|
+
session.index(post(:title => 'A Title'))
|
7
|
+
connection.should have_add_with(:title_ss => 'A Title')
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should correctly index an integer attribute field' do
|
11
|
+
session.index(post(:blog_id => 4))
|
12
|
+
connection.should have_add_with(:blog_id_i => '4')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should correctly index a long attribute field' do
|
16
|
+
session.index(Namespaced::Comment.new(:hash => 2**30))
|
17
|
+
connection.should have_add_with(:hash_l => '1073741824')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should correctly index a float attribute field' do
|
21
|
+
session.index(post(:ratings_average => 2.23))
|
22
|
+
connection.should have_add_with(:average_rating_ft => '2.23')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should correctly index a double attribute field' do
|
26
|
+
session.index(Namespaced::Comment.new(:average_rating => 2.23))
|
27
|
+
connection.should have_add_with(:average_rating_e => '2.23')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should correctly index a trie integer attribute field' do
|
31
|
+
session.index(Photo.new(:size => 104856))
|
32
|
+
connection.should have_add_with(:size_it => '104856')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should correctly index a trie float attribute field' do
|
36
|
+
session.index(Photo.new(:average_rating => 2.23))
|
37
|
+
connection.should have_add_with(:average_rating_ft => '2.23')
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should correctly index a trie time attribute field' do
|
41
|
+
session.index(Photo.new(:created_at => Time.parse('2009-12-16 15:00:00 -0400')))
|
42
|
+
connection.should have_add_with(:created_at_dt => '2009-12-16T19:00:00Z')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should allow indexing by a multiple-value field' do
|
46
|
+
session.index(post(:category_ids => [3, 14]))
|
47
|
+
connection.should have_add_with(:category_ids_im => ['3', '14'])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should not index a single-value field with newlines as multiple' do
|
51
|
+
session.index(post(:title => "Multi\nLine"))
|
52
|
+
connection.adds.last.first.field_by_name(:title_ss).value.should == "Multi\nLine"
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should correctly index a time field' do
|
56
|
+
session.index(
|
57
|
+
post(:published_at => Time.parse('1983-07-08 05:00:00 -0400'))
|
58
|
+
)
|
59
|
+
connection.should have_add_with(:published_at_dt => '1983-07-08T09:00:00Z')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should correctly index a time field that\'s after 32-bit Y2K' do
|
63
|
+
session.index(
|
64
|
+
post(:published_at => DateTime.parse('2050-07-08 05:00:00 -0400'))
|
65
|
+
)
|
66
|
+
connection.should have_add_with(:published_at_dt => '2050-07-08T09:00:00Z')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should correctly index a date field' do
|
70
|
+
session.index(post(:expire_date => Date.new(2009, 07, 13)))
|
71
|
+
connection.should have_add_with(:expire_date_d => '2009-07-13T00:00:00Z')
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should correctly index a boolean field' do
|
75
|
+
session.index(post(:featured => true))
|
76
|
+
connection.should have_add_with(:featured_bs => 'true')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should correctly index a false boolean field' do
|
80
|
+
session.index(post(:featured => false))
|
81
|
+
connection.should have_add_with(:featured_bs => 'false')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should not index a nil boolean field' do
|
85
|
+
session.index(post)
|
86
|
+
connection.should_not have_add_with(:featured_bs)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should index latitude and longitude as a pair' do
|
90
|
+
session.index(post(:coordinates => Sunspot::Util::Coordinates.new(40.7, -73.5)))
|
91
|
+
connection.should have_add_with(:coordinates_s => 'dr5xx3nytvgs')
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should index latitude and longitude passed as non-Floats' do
|
95
|
+
coordinates = Sunspot::Util::Coordinates.new(
|
96
|
+
BigDecimal.new('40.7'), BigDecimal.new('-73.5'))
|
97
|
+
session.index(post(:coordinates => coordinates))
|
98
|
+
connection.should have_add_with(:coordinates_s => 'dr5xx3nytvgs')
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should correctly index an attribute field with block access' do
|
102
|
+
session.index(post(:title => 'The Blog Post'))
|
103
|
+
connection.should have_add_with(:sort_title_s => 'blog post')
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should correctly index an attribute field with instance-external block access' do
|
107
|
+
session.index(post(:category_ids => [1, 2, 3]))
|
108
|
+
connection.should have_add_with(:primary_category_id_i => '1')
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should correctly index a field that is defined on a superclass' do
|
112
|
+
Sunspot.setup(SuperClass) { string :author_name }
|
113
|
+
session.index(post(:author_name => 'Mat Brown'))
|
114
|
+
connection.should have_add_with(:author_name_s => 'Mat Brown')
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should throw a NoMethodError only if a nonexistent type is defined' do
|
118
|
+
lambda { Sunspot.setup(Post) { string :author_name }}.should_not raise_error
|
119
|
+
lambda { Sunspot.setup(Post) { bogus :journey }}.should raise_error(NoMethodError)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should throw a NoMethodError if a nonexistent field argument is passed' do
|
123
|
+
lambda { Sunspot.setup(Post) { string :author_name, :bogus => :argument }}.should raise_error(ArgumentError)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should throw an ArgumentError if single-value field tries to index multiple values' do
|
127
|
+
lambda do
|
128
|
+
Sunspot.setup(Post) { string :author_name }
|
129
|
+
session.index(post(:author_name => ['Mat Brown', 'Matthew Brown']))
|
130
|
+
end.should raise_error(ArgumentError)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should throw an ArgumentError if specifying more_like_this on type that does not support it' do
|
134
|
+
lambda do
|
135
|
+
Sunspot.setup(Post) { integer :popularity, :more_like_this => true }
|
136
|
+
end.should raise_error(ArgumentError)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should use a specified field name when the :as option is set' do
|
140
|
+
session.index(post(:title => 'A Title'))
|
141
|
+
connection.should have_add_with(:legacy_field_s => 'legacy A Title')
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should use a specified field name when the :as option is set for array values' do
|
145
|
+
session.index(post(:title => 'Another Title'))
|
146
|
+
connection.should have_add_with(:legacy_array_field_sm => ['first string', 'second string'])
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'batch indexing', :type => :indexer do
|
4
|
+
let(:posts) { Array.new(2) { |index| Post.new :title => "Post number #{index}!" } }
|
5
|
+
|
6
|
+
it 'should send all batched adds in a single request' do
|
7
|
+
session.batch do
|
8
|
+
for post in posts
|
9
|
+
session.index(post)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
connection.adds.length.should == 1
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should add all batched adds' do
|
16
|
+
session.batch do
|
17
|
+
for post in posts
|
18
|
+
session.index(post)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
add = connection.adds.last
|
22
|
+
connection.adds.first.map { |add| add.field_by_name(:id).value }.should ==
|
23
|
+
posts.map { |post| "Post #{post.id}" }
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should not index changes to models that happen after index call' do
|
27
|
+
post = Post.new
|
28
|
+
session.batch do
|
29
|
+
session.index(post)
|
30
|
+
post.title = 'Title'
|
31
|
+
end
|
32
|
+
connection.adds.first.first.field_by_name(:title_ss).should be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should batch an add and a delete' do
|
36
|
+
pending 'batching all operations'
|
37
|
+
connection.should_not_receive(:add)
|
38
|
+
connection.should_not_receive(:remove)
|
39
|
+
session.batch do
|
40
|
+
session.index(posts[0])
|
41
|
+
session.remove(posts[1])
|
42
|
+
end
|
43
|
+
connection.adds
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "nesting of batches" do
|
47
|
+
let(:a_nested_batch) do
|
48
|
+
session.batch do
|
49
|
+
session.index posts[0]
|
50
|
+
|
51
|
+
session.batch do
|
52
|
+
session.index posts[1]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "behaves like two sets of batches, does the inner first, then outer" do
|
58
|
+
session.batch { session.index posts[1] }
|
59
|
+
session.batch { session.index posts[0] }
|
60
|
+
|
61
|
+
two_sets_of_batches_adds = connection.adds.dup
|
62
|
+
connection.adds.clear
|
63
|
+
|
64
|
+
a_nested_batch
|
65
|
+
nested_batches_adds = connection.adds
|
66
|
+
|
67
|
+
nested_batches_adds.first.first.field_by_name(:title_ss).value.should eq(
|
68
|
+
two_sets_of_batches_adds.first.first.field_by_name(:title_ss).value
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'indexing dynamic fields' do
|
4
|
+
it 'indexes string data' do
|
5
|
+
session.index(post(:custom_string => { :test => 'string' }))
|
6
|
+
connection.should have_add_with(:"custom_string:test_ss" => 'string')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'indexes integer data with virtual accessor' do
|
10
|
+
session.index(post(:category_ids => [1, 2]))
|
11
|
+
connection.should have_add_with(:"custom_integer:1_i" => '1', :"custom_integer:2_i" => '1')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'indexes float data' do
|
15
|
+
session.index(post(:custom_fl => { :test => 1.5 }))
|
16
|
+
connection.should have_add_with(:"custom_float:test_fm" => '1.5')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'indexes time data' do
|
20
|
+
session.index(post(:custom_time => { :test => Time.parse('2009-05-18 18:05:00 -0400') }))
|
21
|
+
connection.should have_add_with(:"custom_time:test_d" => '2009-05-18T22:05:00Z')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'indexes boolean data' do
|
25
|
+
session.index(post(:custom_boolean => { :test => false }))
|
26
|
+
connection.should have_add_with(:"custom_boolean:test_b" => 'false')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'indexes multiple values for a field' do
|
30
|
+
session.index(post(:custom_fl => { :test => [1.0, 2.1, 3.2] }))
|
31
|
+
connection.should have_add_with(:"custom_float:test_fm" => %w(1.0 2.1 3.2))
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should throw a NoMethodError if dynamic text field defined' do
|
35
|
+
lambda do
|
36
|
+
Sunspot.setup(Post) do
|
37
|
+
dynamic_text :custom_text
|
38
|
+
end
|
39
|
+
end.should raise_error(NoMethodError)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'indexing fixed fields', :type => :indexer do
|
4
|
+
it 'should index id' do
|
5
|
+
session.index post
|
6
|
+
connection.should have_add_with(:id => "Post #{post.id}")
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should index type' do
|
10
|
+
session.index post
|
11
|
+
connection.should have_add_with(:type => ['Post', 'SuperClass', 'MockRecord'])
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should index class name' do
|
15
|
+
session.index post
|
16
|
+
connection.should have_add_with(:class_name => 'Post')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should index the array of objects supplied' do
|
20
|
+
posts = Array.new(2) { Post.new }
|
21
|
+
session.index posts
|
22
|
+
connection.should have_add_with(
|
23
|
+
{ :id => "Post #{posts.first.id}" },
|
24
|
+
{ :id => "Post #{posts.last.id}" }
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should index an array containing more than one type of object' do
|
29
|
+
post1, comment, post2 = objects = [Post.new, Namespaced::Comment.new, Post.new]
|
30
|
+
session.index objects
|
31
|
+
connection.should have_add_with(
|
32
|
+
{ :id => "Post #{post1.id}", :type => ['Post', 'SuperClass', 'MockRecord'] },
|
33
|
+
{ :id => "Namespaced::Comment #{comment.id}", :type => ['Namespaced::Comment', 'MockRecord'] },
|
34
|
+
{ :id => "Post #{post2.id}", :type => ['Post', 'SuperClass', 'MockRecord'] }
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'commits immediately after index! called' do
|
39
|
+
connection.should_receive(:add).ordered
|
40
|
+
connection.should_receive(:commit).ordered
|
41
|
+
session.index!(post)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'raises an ArgumentError if an attempt is made to index an object that has no configuration' do
|
45
|
+
lambda { session.index(Blog.new) }.should raise_error(Sunspot::NoSetupError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'raises a NoAdapterError if class without adapter is indexed' do
|
49
|
+
lambda { session.index(User.new) }.should raise_error(Sunspot::NoAdapterError)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'raises an ArgumentError if a non-word character is included in the field name' do
|
53
|
+
lambda do
|
54
|
+
Sunspot.setup(Post) { string :"bad name" }
|
55
|
+
end.should raise_error(ArgumentError)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'indexing fulltext fields' do
|
4
|
+
it 'indexes text field' do
|
5
|
+
session.index(post(:title => 'A Title'))
|
6
|
+
connection.should have_add_with(:title_text => 'A Title')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'indexes stored text field' do
|
10
|
+
session.index(post(:body => 'Test body'))
|
11
|
+
connection.should have_add_with(:body_textsv => 'Test body')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'indexes text field with boost' do
|
15
|
+
session.index(post(:title => 'A Title'))
|
16
|
+
connection.adds.last.first.field_by_name(:title_text).attrs[:boost].should == 2
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'indexes multiple values for a text field' do
|
20
|
+
session.index(post(:body => %w(some title)))
|
21
|
+
connection.should have_add_with(:body_textsv => %w(some title))
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'indexes text via a block accessor' do
|
25
|
+
session.index(post(:title => 'backwards'))
|
26
|
+
connection.should have_add_with(:backwards_title_text => 'sdrawkcab')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'indexes document level boost using block' do
|
30
|
+
session.index(post(:ratings_average => 4.0))
|
31
|
+
connection.adds.last.first.attrs[:boost].should == 1.25
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'indexes document level boost using attribute' do
|
35
|
+
session.index(Namespaced::Comment.new(:boost => 1.5))
|
36
|
+
connection.adds.last.first.attrs[:boost].should == 1.5
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'indexes document level boost defined statically' do
|
40
|
+
session.index(Photo.new)
|
41
|
+
connection.adds.last.first.attrs[:boost].should == 0.75
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'document removal', :type => :indexer do
|
4
|
+
it 'removes an object from the index' do
|
5
|
+
session.remove(post)
|
6
|
+
connection.should have_delete("Post #{post.id}")
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'removes an object by type and id' do
|
10
|
+
session.remove_by_id(Post, 1)
|
11
|
+
connection.should have_delete('Post 1')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'removes an object by type and id and immediately commits' do
|
15
|
+
connection.should_receive(:delete_by_id).with(['Post 1']).ordered
|
16
|
+
connection.should_receive(:commit).ordered
|
17
|
+
session.remove_by_id!(Post, 1)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'removes an object from the index and immediately commits' do
|
21
|
+
connection.should_receive(:delete_by_id).ordered
|
22
|
+
connection.should_receive(:commit).ordered
|
23
|
+
session.remove!(post)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'removes everything from the index' do
|
27
|
+
session.remove_all
|
28
|
+
connection.should have_delete_by_query("*:*")
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'removes everything from the index and immediately commits' do
|
32
|
+
connection.should_receive(:delete_by_query).ordered
|
33
|
+
connection.should_receive(:commit).ordered
|
34
|
+
session.remove_all!
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'removes everything of a given class from the index' do
|
38
|
+
session.remove_all(Post)
|
39
|
+
connection.should have_delete_by_query("type:Post")
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'correctly escapes namespaced classes when removing everything from the index' do
|
43
|
+
connection.should_receive(:delete_by_query).with('type:Namespaced\:\:Comment')
|
44
|
+
session.remove_all(Namespaced::Comment)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should remove by query' do
|
48
|
+
session.remove(Post) do
|
49
|
+
with(:title, 'monkeys')
|
50
|
+
end
|
51
|
+
connection.should have_delete_by_query("(type:Post AND title_ss:monkeys)")
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.join(File.dirname(__FILE__), '..'))
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'indexer', :type => :indexer do
|
4
|
+
it 'should completely wipe setup if class redefined (reloaded)' do
|
5
|
+
Object::ReloadableClass = Class.new(MockRecord)
|
6
|
+
Sunspot.setup(ReloadableClass) { string(:title) }
|
7
|
+
Object.class_eval { remove_const(:ReloadableClass) }
|
8
|
+
Object::ReloadableClass = Class.new(MockRecord)
|
9
|
+
Sunspot.setup(ReloadableClass) {}
|
10
|
+
lambda do
|
11
|
+
Sunspot.search(ReloadableClass) { with(:title, 'title') }
|
12
|
+
end.should raise_error(Sunspot::UnrecognizedFieldError)
|
13
|
+
end
|
14
|
+
end
|