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