ebeigarts-thinking-sphinx 1.1.22 → 1.2.10
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +14 -0
- data/VERSION.yml +4 -0
- data/lib/thinking_sphinx.rb +60 -64
- data/lib/thinking_sphinx/active_record.rb +35 -7
- data/lib/thinking_sphinx/active_record/scopes.rb +39 -0
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +3 -2
- data/lib/thinking_sphinx/attribute.rb +62 -22
- data/lib/thinking_sphinx/configuration.rb +21 -1
- data/lib/thinking_sphinx/core/array.rb +7 -0
- data/lib/thinking_sphinx/deltas/delayed_delta.rb +3 -0
- data/lib/thinking_sphinx/deploy/capistrano.rb +26 -8
- data/lib/thinking_sphinx/excerpter.rb +22 -0
- data/lib/thinking_sphinx/facet.rb +8 -2
- data/lib/thinking_sphinx/facet_search.rb +134 -0
- data/lib/thinking_sphinx/index.rb +2 -2
- data/lib/thinking_sphinx/index/builder.rb +0 -1
- data/lib/thinking_sphinx/property.rb +2 -0
- data/lib/thinking_sphinx/rails_additions.rb +14 -0
- data/lib/thinking_sphinx/search.rb +633 -671
- data/lib/thinking_sphinx/search_methods.rb +421 -0
- data/lib/thinking_sphinx/source.rb +5 -5
- data/lib/thinking_sphinx/source/internal_properties.rb +1 -1
- data/lib/thinking_sphinx/source/sql.rb +10 -8
- data/lib/thinking_sphinx/tasks.rb +14 -9
- data/spec/{unit → lib}/thinking_sphinx/active_record/delta_spec.rb +1 -1
- data/spec/{unit → lib}/thinking_sphinx/active_record/has_many_association_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +96 -0
- data/spec/{unit → lib}/thinking_sphinx/active_record_spec.rb +44 -5
- data/spec/{unit → lib}/thinking_sphinx/association_spec.rb +0 -0
- data/spec/{unit → lib}/thinking_sphinx/attribute_spec.rb +110 -3
- data/spec/{unit → lib}/thinking_sphinx/configuration_spec.rb +87 -41
- data/spec/lib/thinking_sphinx/core/array_spec.rb +9 -0
- data/spec/{unit → lib}/thinking_sphinx/core/string_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
- data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
- data/spec/{unit → lib}/thinking_sphinx/facet_spec.rb +34 -15
- data/spec/{unit → lib}/thinking_sphinx/field_spec.rb +0 -0
- data/spec/{unit → lib}/thinking_sphinx/index/builder_spec.rb +100 -0
- data/spec/{unit → lib}/thinking_sphinx/index/faux_column_spec.rb +0 -0
- data/spec/{unit → lib}/thinking_sphinx/index_spec.rb +0 -0
- data/spec/{unit → lib}/thinking_sphinx/rails_additions_spec.rb +12 -0
- data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
- data/spec/lib/thinking_sphinx/search_spec.rb +1066 -0
- data/spec/{unit → lib}/thinking_sphinx/source_spec.rb +10 -0
- data/spec/{unit → lib}/thinking_sphinx_spec.rb +10 -0
- data/tasks/distribution.rb +20 -38
- data/tasks/testing.rb +3 -1
- data/vendor/riddle/lib/riddle.rb +1 -1
- data/vendor/riddle/lib/riddle/client.rb +3 -0
- data/vendor/riddle/lib/riddle/client/message.rb +4 -3
- data/vendor/riddle/lib/riddle/configuration/section.rb +1 -1
- data/vendor/riddle/lib/riddle/controller.rb +17 -7
- metadata +63 -83
- data/lib/thinking_sphinx/active_record/search.rb +0 -57
- data/lib/thinking_sphinx/collection.rb +0 -148
- data/lib/thinking_sphinx/facet_collection.rb +0 -59
- data/lib/thinking_sphinx/search/facets.rb +0 -104
- data/spec/unit/thinking_sphinx/active_record/search_spec.rb +0 -107
- data/spec/unit/thinking_sphinx/collection_spec.rb +0 -15
- data/spec/unit/thinking_sphinx/facet_collection_spec.rb +0 -64
- data/spec/unit/thinking_sphinx/search_spec.rb +0 -228
@@ -2,7 +2,7 @@ module ThinkingSphinx
|
|
2
2
|
class Source
|
3
3
|
module InternalProperties
|
4
4
|
def add_internal_attributes_and_facets
|
5
|
-
add_internal_attribute :sphinx_internal_id, :integer, @model.
|
5
|
+
add_internal_attribute :sphinx_internal_id, :integer, @model.primary_key_for_sphinx.to_sym
|
6
6
|
add_internal_attribute :class_crc, :integer, crc_column, true
|
7
7
|
add_internal_attribute :subclass_crcs, :multi, subclasses_to_s
|
8
8
|
add_internal_attribute :sphinx_deleted, :integer, "0"
|
@@ -33,10 +33,10 @@ GROUP BY #{ sql_group_clause }
|
|
33
33
|
return nil if @index.options[:disable_range]
|
34
34
|
|
35
35
|
min_statement = adapter.convert_nulls(
|
36
|
-
"MIN(#{quote_column(@model.
|
36
|
+
"MIN(#{quote_column(@model.primary_key_for_sphinx)})", 1
|
37
37
|
)
|
38
38
|
max_statement = adapter.convert_nulls(
|
39
|
-
"MAX(#{quote_column(@model.
|
39
|
+
"MAX(#{quote_column(@model.primary_key_for_sphinx)})", 1
|
40
40
|
)
|
41
41
|
|
42
42
|
sql = "SELECT #{min_statement}, #{max_statement} " +
|
@@ -53,14 +53,14 @@ GROUP BY #{ sql_group_clause }
|
|
53
53
|
#
|
54
54
|
def to_sql_query_info(offset)
|
55
55
|
"SELECT * FROM #{@model.quoted_table_name} WHERE " +
|
56
|
-
"#{quote_column(@model.
|
56
|
+
"#{quote_column(@model.primary_key_for_sphinx)} = (($id - #{offset}) / #{ThinkingSphinx.indexed_models.size})"
|
57
57
|
end
|
58
58
|
|
59
59
|
def sql_select_clause(offset)
|
60
60
|
unique_id_expr = ThinkingSphinx.unique_id_expression(offset)
|
61
61
|
|
62
62
|
(
|
63
|
-
["#{@model.quoted_table_name}.#{quote_column(@model.
|
63
|
+
["#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)} #{unique_id_expr} AS #{quote_column(@model.primary_key_for_sphinx)} "] +
|
64
64
|
@fields.collect { |field| field.to_select_sql } +
|
65
65
|
@attributes.collect { |attribute| attribute.to_select_sql }
|
66
66
|
).compact.join(", ")
|
@@ -69,8 +69,8 @@ GROUP BY #{ sql_group_clause }
|
|
69
69
|
def sql_where_clause(options)
|
70
70
|
logic = []
|
71
71
|
logic += [
|
72
|
-
"#{@model.quoted_table_name}.#{quote_column(@model.
|
73
|
-
"#{@model.quoted_table_name}.#{quote_column(@model.
|
72
|
+
"#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)} >= $start",
|
73
|
+
"#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)} <= $end"
|
74
74
|
] unless @index.options[:disable_range]
|
75
75
|
|
76
76
|
if self.delta? && !@index.delta_object.clause(@model, options[:delta]).blank?
|
@@ -88,7 +88,7 @@ GROUP BY #{ sql_group_clause }
|
|
88
88
|
end
|
89
89
|
|
90
90
|
(
|
91
|
-
["#{@model.quoted_table_name}.#{quote_column(@model.
|
91
|
+
["#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)}"] +
|
92
92
|
@fields.collect { |field| field.to_group_sql }.compact +
|
93
93
|
@attributes.collect { |attribute| attribute.to_group_sql }.compact +
|
94
94
|
@groupings + internal_groupings
|
@@ -112,7 +112,9 @@ GROUP BY #{ sql_group_clause }
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def crc_column
|
115
|
-
if @model.
|
115
|
+
if @model.table_exists? &&
|
116
|
+
@model.column_names.include?(@model.inheritance_column)
|
117
|
+
|
116
118
|
adapter.cast_to_unsigned(adapter.convert_nulls(
|
117
119
|
adapter.crc(adapter.quote_with_table(@model.inheritance_column), true),
|
118
120
|
@model.to_crc32
|
@@ -12,7 +12,7 @@ namespace :thinking_sphinx do
|
|
12
12
|
|
13
13
|
desc "Output the current Thinking Sphinx version"
|
14
14
|
task :version => :app_env do
|
15
|
-
puts "Thinking Sphinx v" + ThinkingSphinx
|
15
|
+
puts "Thinking Sphinx v" + ThinkingSphinx.version
|
16
16
|
end
|
17
17
|
|
18
18
|
desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
|
@@ -30,7 +30,7 @@ namespace :thinking_sphinx do
|
|
30
30
|
|
31
31
|
Dir["#{config.searchd_file_path}/*.spl"].each { |file| File.delete(file) }
|
32
32
|
|
33
|
-
system! "#{config.bin_path}#{config.searchd_binary_name} --pidfile --config #{config.config_file}"
|
33
|
+
system! "#{config.bin_path}#{config.searchd_binary_name} --pidfile --config \"#{config.config_file}\""
|
34
34
|
|
35
35
|
sleep(2)
|
36
36
|
|
@@ -43,11 +43,14 @@ namespace :thinking_sphinx do
|
|
43
43
|
|
44
44
|
desc "Stop Sphinx using Thinking Sphinx's settings"
|
45
45
|
task :stop => :app_env do
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
unless sphinx_running?
|
47
|
+
puts "searchd is not running"
|
48
|
+
else
|
49
|
+
config = ThinkingSphinx::Configuration.instance
|
50
|
+
pid = sphinx_pid
|
51
|
+
system! "#{config.bin_path}#{config.searchd_binary_name} --stop --config \"#{config.config_file}\""
|
52
|
+
puts "Stopped search daemon (pid #{pid})."
|
53
|
+
end
|
51
54
|
end
|
52
55
|
|
53
56
|
desc "Restart Sphinx"
|
@@ -71,7 +74,7 @@ namespace :thinking_sphinx do
|
|
71
74
|
end
|
72
75
|
|
73
76
|
FileUtils.mkdir_p config.searchd_file_path
|
74
|
-
cmd = "#{config.bin_path}#{config.indexer_binary_name} --config #{config.config_file} --all"
|
77
|
+
cmd = "#{config.bin_path}#{config.indexer_binary_name} --config \"#{config.config_file}\" --all"
|
75
78
|
cmd << " --rotate" if sphinx_running?
|
76
79
|
|
77
80
|
system! cmd
|
@@ -111,6 +114,7 @@ namespace :thinking_sphinx do
|
|
111
114
|
# http://www.sphinxsearch.com/docs/current.html#xmlpipe2
|
112
115
|
desc "Streams XML data to STDOUT"
|
113
116
|
task :xml => :app_env do
|
117
|
+
ThinkingSphinx::Configuration.instance.load_models
|
114
118
|
source_name = ENV["NAME"]
|
115
119
|
# STDERR.puts "Source name: #{source_name}"
|
116
120
|
source_name =~ /^(.+)_(delta|core)_(\d+)$/
|
@@ -141,7 +145,8 @@ namespace :thinking_sphinx do
|
|
141
145
|
# STDERR.puts "fetching #{start_id}.. "
|
142
146
|
# STDERR.puts query
|
143
147
|
model_klass.sphinx_database_adapter.select_each(query) do |values|
|
144
|
-
|
148
|
+
pk_name = model_klass.primary_key_for_sphinx.to_s
|
149
|
+
id = values.delete(pk_name)
|
145
150
|
puts %{<sphinx:document id="#{id.to_i}">}
|
146
151
|
values.each do |k, v|
|
147
152
|
if source.sql_attr_bool.include?(k.to_sym)
|
File without changes
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::ActiveRecord::Scopes do
|
4
|
+
after :each do
|
5
|
+
Alpha.remove_sphinx_scopes
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be included into models with indexes" do
|
9
|
+
Alpha.included_modules.should include(ThinkingSphinx::ActiveRecord::Scopes)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not be included into models without indexes" do
|
13
|
+
Gamma.included_modules.should_not include(
|
14
|
+
ThinkingSphinx::ActiveRecord::Scopes
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '.sphinx_scope' do
|
19
|
+
before :each do
|
20
|
+
Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should define a method on the model" do
|
24
|
+
Alpha.should respond_to(:by_name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '.sphinx_scopes' do
|
29
|
+
before :each do
|
30
|
+
Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return an array of defined scope names as symbols" do
|
34
|
+
Alpha.sphinx_scopes.should == [:by_name]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '.remove_sphinx_scopes' do
|
39
|
+
before :each do
|
40
|
+
Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
|
41
|
+
Alpha.remove_sphinx_scopes
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should remove sphinx scope methods" do
|
45
|
+
Alpha.should_not respond_to(:by_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should empty the list of sphinx scopes" do
|
49
|
+
Alpha.sphinx_scopes.should be_empty
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '.example_scope' do
|
54
|
+
before :each do
|
55
|
+
Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
|
56
|
+
Alpha.sphinx_scope(:by_foo) { |foo| {:conditions => {:foo => foo}} }
|
57
|
+
Alpha.sphinx_scope(:with_betas) { {:classes => [Beta]} }
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should return a ThinkingSphinx::Search object" do
|
61
|
+
Alpha.by_name('foo').should be_a(ThinkingSphinx::Search)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should set the classes option" do
|
65
|
+
Alpha.by_name('foo').options[:classes].should == [Alpha]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should be able to be called on a ThinkingSphinx::Search object" do
|
69
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
70
|
+
lambda {
|
71
|
+
search.by_name('foo')
|
72
|
+
}.should_not raise_error
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should return the search object it gets called upon" do
|
76
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
77
|
+
search.by_name('foo').should == search
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should apply the scope options to the underlying search object" do
|
81
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
82
|
+
search.by_name('foo').options[:conditions].should == {:name => 'foo'}
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should combine hash option scopes such as :conditions" do
|
86
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
87
|
+
search.by_name('foo').by_foo('bar').options[:conditions].
|
88
|
+
should == {:name => 'foo', :foo => 'bar'}
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should combine array option scopes such as :classes" do
|
92
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
93
|
+
search.with_betas.options[:classes].should == [Alpha, Beta]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec/spec_helper'
|
2
2
|
|
3
|
-
describe
|
4
|
-
describe
|
3
|
+
describe ThinkingSphinx::ActiveRecord do
|
4
|
+
describe '.define_index' do
|
5
5
|
before :each do
|
6
6
|
module ::TestModule
|
7
7
|
class TestModel < ActiveRecord::Base; end
|
@@ -154,7 +154,7 @@ describe "ThinkingSphinx::ActiveRecord" do
|
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
157
|
-
describe
|
157
|
+
describe '.source_of_sphinx_index' do
|
158
158
|
it "should return self if model defines an index" do
|
159
159
|
Person.source_of_sphinx_index.should == Person
|
160
160
|
end
|
@@ -164,13 +164,13 @@ describe "ThinkingSphinx::ActiveRecord" do
|
|
164
164
|
end
|
165
165
|
end
|
166
166
|
|
167
|
-
describe
|
167
|
+
describe '.to_crc32' do
|
168
168
|
it "should return an integer" do
|
169
169
|
Person.to_crc32.should be_a_kind_of(Integer)
|
170
170
|
end
|
171
171
|
end
|
172
172
|
|
173
|
-
describe
|
173
|
+
describe '.to_crc32s' do
|
174
174
|
it "should return an array" do
|
175
175
|
Person.to_crc32s.should be_a_kind_of(Array)
|
176
176
|
end
|
@@ -326,4 +326,43 @@ describe "ThinkingSphinx::ActiveRecord" do
|
|
326
326
|
|
327
327
|
(beta.id * model_count + offset).should == beta.sphinx_document_id
|
328
328
|
end
|
329
|
+
|
330
|
+
describe '#primary_key_for_sphinx' do
|
331
|
+
before :each do
|
332
|
+
@person = Person.find(:first)
|
333
|
+
end
|
334
|
+
|
335
|
+
after :each do
|
336
|
+
Person.set_sphinx_primary_key nil
|
337
|
+
end
|
338
|
+
|
339
|
+
it "should return the id by default" do
|
340
|
+
@person.primary_key_for_sphinx.should == @person.id
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should use the sphinx primary key to determine the value" do
|
344
|
+
Person.set_sphinx_primary_key :first_name
|
345
|
+
@person.primary_key_for_sphinx.should == @person.first_name
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should not use accessor methods but the attributes hash" do
|
349
|
+
id = @person.id
|
350
|
+
@person.stub!(:id => 'unique_hash')
|
351
|
+
@person.primary_key_for_sphinx.should == id
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
describe '.sphinx_index_names' do
|
356
|
+
it "should return the core index" do
|
357
|
+
Alpha.sphinx_index_names.should == ['alpha_core']
|
358
|
+
end
|
359
|
+
|
360
|
+
it "should return the delta index if enabled" do
|
361
|
+
Beta.sphinx_index_names.should == ['beta_core', 'beta_delta']
|
362
|
+
end
|
363
|
+
|
364
|
+
it "should return the superclass with an index definition" do
|
365
|
+
Parent.sphinx_index_names.should == ['person_core', 'person_delta']
|
366
|
+
end
|
367
|
+
end
|
329
368
|
end
|
File without changes
|
@@ -4,6 +4,8 @@ describe ThinkingSphinx::Attribute do
|
|
4
4
|
before :each do
|
5
5
|
@index = ThinkingSphinx::Index.new(Person)
|
6
6
|
@source = ThinkingSphinx::Source.new(@index)
|
7
|
+
|
8
|
+
@index.delta_object = ThinkingSphinx::Deltas::DefaultDelta.new @index, @index.local_options
|
7
9
|
end
|
8
10
|
|
9
11
|
describe '#initialize' do
|
@@ -86,6 +88,19 @@ describe ThinkingSphinx::Attribute do
|
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
91
|
+
describe '#to_select_sql' do
|
92
|
+
it "should convert a mixture of dates and datetimes to timestamps" do
|
93
|
+
attribute = ThinkingSphinx::Attribute.new(@source,
|
94
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:created_at),
|
95
|
+
ThinkingSphinx::Index::FauxColumn.new(:created_on) ],
|
96
|
+
:as => :times
|
97
|
+
)
|
98
|
+
attribute.model = Friendship
|
99
|
+
|
100
|
+
attribute.to_select_sql.should == "CONCAT_WS(',', UNIX_TIMESTAMP(`friendships`.`created_at`), UNIX_TIMESTAMP(`friendships`.`created_on`)) AS `times`"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
89
104
|
describe "is_many? method" do
|
90
105
|
before :each do
|
91
106
|
@assoc_a = Object.stub_instance(:is_many? => true)
|
@@ -189,7 +204,7 @@ describe ThinkingSphinx::Attribute do
|
|
189
204
|
attribute.model = Person
|
190
205
|
attribute.columns.each { |col| attribute.associations[col] = [] }
|
191
206
|
|
192
|
-
attribute.
|
207
|
+
attribute.should be_all_ints
|
193
208
|
end
|
194
209
|
|
195
210
|
it "should return false if only some columns are integers" do
|
@@ -200,7 +215,7 @@ describe ThinkingSphinx::Attribute do
|
|
200
215
|
attribute.model = Person
|
201
216
|
attribute.columns.each { |col| attribute.associations[col] = [] }
|
202
217
|
|
203
|
-
attribute.
|
218
|
+
attribute.should_not be_all_ints
|
204
219
|
end
|
205
220
|
|
206
221
|
it "should return false if no columns are integers" do
|
@@ -211,7 +226,42 @@ describe ThinkingSphinx::Attribute do
|
|
211
226
|
attribute.model = Person
|
212
227
|
attribute.columns.each { |col| attribute.associations[col] = [] }
|
213
228
|
|
214
|
-
attribute.
|
229
|
+
attribute.should_not be_all_ints
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "all_datetimes? method" do
|
234
|
+
it "should return true if all columns are datetimes" do
|
235
|
+
attribute = ThinkingSphinx::Attribute.new(@source,
|
236
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:created_at),
|
237
|
+
ThinkingSphinx::Index::FauxColumn.new(:updated_at) ]
|
238
|
+
)
|
239
|
+
attribute.model = Friendship
|
240
|
+
attribute.columns.each { |col| attribute.associations[col] = [] }
|
241
|
+
|
242
|
+
attribute.should be_all_datetimes
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should return false if only some columns are datetimes" do
|
246
|
+
attribute = ThinkingSphinx::Attribute.new(@source,
|
247
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:id),
|
248
|
+
ThinkingSphinx::Index::FauxColumn.new(:created_at) ]
|
249
|
+
)
|
250
|
+
attribute.model = Friendship
|
251
|
+
attribute.columns.each { |col| attribute.associations[col] = [] }
|
252
|
+
|
253
|
+
attribute.should_not be_all_datetimes
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should return true if all columns can be " do
|
257
|
+
attribute = ThinkingSphinx::Attribute.new(@source,
|
258
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:created_at),
|
259
|
+
ThinkingSphinx::Index::FauxColumn.new(:created_on) ]
|
260
|
+
)
|
261
|
+
attribute.model = Friendship
|
262
|
+
attribute.columns.each { |col| attribute.associations[col] = [] }
|
263
|
+
|
264
|
+
attribute.should be_all_datetimes
|
215
265
|
end
|
216
266
|
end
|
217
267
|
|
@@ -232,6 +282,23 @@ describe ThinkingSphinx::Attribute do
|
|
232
282
|
end
|
233
283
|
end
|
234
284
|
|
285
|
+
describe "MVA with source query for a delta source" do
|
286
|
+
before :each do
|
287
|
+
@attribute = ThinkingSphinx::Attribute.new(@source,
|
288
|
+
[ThinkingSphinx::Index::FauxColumn.new(:tags, :id)],
|
289
|
+
:as => :tag_ids, :source => :query
|
290
|
+
)
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should use a query" do
|
294
|
+
@attribute.type_to_config.should == :sql_attr_multi
|
295
|
+
|
296
|
+
declaration, query = @attribute.config_value(nil, true).split('; ')
|
297
|
+
declaration.should == "uint tag_ids from query"
|
298
|
+
query.should == "SELECT `tags`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `tags`.`id` AS `tag_ids` FROM `tags` WHERE `tags`.`person_id` IN (SELECT `id` FROM `people` WHERE `people`.`delta` = 1)"
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
235
302
|
describe "MVA via a HABTM association with a source query" do
|
236
303
|
before :each do
|
237
304
|
@attribute = ThinkingSphinx::Attribute.new(@source,
|
@@ -267,6 +334,24 @@ describe ThinkingSphinx::Attribute do
|
|
267
334
|
end
|
268
335
|
end
|
269
336
|
|
337
|
+
describe "MVA with ranged source query for a delta source" do
|
338
|
+
before :each do
|
339
|
+
@attribute = ThinkingSphinx::Attribute.new(@source,
|
340
|
+
[ThinkingSphinx::Index::FauxColumn.new(:tags, :id)],
|
341
|
+
:as => :tag_ids, :source => :ranged_query
|
342
|
+
)
|
343
|
+
end
|
344
|
+
|
345
|
+
it "should use a ranged query" do
|
346
|
+
@attribute.type_to_config.should == :sql_attr_multi
|
347
|
+
|
348
|
+
declaration, query, range_query = @attribute.config_value(nil, true).split('; ')
|
349
|
+
declaration.should == "uint tag_ids from ranged-query"
|
350
|
+
query.should == "SELECT `tags`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `tags`.`id` AS `tag_ids` FROM `tags` WHERE `tags`.`person_id` >= $start AND `tags`.`person_id` <= $end AND `tags`.`person_id` IN (SELECT `id` FROM `people` WHERE `people`.`delta` = 1)"
|
351
|
+
range_query.should == "SELECT MIN(`tags`.`person_id`), MAX(`tags`.`person_id`) FROM `tags`"
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
270
355
|
describe "MVA via a has-many :through with a ranged source query" do
|
271
356
|
before :each do
|
272
357
|
@attribute = ThinkingSphinx::Attribute.new(@source,
|
@@ -341,6 +426,28 @@ describe ThinkingSphinx::Attribute do
|
|
341
426
|
end
|
342
427
|
end
|
343
428
|
|
429
|
+
describe "MVA via two has-many associations with a ranged source query for a delta source" do
|
430
|
+
before :each do
|
431
|
+
@index = ThinkingSphinx::Index.new(Alpha)
|
432
|
+
@source = ThinkingSphinx::Source.new(@index)
|
433
|
+
@attribute = ThinkingSphinx::Attribute.new(@source,
|
434
|
+
[ThinkingSphinx::Index::FauxColumn.new(:betas, :gammas, :value)],
|
435
|
+
:as => :gamma_values, :source => :ranged_query
|
436
|
+
)
|
437
|
+
|
438
|
+
@index.delta_object = ThinkingSphinx::Deltas::DefaultDelta.new @index, @index.local_options
|
439
|
+
end
|
440
|
+
|
441
|
+
it "should use a ranged query" do
|
442
|
+
@attribute.type_to_config.should == :sql_attr_multi
|
443
|
+
|
444
|
+
declaration, query, range_query = @attribute.config_value(nil, true).split('; ')
|
445
|
+
declaration.should == "uint gamma_values from ranged-query"
|
446
|
+
query.should == "SELECT `betas`.`alpha_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `gammas`.`value` AS `gamma_values` FROM `betas` LEFT OUTER JOIN `gammas` ON gammas.beta_id = betas.id WHERE `betas`.`alpha_id` >= $start AND `betas`.`alpha_id` <= $end AND `betas`.`alpha_id` IN (SELECT `id` FROM `alphas` WHERE `alphas`.`delta` = 1)"
|
447
|
+
range_query.should == "SELECT MIN(`betas`.`alpha_id`), MAX(`betas`.`alpha_id`) FROM `betas`"
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
344
451
|
describe "with custom queries" do
|
345
452
|
before :each do
|
346
453
|
index = CricketTeam.sphinx_indexes.first
|