dpickett-thinking-sphinx 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENCE +20 -0
- data/README +107 -0
- data/lib/thinking_sphinx/active_record/delta.rb +74 -0
- data/lib/thinking_sphinx/active_record/has_many_association.rb +29 -0
- data/lib/thinking_sphinx/active_record/search.rb +57 -0
- data/lib/thinking_sphinx/active_record.rb +245 -0
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +34 -0
- data/lib/thinking_sphinx/adapters/mysql_adapter.rb +53 -0
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +129 -0
- data/lib/thinking_sphinx/association.rb +144 -0
- data/lib/thinking_sphinx/attribute.rb +254 -0
- data/lib/thinking_sphinx/class_facet.rb +20 -0
- data/lib/thinking_sphinx/collection.rb +142 -0
- data/lib/thinking_sphinx/configuration.rb +236 -0
- data/lib/thinking_sphinx/core/string.rb +22 -0
- data/lib/thinking_sphinx/deltas/datetime_delta.rb +50 -0
- data/lib/thinking_sphinx/deltas/default_delta.rb +65 -0
- data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +24 -0
- data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +27 -0
- data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +26 -0
- data/lib/thinking_sphinx/deltas/delayed_delta.rb +25 -0
- data/lib/thinking_sphinx/deltas.rb +22 -0
- data/lib/thinking_sphinx/facet.rb +58 -0
- data/lib/thinking_sphinx/facet_collection.rb +45 -0
- data/lib/thinking_sphinx/field.rb +172 -0
- data/lib/thinking_sphinx/index/builder.rb +233 -0
- data/lib/thinking_sphinx/index/faux_column.rb +110 -0
- data/lib/thinking_sphinx/index.rb +432 -0
- data/lib/thinking_sphinx/rails_additions.rb +133 -0
- data/lib/thinking_sphinx/search.rb +654 -0
- data/lib/thinking_sphinx/tasks.rb +128 -0
- data/lib/thinking_sphinx.rb +145 -0
- data/spec/unit/thinking_sphinx/active_record/delta_spec.rb +136 -0
- data/spec/unit/thinking_sphinx/active_record/has_many_association_spec.rb +53 -0
- data/spec/unit/thinking_sphinx/active_record/search_spec.rb +107 -0
- data/spec/unit/thinking_sphinx/active_record_spec.rb +256 -0
- data/spec/unit/thinking_sphinx/association_spec.rb +247 -0
- data/spec/unit/thinking_sphinx/attribute_spec.rb +212 -0
- data/spec/unit/thinking_sphinx/collection_spec.rb +14 -0
- data/spec/unit/thinking_sphinx/configuration_spec.rb +136 -0
- data/spec/unit/thinking_sphinx/core/string_spec.rb +9 -0
- data/spec/unit/thinking_sphinx/field_spec.rb +145 -0
- data/spec/unit/thinking_sphinx/index/builder_spec.rb +5 -0
- data/spec/unit/thinking_sphinx/index/faux_column_spec.rb +30 -0
- data/spec/unit/thinking_sphinx/index_spec.rb +54 -0
- data/spec/unit/thinking_sphinx/search_spec.rb +59 -0
- data/spec/unit/thinking_sphinx_spec.rb +129 -0
- data/tasks/distribution.rb +48 -0
- data/tasks/rails.rake +1 -0
- data/tasks/testing.rb +86 -0
- data/vendor/after_commit/LICENSE +20 -0
- data/vendor/after_commit/README +16 -0
- data/vendor/after_commit/Rakefile +22 -0
- data/vendor/after_commit/init.rb +5 -0
- data/vendor/after_commit/lib/after_commit/active_record.rb +91 -0
- data/vendor/after_commit/lib/after_commit/connection_adapters.rb +103 -0
- data/vendor/after_commit/lib/after_commit.rb +42 -0
- data/vendor/after_commit/test/after_commit_test.rb +53 -0
- data/vendor/delayed_job/lib/delayed/job.rb +251 -0
- data/vendor/delayed_job/lib/delayed/message_sending.rb +7 -0
- data/vendor/delayed_job/lib/delayed/performable_method.rb +55 -0
- data/vendor/delayed_job/lib/delayed/worker.rb +54 -0
- data/vendor/riddle/lib/riddle/client/filter.rb +53 -0
- data/vendor/riddle/lib/riddle/client/message.rb +65 -0
- data/vendor/riddle/lib/riddle/client/response.rb +84 -0
- data/vendor/riddle/lib/riddle/client.rb +619 -0
- data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +48 -0
- data/vendor/riddle/lib/riddle/configuration/index.rb +142 -0
- data/vendor/riddle/lib/riddle/configuration/indexer.rb +19 -0
- data/vendor/riddle/lib/riddle/configuration/remote_index.rb +17 -0
- data/vendor/riddle/lib/riddle/configuration/searchd.rb +25 -0
- data/vendor/riddle/lib/riddle/configuration/section.rb +37 -0
- data/vendor/riddle/lib/riddle/configuration/source.rb +23 -0
- data/vendor/riddle/lib/riddle/configuration/sql_source.rb +34 -0
- data/vendor/riddle/lib/riddle/configuration/xml_source.rb +28 -0
- data/vendor/riddle/lib/riddle/configuration.rb +33 -0
- data/vendor/riddle/lib/riddle/controller.rb +44 -0
- data/vendor/riddle/lib/riddle.rb +30 -0
- metadata +158 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Attribute do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'raises if no columns are provided so that configuration errors are easier to track down' do
|
6
|
+
lambda {
|
7
|
+
ThinkingSphinx::Attribute.new([])
|
8
|
+
}.should raise_error(RuntimeError)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
|
12
|
+
lambda {
|
13
|
+
ThinkingSphinx::Attribute.new([1234])
|
14
|
+
}.should raise_error(RuntimeError)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "unique_name method" do
|
19
|
+
before :each do
|
20
|
+
@attribute = ThinkingSphinx::Attribute.new [
|
21
|
+
Object.stub_instance(:__stack => [], :__name => "col_name")
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should use the alias if there is one" do
|
26
|
+
@attribute.alias = "alias"
|
27
|
+
@attribute.unique_name.should == "alias"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should use the alias if there's multiple columns" do
|
31
|
+
@attribute.columns << Object.stub_instance(:__stack => [], :__name => "col_name")
|
32
|
+
@attribute.unique_name.should be_nil
|
33
|
+
|
34
|
+
@attribute.alias = "alias"
|
35
|
+
@attribute.unique_name.should == "alias"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should use the column name if there's no alias and just one column" do
|
39
|
+
@attribute.unique_name.should == "col_name"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "column_with_prefix method" do
|
44
|
+
before :each do
|
45
|
+
@attribute = ThinkingSphinx::Attribute.new [
|
46
|
+
ThinkingSphinx::Index::FauxColumn.new(:col_name)
|
47
|
+
]
|
48
|
+
@attribute.columns.each { |col| @attribute.associations[col] = [] }
|
49
|
+
@attribute.model = Person
|
50
|
+
|
51
|
+
@first_join = Object.stub_instance(:aliased_table_name => "tabular")
|
52
|
+
@second_join = Object.stub_instance(:aliased_table_name => "data")
|
53
|
+
|
54
|
+
@first_assoc = ThinkingSphinx::Association.stub_instance(
|
55
|
+
:join => @first_join, :has_column? => true
|
56
|
+
)
|
57
|
+
@second_assoc = ThinkingSphinx::Association.stub_instance(
|
58
|
+
:join => @second_join, :has_column? => true
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return the column name if the column is a string" do
|
63
|
+
@attribute.columns = [ThinkingSphinx::Index::FauxColumn.new("string")]
|
64
|
+
@attribute.send(:column_with_prefix, @attribute.columns.first).should == "string"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return the column with model's table prefix if there's no associations for the column" do
|
68
|
+
@attribute.send(:column_with_prefix, @attribute.columns.first).should == "`people`.`col_name`"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return the column with its join table prefix if an association exists" do
|
72
|
+
column = @attribute.columns.first
|
73
|
+
@attribute.associations[column] = [@first_assoc]
|
74
|
+
@attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should return multiple columns concatenated if more than one association exists" do
|
78
|
+
column = @attribute.columns.first
|
79
|
+
@attribute.associations[column] = [@first_assoc, @second_assoc]
|
80
|
+
@attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "is_many? method" do
|
85
|
+
before :each do
|
86
|
+
@assoc_a = Object.stub_instance(:is_many? => true)
|
87
|
+
@assoc_b = Object.stub_instance(:is_many? => true)
|
88
|
+
@assoc_c = Object.stub_instance(:is_many? => true)
|
89
|
+
|
90
|
+
@attribute = ThinkingSphinx::Attribute.new(
|
91
|
+
[ThinkingSphinx::Index::FauxColumn.new(:col_name)]
|
92
|
+
)
|
93
|
+
@attribute.associations = {
|
94
|
+
:a => @assoc_a, :b => @assoc_b, :c => @assoc_c
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should return true if all associations return true to is_many?" do
|
99
|
+
@attribute.send(:is_many?).should be_true
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return true if one association returns true to is_many?" do
|
103
|
+
@assoc_b.stub_method(:is_many? => false)
|
104
|
+
@assoc_c.stub_method(:is_many? => false)
|
105
|
+
|
106
|
+
@attribute.send(:is_many?).should be_true
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should return false if all associations return false to is_many?" do
|
110
|
+
@assoc_a.stub_method(:is_many? => false)
|
111
|
+
@assoc_b.stub_method(:is_many? => false)
|
112
|
+
@assoc_c.stub_method(:is_many? => false)
|
113
|
+
|
114
|
+
@attribute.send(:is_many?).should be_false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "is_string? method" do
|
119
|
+
before :each do
|
120
|
+
@col_a = ThinkingSphinx::Index::FauxColumn.new("a")
|
121
|
+
@col_b = ThinkingSphinx::Index::FauxColumn.new("b")
|
122
|
+
@col_c = ThinkingSphinx::Index::FauxColumn.new("c")
|
123
|
+
|
124
|
+
@attribute = ThinkingSphinx::Attribute.new(
|
125
|
+
[@col_a, @col_b, @col_c]
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should return true if all columns return true to is_string?" do
|
130
|
+
@attribute.send(:is_string?).should be_true
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should return false if one column returns true to is_string?" do
|
134
|
+
@col_a.send(:instance_variable_set, :@name, :a)
|
135
|
+
@attribute.send(:is_string?).should be_false
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should return false if all columns return false to is_string?" do
|
139
|
+
@col_a.send(:instance_variable_set, :@name, :a)
|
140
|
+
@col_b.send(:instance_variable_set, :@name, :b)
|
141
|
+
@col_c.send(:instance_variable_set, :@name, :c)
|
142
|
+
@attribute.send(:is_string?).should be_false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "type method" do
|
147
|
+
before :each do
|
148
|
+
@column = ThinkingSphinx::Index::FauxColumn.new(:col_name)
|
149
|
+
@attribute = ThinkingSphinx::Attribute.new([@column])
|
150
|
+
@attribute.model = Person
|
151
|
+
@attribute.stub_method(:is_many? => false)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should return :multi if is_many? is true" do
|
155
|
+
@attribute.stub_method(:is_many? => true)
|
156
|
+
@attribute.send(:type).should == :multi
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should return :string if there's more than one association" do
|
160
|
+
@attribute.associations = {:a => :assoc, :b => :assoc}
|
161
|
+
@attribute.send(:type).should == :string
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should return the column type from the database if not :multi or more than one association" do
|
165
|
+
@column.send(:instance_variable_set, :@name, "birthday")
|
166
|
+
@attribute.send(:type).should == :datetime
|
167
|
+
|
168
|
+
@attribute.send(:instance_variable_set, :@type, nil)
|
169
|
+
@column.send(:instance_variable_set, :@name, "first_name")
|
170
|
+
@attribute.send(:type).should == :string
|
171
|
+
|
172
|
+
@attribute.send(:instance_variable_set, :@type, nil)
|
173
|
+
@column.send(:instance_variable_set, :@name, "id")
|
174
|
+
@attribute.send(:type).should == :integer
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "all_ints? method" do
|
179
|
+
it "should return true if all columns are integers" do
|
180
|
+
attribute = ThinkingSphinx::Attribute.new(
|
181
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:id),
|
182
|
+
ThinkingSphinx::Index::FauxColumn.new(:team_id) ]
|
183
|
+
)
|
184
|
+
attribute.model = Person
|
185
|
+
attribute.columns.each { |col| attribute.associations[col] = [] }
|
186
|
+
|
187
|
+
attribute.send(:all_ints?).should be_true
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should return false if only some columns are integers" do
|
191
|
+
attribute = ThinkingSphinx::Attribute.new(
|
192
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:id),
|
193
|
+
ThinkingSphinx::Index::FauxColumn.new(:first_name) ]
|
194
|
+
)
|
195
|
+
attribute.model = Person
|
196
|
+
attribute.columns.each { |col| attribute.associations[col] = [] }
|
197
|
+
|
198
|
+
attribute.send(:all_ints?).should be_false
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should return false if no columns are integers" do
|
202
|
+
attribute = ThinkingSphinx::Attribute.new(
|
203
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:first_name),
|
204
|
+
ThinkingSphinx::Index::FauxColumn.new(:last_name) ]
|
205
|
+
)
|
206
|
+
attribute.model = Person
|
207
|
+
attribute.columns.each { |col| attribute.associations[col] = [] }
|
208
|
+
|
209
|
+
attribute.send(:all_ints?).should be_false
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Collection do
|
4
|
+
it "should behave like WillPaginate::Collection" do
|
5
|
+
ThinkingSphinx::Collection.instance_methods.should include("previous_page")
|
6
|
+
ThinkingSphinx::Collection.instance_methods.should include("next_page")
|
7
|
+
ThinkingSphinx::Collection.instance_methods.should include("current_page")
|
8
|
+
ThinkingSphinx::Collection.instance_methods.should include("total_pages")
|
9
|
+
ThinkingSphinx::Collection.instance_methods.should include("total_entries")
|
10
|
+
ThinkingSphinx::Collection.instance_methods.should include("offset")
|
11
|
+
|
12
|
+
ThinkingSphinx::Collection.ancestors.should include(Array)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Configuration do
|
4
|
+
describe "environment class method" do
|
5
|
+
before :each do
|
6
|
+
ThinkingSphinx::Configuration.send(:class_variable_set, :@@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_method(:defined? => true)
|
17
|
+
Merb.stub_method(: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
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
|
56
|
+
f.write YAML.dump(@settings)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should use the accessors to set the configuration values" do
|
61
|
+
config = ThinkingSphinx::Configuration.instance
|
62
|
+
config.send(:parse_config)
|
63
|
+
|
64
|
+
%w(config_file searchd_log_file query_log_file pid_file searchd_file_path
|
65
|
+
address port).each do |key|
|
66
|
+
config.send(key).should == @settings["development"][key]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
after :each do
|
71
|
+
FileUtils.rm "#{RAILS_ROOT}/config/sphinx.yml"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "initialisation" do
|
76
|
+
it "should have a default bin_path of nothing" do
|
77
|
+
ThinkingSphinx::Configuration.instance.bin_path.should == ""
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should append a / to bin_path if one is supplied" do
|
81
|
+
@settings = {
|
82
|
+
"development" => {
|
83
|
+
"bin_path" => "path/to/somewhere"
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
|
88
|
+
f.write YAML.dump(@settings)
|
89
|
+
end
|
90
|
+
|
91
|
+
ThinkingSphinx::Configuration.instance.send(:parse_config)
|
92
|
+
ThinkingSphinx::Configuration.instance.bin_path.should match(/\/$/)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should insert set index options into the configuration file" do
|
97
|
+
config = ThinkingSphinx::Configuration.instance
|
98
|
+
ThinkingSphinx::Configuration::IndexOptions.each do |option|
|
99
|
+
config.index_options[option.to_sym] = "something"
|
100
|
+
config.build
|
101
|
+
|
102
|
+
file = open(config.config_file) { |f| f.read }
|
103
|
+
file.should match(/#{option}\s+= something/)
|
104
|
+
|
105
|
+
config.index_options[option.to_sym] = nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should insert set source options into the configuration file" do
|
110
|
+
config = ThinkingSphinx::Configuration.instance
|
111
|
+
ThinkingSphinx::Configuration::SourceOptions.each do |option|
|
112
|
+
config.source_options[option.to_sym] = "something"
|
113
|
+
config.build
|
114
|
+
|
115
|
+
file = open(config.config_file) { |f| f.read }
|
116
|
+
file.should match(/#{option}\s+= something/)
|
117
|
+
|
118
|
+
config.source_options[option.to_sym] = nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should set any explicit prefixed or infixed fields" do
|
123
|
+
file = open(ThinkingSphinx::Configuration.instance.config_file) { |f|
|
124
|
+
f.read
|
125
|
+
}
|
126
|
+
file.should match(/prefix_fields\s+= city/)
|
127
|
+
file.should match(/infix_fields\s+= state/)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should not have prefix fields in indexes where nothing is set" do
|
131
|
+
file = open(ThinkingSphinx::Configuration.instance.config_file) { |f|
|
132
|
+
f.read
|
133
|
+
}
|
134
|
+
file.should_not match(/index alpha_core\s+\{\s+[^\}]*prefix_fields\s+=[^\}]*\}/m)
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Field do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'raises if no columns are provided so that configuration errors are easier to track down' do
|
6
|
+
lambda {
|
7
|
+
ThinkingSphinx::Field.new([])
|
8
|
+
}.should raise_error(RuntimeError)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
|
12
|
+
lambda {
|
13
|
+
ThinkingSphinx::Field.new([1234])
|
14
|
+
}.should raise_error(RuntimeError)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "unique_name method" do
|
19
|
+
before :each do
|
20
|
+
@field = ThinkingSphinx::Field.new [
|
21
|
+
Object.stub_instance(:__stack => [], :__name => "col_name")
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should use the alias if there is one" do
|
26
|
+
@field.alias = "alias"
|
27
|
+
@field.unique_name.should == "alias"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should use the alias if there's multiple columns" do
|
31
|
+
@field.columns << Object.stub_instance(:__stack => [], :__name => "col_name")
|
32
|
+
@field.unique_name.should be_nil
|
33
|
+
|
34
|
+
@field.alias = "alias"
|
35
|
+
@field.unique_name.should == "alias"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should use the column name if there's no alias and just one column" do
|
39
|
+
@field.unique_name.should == "col_name"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "prefixes method" do
|
44
|
+
it "should default to false" do
|
45
|
+
@field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
|
46
|
+
@field.prefixes.should be_false
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should be true if the corresponding option is set" do
|
50
|
+
@field = ThinkingSphinx::Field.new(
|
51
|
+
[Object.stub_instance(:__stack => [])], :prefixes => true
|
52
|
+
)
|
53
|
+
@field.prefixes.should be_true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "infixes method" do
|
58
|
+
it "should default to false" do
|
59
|
+
@field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
|
60
|
+
@field.infixes.should be_false
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should be true if the corresponding option is set" do
|
64
|
+
@field = ThinkingSphinx::Field.new(
|
65
|
+
[Object.stub_instance(:__stack => [])], :infixes => true
|
66
|
+
)
|
67
|
+
@field.infixes.should be_true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "column_with_prefix method" do
|
72
|
+
before :each do
|
73
|
+
@field = ThinkingSphinx::Field.new [
|
74
|
+
ThinkingSphinx::Index::FauxColumn.new(:col_name)
|
75
|
+
]
|
76
|
+
@field.columns.each { |col| @field.associations[col] = [] }
|
77
|
+
@field.model = Person
|
78
|
+
|
79
|
+
@first_join = Object.stub_instance(:aliased_table_name => "tabular")
|
80
|
+
@second_join = Object.stub_instance(:aliased_table_name => "data")
|
81
|
+
|
82
|
+
@first_assoc = ThinkingSphinx::Association.stub_instance(
|
83
|
+
:join => @first_join, :has_column? => true
|
84
|
+
)
|
85
|
+
@second_assoc = ThinkingSphinx::Association.stub_instance(
|
86
|
+
:join => @second_join, :has_column? => true
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should return the column name if the column is a string" do
|
91
|
+
@field.columns = [ThinkingSphinx::Index::FauxColumn.new("string")]
|
92
|
+
@field.send(:column_with_prefix, @field.columns.first).should == "string"
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return the column with model's table prefix if there's no associations for the column" do
|
96
|
+
@field.send(:column_with_prefix, @field.columns.first).should == "`people`.`col_name`"
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should return the column with its join table prefix if an association exists" do
|
100
|
+
column = @field.columns.first
|
101
|
+
@field.associations[column] = [@first_assoc]
|
102
|
+
@field.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should return multiple columns concatenated if more than one association exists" do
|
106
|
+
column = @field.columns.first
|
107
|
+
@field.associations[column] = [@first_assoc, @second_assoc]
|
108
|
+
@field.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "is_many? method" do
|
113
|
+
before :each do
|
114
|
+
@assoc_a = Object.stub_instance(:is_many? => true)
|
115
|
+
@assoc_b = Object.stub_instance(:is_many? => true)
|
116
|
+
@assoc_c = Object.stub_instance(:is_many? => true)
|
117
|
+
|
118
|
+
@field = ThinkingSphinx::Field.new(
|
119
|
+
[ThinkingSphinx::Index::FauxColumn.new(:col_name)]
|
120
|
+
)
|
121
|
+
@field.associations = {
|
122
|
+
:a => @assoc_a, :b => @assoc_b, :c => @assoc_c
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should return true if all associations return true to is_many?" do
|
127
|
+
@field.send(:is_many?).should be_true
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should return true if one association returns true to is_many?" do
|
131
|
+
@assoc_b.stub_method(:is_many? => false)
|
132
|
+
@assoc_c.stub_method(:is_many? => false)
|
133
|
+
|
134
|
+
@field.send(:is_many?).should be_true
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should return false if all associations return false to is_many?" do
|
138
|
+
@assoc_a.stub_method(:is_many? => false)
|
139
|
+
@assoc_b.stub_method(:is_many? => false)
|
140
|
+
@assoc_c.stub_method(:is_many? => false)
|
141
|
+
|
142
|
+
@field.send(:is_many?).should be_false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Index::FauxColumn do
|
4
|
+
describe "coerce class method" do
|
5
|
+
before :each do
|
6
|
+
@column = ThinkingSphinx::Index::FauxColumn.stub_instance
|
7
|
+
ThinkingSphinx::Index::FauxColumn.stub_method(:new => @column)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return a single faux column if passed a string" do
|
11
|
+
ThinkingSphinx::Index::FauxColumn.coerce("string").should == @column
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return a single faux column if passed a symbol" do
|
15
|
+
ThinkingSphinx::Index::FauxColumn.coerce(:string).should == @column
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return an array of faux columns if passed an array of strings" do
|
19
|
+
ThinkingSphinx::Index::FauxColumn.coerce(["one", "two"]).should == [
|
20
|
+
@column, @column
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return an array of faux columns if passed an array of symbols" do
|
25
|
+
ThinkingSphinx::Index::FauxColumn.coerce([:one, :two]).should == [
|
26
|
+
@column, @column
|
27
|
+
]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Index do
|
4
|
+
describe "generated sql_query" do
|
5
|
+
it "should include explicit groupings if requested" do
|
6
|
+
@index = ThinkingSphinx::Index.new(Person)
|
7
|
+
|
8
|
+
@index.groupings << "custom_sql"
|
9
|
+
@index.to_riddle_for_core(0, 0).sql_query.should match(/GROUP BY.+custom_sql/)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "prefix_fields method" do
|
14
|
+
before :each do
|
15
|
+
@index = ThinkingSphinx::Index.new(Person)
|
16
|
+
|
17
|
+
@field_a = ThinkingSphinx::Field.stub_instance(:prefixes => true)
|
18
|
+
@field_b = ThinkingSphinx::Field.stub_instance(:prefixes => false)
|
19
|
+
@field_c = ThinkingSphinx::Field.stub_instance(:prefixes => true)
|
20
|
+
|
21
|
+
@index.fields = [@field_a, @field_b, @field_c]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return fields that are flagged as prefixed" do
|
25
|
+
@index.prefix_fields.should include(@field_a)
|
26
|
+
@index.prefix_fields.should include(@field_c)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not return fields that aren't flagged as prefixed" do
|
30
|
+
@index.prefix_fields.should_not include(@field_b)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "infix_fields method" do
|
35
|
+
before :each do
|
36
|
+
@index = ThinkingSphinx::Index.new(Person)
|
37
|
+
|
38
|
+
@field_a = ThinkingSphinx::Field.stub_instance(:infixes => true)
|
39
|
+
@field_b = ThinkingSphinx::Field.stub_instance(:infixes => false)
|
40
|
+
@field_c = ThinkingSphinx::Field.stub_instance(:infixes => true)
|
41
|
+
|
42
|
+
@index.fields = [@field_a, @field_b, @field_c]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return fields that are flagged as infixed" do
|
46
|
+
@index.infix_fields.should include(@field_a)
|
47
|
+
@index.infix_fields.should include(@field_c)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not return fields that aren't flagged as infixed" do
|
51
|
+
@index.infix_fields.should_not include(@field_b)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'will_paginate/collection'
|
3
|
+
|
4
|
+
describe ThinkingSphinx::Search do
|
5
|
+
describe "search method" do
|
6
|
+
before :each do
|
7
|
+
@client = Riddle::Client.stub_instance(
|
8
|
+
:filters => [],
|
9
|
+
:filters= => true,
|
10
|
+
:id_range= => true,
|
11
|
+
:sort_mode => :asc,
|
12
|
+
:limit => 5,
|
13
|
+
:offset= => 0,
|
14
|
+
:sort_mode= => true,
|
15
|
+
:query => {
|
16
|
+
:matches => [],
|
17
|
+
:total => 50
|
18
|
+
}
|
19
|
+
)
|
20
|
+
|
21
|
+
ThinkingSphinx::Search.stub_methods(
|
22
|
+
:client_from_options => @client,
|
23
|
+
:search_conditions => ["", []]
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
describe ":star option" do
|
28
|
+
|
29
|
+
it "should not apply by default" do
|
30
|
+
ThinkingSphinx::Search.search "foo bar"
|
31
|
+
@client.should have_received(:query).with("foo bar")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should apply when passed, and handle full extended syntax" do
|
35
|
+
input = %{a b* c (d | e) 123 5&6 (f_f g) !h "i j" "k l"~10 "m n"/3 @o p -(q|r)}
|
36
|
+
expected = %{*a* b* *c* (*d* | *e*) *123* *5*&*6* (*f_f* *g*) !*h* "i j" "k l"~10 "m n"/3 @o *p* -(*q*|*r*)}
|
37
|
+
ThinkingSphinx::Search.search input, :star => true
|
38
|
+
@client.should have_received(:query).with(expected)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should default to /\w+/ as token" do
|
42
|
+
ThinkingSphinx::Search.search "foo@bar.com", :star => true
|
43
|
+
@client.should have_received(:query).with("*foo*@*bar*.*com*")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should honour custom token" do
|
47
|
+
ThinkingSphinx::Search.search "foo@bar.com -foo-bar", :star => /[\w@.-]+/u
|
48
|
+
@client.should have_received(:query).with("*foo@bar.com* -*foo-bar*")
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe ThinkingSphinx::Search, "playing nice with Search model" do
|
56
|
+
it "should not conflict with models called Search" do
|
57
|
+
lambda { Search.find(:all) }.should_not raise_error
|
58
|
+
end
|
59
|
+
end
|