thinking-sphinx 3.1.2 → 3.1.3

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.
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