skalee-thinking-sphinx 1.3.14.1
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/LICENCE +20 -0
- data/README.textile +201 -0
- data/Rakefile +3 -0
- data/VERSION +1 -0
- data/contribute.rb +385 -0
- data/cucumber.yml +1 -0
- data/features/abstract_inheritance.feature +10 -0
- data/features/alternate_primary_key.feature +27 -0
- data/features/attribute_transformation.feature +22 -0
- data/features/attribute_updates.feature +51 -0
- data/features/deleting_instances.feature +67 -0
- data/features/direct_attributes.feature +11 -0
- data/features/excerpts.feature +13 -0
- data/features/extensible_delta_indexing.feature +9 -0
- data/features/facets.feature +82 -0
- data/features/facets_across_model.feature +29 -0
- data/features/handling_edits.feature +92 -0
- data/features/retry_stale_indexes.feature +24 -0
- data/features/searching_across_models.feature +20 -0
- data/features/searching_by_index.feature +40 -0
- data/features/searching_by_model.feature +175 -0
- data/features/searching_with_find_arguments.feature +56 -0
- data/features/sphinx_detection.feature +25 -0
- data/features/sphinx_scopes.feature +42 -0
- data/features/step_definitions/alpha_steps.rb +16 -0
- data/features/step_definitions/beta_steps.rb +7 -0
- data/features/step_definitions/common_steps.rb +188 -0
- data/features/step_definitions/extensible_delta_indexing_steps.rb +7 -0
- data/features/step_definitions/facet_steps.rb +96 -0
- data/features/step_definitions/find_arguments_steps.rb +36 -0
- data/features/step_definitions/gamma_steps.rb +15 -0
- data/features/step_definitions/scope_steps.rb +15 -0
- data/features/step_definitions/search_steps.rb +89 -0
- data/features/step_definitions/sphinx_steps.rb +35 -0
- data/features/sti_searching.feature +19 -0
- data/features/support/database.example.yml +3 -0
- data/features/support/db/.gitignore +1 -0
- data/features/support/db/fixtures/alphas.rb +10 -0
- data/features/support/db/fixtures/authors.rb +1 -0
- data/features/support/db/fixtures/betas.rb +10 -0
- data/features/support/db/fixtures/boxes.rb +9 -0
- data/features/support/db/fixtures/categories.rb +1 -0
- data/features/support/db/fixtures/cats.rb +3 -0
- data/features/support/db/fixtures/comments.rb +24 -0
- data/features/support/db/fixtures/developers.rb +29 -0
- data/features/support/db/fixtures/dogs.rb +3 -0
- data/features/support/db/fixtures/extensible_betas.rb +10 -0
- data/features/support/db/fixtures/foxes.rb +3 -0
- data/features/support/db/fixtures/gammas.rb +10 -0
- data/features/support/db/fixtures/music.rb +4 -0
- data/features/support/db/fixtures/people.rb +1001 -0
- data/features/support/db/fixtures/posts.rb +6 -0
- data/features/support/db/fixtures/robots.rb +14 -0
- data/features/support/db/fixtures/tags.rb +27 -0
- data/features/support/db/migrations/create_alphas.rb +8 -0
- data/features/support/db/migrations/create_animals.rb +5 -0
- data/features/support/db/migrations/create_authors.rb +3 -0
- data/features/support/db/migrations/create_authors_posts.rb +6 -0
- data/features/support/db/migrations/create_betas.rb +5 -0
- data/features/support/db/migrations/create_boxes.rb +5 -0
- data/features/support/db/migrations/create_categories.rb +3 -0
- data/features/support/db/migrations/create_comments.rb +10 -0
- data/features/support/db/migrations/create_developers.rb +9 -0
- data/features/support/db/migrations/create_extensible_betas.rb +5 -0
- data/features/support/db/migrations/create_gammas.rb +3 -0
- data/features/support/db/migrations/create_genres.rb +3 -0
- data/features/support/db/migrations/create_music.rb +6 -0
- data/features/support/db/migrations/create_people.rb +13 -0
- data/features/support/db/migrations/create_posts.rb +5 -0
- data/features/support/db/migrations/create_robots.rb +4 -0
- data/features/support/db/migrations/create_taggings.rb +5 -0
- data/features/support/db/migrations/create_tags.rb +4 -0
- data/features/support/env.rb +21 -0
- data/features/support/lib/generic_delta_handler.rb +8 -0
- data/features/support/models/alpha.rb +22 -0
- data/features/support/models/animal.rb +5 -0
- data/features/support/models/author.rb +3 -0
- data/features/support/models/beta.rb +8 -0
- data/features/support/models/box.rb +8 -0
- data/features/support/models/cat.rb +3 -0
- data/features/support/models/category.rb +4 -0
- data/features/support/models/comment.rb +10 -0
- data/features/support/models/developer.rb +16 -0
- data/features/support/models/dog.rb +3 -0
- data/features/support/models/extensible_beta.rb +9 -0
- data/features/support/models/fox.rb +5 -0
- data/features/support/models/gamma.rb +5 -0
- data/features/support/models/genre.rb +3 -0
- data/features/support/models/medium.rb +5 -0
- data/features/support/models/music.rb +8 -0
- data/features/support/models/person.rb +23 -0
- data/features/support/models/post.rb +21 -0
- data/features/support/models/robot.rb +12 -0
- data/features/support/models/tag.rb +3 -0
- data/features/support/models/tagging.rb +4 -0
- data/ginger_scenarios.rb +28 -0
- data/init.rb +5 -0
- data/install.rb +5 -0
- data/lib/cucumber/thinking_sphinx/external_world.rb +8 -0
- data/lib/cucumber/thinking_sphinx/internal_world.rb +126 -0
- data/lib/cucumber/thinking_sphinx/sql_logger.rb +20 -0
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +19 -0
- data/lib/thinking_sphinx/active_record/delta.rb +47 -0
- data/lib/thinking_sphinx/active_record/has_many_association.rb +29 -0
- data/lib/thinking_sphinx/active_record/scopes.rb +75 -0
- data/lib/thinking_sphinx/active_record.rb +348 -0
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +42 -0
- data/lib/thinking_sphinx/adapters/mysql_adapter.rb +54 -0
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +143 -0
- data/lib/thinking_sphinx/association.rb +164 -0
- data/lib/thinking_sphinx/attribute.rb +362 -0
- data/lib/thinking_sphinx/auto_version.rb +22 -0
- data/lib/thinking_sphinx/class_facet.rb +15 -0
- data/lib/thinking_sphinx/configuration.rb +300 -0
- data/lib/thinking_sphinx/context.rb +68 -0
- data/lib/thinking_sphinx/core/array.rb +7 -0
- data/lib/thinking_sphinx/core/string.rb +15 -0
- data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
- data/lib/thinking_sphinx/deltas.rb +28 -0
- data/lib/thinking_sphinx/deploy/capistrano.rb +100 -0
- data/lib/thinking_sphinx/excerpter.rb +22 -0
- data/lib/thinking_sphinx/facet.rb +125 -0
- data/lib/thinking_sphinx/facet_search.rb +136 -0
- data/lib/thinking_sphinx/field.rb +82 -0
- data/lib/thinking_sphinx/index/builder.rb +296 -0
- data/lib/thinking_sphinx/index/faux_column.rb +110 -0
- data/lib/thinking_sphinx/index.rb +157 -0
- data/lib/thinking_sphinx/property.rb +162 -0
- data/lib/thinking_sphinx/rails_additions.rb +150 -0
- data/lib/thinking_sphinx/search.rb +769 -0
- data/lib/thinking_sphinx/search_methods.rb +439 -0
- data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
- data/lib/thinking_sphinx/source/sql.rb +130 -0
- data/lib/thinking_sphinx/source.rb +153 -0
- data/lib/thinking_sphinx/tasks.rb +131 -0
- data/lib/thinking_sphinx/test.rb +52 -0
- data/lib/thinking_sphinx.rb +225 -0
- data/rails/init.rb +16 -0
- data/recipes/thinking_sphinx.rb +3 -0
- data/spec/fixtures/data.sql +32 -0
- data/spec/fixtures/database.yml.default +3 -0
- data/spec/fixtures/models.rb +145 -0
- data/spec/fixtures/structure.sql +125 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/sphinx_helper.rb +81 -0
- data/spec/thinking_sphinx/active_record/delta_spec.rb +128 -0
- data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +55 -0
- data/spec/thinking_sphinx/active_record/scopes_spec.rb +177 -0
- data/spec/thinking_sphinx/active_record_spec.rb +622 -0
- data/spec/thinking_sphinx/association_spec.rb +239 -0
- data/spec/thinking_sphinx/attribute_spec.rb +570 -0
- data/spec/thinking_sphinx/auto_version_spec.rb +39 -0
- data/spec/thinking_sphinx/configuration_spec.rb +234 -0
- data/spec/thinking_sphinx/context_spec.rb +119 -0
- data/spec/thinking_sphinx/core/array_spec.rb +9 -0
- data/spec/thinking_sphinx/core/string_spec.rb +9 -0
- data/spec/thinking_sphinx/excerpter_spec.rb +57 -0
- data/spec/thinking_sphinx/facet_search_spec.rb +176 -0
- data/spec/thinking_sphinx/facet_spec.rb +333 -0
- data/spec/thinking_sphinx/field_spec.rb +154 -0
- data/spec/thinking_sphinx/index/builder_spec.rb +479 -0
- data/spec/thinking_sphinx/index/faux_column_spec.rb +30 -0
- data/spec/thinking_sphinx/index_spec.rb +183 -0
- data/spec/thinking_sphinx/rails_additions_spec.rb +203 -0
- data/spec/thinking_sphinx/search_methods_spec.rb +152 -0
- data/spec/thinking_sphinx/search_spec.rb +1181 -0
- data/spec/thinking_sphinx/source_spec.rb +235 -0
- data/spec/thinking_sphinx_spec.rb +204 -0
- data/tasks/distribution.rb +41 -0
- data/tasks/rails.rake +1 -0
- data/tasks/testing.rb +72 -0
- data/vendor/after_commit/.gitignore +1 -0
- data/vendor/after_commit/lib/after_commit/active_record.rb +122 -0
- data/vendor/after_commit/lib/after_commit/connection_adapters.rb +168 -0
- data/vendor/after_commit/lib/after_commit/test_bypass.rb +30 -0
- data/vendor/after_commit/lib/after_commit.rb +70 -0
- data/vendor/riddle/lib/riddle/0.9.8.rb +1 -0
- data/vendor/riddle/lib/riddle/0.9.9/client/filter.rb +22 -0
- data/vendor/riddle/lib/riddle/0.9.9/client.rb +49 -0
- data/vendor/riddle/lib/riddle/0.9.9/configuration/searchd.rb +28 -0
- data/vendor/riddle/lib/riddle/0.9.9.rb +7 -0
- data/vendor/riddle/lib/riddle/auto_version.rb +11 -0
- data/vendor/riddle/lib/riddle/client/filter.rb +62 -0
- data/vendor/riddle/lib/riddle/client/message.rb +70 -0
- data/vendor/riddle/lib/riddle/client/response.rb +94 -0
- data/vendor/riddle/lib/riddle/client.rb +745 -0
- data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +49 -0
- data/vendor/riddle/lib/riddle/configuration/index.rb +149 -0
- data/vendor/riddle/lib/riddle/configuration/indexer.rb +20 -0
- data/vendor/riddle/lib/riddle/configuration/remote_index.rb +17 -0
- data/vendor/riddle/lib/riddle/configuration/searchd.rb +28 -0
- data/vendor/riddle/lib/riddle/configuration/section.rb +43 -0
- data/vendor/riddle/lib/riddle/configuration/source.rb +23 -0
- data/vendor/riddle/lib/riddle/configuration/sql_source.rb +53 -0
- data/vendor/riddle/lib/riddle/configuration/xml_source.rb +29 -0
- data/vendor/riddle/lib/riddle/configuration.rb +33 -0
- data/vendor/riddle/lib/riddle/controller.rb +78 -0
- data/vendor/riddle/lib/riddle.rb +51 -0
- metadata +312 -0
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Configuration do
|
4
|
+
describe "environment class method" do
|
5
|
+
before :each do
|
6
|
+
Thread.current[:thinking_sphinx_environment] = nil
|
7
|
+
|
8
|
+
ENV["RAILS_ENV"] = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should use the Merb environment value if set" do
|
12
|
+
unless defined?(Merb)
|
13
|
+
module ::Merb; end
|
14
|
+
end
|
15
|
+
|
16
|
+
ThinkingSphinx::Configuration.stub!(:defined? => true)
|
17
|
+
Merb.stub!(:environment => "merb_production")
|
18
|
+
ThinkingSphinx::Configuration.environment.should == "merb_production"
|
19
|
+
|
20
|
+
Object.send(:remove_const, :Merb)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should use the Rails environment value if set" do
|
24
|
+
ENV["RAILS_ENV"] = "rails_production"
|
25
|
+
ThinkingSphinx::Configuration.environment.should == "rails_production"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should default to development" do
|
29
|
+
ThinkingSphinx::Configuration.environment.should == "development"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "parse_config method" do
|
34
|
+
before :each do
|
35
|
+
@settings = {
|
36
|
+
"development" => {
|
37
|
+
"config_file" => "tmp/config/development.sphinx.conf",
|
38
|
+
"searchd_log_file" => "searchd_log_file.log",
|
39
|
+
"query_log_file" => "query_log_file.log",
|
40
|
+
"pid_file" => "pid_file.pid",
|
41
|
+
"searchd_file_path" => "searchd/file/path",
|
42
|
+
"address" => "127.0.0.1",
|
43
|
+
"port" => 3333,
|
44
|
+
"min_prefix_len" => 2,
|
45
|
+
"min_infix_len" => 3,
|
46
|
+
"mem_limit" => "128M",
|
47
|
+
"max_matches" => 1001,
|
48
|
+
"morphology" => "stem_ru",
|
49
|
+
"charset_type" => "latin1",
|
50
|
+
"charset_table" => "table",
|
51
|
+
"ignore_chars" => "e",
|
52
|
+
"searchd_binary_name" => "sphinx-searchd",
|
53
|
+
"indexer_binary_name" => "sphinx-indexer",
|
54
|
+
"index_exact_words" => true
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
|
59
|
+
f.write YAML.dump(@settings)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should use the accessors to set the configuration values" do
|
64
|
+
config = ThinkingSphinx::Configuration.instance
|
65
|
+
config.send(:parse_config)
|
66
|
+
|
67
|
+
%w(config_file searchd_log_file query_log_file pid_file searchd_file_path
|
68
|
+
address port searchd_binary_name indexer_binary_name).each do |key|
|
69
|
+
config.send(key).should == @settings["development"][key]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
after :each do
|
74
|
+
FileUtils.rm "#{RAILS_ROOT}/config/sphinx.yml"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "block configuration" do
|
79
|
+
it "should let the user set-up a custom app_root" do
|
80
|
+
ThinkingSphinx::Configuration.configure do |config|
|
81
|
+
config.app_root = "/here/somewhere"
|
82
|
+
end
|
83
|
+
ThinkingSphinx::Configuration.instance.app_root.should == "/here/somewhere"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "initialisation" do
|
88
|
+
it "should have a default bin_path of nothing" do
|
89
|
+
ThinkingSphinx::Configuration.instance.bin_path.should == ""
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should append a / to bin_path if one is supplied" do
|
93
|
+
@settings = {
|
94
|
+
"development" => {
|
95
|
+
"bin_path" => "path/to/somewhere"
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
|
100
|
+
f.write YAML.dump(@settings)
|
101
|
+
end
|
102
|
+
|
103
|
+
ThinkingSphinx::Configuration.instance.send(:parse_config)
|
104
|
+
ThinkingSphinx::Configuration.instance.bin_path.should match(/\/$/)
|
105
|
+
|
106
|
+
FileUtils.rm "#{RAILS_ROOT}/config/sphinx.yml"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "index options" do
|
111
|
+
before :each do
|
112
|
+
@settings = {
|
113
|
+
"development" => {"disable_range" => true}
|
114
|
+
}
|
115
|
+
|
116
|
+
open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
|
117
|
+
f.write YAML.dump(@settings)
|
118
|
+
end
|
119
|
+
|
120
|
+
@config = ThinkingSphinx::Configuration.instance
|
121
|
+
@config.send(:parse_config)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should collect disable_range" do
|
125
|
+
@config.index_options[:disable_range].should be_true
|
126
|
+
end
|
127
|
+
|
128
|
+
after :each do
|
129
|
+
FileUtils.rm "#{RAILS_ROOT}/config/sphinx.yml"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should insert set index options into the configuration file" do
|
134
|
+
config = ThinkingSphinx::Configuration.instance
|
135
|
+
|
136
|
+
ThinkingSphinx::Configuration::IndexOptions.each do |option|
|
137
|
+
config.reset
|
138
|
+
config.index_options[option.to_sym] = "something"
|
139
|
+
config.build
|
140
|
+
|
141
|
+
file = open(config.config_file) { |f| f.read }
|
142
|
+
file.should match(/#{option}\s+= something/)
|
143
|
+
|
144
|
+
config.index_options[option.to_sym] = nil
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should insert set source options into the configuration file" do
|
149
|
+
config = ThinkingSphinx::Configuration.instance
|
150
|
+
config.reset
|
151
|
+
|
152
|
+
config.source_options[:sql_query_pre] = ["something"]
|
153
|
+
ThinkingSphinx::Configuration::SourceOptions.each do |option|
|
154
|
+
config.source_options[option.to_sym] ||= "something"
|
155
|
+
config.build
|
156
|
+
|
157
|
+
file = open(config.config_file) { |f| f.read }
|
158
|
+
file.should match(/#{option}\s+= something/)
|
159
|
+
|
160
|
+
config.source_options.delete option.to_sym
|
161
|
+
end
|
162
|
+
|
163
|
+
config.source_options[:sql_query_pre] = nil
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should not blow away delta or utf options if sql pre is specified in config" do
|
167
|
+
config = ThinkingSphinx::Configuration.instance
|
168
|
+
config.reset
|
169
|
+
|
170
|
+
config.source_options[:sql_query_pre] = ["a pre query"]
|
171
|
+
config.build
|
172
|
+
file = open(config.config_file) { |f| f.read }
|
173
|
+
|
174
|
+
file.should match(/sql_query_pre = a pre query\n\s*sql_query_pre = UPDATE `\w+` SET `delta` = 0 WHERE `delta` = 1/im)
|
175
|
+
file.should match(/sql_query_pre = a pre query\n\s*sql_query_pre = \n/im)
|
176
|
+
|
177
|
+
config.source_options[:sql_query_pre] = nil
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should set any explicit prefixed or infixed fields" do
|
181
|
+
file = open(ThinkingSphinx::Configuration.instance.config_file) { |f|
|
182
|
+
f.read
|
183
|
+
}
|
184
|
+
file.should match(/prefix_fields\s+= city/)
|
185
|
+
file.should match(/infix_fields\s+= state/)
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should not have prefix fields in indexes where nothing is set" do
|
189
|
+
file = open(ThinkingSphinx::Configuration.instance.config_file) { |f|
|
190
|
+
f.read
|
191
|
+
}
|
192
|
+
file.should_not match(/index alpha_core\s+\{\s+[^\}]*prefix_fields\s+=[^\}]*\}/m)
|
193
|
+
end
|
194
|
+
|
195
|
+
describe '#client' do
|
196
|
+
before :each do
|
197
|
+
@config = ThinkingSphinx::Configuration.instance
|
198
|
+
@config.address = 'domain.url'
|
199
|
+
@config.port = 3333
|
200
|
+
@config.configuration.searchd.max_matches = 100
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should return an instance of Riddle::Client" do
|
204
|
+
@config.client.should be_a(Riddle::Client)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should use the configuration address" do
|
208
|
+
@config.client.server.should == 'domain.url'
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should use the configuration port" do
|
212
|
+
@config.client.port.should == 3333
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should use the configuration max matches" do
|
216
|
+
@config.client.max_matches.should == 100
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe '#models_by_crc' do
|
221
|
+
before :each do
|
222
|
+
@config = ThinkingSphinx::Configuration.instance
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should return a hash" do
|
226
|
+
@config.models_by_crc.should be_a(Hash)
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should pair class names to their crc codes" do
|
230
|
+
@config.models_by_crc[Person.to_crc32].should == 'Person'
|
231
|
+
@config.models_by_crc[Alpha.to_crc32].should == 'Alpha'
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Context do
|
4
|
+
before :each do
|
5
|
+
@context = ThinkingSphinx::Context.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '#prepare' do
|
9
|
+
before :each do
|
10
|
+
@config = ThinkingSphinx::Configuration.instance
|
11
|
+
@config.model_directories = ['']
|
12
|
+
|
13
|
+
@file_name = 'a.rb'
|
14
|
+
@model_name_lower = 'a'
|
15
|
+
@class_name = 'A'
|
16
|
+
|
17
|
+
@file_name.stub!(:gsub).and_return(@model_name_lower)
|
18
|
+
@model_name_lower.stub!(:camelize).and_return(@class_name)
|
19
|
+
Dir.stub(:[]).and_return([@file_name])
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should load the files by guessing the file name" do
|
23
|
+
@class_name.should_receive(:constantize).and_return(true)
|
24
|
+
|
25
|
+
@context.prepare
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not raise errors if the model name is nil" do
|
29
|
+
@file_name.stub!(:gsub).and_return(nil)
|
30
|
+
|
31
|
+
lambda {
|
32
|
+
@context.prepare
|
33
|
+
}.should_not raise_error
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not raise errors if the file name does not represent a class name" do
|
37
|
+
@class_name.should_receive(:constantize).and_raise(NameError)
|
38
|
+
|
39
|
+
lambda {
|
40
|
+
@context.prepare
|
41
|
+
}.should_not raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should retry if the first pass fails and contains a directory" do
|
45
|
+
@model_name_lower.stub!(:gsub!).and_return(true, nil)
|
46
|
+
@class_name.stub(:constantize).and_raise(LoadError)
|
47
|
+
@model_name_lower.should_receive(:camelize).twice
|
48
|
+
|
49
|
+
lambda {
|
50
|
+
@context.prepare
|
51
|
+
}.should_not raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should catch database errors with a warning" do
|
55
|
+
@class_name.should_receive(:constantize).and_raise(Mysql::Error)
|
56
|
+
STDERR.should_receive(:puts).with('Warning: Error loading a.rb')
|
57
|
+
|
58
|
+
lambda {
|
59
|
+
@context.prepare
|
60
|
+
}.should_not raise_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#define_indexes' do
|
65
|
+
it "should call define_indexes on all known indexed models" do
|
66
|
+
@context.stub!(:indexed_models => ['Alpha', 'Beta'])
|
67
|
+
Alpha.should_receive(:define_indexes)
|
68
|
+
Beta.should_receive(:define_indexes)
|
69
|
+
|
70
|
+
@context.define_indexes
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#add_indexed_model' do
|
75
|
+
before :each do
|
76
|
+
@context.indexed_models.clear
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should add the model to the collection" do
|
80
|
+
@context.add_indexed_model 'Alpha'
|
81
|
+
|
82
|
+
@context.indexed_models.should == ['Alpha']
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not duplicate models in the collection" do
|
86
|
+
@context.add_indexed_model 'Alpha'
|
87
|
+
@context.add_indexed_model 'Alpha'
|
88
|
+
|
89
|
+
@context.indexed_models.should == ['Alpha']
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should keep the collection in alphabetical order" do
|
93
|
+
@context.add_indexed_model 'Beta'
|
94
|
+
@context.add_indexed_model 'Alpha'
|
95
|
+
|
96
|
+
@context.indexed_models.should == ['Alpha', 'Beta']
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should translate classes to their names" do
|
100
|
+
@context.add_indexed_model Alpha
|
101
|
+
|
102
|
+
@context.indexed_models.should == ['Alpha']
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#superclass_indexed_models' do
|
107
|
+
it "should return indexed model names" do
|
108
|
+
@context.stub!(:indexed_models => ['Alpha', 'Beta'])
|
109
|
+
|
110
|
+
@context.superclass_indexed_models.should == ['Alpha', 'Beta']
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should not include classes which have indexed superclasses" do
|
114
|
+
@context.stub!(:indexed_models => ['Parent', 'Person'])
|
115
|
+
|
116
|
+
@context.superclass_indexed_models.should == ['Person']
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Excerpter do
|
4
|
+
before :each do
|
5
|
+
@alpha = Alpha.find(:first)
|
6
|
+
@search = mock 'search', :excerpt_for => 'excerpted value'
|
7
|
+
@excerpter = ThinkingSphinx::Excerpter.new(@search, @alpha)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should not respond to id" do
|
11
|
+
@excerpter.should_not respond_to(:id)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#method_missing' do
|
15
|
+
it "should return the excerpt from Sphinx" do
|
16
|
+
@excerpter.name.should == 'excerpted value'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should send through the instance class to excerpt_for" do
|
20
|
+
@search.should_receive(:excerpt_for) do |string, model|
|
21
|
+
model.should == Alpha
|
22
|
+
end
|
23
|
+
|
24
|
+
@excerpter.name
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should use attribute methods for excerpts calls" do
|
28
|
+
@search.should_receive(:excerpt_for) do |string, model|
|
29
|
+
string.should == 'one'
|
30
|
+
end
|
31
|
+
|
32
|
+
@excerpter.name
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should use instance methods for excerpts calls" do
|
36
|
+
@search.should_receive(:excerpt_for) do |string, model|
|
37
|
+
string.should == 'ONE'
|
38
|
+
end
|
39
|
+
|
40
|
+
@excerpter.big_name
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should escape the text in the excerpt" do
|
44
|
+
@search.should_receive(:excerpt_for) do |string, model|
|
45
|
+
string.should == 'test "escaping" <characters>'
|
46
|
+
end
|
47
|
+
|
48
|
+
@excerpter.string_to_escape
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should still raise an exception if no column or method exists" do
|
52
|
+
lambda {
|
53
|
+
@excerpter.foo
|
54
|
+
}.should raise_error(NoMethodError)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::FacetSearch do
|
4
|
+
describe 'populate' do
|
5
|
+
it "should make separate Sphinx queries for each facet" do
|
6
|
+
ThinkingSphinx.should_receive(:search).with(
|
7
|
+
hash_including(:group_by => 'city_facet')
|
8
|
+
).and_return([])
|
9
|
+
ThinkingSphinx.should_receive(:search).with(
|
10
|
+
hash_including(:group_by => 'state_facet')
|
11
|
+
).and_return([])
|
12
|
+
ThinkingSphinx.should_receive(:search).with(
|
13
|
+
hash_including(:group_by => 'birthday')
|
14
|
+
).and_return([])
|
15
|
+
|
16
|
+
ThinkingSphinx::FacetSearch.new(:classes => [Person])
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should request all shared facets in a multi-model request by default" do
|
20
|
+
ThinkingSphinx.stub!(:search => [])
|
21
|
+
ThinkingSphinx::FacetSearch.new.facet_names.should == ['class_crc']
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should request all facets in a multi-model request if specified" do
|
25
|
+
ThinkingSphinx.stub!(:search => [])
|
26
|
+
ThinkingSphinx::FacetSearch.new(
|
27
|
+
:all_facets => true
|
28
|
+
).facet_names.should == [
|
29
|
+
'class_crc', 'city_facet', 'state_facet', 'birthday'
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
describe ':facets option' do
|
34
|
+
it "should limit facets to the requested set" do
|
35
|
+
ThinkingSphinx.should_receive(:search).once.and_return([])
|
36
|
+
|
37
|
+
ThinkingSphinx::FacetSearch.new(
|
38
|
+
:classes => [Person], :facets => :state
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "empty result set for attributes" do
|
44
|
+
before :each do
|
45
|
+
ThinkingSphinx.stub!(:search => [])
|
46
|
+
@facets = ThinkingSphinx::FacetSearch.new(
|
47
|
+
:classes => [Person], :facets => :state
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should add key as attribute" do
|
52
|
+
@facets.should have_key(:state)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return an empty hash for the facet results" do
|
56
|
+
@facets[:state].should be_empty
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "non-empty result set" do
|
61
|
+
before :each do
|
62
|
+
@person = Person.find(:first)
|
63
|
+
@people = [@person]
|
64
|
+
@people.stub!(:each_with_groupby_and_count).
|
65
|
+
and_yield(@person, @person.city.to_crc32, 1)
|
66
|
+
ThinkingSphinx.stub!(:search => @people)
|
67
|
+
|
68
|
+
@facets = ThinkingSphinx::FacetSearch.new(
|
69
|
+
:classes => [Person], :facets => :city
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should return a hash" do
|
74
|
+
@facets.should be_a_kind_of(Hash)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should add key as attribute" do
|
78
|
+
@facets.keys.should include(:city)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should return a hash" do
|
82
|
+
@facets[:city].should == {@person.city => 1}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
before :each do
|
87
|
+
@config = ThinkingSphinx::Configuration.instance
|
88
|
+
@config.configuration.searchd.max_matches = 10_000
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should use the system-set max_matches for limit on facet calls" do
|
92
|
+
ThinkingSphinx.should_receive(:search) do |options|
|
93
|
+
options[:max_matches].should == 10_000
|
94
|
+
options[:limit].should == 10_000
|
95
|
+
[]
|
96
|
+
end
|
97
|
+
|
98
|
+
ThinkingSphinx::FacetSearch.new
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should use the default max-matches if there is no explicit setting" do
|
102
|
+
@config.configuration.searchd.max_matches = nil
|
103
|
+
ThinkingSphinx.should_receive(:search) do |options|
|
104
|
+
options[:max_matches].should == 1000
|
105
|
+
options[:limit].should == 1000
|
106
|
+
[]
|
107
|
+
end
|
108
|
+
|
109
|
+
ThinkingSphinx::FacetSearch.new
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should ignore user-provided max_matches and limit on facet calls" do
|
113
|
+
ThinkingSphinx.should_receive(:search) do |options|
|
114
|
+
options[:max_matches].should == 10_000
|
115
|
+
options[:limit].should == 10_000
|
116
|
+
[]
|
117
|
+
end
|
118
|
+
|
119
|
+
ThinkingSphinx::FacetSearch.new(
|
120
|
+
:max_matches => 500,
|
121
|
+
:limit => 200
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should not use an explicit :page" do
|
126
|
+
ThinkingSphinx.should_receive(:search) do |options|
|
127
|
+
options[:page].should == 1
|
128
|
+
[]
|
129
|
+
end
|
130
|
+
|
131
|
+
ThinkingSphinx::FacetSearch.new(:page => 3)
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "conflicting facets" do
|
135
|
+
before :each do
|
136
|
+
@index = ThinkingSphinx::Index::Builder.generate(Alpha) do
|
137
|
+
indexes :name
|
138
|
+
has :value, :as => :city, :facet => true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
after :each do
|
143
|
+
Alpha.sphinx_facets.delete_at(-1)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should raise an error if searching with facets of same name but different type" do
|
147
|
+
lambda {
|
148
|
+
facets = ThinkingSphinx.facets :all_facets => true
|
149
|
+
}.should raise_error
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "#for" do
|
155
|
+
before do
|
156
|
+
@person = Person.find(:first)
|
157
|
+
@people = [@person]
|
158
|
+
@people.stub!(:each_with_groupby_and_count).
|
159
|
+
and_yield(@person, @person.city.to_crc32, 1)
|
160
|
+
ThinkingSphinx.stub!(:search => @people)
|
161
|
+
|
162
|
+
@facets = ThinkingSphinx::FacetSearch.new(
|
163
|
+
:classes => [Person], :facets => :city
|
164
|
+
)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should return the search results for the attribute and key pair" do
|
168
|
+
ThinkingSphinx.should_receive(:search) do |options|
|
169
|
+
options[:with].should have_key('city_facet')
|
170
|
+
options[:with]['city_facet'].should == @person.city.to_crc32
|
171
|
+
end
|
172
|
+
|
173
|
+
@facets.for(:city => @person.city)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|