acts_as_solr 1.0.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 (163) hide show
  1. data/.gitignore +8 -0
  2. data/CHANGE_LOG +233 -0
  3. data/FORKED_CHANGES +3 -0
  4. data/LICENSE +19 -0
  5. data/README.markdown +94 -0
  6. data/README.rdoc +84 -0
  7. data/Rakefile +57 -0
  8. data/TESTING_THE_PLUGIN +25 -0
  9. data/VERSION +1 -0
  10. data/acts_as_solr.gemspec +237 -0
  11. data/config/solr.yml +15 -0
  12. data/config/solr_environment.rb +22 -0
  13. data/init.rb +21 -0
  14. data/install.rb +11 -0
  15. data/lib/acts_as_solr.rb +61 -0
  16. data/lib/acts_methods.rb +284 -0
  17. data/lib/class_methods.rb +239 -0
  18. data/lib/common_methods.rb +89 -0
  19. data/lib/deprecation.rb +61 -0
  20. data/lib/instance_methods.rb +181 -0
  21. data/lib/lazy_document.rb +18 -0
  22. data/lib/parser_methods.rb +230 -0
  23. data/lib/search_results.rb +69 -0
  24. data/lib/solr/connection.rb +191 -0
  25. data/lib/solr/document.rb +78 -0
  26. data/lib/solr/exception.rb +13 -0
  27. data/lib/solr/field.rb +39 -0
  28. data/lib/solr/importer/array_mapper.rb +26 -0
  29. data/lib/solr/importer/delimited_file_source.rb +38 -0
  30. data/lib/solr/importer/hpricot_mapper.rb +27 -0
  31. data/lib/solr/importer/mapper.rb +51 -0
  32. data/lib/solr/importer/solr_source.rb +43 -0
  33. data/lib/solr/importer/xpath_mapper.rb +35 -0
  34. data/lib/solr/importer.rb +19 -0
  35. data/lib/solr/indexer.rb +52 -0
  36. data/lib/solr/request/add_document.rb +63 -0
  37. data/lib/solr/request/base.rb +36 -0
  38. data/lib/solr/request/commit.rb +31 -0
  39. data/lib/solr/request/delete.rb +50 -0
  40. data/lib/solr/request/dismax.rb +46 -0
  41. data/lib/solr/request/index_info.rb +22 -0
  42. data/lib/solr/request/modify_document.rb +51 -0
  43. data/lib/solr/request/optimize.rb +21 -0
  44. data/lib/solr/request/ping.rb +36 -0
  45. data/lib/solr/request/select.rb +56 -0
  46. data/lib/solr/request/spellcheck.rb +30 -0
  47. data/lib/solr/request/standard.rb +402 -0
  48. data/lib/solr/request/update.rb +23 -0
  49. data/lib/solr/request.rb +26 -0
  50. data/lib/solr/response/add_document.rb +17 -0
  51. data/lib/solr/response/base.rb +42 -0
  52. data/lib/solr/response/commit.rb +17 -0
  53. data/lib/solr/response/delete.rb +13 -0
  54. data/lib/solr/response/dismax.rb +8 -0
  55. data/lib/solr/response/index_info.rb +26 -0
  56. data/lib/solr/response/modify_document.rb +17 -0
  57. data/lib/solr/response/optimize.rb +14 -0
  58. data/lib/solr/response/ping.rb +28 -0
  59. data/lib/solr/response/ruby.rb +42 -0
  60. data/lib/solr/response/select.rb +17 -0
  61. data/lib/solr/response/spellcheck.rb +20 -0
  62. data/lib/solr/response/standard.rb +64 -0
  63. data/lib/solr/response/xml.rb +42 -0
  64. data/lib/solr/response.rb +27 -0
  65. data/lib/solr/solrtasks.rb +27 -0
  66. data/lib/solr/util.rb +32 -0
  67. data/lib/solr/xml.rb +44 -0
  68. data/lib/solr.rb +21 -0
  69. data/lib/solr_fixtures.rb +13 -0
  70. data/lib/tasks/database.rake +18 -0
  71. data/lib/tasks/solr.rake +137 -0
  72. data/lib/tasks/test.rake +7 -0
  73. data/lib/will_paginate_support.rb +12 -0
  74. data/solr/CHANGES.txt +1207 -0
  75. data/solr/LICENSE.txt +712 -0
  76. data/solr/NOTICE.txt +90 -0
  77. data/solr/etc/jetty.xml +205 -0
  78. data/solr/etc/webdefault.xml +379 -0
  79. data/solr/lib/easymock.jar +0 -0
  80. data/solr/lib/jetty-6.1.3.jar +0 -0
  81. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  82. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  83. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  84. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  85. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  86. data/solr/lib/servlet-api-2.4.jar +0 -0
  87. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  88. data/solr/lib/xpp3-1.1.3.4.O.jar +0 -0
  89. data/solr/logs/.empty-dir-for-git +0 -0
  90. data/solr/solr/README.txt +52 -0
  91. data/solr/solr/bin/abc +176 -0
  92. data/solr/solr/bin/abo +176 -0
  93. data/solr/solr/bin/backup +108 -0
  94. data/solr/solr/bin/backupcleaner +142 -0
  95. data/solr/solr/bin/commit +128 -0
  96. data/solr/solr/bin/optimize +129 -0
  97. data/solr/solr/bin/readercycle +129 -0
  98. data/solr/solr/bin/rsyncd-disable +77 -0
  99. data/solr/solr/bin/rsyncd-enable +76 -0
  100. data/solr/solr/bin/rsyncd-start +145 -0
  101. data/solr/solr/bin/rsyncd-stop +105 -0
  102. data/solr/solr/bin/scripts-util +83 -0
  103. data/solr/solr/bin/snapcleaner +148 -0
  104. data/solr/solr/bin/snapinstaller +168 -0
  105. data/solr/solr/bin/snappuller +248 -0
  106. data/solr/solr/bin/snappuller-disable +77 -0
  107. data/solr/solr/bin/snappuller-enable +77 -0
  108. data/solr/solr/bin/snapshooter +109 -0
  109. data/solr/solr/conf/admin-extra.html +31 -0
  110. data/solr/solr/conf/protwords.txt +21 -0
  111. data/solr/solr/conf/schema.xml +126 -0
  112. data/solr/solr/conf/scripts.conf +24 -0
  113. data/solr/solr/conf/solrconfig.xml +458 -0
  114. data/solr/solr/conf/stopwords.txt +57 -0
  115. data/solr/solr/conf/synonyms.txt +31 -0
  116. data/solr/solr/conf/xslt/example.xsl +132 -0
  117. data/solr/solr/conf/xslt/example_atom.xsl +63 -0
  118. data/solr/solr/conf/xslt/example_rss.xsl +62 -0
  119. data/solr/start.jar +0 -0
  120. data/solr/tmp/.empty-dir-for-git +0 -0
  121. data/solr/webapps/solr.war +0 -0
  122. data/test/config/solr.yml +2 -0
  123. data/test/db/connections/mysql/connection.rb +10 -0
  124. data/test/db/connections/sqlite/connection.rb +8 -0
  125. data/test/db/migrate/001_create_books.rb +15 -0
  126. data/test/db/migrate/002_create_movies.rb +12 -0
  127. data/test/db/migrate/003_create_categories.rb +11 -0
  128. data/test/db/migrate/004_create_electronics.rb +16 -0
  129. data/test/db/migrate/005_create_authors.rb +12 -0
  130. data/test/db/migrate/006_create_postings.rb +9 -0
  131. data/test/db/migrate/007_create_posts.rb +13 -0
  132. data/test/db/migrate/008_create_gadgets.rb +11 -0
  133. data/test/fixtures/authors.yml +9 -0
  134. data/test/fixtures/books.yml +13 -0
  135. data/test/fixtures/categories.yml +7 -0
  136. data/test/fixtures/db_definitions/mysql.sql +41 -0
  137. data/test/fixtures/electronics.yml +49 -0
  138. data/test/fixtures/movies.yml +9 -0
  139. data/test/fixtures/postings.yml +10 -0
  140. data/test/functional/acts_as_solr_test.rb +413 -0
  141. data/test/functional/association_indexing_test.rb +37 -0
  142. data/test/functional/faceted_search_test.rb +163 -0
  143. data/test/functional/multi_solr_search_test.rb +51 -0
  144. data/test/models/author.rb +10 -0
  145. data/test/models/book.rb +10 -0
  146. data/test/models/category.rb +8 -0
  147. data/test/models/electronic.rb +21 -0
  148. data/test/models/gadget.rb +9 -0
  149. data/test/models/movie.rb +17 -0
  150. data/test/models/novel.rb +2 -0
  151. data/test/models/post.rb +3 -0
  152. data/test/models/posting.rb +11 -0
  153. data/test/test_helper.rb +51 -0
  154. data/test/unit/acts_methods_shoulda.rb +70 -0
  155. data/test/unit/class_methods_shoulda.rb +90 -0
  156. data/test/unit/common_methods_shoulda.rb +112 -0
  157. data/test/unit/instance_methods_shoulda.rb +326 -0
  158. data/test/unit/lazy_document_shoulda.rb +35 -0
  159. data/test/unit/parser_instance.rb +19 -0
  160. data/test/unit/parser_methods_shoulda.rb +279 -0
  161. data/test/unit/solr_instance.rb +46 -0
  162. data/test/unit/test_helper.rb +26 -0
  163. metadata +259 -0
@@ -0,0 +1,326 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'instance_methods'
3
+ require 'logger'
4
+ module Solr; end
5
+ require 'solr/xml'
6
+ require 'solr/field'
7
+ require 'solr/document'
8
+ require 'solr_instance'
9
+ require 'erb'
10
+ require 'ostruct'
11
+
12
+ class InstanceMethodsTest < Test::Unit::TestCase
13
+
14
+ context "With a Solr record instance" do
15
+ setup do
16
+ @instance = SolrInstance.new
17
+ end
18
+
19
+ context "when checking whether indexing is disabled" do
20
+
21
+ setup do
22
+ @instance.configuration = {:if => true}
23
+ end
24
+
25
+ should "return true if the specified proc returns true " do
26
+ @instance.configuration[:offline] = proc {|record| true}
27
+ assert @instance.indexing_disabled?
28
+ end
29
+
30
+ should "return false if the specified proc returns false" do
31
+ @instance.configuration[:offline] = proc {|record| false}
32
+ assert !@instance.indexing_disabled?
33
+ end
34
+
35
+ should "return true if no valid offline option was specified" do
36
+ @instance.configuration[:offline] = nil
37
+ @instance.configuration[:if] = proc {true}
38
+ assert !@instance.indexing_disabled?
39
+ end
40
+ end
41
+
42
+ context "when validating the boost" do
43
+ setup do
44
+ @instance.solr_configuration = {:default_boost => 10.0}
45
+ @instance.configuration = {:if => true}
46
+ end
47
+
48
+ should "accept and evaluate a block" do
49
+ @instance.configuration[:boost] = proc {|record| record.boost_rate}
50
+ assert_equal 10.0, @instance.send(:validate_boost, @instance.configuration[:boost])
51
+ end
52
+
53
+ should "accept and return a float" do
54
+ @instance.configuration[:boost] = 9.0
55
+ assert_equal 9.0, @instance.send(:validate_boost, @instance.configuration[:boost])
56
+ end
57
+
58
+ should "return the default float when the specified is negative" do
59
+ @instance.configuration[:boost] = -1.0
60
+ assert_equal 10.0, @instance.send(:validate_boost, @instance.configuration[:boost])
61
+ end
62
+
63
+ should "execute the according method when value is a symbol" do
64
+ @instance.configuration[:boost] = :irate
65
+ assert_equal 8.0, @instance.send(:validate_boost, @instance.configuration[:boost])
66
+ end
67
+
68
+ should "return the default boost when there is no valid boost" do
69
+ @instance.configuration[:boost] = "boost!"
70
+ assert_equal 10.0, @instance.send(:validate_boost, @instance.configuration[:boost])
71
+ end
72
+ end
73
+
74
+ context "when determining the solr document id" do
75
+ should "combine class name and id" do
76
+ assert_equal "SolrInstance:10", @instance.solr_id
77
+ end
78
+ end
79
+
80
+ context "when saving the instance to solr" do
81
+ context "with indexing disabled" do
82
+ setup do
83
+ @instance.configuration = {:fields => [:name], :if => nil}
84
+ end
85
+
86
+ should "just return and do nothing" do
87
+ @instance.expects(:solr_add).never
88
+ @instance.expects(:solr_destroy).never
89
+ assert @instance.solr_save
90
+ end
91
+ end
92
+
93
+ context "with indexing enabled" do
94
+ setup do
95
+ @instance.configuration = {:fields => [:name], :if => "true", :auto_commit => true}
96
+ @instance.stubs(:solr_commit)
97
+ @instance.stubs(:solr_add)
98
+ @instance.stubs(:to_solr_doc).returns("My test document")
99
+ end
100
+
101
+ should "add the solr document" do
102
+ @instance.expects(:solr_add).with("My test document").once
103
+ @instance.solr_save
104
+ end
105
+
106
+ should "commit to solr" do
107
+ @instance.expects(:solr_commit).once
108
+ @instance.solr_save
109
+ end
110
+
111
+ should "not commit if auto_commit is disabled" do
112
+ @instance.configuration.merge!(:auto_commit => false)
113
+ @instance.expects(:solr_commit).never
114
+ @instance.solr_save
115
+ end
116
+
117
+ should "destroy the document if :if clause is false" do
118
+ @instance.configuration.merge!(:if => "false")
119
+ @instance.expects(:solr_destroy).once
120
+ @instance.solr_save
121
+ end
122
+ end
123
+ end
124
+
125
+ context "when destroying an instance in solr" do
126
+ setup do
127
+ @instance.configuration = {:if => true, :auto_commit => true}
128
+ @instance.stubs(:solr_commit)
129
+ @instance.stubs(:solr_delete)
130
+ end
131
+
132
+ should "delete the instance" do
133
+ @instance.expects(:solr_delete).with("SolrInstance:10")
134
+ @instance.solr_destroy
135
+ end
136
+
137
+ should "commit to solr" do
138
+ @instance.expects(:solr_commit)
139
+ @instance.solr_destroy
140
+ end
141
+
142
+ should "not commit if auto_commit is disabled" do
143
+ @instance.configuration.merge!(:auto_commit => false)
144
+ @instance.expects(:solr_commit).never
145
+ @instance.solr_destroy
146
+ end
147
+
148
+ context "with indexing disabled" do
149
+ should "not contact solr" do
150
+ @instance.configuration.merge!(:offline => true, :if => nil)
151
+ @instance.expects(:solr_delete).never
152
+ @instance.solr_destroy
153
+ end
154
+ end
155
+ end
156
+
157
+ context "when converting an instance to a solr document" do
158
+ setup do
159
+ @instance.configuration = {:if => true, :auto_commit => true, :solr_fields => {:name => {:boost => 9.0}}, :boost => 10.0}
160
+ @instance.solr_configuration = {:type_field => "type", :primary_key_field => "pk_id", :default_boost => 25.0}
161
+ end
162
+
163
+ should "add a document boost" do
164
+ assert_equal 10, @instance.to_solr_doc.boost
165
+ end
166
+
167
+ should "set the solr id" do
168
+ assert_equal "SolrInstance:10", @instance.to_solr_doc[:id]
169
+ end
170
+
171
+ should "set the type field" do
172
+ assert_equal "SolrInstance", @instance.to_solr_doc[:type]
173
+ end
174
+
175
+ should "set the primary key fields" do
176
+ assert_equal("10", @instance.to_solr_doc[:pk_id])
177
+ end
178
+
179
+ should "add the includes if they were configured" do
180
+ @instance.configuration.merge! :include => [:author]
181
+ @instance.expects(:add_includes)
182
+ @instance.to_solr_doc
183
+ end
184
+
185
+ context "with indexed fields" do
186
+ should "add fields with type" do
187
+ assert_equal "Chunky bacon!", @instance.to_solr_doc[:name_s]
188
+ end
189
+
190
+ should "add the field boost" do
191
+ field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "name_s"}
192
+ assert_equal 9.0, field.boost
193
+ end
194
+
195
+ should "set the default boost for the field, if none is configured" do
196
+ @instance.configuration[:solr_fields][:name][:boost] = nil
197
+ field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "name_s"}
198
+ assert_equal 25.0, field.boost
199
+ end
200
+
201
+ should "not overwrite the type or id field" do
202
+ @instance.configuration[:solr_fields] = {:type => {}, :id => {}}
203
+ doc = @instance.to_solr_doc
204
+ assert_not_equal "humbug", doc[:type]
205
+ assert_not_equal "bogus", doc[:id]
206
+ end
207
+
208
+ should "set the default value if field value is nil" do
209
+ @instance.name = nil
210
+ @instance.expects(:set_value_if_nil).with('s')
211
+ @instance.to_solr_doc
212
+ end
213
+
214
+ should "not include nil values" do
215
+ @instance.name = ""
216
+ @instance.stubs(:set_value_if_nil).returns ""
217
+ assert_nil @instance.to_solr_doc[:name_s]
218
+ end
219
+
220
+ should "escape the contents" do
221
+ @instance.name = "<script>malicious()</script>"
222
+ assert_equal "&lt;script&gt;malicious()&lt;/script&gt;", @instance.to_solr_doc[:name_s]
223
+ end
224
+
225
+ should "use an alternate field name if specified in options" do
226
+ @instance.stubs(:nickname_for_solr).returns('Nick')
227
+ @instance.configuration[:solr_fields].merge! :nickname => {:as => :alias}
228
+ doc = @instance.to_solr_doc
229
+ assert_not_nil @instance.to_solr_doc.fields.find {|f| f.name.to_s == "alias_s"}
230
+ assert_nil @instance.to_solr_doc.fields.find {|f| f.name.to_s == "nickname_s"}
231
+ end
232
+
233
+ context "when associations are included" do
234
+ setup do
235
+ class AssocLabel < String
236
+ @@singular = {'people' => 'person'}
237
+ def to_s
238
+ self
239
+ end
240
+ def singularize
241
+ @@singular[self]
242
+ end
243
+ end
244
+ @assoc = AssocLabel.new('people')
245
+ person = {:name => 'Hank Venture', :address => 'Venture Compound'}
246
+ @people = [OpenStruct.new(person.merge(:attributes => person))]
247
+ @instance.stubs(:people).returns(@people)
248
+ @reflection = OpenStruct.new(:macro => :has_many)
249
+ @instance.class.stubs(:reflect_on_association).returns(@reflection)
250
+ @instance.configuration[:solr_includes] = {@assoc => {}}
251
+ @instance.solr_configuration.merge! :default_boost => 35.0
252
+ end
253
+
254
+ should "set the default name for the include, if none is configured" do
255
+ @instance.configuration[:solr_includes] = {@assoc => {:type => :text}}
256
+ doc = @instance.to_solr_doc
257
+ assert_not_nil doc.fields.find {|f| f.name.to_s == "person_s"}
258
+ end
259
+
260
+ should "add the include alias" do
261
+ @instance.configuration[:solr_includes] = {@assoc => {:as => :human, :type => :text}}
262
+ doc = @instance.to_solr_doc
263
+ assert_not_nil doc.fields.find {|f| f.name.to_s == "human_s"}
264
+ assert_nil doc.fields.find {|f| f.name.to_s == "person_s"}
265
+ end
266
+
267
+ should "add the include type" do
268
+ @instance.configuration[:solr_includes] = {@assoc => {:type => :date}}
269
+ @instance.expects(:get_solr_field_type).with(){|v| true}.at_least_once.returns('s')
270
+ @instance.expects(:get_solr_field_type).with(:date).once.returns('d')
271
+ doc = @instance.to_solr_doc
272
+ end
273
+
274
+ should "set the default boost for the include, if none is configured" do
275
+ # @instance.configuration[:solr_includes] = {@assoc => {}}
276
+ field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"}
277
+ assert_equal 35.0, field.boost
278
+ end
279
+
280
+ should "add the include boost" do
281
+ @instance.configuration[:solr_includes] = {@assoc => {:boost => 10.0}}
282
+ field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"}
283
+ assert_equal 10.0, field.boost
284
+ end
285
+
286
+ should "default to a field value with all association attributes" do
287
+ # @instance.configuration[:solr_includes] = {@assoc => {}}
288
+ field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"}
289
+ @people.first.attributes.each do |attr, value|
290
+ assert_match /#{attr}=#{value}/, field.value
291
+ end
292
+ end
293
+
294
+ should "use a field value from an association method, if one is configured" do
295
+ @instance.configuration[:solr_includes] = {@assoc => {:using => :name}}
296
+ field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"}
297
+ assert_equal @people.first.name, field.value
298
+ end
299
+
300
+ should "use a field value from a proc, if one is configured" do
301
+ @instance.configuration[:solr_includes] = {@assoc => {:using => lambda{|r| r.name.reverse}}}
302
+ field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"}
303
+ assert_equal @people.first.name.reverse, field.value
304
+ end
305
+
306
+ should "join multiple values into a single field unless the :multivalued options is specified" do
307
+ @instance.configuration[:solr_includes] = {@assoc => {:multivalued => :true}}
308
+ second_person = {:name => 'Dean Venture', :address => 'Venture Compound'}
309
+ @people << OpenStruct.new(second_person.merge(:attributes => second_person))
310
+ fields = @instance.to_solr_doc.fields.select {|f| f.name.to_s == "person_s"}
311
+ assert_equal @people.size, fields.size
312
+ end
313
+
314
+ should "include multiple values separately if the :multivalued options is specified" do
315
+ # @instance.configuration[:solr_includes] = {@assoc => {}}
316
+ second_person = {:name => 'Dean Venture', :address => 'Venture Compound'}
317
+ @people << OpenStruct.new(second_person.merge(:attributes => second_person))
318
+ fields = @instance.to_solr_doc.fields.select {|f| f.name.to_s == "person_s"}
319
+ assert_not_equal @people.size, fields.size
320
+ assert_equal 1, fields.size
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+ require 'lazy_document'
3
+
4
+ class UserModel; end
5
+
6
+ class LazyDocumentTest < Test::Unit::TestCase
7
+ context "With a lazy document" do
8
+ setup do
9
+ @record = stub(:record)
10
+ @record.stubs(:is_valid?).returns true
11
+ UserModel.stubs(:find).returns @record
12
+ @document = ActsAsSolr::LazyDocument.new(1, UserModel)
13
+ end
14
+
15
+ context "with an uninitialized document" do
16
+ should "fetch the record from the database" do
17
+ UserModel.expects(:find).with(1).returns(@record)
18
+ @document.is_valid?
19
+ end
20
+ end
21
+
22
+ context "with an initialized document" do
23
+ should "not fetch the record again" do
24
+ @document.is_valid?
25
+ @document.expects(:find).never
26
+ @document.is_valid?
27
+ end
28
+
29
+ should "reroute the calls to the record" do
30
+ @record.expects(:is_valid?).once
31
+ @document.is_valid?
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ class ActsAsSolr::ParserInstance
2
+ include ActsAsSolr::ParserMethods
3
+ include ActsAsSolr::CommonMethods
4
+ attr_accessor :configuration, :solr_configuration
5
+
6
+ def table_name
7
+ "documents"
8
+ end
9
+
10
+ def primary_key
11
+ "id"
12
+ end
13
+
14
+ def find(*args)
15
+ []
16
+ end
17
+
18
+ public :parse_results, :reorder, :parse_query, :add_scores, :replace_types
19
+ end
@@ -0,0 +1,279 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'parser_methods'
3
+ require 'common_methods'
4
+ require 'search_results'
5
+ require 'deprecation'
6
+ module Solr; module Request; end; end
7
+ require 'solr/request/base'
8
+ require 'solr/request/select'
9
+ require 'solr/request/standard'
10
+ require 'parser_instance'
11
+ require 'lazy_document'
12
+
13
+ class ActsAsSolr::Post; end
14
+
15
+ class ParserMethodsTest < Test::Unit::TestCase
16
+
17
+ context "With a parser instance" do
18
+ setup do
19
+ @parser = ActsAsSolr::ParserInstance.new
20
+ end
21
+
22
+ context "When parsing results" do
23
+ setup do
24
+ @results = stub(:results)
25
+ @results.stubs(:highlighting).returns({})
26
+ @results.stubs(:total_hits).returns(2)
27
+ @results.stubs(:hits).returns([])
28
+ @results.stubs(:max_score).returns 2.1
29
+ @results.stubs(:data).returns({"responseHeader" => {"QTime" => "10.2"}})
30
+ end
31
+
32
+ should "return a SearchResults object" do
33
+ assert_equal ActsAsSolr::SearchResults, @parser.parse_results(@results).class
34
+ end
35
+
36
+ should "set the max score" do
37
+ assert_equal 2.1, @parser.parse_results(@results).max_score
38
+ end
39
+
40
+ should "include the facets" do
41
+ @results.stubs(:data).returns({"responseHeader" => {"QTime" => "10.2"}, "facet_counts" => 2})
42
+ assert_equal 2, @parser.parse_results(@results, :facets => true).facets
43
+ end
44
+
45
+ context "when the format requests objects" do
46
+ setup do
47
+ @parser.configuration = {:format => :objects}
48
+ @parser.solr_configuration = {:primary_key_field => :pk_id}
49
+ @results.stubs(:hits).returns [{"pk_id" => 1}, {"pk_id" => 2}]
50
+ @parser.stubs(:reorder)
51
+ end
52
+
53
+ should "query with the record ids" do
54
+ @parser.expects(:find).with(:all, :conditions => ["documents.id in (?)", [1, 2]]).returns [1, 2]
55
+ @parser.parse_results(@results)
56
+ end
57
+
58
+ should "reorder the records" do
59
+ @parser.expects(:reorder).with([], [1, 2])
60
+ @parser.parse_results(@results)
61
+ end
62
+
63
+ should "add :include if :include was specified" do
64
+ @parser.expects(:find).with(:all, :conditions => ["documents.id in (?)", [1, 2]], :include => [:author]).returns [1, 2]
65
+ @parser.parse_results(@results, :include => [:author])
66
+ end
67
+ end
68
+
69
+ context "when the format doesn't request objects" do
70
+ setup do
71
+ @parser.solr_configuration = {:primary_key_field => "pk_id"}
72
+ end
73
+
74
+ should "not query the database" do
75
+ @parser.expects(:find).never
76
+ @parser.parse_results(@results, :format => nil)
77
+ end
78
+
79
+ should "return just the ids" do
80
+ @results.stubs(:hits).returns([{"pk_id" => 1}, {"pk_id" => 2}])
81
+ assert_equal [1, 2], @parser.parse_results(@results, :format => nil).docs
82
+ end
83
+
84
+ should "ignore the :lazy option" do
85
+ @results.stubs(:hits).returns([{"pk_id" => 1}, {"pk_id" => 2}])
86
+ assert_equal [1, 2], @parser.parse_results(@results, :format => :ids, :lazy => true).docs
87
+ end
88
+ end
89
+
90
+ context "with an empty result set" do
91
+ setup do
92
+ @results.stubs(:total_hits).returns(0)
93
+ @results.stubs(:hits).returns([])
94
+ end
95
+
96
+ should "return an empty search results set" do
97
+ assert_equal 0, @parser.parse_results(@results).total
98
+ end
99
+
100
+ should "not have any search results" do
101
+ assert_equal [], @parser.parse_results(@results).docs
102
+ end
103
+ end
104
+
105
+ context "with a nil result set" do
106
+ should "return an empty search results set" do
107
+ assert_equal 0, @parser.parse_results(nil).total
108
+ end
109
+ end
110
+
111
+ context "with the scores option" do
112
+ should "add the scores" do
113
+ @parser.expects(:add_scores).with([], @results)
114
+ @parser.parse_results(@results, :scores => true)
115
+ end
116
+ end
117
+
118
+ context "with lazy format" do
119
+ setup do
120
+ @parser.solr_configuration = {:primary_key_field => :pk_id}
121
+ @results.stubs(:hits).returns([{"pk_id" => 1}, {"pk_id" => 2}])
122
+ end
123
+
124
+ should "create LazyDocuments for the resulting docs" do
125
+ result = @parser.parse_results(@results, :lazy => true)
126
+ assert_equal ActsAsSolr::LazyDocument, result.results.first.class
127
+ end
128
+
129
+ should "set the document id as the record id" do
130
+ result = @parser.parse_results(@results, :lazy => true)
131
+ assert_equal 1, result.results.first.id
132
+ end
133
+
134
+ should "set the document class" do
135
+ result = @parser.parse_results(@results, :lazy => true)
136
+ assert_equal ActsAsSolr::ParserInstance, result.results.first.clazz.class
137
+ end
138
+ end
139
+
140
+ end
141
+
142
+ context "when reordering results" do
143
+ should "raise an error if arguments don't have the same number of elements" do
144
+ assert_raise(RuntimeError) {@parser.reorder([], [1])}
145
+ end
146
+
147
+ should "reorder the results to match the order of the documents returned by solr" do
148
+ thing1 = stub(:thing1)
149
+ thing1.stubs(:id).returns 5
150
+ thing2 = stub(:thing2)
151
+ thing2.stubs(:id).returns 1
152
+ thing3 = stub(:things3)
153
+ thing3.stubs(:id).returns 3
154
+ things = [thing1, thing2, thing3]
155
+ reordered = @parser.reorder(things, [1, 3, 5])
156
+ assert_equal [1, 3, 5], reordered.collect{|thing| thing.id}
157
+ end
158
+ end
159
+
160
+ context "When parsing a query" do
161
+ setup do
162
+ ActsAsSolr::Post.stubs(:execute)
163
+ @parser.stubs(:solr_type_condition).returns "(type:ParserMethodsTest)"
164
+ @parser.solr_configuration = {:primary_key_field => "id"}
165
+ @parser.configuration = {:solr_fields => nil}
166
+ end
167
+
168
+ should "set the limit and offset" do
169
+ ActsAsSolr::Post.expects(:execute).with {|request|
170
+ 10 == request.to_hash[:rows]
171
+ 20 == request.to_hash[:start]
172
+ }
173
+ @parser.parse_query "foo", :limit => 10, :offset => 20
174
+ end
175
+
176
+ should "set the operator" do
177
+ ActsAsSolr::Post.expects(:execute).with {|request|
178
+ "OR" == request.to_hash["q.op"]
179
+ }
180
+ @parser.parse_query "foo", :operator => :or
181
+ end
182
+
183
+ should "not execute anything if the query is nil" do
184
+ ActsAsSolr::Post.expects(:execute).never
185
+ assert_nil @parser.parse_query(nil)
186
+ end
187
+
188
+ should "not execute anything if the query is ''" do
189
+ ActsAsSolr::Post.expects(:execute).never
190
+ assert_nil @parser.parse_query('')
191
+ end
192
+
193
+ should "raise an error if invalid options where specified" do
194
+ assert_raise(RuntimeError) {@parser.parse_query "foo", :invalid => true}
195
+ end
196
+
197
+ should "add the type" do
198
+ ActsAsSolr::Post.expects(:execute).with {|request|
199
+ request.to_hash[:q].include?("(type:ParserMethodsTest)")
200
+ }
201
+ @parser.parse_query "foo"
202
+ end
203
+
204
+ should "append the field types for the specified fields" do
205
+ ActsAsSolr::Post.expects(:execute).with {|request|
206
+ request.to_hash[:q].include?("(username_t:Chunky)")
207
+ }
208
+ @parser.parse_query "username:Chunky"
209
+ end
210
+
211
+ should "replace the field types" do
212
+ @parser.expects(:replace_types).returns(["active_i:1"])
213
+ ActsAsSolr::Post.expects(:execute).with {|request|
214
+ request.to_hash[:q].include?("active_i:1")
215
+ }
216
+ @parser.parse_query "active:1"
217
+ end
218
+
219
+ should "add score and primary key to field list" do
220
+ ActsAsSolr::Post.expects(:execute).with {|request|
221
+ request.to_hash[:fl] == ('id,score')
222
+ }
223
+ @parser.parse_query "foo"
224
+ end
225
+
226
+ context "with the order option" do
227
+ should "add the order criteria to the query" do
228
+ ActsAsSolr::Post.expects(:execute).with {|request|
229
+ request.to_hash[:q].include?(";active_t desc")
230
+ }
231
+ @parser.parse_query "active:1", :order => "active desc"
232
+ end
233
+ end
234
+
235
+ context "with facets" do
236
+ end
237
+ end
238
+
239
+ context "When setting the field types" do
240
+ setup do
241
+ @parser.configuration = {:solr_fields => {:name => {:type => :string},
242
+ :age => {:type => :integer}}}
243
+ end
244
+
245
+ should "replace the _t suffix with the real type" do
246
+ assert_equal ["name_s:Chunky AND age_i:21"], @parser.replace_types(["name_t:Chunky AND age_t:21"])
247
+ end
248
+
249
+ context "with a suffix" do
250
+ should "not include the colon when false" do
251
+ assert_equal ["name_s"], @parser.replace_types(["name_t"], false)
252
+ end
253
+
254
+ should "include the colon by default" do
255
+ assert_equal ["name_s:Chunky"], @parser.replace_types(["name_t:Chunky"])
256
+ end
257
+ end
258
+ end
259
+
260
+ context "When adding scores" do
261
+ setup do
262
+ @solr_data = stub(:results)
263
+ @solr_data.stubs(:total_hits).returns(1)
264
+ @solr_data.stubs(:hits).returns([{"id" => 2, "score" => 2.546}])
265
+ @solr_data.stubs(:max_score).returns 2.1
266
+
267
+ @results = [Array.new]
268
+
269
+ @parser.stubs(:record_id).returns(2)
270
+
271
+ @parser.solr_configuration = {:primary_key_field => "id"}
272
+ end
273
+
274
+ should "add the score to the result document" do
275
+ assert_equal 2.546, @parser.add_scores(@results, @solr_data).first.last.solr_score
276
+ end
277
+ end
278
+ end
279
+ end