sunspot_rbg 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. data/.gitignore +12 -0
  2. data/Gemfile +4 -0
  3. data/History.txt +222 -0
  4. data/LICENSE +18 -0
  5. data/Rakefile +17 -0
  6. data/TODO +13 -0
  7. data/VERSION.yml +4 -0
  8. data/bin/sunspot-installer +19 -0
  9. data/bin/sunspot-solr +74 -0
  10. data/installer/config/schema.yml +95 -0
  11. data/lib/light_config.rb +40 -0
  12. data/lib/sunspot/adapters.rb +265 -0
  13. data/lib/sunspot/composite_setup.rb +202 -0
  14. data/lib/sunspot/configuration.rb +46 -0
  15. data/lib/sunspot/data_extractor.rb +50 -0
  16. data/lib/sunspot/dsl/adjustable.rb +47 -0
  17. data/lib/sunspot/dsl/field_query.rb +279 -0
  18. data/lib/sunspot/dsl/fields.rb +103 -0
  19. data/lib/sunspot/dsl/fulltext.rb +243 -0
  20. data/lib/sunspot/dsl/function.rb +14 -0
  21. data/lib/sunspot/dsl/functional.rb +44 -0
  22. data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
  23. data/lib/sunspot/dsl/paginatable.rb +28 -0
  24. data/lib/sunspot/dsl/query_facet.rb +36 -0
  25. data/lib/sunspot/dsl/restriction.rb +25 -0
  26. data/lib/sunspot/dsl/restriction_with_near.rb +121 -0
  27. data/lib/sunspot/dsl/scope.rb +217 -0
  28. data/lib/sunspot/dsl/search.rb +30 -0
  29. data/lib/sunspot/dsl/standard_query.rb +121 -0
  30. data/lib/sunspot/dsl.rb +5 -0
  31. data/lib/sunspot/field.rb +193 -0
  32. data/lib/sunspot/field_factory.rb +129 -0
  33. data/lib/sunspot/indexer.rb +131 -0
  34. data/lib/sunspot/installer/library_installer.rb +45 -0
  35. data/lib/sunspot/installer/schema_builder.rb +219 -0
  36. data/lib/sunspot/installer/solrconfig_updater.rb +76 -0
  37. data/lib/sunspot/installer/task_helper.rb +18 -0
  38. data/lib/sunspot/installer.rb +31 -0
  39. data/lib/sunspot/query/abstract_field_facet.rb +52 -0
  40. data/lib/sunspot/query/boost_query.rb +24 -0
  41. data/lib/sunspot/query/common_query.rb +85 -0
  42. data/lib/sunspot/query/composite_fulltext.rb +36 -0
  43. data/lib/sunspot/query/connective.rb +206 -0
  44. data/lib/sunspot/query/date_field_facet.rb +14 -0
  45. data/lib/sunspot/query/dismax.rb +128 -0
  46. data/lib/sunspot/query/field_facet.rb +41 -0
  47. data/lib/sunspot/query/filter.rb +38 -0
  48. data/lib/sunspot/query/function_query.rb +52 -0
  49. data/lib/sunspot/query/geo.rb +53 -0
  50. data/lib/sunspot/query/highlighting.rb +55 -0
  51. data/lib/sunspot/query/more_like_this.rb +61 -0
  52. data/lib/sunspot/query/more_like_this_query.rb +12 -0
  53. data/lib/sunspot/query/pagination.rb +38 -0
  54. data/lib/sunspot/query/query_facet.rb +16 -0
  55. data/lib/sunspot/query/restriction.rb +262 -0
  56. data/lib/sunspot/query/scope.rb +9 -0
  57. data/lib/sunspot/query/sort.rb +95 -0
  58. data/lib/sunspot/query/sort_composite.rb +33 -0
  59. data/lib/sunspot/query/standard_query.rb +16 -0
  60. data/lib/sunspot/query/text_field_boost.rb +17 -0
  61. data/lib/sunspot/query.rb +11 -0
  62. data/lib/sunspot/schema.rb +151 -0
  63. data/lib/sunspot/search/abstract_search.rb +293 -0
  64. data/lib/sunspot/search/date_facet.rb +35 -0
  65. data/lib/sunspot/search/facet_row.rb +27 -0
  66. data/lib/sunspot/search/field_facet.rb +88 -0
  67. data/lib/sunspot/search/highlight.rb +38 -0
  68. data/lib/sunspot/search/hit.rb +136 -0
  69. data/lib/sunspot/search/more_like_this_search.rb +31 -0
  70. data/lib/sunspot/search/paginated_collection.rb +55 -0
  71. data/lib/sunspot/search/query_facet.rb +67 -0
  72. data/lib/sunspot/search/standard_search.rb +21 -0
  73. data/lib/sunspot/search.rb +9 -0
  74. data/lib/sunspot/server.rb +152 -0
  75. data/lib/sunspot/session.rb +260 -0
  76. data/lib/sunspot/session_proxy/abstract_session_proxy.rb +29 -0
  77. data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +66 -0
  78. data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +89 -0
  79. data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +43 -0
  80. data/lib/sunspot/session_proxy/sharding_session_proxy.rb +222 -0
  81. data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +42 -0
  82. data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +37 -0
  83. data/lib/sunspot/session_proxy.rb +87 -0
  84. data/lib/sunspot/setup.rb +350 -0
  85. data/lib/sunspot/text_field_setup.rb +29 -0
  86. data/lib/sunspot/type.rb +372 -0
  87. data/lib/sunspot/util.rb +243 -0
  88. data/lib/sunspot/version.rb +3 -0
  89. data/lib/sunspot.rb +569 -0
  90. data/lib/sunspot_rbg.rb +7 -0
  91. data/log/.gitignore +1 -0
  92. data/pkg/.gitignore +1 -0
  93. data/script/console +10 -0
  94. data/solr/README.txt +42 -0
  95. data/solr/etc/jetty.xml +218 -0
  96. data/solr/etc/webdefault.xml +379 -0
  97. data/solr/lib/jetty-6.1.3.jar +0 -0
  98. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  99. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  100. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  101. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  102. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  103. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  104. data/solr/logs/.gitignore +1 -0
  105. data/solr/solr/.gitignore +1 -0
  106. data/solr/solr/README.txt +54 -0
  107. data/solr/solr/conf/admin-extra.html +31 -0
  108. data/solr/solr/conf/elevate.xml +36 -0
  109. data/solr/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  110. data/solr/solr/conf/protwords.txt +21 -0
  111. data/solr/solr/conf/schema.xml +238 -0
  112. data/solr/solr/conf/scripts.conf +24 -0
  113. data/solr/solr/conf/solrconfig.xml +934 -0
  114. data/solr/solr/conf/spellings.txt +2 -0
  115. data/solr/solr/conf/stopwords.txt +58 -0
  116. data/solr/solr/conf/synonyms.txt +31 -0
  117. data/solr/solr/conf/xslt/example.xsl +132 -0
  118. data/solr/solr/conf/xslt/example_atom.xsl +67 -0
  119. data/solr/solr/conf/xslt/example_rss.xsl +66 -0
  120. data/solr/solr/conf/xslt/luke.xsl +337 -0
  121. data/solr/start.jar +0 -0
  122. data/solr/webapps/solr.war +0 -0
  123. data/solr-1.3/etc/jetty.xml +212 -0
  124. data/solr-1.3/etc/webdefault.xml +379 -0
  125. data/solr-1.3/lib/jetty-6.1.3.jar +0 -0
  126. data/solr-1.3/lib/jetty-util-6.1.3.jar +0 -0
  127. data/solr-1.3/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  128. data/solr-1.3/lib/jsp-2.1/core-3.1.1.jar +0 -0
  129. data/solr-1.3/lib/jsp-2.1/jsp-2.1.jar +0 -0
  130. data/solr-1.3/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  131. data/solr-1.3/lib/servlet-api-2.5-6.1.3.jar +0 -0
  132. data/solr-1.3/solr/conf/elevate.xml +36 -0
  133. data/solr-1.3/solr/conf/protwords.txt +21 -0
  134. data/solr-1.3/solr/conf/schema.xml +64 -0
  135. data/solr-1.3/solr/conf/solrconfig.xml +725 -0
  136. data/solr-1.3/solr/conf/stopwords.txt +57 -0
  137. data/solr-1.3/solr/conf/synonyms.txt +31 -0
  138. data/solr-1.3/solr/lib/geoapi-nogenerics-2.1-M2.jar +0 -0
  139. data/solr-1.3/solr/lib/gt2-referencing-2.3.1.jar +0 -0
  140. data/solr-1.3/solr/lib/jsr108-0.01.jar +0 -0
  141. data/solr-1.3/solr/lib/locallucene.jar +0 -0
  142. data/solr-1.3/solr/lib/localsolr.jar +0 -0
  143. data/solr-1.3/start.jar +0 -0
  144. data/solr-1.3/webapps/solr.war +0 -0
  145. data/spec/api/adapters_spec.rb +33 -0
  146. data/spec/api/binding_spec.rb +50 -0
  147. data/spec/api/indexer/attributes_spec.rb +149 -0
  148. data/spec/api/indexer/batch_spec.rb +46 -0
  149. data/spec/api/indexer/dynamic_fields_spec.rb +42 -0
  150. data/spec/api/indexer/fixed_fields_spec.rb +57 -0
  151. data/spec/api/indexer/fulltext_spec.rb +43 -0
  152. data/spec/api/indexer/removal_spec.rb +53 -0
  153. data/spec/api/indexer/spec_helper.rb +1 -0
  154. data/spec/api/indexer_spec.rb +14 -0
  155. data/spec/api/query/advanced_manipulation_examples.rb +35 -0
  156. data/spec/api/query/connectives_examples.rb +189 -0
  157. data/spec/api/query/dsl_spec.rb +18 -0
  158. data/spec/api/query/dynamic_fields_examples.rb +165 -0
  159. data/spec/api/query/faceting_examples.rb +397 -0
  160. data/spec/api/query/fulltext_examples.rb +313 -0
  161. data/spec/api/query/function_spec.rb +70 -0
  162. data/spec/api/query/geo_examples.rb +68 -0
  163. data/spec/api/query/highlighting_examples.rb +223 -0
  164. data/spec/api/query/more_like_this_spec.rb +140 -0
  165. data/spec/api/query/ordering_pagination_examples.rb +95 -0
  166. data/spec/api/query/scope_examples.rb +275 -0
  167. data/spec/api/query/spec_helper.rb +1 -0
  168. data/spec/api/query/standard_spec.rb +28 -0
  169. data/spec/api/query/text_field_scoping_examples.rb +30 -0
  170. data/spec/api/query/types_spec.rb +20 -0
  171. data/spec/api/search/dynamic_fields_spec.rb +33 -0
  172. data/spec/api/search/faceting_spec.rb +360 -0
  173. data/spec/api/search/highlighting_spec.rb +69 -0
  174. data/spec/api/search/hits_spec.rb +120 -0
  175. data/spec/api/search/paginated_collection_spec.rb +26 -0
  176. data/spec/api/search/results_spec.rb +66 -0
  177. data/spec/api/search/search_spec.rb +23 -0
  178. data/spec/api/search/spec_helper.rb +1 -0
  179. data/spec/api/server_spec.rb +91 -0
  180. data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +85 -0
  181. data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +30 -0
  182. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +41 -0
  183. data/spec/api/session_proxy/sharding_session_proxy_spec.rb +77 -0
  184. data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +24 -0
  185. data/spec/api/session_proxy/spec_helper.rb +9 -0
  186. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +50 -0
  187. data/spec/api/session_spec.rb +220 -0
  188. data/spec/api/spec_helper.rb +3 -0
  189. data/spec/api/sunspot_spec.rb +18 -0
  190. data/spec/ext.rb +11 -0
  191. data/spec/helpers/indexer_helper.rb +29 -0
  192. data/spec/helpers/query_helper.rb +38 -0
  193. data/spec/helpers/search_helper.rb +80 -0
  194. data/spec/integration/dynamic_fields_spec.rb +55 -0
  195. data/spec/integration/faceting_spec.rb +238 -0
  196. data/spec/integration/highlighting_spec.rb +22 -0
  197. data/spec/integration/indexing_spec.rb +33 -0
  198. data/spec/integration/keyword_search_spec.rb +317 -0
  199. data/spec/integration/local_search_spec.rb +64 -0
  200. data/spec/integration/more_like_this_spec.rb +43 -0
  201. data/spec/integration/scoped_search_spec.rb +354 -0
  202. data/spec/integration/spec_helper.rb +7 -0
  203. data/spec/integration/stored_fields_spec.rb +10 -0
  204. data/spec/integration/test_pagination.rb +32 -0
  205. data/spec/mocks/adapters.rb +32 -0
  206. data/spec/mocks/blog.rb +3 -0
  207. data/spec/mocks/comment.rb +21 -0
  208. data/spec/mocks/connection.rb +126 -0
  209. data/spec/mocks/mock_adapter.rb +30 -0
  210. data/spec/mocks/mock_class_sharding_session_proxy.rb +24 -0
  211. data/spec/mocks/mock_record.rb +52 -0
  212. data/spec/mocks/mock_sharding_session_proxy.rb +15 -0
  213. data/spec/mocks/photo.rb +11 -0
  214. data/spec/mocks/post.rb +85 -0
  215. data/spec/mocks/super_class.rb +2 -0
  216. data/spec/mocks/user.rb +13 -0
  217. data/spec/spec_helper.rb +30 -0
  218. data/sunspot.gemspec +40 -0
  219. data/tasks/rdoc.rake +27 -0
  220. data/tasks/schema.rake +19 -0
  221. data/tasks/todo.rake +4 -0
  222. metadata +457 -0
@@ -0,0 +1,57 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright ownership.
4
+ # The ASF licenses this file to You under the Apache License, Version 2.0
5
+ # (the "License"); you may not use this file except in compliance with
6
+ # the License. You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ #-----------------------------------------------------------------------
17
+ # a couple of test stopwords to test that the words are really being
18
+ # configured from this file:
19
+ stopworda
20
+ stopwordb
21
+
22
+ #Standard english stop words taken from Lucene's StopAnalyzer
23
+ an
24
+ and
25
+ are
26
+ as
27
+ at
28
+ be
29
+ but
30
+ by
31
+ for
32
+ if
33
+ in
34
+ into
35
+ is
36
+ it
37
+ no
38
+ not
39
+ of
40
+ on
41
+ or
42
+ s
43
+ such
44
+ t
45
+ that
46
+ the
47
+ their
48
+ then
49
+ there
50
+ these
51
+ they
52
+ this
53
+ to
54
+ was
55
+ will
56
+ with
57
+
@@ -0,0 +1,31 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ #-----------------------------------------------------------------------
14
+ #some test synonym mappings unlikely to appear in real input text
15
+ aaa => aaaa
16
+ bbb => bbbb1 bbbb2
17
+ ccc => cccc1,cccc2
18
+ a\=>a => b\=>b
19
+ a\,a => b\,b
20
+ fooaaa,baraaa,bazaaa
21
+
22
+ # Some synonym groups specific to this example
23
+ GB,gib,gigabyte,gigabytes
24
+ MB,mib,megabyte,megabytes
25
+ Television, Televisions, TV, TVs
26
+ #notice we use "gib" instead of "GiB" so any WordDelimiterFilter coming
27
+ #after us won't split it into two words.
28
+
29
+ # Synonym mappings can be used for spelling correction too
30
+ pixima => pixma
31
+
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,33 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Sunspot::Adapters::InstanceAdapter do
4
+ it "finds adapter by superclass" do
5
+ Sunspot::Adapters::InstanceAdapter::for(Model).should be(AbstractModelInstanceAdapter)
6
+ end
7
+
8
+ it "finds adapter by mixin" do
9
+ Sunspot::Adapters::InstanceAdapter::for(MixModel).should be(MixInModelInstanceAdapter)
10
+ end
11
+
12
+ it 'throws NoAdapterError if anonymous module passed in' do
13
+ lambda do
14
+ Sunspot::Adapters::InstanceAdapter::for(Module.new)
15
+ end.should raise_error(Sunspot::NoAdapterError)
16
+ end
17
+ end
18
+
19
+ describe Sunspot::Adapters::DataAccessor do
20
+ it "finds adapter by superclass" do
21
+ Sunspot::Adapters::DataAccessor::for(Model).should be(AbstractModelDataAccessor)
22
+ end
23
+
24
+ it "finds adapter by mixin" do
25
+ Sunspot::Adapters::DataAccessor::for(MixModel).should be(MixInModelDataAccessor)
26
+ end
27
+
28
+ it 'throws NoAdapterError if anonymous module passed in' do
29
+ lambda do
30
+ Sunspot::Adapters::DataAccessor::for(Module.new)
31
+ end.should raise_error(Sunspot::NoAdapterError)
32
+ end
33
+ 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,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,46 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'batch indexing', :type => :indexer do
4
+ it 'should send all batched adds in a single request' do
5
+ posts = Array.new(2) { Post.new }
6
+ session.batch do
7
+ for post in posts
8
+ session.index(post)
9
+ end
10
+ end
11
+ connection.adds.length.should == 1
12
+ end
13
+
14
+ it 'should add all batched adds' do
15
+ posts = Array.new(2) { Post.new }
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
+ posts = Array.new(2) { Post.new }
40
+ session.batch do
41
+ session.index(posts[0])
42
+ session.remove(posts[1])
43
+ end
44
+ connection.adds
45
+ end
46
+ 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
@@ -0,0 +1,35 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ shared_examples_for "query with advanced manipulation" do
4
+ describe 'adjust_solr_params' do
5
+ before :each do
6
+ search do
7
+ adjust_solr_params do |params|
8
+ params[:rows] = 40
9
+ params[:qt] = 'complicated'
10
+ end
11
+ end
12
+ end
13
+
14
+ it "modifies existing param" do
15
+ connection.should have_last_search_with(:rows => 40)
16
+ end
17
+
18
+ it "adds new param" do
19
+ connection.should have_last_search_with(:qt => 'complicated')
20
+ end
21
+ end
22
+
23
+ describe 'request_handler' do
24
+ before :each do
25
+ connection.expected_handler = :myRequestHandler
26
+ search do
27
+ request_handler :myRequestHandler
28
+ end
29
+ end
30
+
31
+ it 'should use specified request handler' do
32
+ connection.should have_last_search_with({})
33
+ end
34
+ end
35
+ end