thinking-sphinx 3.1.2 → 3.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/Appraisals +7 -3
  4. data/HISTORY +12 -0
  5. data/README.textile +5 -3
  6. data/gemfiles/rails_3_2.gemfile +1 -1
  7. data/gemfiles/rails_4_0.gemfile +1 -1
  8. data/gemfiles/rails_4_1.gemfile +1 -1
  9. data/gemfiles/rails_4_2.gemfile +11 -0
  10. data/lib/thinking_sphinx.rb +1 -1
  11. data/lib/thinking_sphinx/active_record.rb +1 -1
  12. data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +3 -1
  13. data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +1 -1
  14. data/lib/thinking_sphinx/active_record/filter_reflection.rb +75 -0
  15. data/lib/thinking_sphinx/active_record/polymorpher.rb +4 -4
  16. data/lib/thinking_sphinx/active_record/property_query.rb +1 -1
  17. data/lib/thinking_sphinx/active_record/simple_many_query.rb +1 -1
  18. data/lib/thinking_sphinx/active_record/sql_builder.rb +0 -4
  19. data/lib/thinking_sphinx/active_record/sql_builder/statement.rb +0 -1
  20. data/lib/thinking_sphinx/configuration.rb +6 -3
  21. data/lib/thinking_sphinx/core/index.rb +1 -1
  22. data/lib/thinking_sphinx/excerpter.rb +4 -1
  23. data/lib/thinking_sphinx/facet_search.rb +8 -2
  24. data/lib/thinking_sphinx/index_set.rb +33 -11
  25. data/lib/thinking_sphinx/middlewares/inquirer.rb +1 -1
  26. data/lib/thinking_sphinx/middlewares/sphinxql.rb +3 -1
  27. data/lib/thinking_sphinx/railtie.rb +4 -2
  28. data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +2 -4
  29. data/lib/thinking_sphinx/real_time/index.rb +2 -0
  30. data/lib/thinking_sphinx/real_time/index/template.rb +1 -1
  31. data/spec/acceptance/big_integers_spec.rb +27 -6
  32. data/spec/acceptance/facets_spec.rb +1 -2
  33. data/spec/acceptance/real_time_updates_spec.rb +8 -0
  34. data/spec/acceptance/remove_deleted_records_spec.rb +4 -2
  35. data/spec/acceptance/searching_across_schemas_spec.rb +38 -0
  36. data/spec/acceptance/searching_with_sti_spec.rb +19 -7
  37. data/spec/internal/app/indices/bird_index.rb +4 -0
  38. data/spec/internal/app/indices/product_index.rb +21 -0
  39. data/spec/internal/db/schema.rb +9 -9
  40. data/spec/spec_helper.rb +2 -1
  41. data/spec/support/multi_schema.rb +46 -0
  42. data/spec/thinking_sphinx/active_record/callbacks/delta_callbacks_spec.rb +5 -3
  43. data/spec/thinking_sphinx/active_record/filter_reflection_spec.rb +172 -0
  44. data/spec/thinking_sphinx/active_record/polymorpher_spec.rb +18 -11
  45. data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +0 -105
  46. data/spec/thinking_sphinx/configuration_spec.rb +0 -13
  47. data/spec/thinking_sphinx/facet_search_spec.rb +1 -2
  48. data/spec/thinking_sphinx/index_set_spec.rb +31 -13
  49. data/spec/thinking_sphinx/middlewares/inquirer_spec.rb +19 -0
  50. data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +6 -4
  51. data/thinking-sphinx.gemspec +1 -1
  52. metadata +13 -6
  53. data/lib/thinking_sphinx/active_record/filtered_reflection.rb +0 -75
  54. data/spec/thinking_sphinx/active_record/filtered_reflection_spec.rb +0 -141
@@ -46,7 +46,7 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::DeltaCallbacks do
46
46
  }
47
47
 
48
48
  before :each do
49
- ThinkingSphinx::IndexSet.stub :new => [index]
49
+ config.stub :index_set_class => double(:new => [index])
50
50
  end
51
51
 
52
52
  context 'without delta indices' do
@@ -72,7 +72,9 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::DeltaCallbacks do
72
72
  before :each do
73
73
  ThinkingSphinx::Deltas.stub :suspended? => false
74
74
 
75
- ThinkingSphinx::IndexSet.stub :new => [core_index, delta_index]
75
+ config.stub :index_set_class => double(
76
+ :new => [core_index, delta_index]
77
+ )
76
78
  end
77
79
 
78
80
  it "only indexes delta indices" do
@@ -127,7 +129,7 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::DeltaCallbacks do
127
129
  }
128
130
 
129
131
  before :each do
130
- ThinkingSphinx::IndexSet.stub :new => [index]
132
+ config.stub :index_set_class => double(:new => [index])
131
133
  end
132
134
 
133
135
  it "sets delta to true if there are delta indices" do
@@ -0,0 +1,172 @@
1
+ require 'spec_helper'
2
+
3
+ describe ThinkingSphinx::ActiveRecord::FilterReflection do
4
+ describe '.call' do
5
+ let(:reflection) { double('Reflection', :macro => :has_some,
6
+ :options => options, :active_record => double, :name => 'baz',
7
+ :foreign_type => :foo_type, :class => reflection_klass) }
8
+ let(:options) { {:polymorphic => true} }
9
+ let(:filtered_reflection) { double 'filtered reflection' }
10
+ let(:reflection_klass) { double :new => filtered_reflection }
11
+
12
+ before :each do
13
+ reflection.active_record.stub_chain(:connection, :quote_column_name).
14
+ and_return('"foo_type"')
15
+ end
16
+
17
+ it "uses the existing reflection's macro" do
18
+ reflection_klass.should_receive(:new).
19
+ with(:has_some, anything, anything, anything)
20
+
21
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
22
+ reflection, 'foo_bar', 'Bar'
23
+ )
24
+ end unless defined?(ActiveRecord::Reflection::MacroReflection)
25
+
26
+ it "uses the supplied name" do
27
+ if defined?(ActiveRecord::Reflection::MacroReflection)
28
+ reflection_klass.should_receive(:new).
29
+ with('foo_bar', anything, anything, anything)
30
+ else
31
+ reflection_klass.should_receive(:new).
32
+ with(anything, 'foo_bar', anything, anything)
33
+ end
34
+
35
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
36
+ reflection, 'foo_bar', 'Bar'
37
+ )
38
+ end
39
+
40
+ it "uses the existing reflection's parent" do
41
+ if defined?(ActiveRecord::Reflection::MacroReflection)
42
+ reflection_klass.should_receive(:new).
43
+ with(anything, anything, anything, reflection.active_record)
44
+ else
45
+ reflection_klass.should_receive(:new).
46
+ with(anything, anything, anything, reflection.active_record)
47
+ end
48
+
49
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
50
+ reflection, 'foo_bar', 'Bar'
51
+ )
52
+ end
53
+
54
+ it "removes the polymorphic setting from the options" do
55
+ if defined?(ActiveRecord::Reflection::MacroReflection)
56
+ reflection_klass.should_receive(:new) do |name, scope, options, parent|
57
+ options[:polymorphic].should be_nil
58
+ end
59
+ else
60
+ reflection_klass.should_receive(:new) do |macro, name, options, parent|
61
+ options[:polymorphic].should be_nil
62
+ end
63
+ end
64
+
65
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
66
+ reflection, 'foo_bar', 'Bar'
67
+ )
68
+ end
69
+
70
+ it "adds the class name option" do
71
+ if defined?(ActiveRecord::Reflection::MacroReflection)
72
+ reflection_klass.should_receive(:new) do |name, scope, options, parent|
73
+ options[:class_name].should == 'Bar'
74
+ end
75
+ else
76
+ reflection_klass.should_receive(:new) do |macro, name, options, parent|
77
+ options[:class_name].should == 'Bar'
78
+ end
79
+ end
80
+
81
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
82
+ reflection, 'foo_bar', 'Bar'
83
+ )
84
+ end
85
+
86
+ it "sets the foreign key if necessary" do
87
+ if defined?(ActiveRecord::Reflection::MacroReflection)
88
+ reflection_klass.should_receive(:new) do |name, scope, options, parent|
89
+ options[:foreign_key].should == 'baz_id'
90
+ end
91
+ else
92
+ reflection_klass.should_receive(:new) do |macro, name, options, parent|
93
+ options[:foreign_key].should == 'baz_id'
94
+ end
95
+ end
96
+
97
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
98
+ reflection, 'foo_bar', 'Bar'
99
+ )
100
+ end
101
+
102
+ it "respects supplied foreign keys" do
103
+ options[:foreign_key] = 'qux_id'
104
+
105
+ if defined?(ActiveRecord::Reflection::MacroReflection)
106
+ reflection_klass.should_receive(:new) do |name, scope, options, parent|
107
+ options[:foreign_key].should == 'qux_id'
108
+ end
109
+ else
110
+ reflection_klass.should_receive(:new) do |macro, name, options, parent|
111
+ options[:foreign_key].should == 'qux_id'
112
+ end
113
+ end
114
+
115
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
116
+ reflection, 'foo_bar', 'Bar'
117
+ )
118
+ end
119
+
120
+ it "sets conditions if there are none" do
121
+ reflection_klass.should_receive(:new) do |macro, name, options, parent|
122
+ options[:conditions].should == "::ts_join_alias::.\"foo_type\" = 'Bar'"
123
+ end
124
+
125
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
126
+ reflection, 'foo_bar', 'Bar'
127
+ )
128
+ end unless defined?(ActiveRecord::Reflection::MacroReflection)
129
+
130
+ it "appends to the conditions array" do
131
+ options[:conditions] = ['existing']
132
+
133
+ reflection_klass.should_receive(:new) do |macro, name, options, parent|
134
+ options[:conditions].should == ['existing', "::ts_join_alias::.\"foo_type\" = 'Bar'"]
135
+ end
136
+
137
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
138
+ reflection, 'foo_bar', 'Bar'
139
+ )
140
+ end unless defined?(ActiveRecord::Reflection::MacroReflection)
141
+
142
+ it "extends the conditions hash" do
143
+ options[:conditions] = {:x => :y}
144
+
145
+ reflection_klass.should_receive(:new) do |macro, name, options, parent|
146
+ options[:conditions].should == {:x => :y, :foo_type => 'Bar'}
147
+ end
148
+
149
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
150
+ reflection, 'foo_bar', 'Bar'
151
+ )
152
+ end unless defined?(ActiveRecord::Reflection::MacroReflection)
153
+
154
+ it "appends to the conditions string" do
155
+ options[:conditions] = 'existing'
156
+
157
+ reflection_klass.should_receive(:new) do |macro, name, options, parent|
158
+ options[:conditions].should == "existing AND ::ts_join_alias::.\"foo_type\" = 'Bar'"
159
+ end
160
+
161
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
162
+ reflection, 'foo_bar', 'Bar'
163
+ )
164
+ end unless defined?(ActiveRecord::Reflection::MacroReflection)
165
+
166
+ it "returns the new reflection" do
167
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
168
+ reflection, 'foo_bar', 'Bar'
169
+ ).should == filtered_reflection
170
+ end
171
+ end
172
+ end
@@ -10,9 +10,12 @@ describe ThinkingSphinx::ActiveRecord::Polymorpher do
10
10
  let(:class_names) { %w( Article Animal ) }
11
11
  let(:field) { double :rebase => true }
12
12
  let(:attribute) { double :rebase => true }
13
- let(:outer) { double :reflections => {:a => double(:klass => inner)} }
14
- let(:inner) { double :reflections => {:b => double(:klass => model)} }
15
- let(:model) { double 'Model', :reflections => {:foo => reflection} }
13
+ let(:outer) { double(
14
+ :reflect_on_association => double(:klass => inner)) }
15
+ let(:inner) { double(
16
+ :reflect_on_association => double(:klass => model)) }
17
+ let(:model) { double 'Model', :reflections => {},
18
+ :reflect_on_association => reflection }
16
19
  let(:reflection) { double 'Polymorphic Reflection' }
17
20
 
18
21
  describe '#morph!' do
@@ -20,25 +23,29 @@ describe ThinkingSphinx::ActiveRecord::Polymorpher do
20
23
  let(:animal_reflection) { double 'Animal Reflection' }
21
24
 
22
25
  before :each do
23
- ThinkingSphinx::ActiveRecord::FilteredReflection.
24
- stub(:clone_with_filter).
26
+ ThinkingSphinx::ActiveRecord::FilterReflection.
27
+ stub(:call).
25
28
  and_return(article_reflection, animal_reflection)
26
29
 
30
+ model.stub(:reflect_on_association) do |name|
31
+ name == :foo ? reflection : nil
32
+ end
33
+
27
34
  if ActiveRecord::Reflection.respond_to?(:add_reflection)
28
35
  ActiveRecord::Reflection.stub :add_reflection
29
36
  end
30
37
  end
31
38
 
32
39
  it "creates a new reflection for each class" do
33
- ThinkingSphinx::ActiveRecord::FilteredReflection.
34
- unstub :clone_with_filter
40
+ ThinkingSphinx::ActiveRecord::FilterReflection.
41
+ unstub :call
35
42
 
36
- ThinkingSphinx::ActiveRecord::FilteredReflection.
37
- should_receive(:clone_with_filter).
43
+ ThinkingSphinx::ActiveRecord::FilterReflection.
44
+ should_receive(:call).
38
45
  with(reflection, :foo_article, 'Article').
39
46
  and_return(article_reflection)
40
- ThinkingSphinx::ActiveRecord::FilteredReflection.
41
- should_receive(:clone_with_filter).
47
+ ThinkingSphinx::ActiveRecord::FilterReflection.
48
+ should_receive(:call).
42
49
  with(reflection, :foo_animal, 'Animal').
43
50
  and_return(animal_reflection)
44
51
 
@@ -192,27 +192,6 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
192
192
  model.stub! :store_full_sti_class => true
193
193
  end
194
194
 
195
- it "limits results to just the model" do
196
- relation.should_receive(:where) do |string|
197
- string.should match(/`users`.`type` = 'User'/)
198
- relation
199
- end
200
-
201
- builder.sql_query
202
- end
203
-
204
- it "uses the demodulised name if that's what is stored" do
205
- model.stub! :store_full_sti_class => false
206
- model.name.stub! :demodulize => 'U'
207
-
208
- relation.should_receive(:where) do |string|
209
- string.should match(/`users`.`type` = 'U'/)
210
- relation
211
- end
212
-
213
- builder.sql_query
214
- end
215
-
216
195
  it "groups by the inheritance column" do
217
196
  relation.should_receive(:group) do |string|
218
197
  string.should match(/`users`.`type`/)
@@ -228,15 +207,6 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
228
207
  model.stub :inheritance_column => 'custom_type'
229
208
  end
230
209
 
231
- it "limits results on the right column" do
232
- relation.should_receive(:where) do |string|
233
- string.should match(/`users`.`custom_type` = 'User'/)
234
- relation
235
- end
236
-
237
- builder.sql_query
238
- end
239
-
240
210
  it "groups by the right column" do
241
211
  relation.should_receive(:group) do |string|
242
212
  string.should match(/`users`.`custom_type`/)
@@ -452,27 +422,6 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
452
422
  model.stub! :store_full_sti_class => true
453
423
  end
454
424
 
455
- it "limits results to just the model" do
456
- relation.should_receive(:where) do |string|
457
- string.should match(/"users"."type" = 'User'/)
458
- relation
459
- end
460
-
461
- builder.sql_query
462
- end
463
-
464
- it "uses the demodulised name if that's what is stored" do
465
- model.stub! :store_full_sti_class => false
466
- model.name.stub! :demodulize => 'U'
467
-
468
- relation.should_receive(:where) do |string|
469
- string.should match(/"users"."type" = 'U'/)
470
- relation
471
- end
472
-
473
- builder.sql_query
474
- end
475
-
476
425
  it "groups by the inheritance column" do
477
426
  relation.should_receive(:group) do |string|
478
427
  string.should match(/"users"."type"/)
@@ -488,15 +437,6 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
488
437
  model.stub :inheritance_column => 'custom_type'
489
438
  end
490
439
 
491
- it "limits results on the right column" do
492
- relation.should_receive(:where) do |string|
493
- string.should match(/"users"."custom_type" = 'User'/)
494
- relation
495
- end
496
-
497
- builder.sql_query
498
- end
499
-
500
440
  it "groups by the right column" do
501
441
  relation.should_receive(:group) do |string|
502
442
  string.should match(/"users"."custom_type"/)
@@ -675,51 +615,6 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
675
615
  builder.sql_query_range
676
616
  end
677
617
 
678
- context 'STI model' do
679
- before :each do
680
- model.column_names << 'type'
681
- model.stub! :descends_from_active_record? => false
682
- model.stub! :store_full_sti_class => true
683
- end
684
-
685
- it "limits results to just the model" do
686
- relation.should_receive(:where) do |string|
687
- string.should match(/`users`.`type` = 'User'/)
688
- relation
689
- end
690
-
691
- builder.sql_query_range
692
- end
693
-
694
- it "uses the demodulised name if that's what is stored" do
695
- model.stub! :store_full_sti_class => false
696
- model.name.stub! :demodulize => 'U'
697
-
698
- relation.should_receive(:where) do |string|
699
- string.should match(/`users`.`type` = 'U'/)
700
- relation
701
- end
702
-
703
- builder.sql_query_range
704
- end
705
-
706
- context 'with a custom inheritance column' do
707
- before :each do
708
- model.column_names << 'custom_type'
709
- model.stub :inheritance_column => 'custom_type'
710
- end
711
-
712
- it "limits results on the right column" do
713
- relation.should_receive(:where) do |string|
714
- string.should match(/`users`.`custom_type` = 'User'/)
715
- relation
716
- end
717
-
718
- builder.sql_query_range
719
- end
720
- end
721
- end
722
-
723
618
  context 'with a delta processor' do
724
619
  let(:processor) { double('processor') }
725
620
 
@@ -101,19 +101,6 @@ describe ThinkingSphinx::Configuration do
101
101
  end
102
102
  end
103
103
 
104
- describe '#indices_for_references' do
105
- it "selects from the full index set those with matching references" do
106
- config.preload_indices
107
- config.indices.clear
108
-
109
- config.indices << double('index', :reference => :article)
110
- config.indices << double('index', :reference => :book)
111
- config.indices << double('index', :reference => :page)
112
-
113
- config.indices_for_references(:book, :article).length.should == 2
114
- end
115
- end
116
-
117
104
  describe '#indices_location' do
118
105
  it "stores index files in db/sphinx/ENVIRONMENT" do
119
106
  config.indices_location.
@@ -10,10 +10,9 @@ describe ThinkingSphinx::FacetSearch do
10
10
  :multi? => false) }
11
11
  let(:property_b) { double('property', :name => 'category_id',
12
12
  :multi? => false) }
13
- let(:configuration) { double 'configuration', :settings => {} }
13
+ let(:configuration) { double 'configuration', :settings => {}, :index_set_class => double(:new => index_set) }
14
14
 
15
15
  before :each do
16
- stub_const 'ThinkingSphinx::IndexSet', double(:new => index_set)
17
16
  stub_const 'ThinkingSphinx::BatchedSearch', double(:new => batch)
18
17
  stub_const 'ThinkingSphinx::Search', DumbSearch
19
18
  stub_const 'ThinkingSphinx::Middlewares::RAW_ONLY', double
@@ -5,13 +5,11 @@ require 'active_support/core_ext/module/delegation'
5
5
  require 'thinking_sphinx/index_set'
6
6
 
7
7
  describe ThinkingSphinx::IndexSet do
8
- let(:set) { ThinkingSphinx::IndexSet.new classes, indices,
9
- configuration }
10
- let(:classes) { [] }
11
- let(:indices) { [] }
8
+ let(:set) { ThinkingSphinx::IndexSet.new options, configuration }
12
9
  let(:configuration) { double('configuration', :preload_indices => true,
13
10
  :indices => []) }
14
11
  let(:ar_base) { double('ActiveRecord::Base') }
12
+ let(:options) { {} }
15
13
 
16
14
  before :each do
17
15
  stub_const 'ActiveRecord::Base', ar_base
@@ -43,21 +41,29 @@ describe ThinkingSphinx::IndexSet do
43
41
  end
44
42
 
45
43
  it "uses indices for the given classes" do
46
- classes << class_double('Article')
44
+ configuration.indices.replace [
45
+ double(:reference => :article, :distributed? => false),
46
+ double(:reference => :opinion_article, :distributed? => false),
47
+ double(:reference => :page, :distributed? => false)
48
+ ]
47
49
 
48
- configuration.should_receive(:indices_for_references).with(:article).
49
- and_return([])
50
+ options[:classes] = [class_double('Article')]
50
51
 
51
- set.to_a
52
+ set.to_a.length.should == 1
52
53
  end
53
54
 
54
55
  it "requests indices for any superclasses" do
55
- classes << class_double('OpinionArticle', class_double('Article'))
56
+ configuration.indices.replace [
57
+ double(:reference => :article, :distributed? => false),
58
+ double(:reference => :opinion_article, :distributed? => false),
59
+ double(:reference => :page, :distributed? => false)
60
+ ]
56
61
 
57
- configuration.should_receive(:indices_for_references).
58
- with(:opinion_article, :article).and_return([])
62
+ options[:classes] = [
63
+ class_double('OpinionArticle', class_double('Article'))
64
+ ]
59
65
 
60
- set.to_a
66
+ set.to_a.length.should == 2
61
67
  end
62
68
 
63
69
  it "uses named indices if names are provided" do
@@ -65,9 +71,21 @@ describe ThinkingSphinx::IndexSet do
65
71
  user_core = double('index', :name => 'user_core')
66
72
  configuration.indices.replace [article_core, user_core]
67
73
 
68
- indices << 'article_core'
74
+ options[:indices] = ['article_core']
69
75
 
70
76
  set.to_a.should == [article_core]
71
77
  end
78
+
79
+ it "selects from the full index set those with matching references" do
80
+ configuration.indices.replace [
81
+ double('index', :reference => :article, :distributed? => false),
82
+ double('index', :reference => :book, :distributed? => false),
83
+ double('index', :reference => :page, :distributed? => false)
84
+ ]
85
+
86
+ options[:references] = [:book, :article]
87
+
88
+ set.to_a.length.should == 2
89
+ end
72
90
  end
73
91
  end