initforthe-thinking-sphinx 1.1.21

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 (91) hide show
  1. data/LICENCE +20 -0
  2. data/README.textile +141 -0
  3. data/lib/thinking_sphinx.rb +215 -0
  4. data/lib/thinking_sphinx/active_record.rb +278 -0
  5. data/lib/thinking_sphinx/active_record/attribute_updates.rb +48 -0
  6. data/lib/thinking_sphinx/active_record/delta.rb +87 -0
  7. data/lib/thinking_sphinx/active_record/has_many_association.rb +29 -0
  8. data/lib/thinking_sphinx/active_record/search.rb +57 -0
  9. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +42 -0
  10. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +54 -0
  11. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +135 -0
  12. data/lib/thinking_sphinx/association.rb +164 -0
  13. data/lib/thinking_sphinx/attribute.rb +268 -0
  14. data/lib/thinking_sphinx/class_facet.rb +15 -0
  15. data/lib/thinking_sphinx/collection.rb +148 -0
  16. data/lib/thinking_sphinx/configuration.rb +262 -0
  17. data/lib/thinking_sphinx/core/string.rb +15 -0
  18. data/lib/thinking_sphinx/deltas.rb +30 -0
  19. data/lib/thinking_sphinx/deltas/datetime_delta.rb +50 -0
  20. data/lib/thinking_sphinx/deltas/default_delta.rb +68 -0
  21. data/lib/thinking_sphinx/deltas/delayed_delta.rb +27 -0
  22. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +24 -0
  23. data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +27 -0
  24. data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +26 -0
  25. data/lib/thinking_sphinx/deploy/capistrano.rb +82 -0
  26. data/lib/thinking_sphinx/facet.rb +108 -0
  27. data/lib/thinking_sphinx/facet_collection.rb +59 -0
  28. data/lib/thinking_sphinx/field.rb +82 -0
  29. data/lib/thinking_sphinx/index.rb +99 -0
  30. data/lib/thinking_sphinx/index/builder.rb +287 -0
  31. data/lib/thinking_sphinx/index/faux_column.rb +110 -0
  32. data/lib/thinking_sphinx/property.rb +160 -0
  33. data/lib/thinking_sphinx/rails_additions.rb +136 -0
  34. data/lib/thinking_sphinx/search.rb +727 -0
  35. data/lib/thinking_sphinx/search/facets.rb +104 -0
  36. data/lib/thinking_sphinx/source.rb +150 -0
  37. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  38. data/lib/thinking_sphinx/source/sql.rb +126 -0
  39. data/lib/thinking_sphinx/tasks.rb +162 -0
  40. data/rails/init.rb +14 -0
  41. data/spec/unit/thinking_sphinx/active_record/delta_spec.rb +136 -0
  42. data/spec/unit/thinking_sphinx/active_record/has_many_association_spec.rb +53 -0
  43. data/spec/unit/thinking_sphinx/active_record/search_spec.rb +107 -0
  44. data/spec/unit/thinking_sphinx/active_record_spec.rb +329 -0
  45. data/spec/unit/thinking_sphinx/association_spec.rb +246 -0
  46. data/spec/unit/thinking_sphinx/attribute_spec.rb +338 -0
  47. data/spec/unit/thinking_sphinx/collection_spec.rb +15 -0
  48. data/spec/unit/thinking_sphinx/configuration_spec.rb +222 -0
  49. data/spec/unit/thinking_sphinx/core/string_spec.rb +9 -0
  50. data/spec/unit/thinking_sphinx/facet_collection_spec.rb +64 -0
  51. data/spec/unit/thinking_sphinx/facet_spec.rb +302 -0
  52. data/spec/unit/thinking_sphinx/field_spec.rb +154 -0
  53. data/spec/unit/thinking_sphinx/index/builder_spec.rb +355 -0
  54. data/spec/unit/thinking_sphinx/index/faux_column_spec.rb +30 -0
  55. data/spec/unit/thinking_sphinx/index_spec.rb +45 -0
  56. data/spec/unit/thinking_sphinx/rails_additions_spec.rb +191 -0
  57. data/spec/unit/thinking_sphinx/search_spec.rb +228 -0
  58. data/spec/unit/thinking_sphinx/source_spec.rb +217 -0
  59. data/spec/unit/thinking_sphinx_spec.rb +151 -0
  60. data/tasks/distribution.rb +67 -0
  61. data/tasks/rails.rake +1 -0
  62. data/tasks/testing.rb +78 -0
  63. data/vendor/after_commit/LICENSE +20 -0
  64. data/vendor/after_commit/README +16 -0
  65. data/vendor/after_commit/Rakefile +22 -0
  66. data/vendor/after_commit/init.rb +8 -0
  67. data/vendor/after_commit/lib/after_commit.rb +45 -0
  68. data/vendor/after_commit/lib/after_commit/active_record.rb +114 -0
  69. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +103 -0
  70. data/vendor/after_commit/test/after_commit_test.rb +53 -0
  71. data/vendor/delayed_job/lib/delayed/job.rb +251 -0
  72. data/vendor/delayed_job/lib/delayed/message_sending.rb +7 -0
  73. data/vendor/delayed_job/lib/delayed/performable_method.rb +55 -0
  74. data/vendor/delayed_job/lib/delayed/worker.rb +54 -0
  75. data/vendor/riddle/lib/riddle.rb +30 -0
  76. data/vendor/riddle/lib/riddle/client.rb +619 -0
  77. data/vendor/riddle/lib/riddle/client/filter.rb +53 -0
  78. data/vendor/riddle/lib/riddle/client/message.rb +65 -0
  79. data/vendor/riddle/lib/riddle/client/response.rb +84 -0
  80. data/vendor/riddle/lib/riddle/configuration.rb +33 -0
  81. data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +48 -0
  82. data/vendor/riddle/lib/riddle/configuration/index.rb +142 -0
  83. data/vendor/riddle/lib/riddle/configuration/indexer.rb +19 -0
  84. data/vendor/riddle/lib/riddle/configuration/remote_index.rb +17 -0
  85. data/vendor/riddle/lib/riddle/configuration/searchd.rb +25 -0
  86. data/vendor/riddle/lib/riddle/configuration/section.rb +43 -0
  87. data/vendor/riddle/lib/riddle/configuration/source.rb +23 -0
  88. data/vendor/riddle/lib/riddle/configuration/sql_source.rb +34 -0
  89. data/vendor/riddle/lib/riddle/configuration/xml_source.rb +28 -0
  90. data/vendor/riddle/lib/riddle/controller.rb +44 -0
  91. metadata +190 -0
@@ -0,0 +1,246 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Association do
4
+ describe "class-level children method" do
5
+ before :each do
6
+ @normal_reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
7
+ :options => {:polymorphic => false}
8
+ )
9
+ @normal_association = ThinkingSphinx::Association.stub_instance
10
+ @poly_reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
11
+ :options => {:polymorphic => true},
12
+ :macro => :has_many,
13
+ :name => "polly",
14
+ :active_record => "AR"
15
+ )
16
+ @non_poly_reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance
17
+
18
+ Person.stub_method(:reflect_on_association => @normal_reflection)
19
+ ThinkingSphinx::Association.stub_methods(
20
+ :new => @normal_association,
21
+ :polymorphic_classes => [Person, Person],
22
+ :casted_options => {:casted => :options}
23
+ )
24
+ ::ActiveRecord::Reflection::AssociationReflection.stub_method(
25
+ :new => @non_poly_reflection
26
+ )
27
+ end
28
+
29
+ it "should return an empty array if no association exists" do
30
+ Person.stub_method(:reflect_on_association => nil)
31
+
32
+ ThinkingSphinx::Association.children(Person, :assoc).should == []
33
+ end
34
+
35
+ it "should return a single association instance in an array if assocation isn't polymorphic" do
36
+ ThinkingSphinx::Association.children(Person, :assoc).should == [@normal_association]
37
+ end
38
+
39
+ it "should return multiple association instances for polymorphic associations" do
40
+ Person.stub_method(:reflect_on_association => @poly_reflection)
41
+
42
+ ThinkingSphinx::Association.children(Person, :assoc).should ==
43
+ [@normal_association, @normal_association]
44
+ end
45
+
46
+ it "should generate non-polymorphic 'casted' associations for each polymorphic possibility" do
47
+ Person.stub_method(:reflect_on_association => @poly_reflection)
48
+
49
+ ThinkingSphinx::Association.children(Person, :assoc)
50
+
51
+ ThinkingSphinx::Association.should have_received(:casted_options).with(
52
+ Person, @poly_reflection
53
+ ).twice
54
+
55
+ ::ActiveRecord::Reflection::AssociationReflection.should have_received(:new).with(
56
+ :has_many, :polly_Person, {:casted => :options}, "AR"
57
+ ).twice
58
+
59
+ ThinkingSphinx::Association.should have_received(:new).with(
60
+ nil, @non_poly_reflection
61
+ ).twice
62
+ end
63
+ end
64
+
65
+ describe "instance-level children method" do
66
+ it "should return the children associations for the given association" do
67
+ @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
68
+ :klass => :klass
69
+ )
70
+ @association = ThinkingSphinx::Association.new(nil, @reflection)
71
+ ThinkingSphinx::Association.stub_method(:children => :result)
72
+
73
+ @association.children(:assoc).should == :result
74
+ ThinkingSphinx::Association.should have_received(:children).with(:klass, :assoc, @association)
75
+ end
76
+ end
77
+
78
+ describe "join_to method" do
79
+ before :each do
80
+ @parent_join = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_instance
81
+ @join = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_instance
82
+ @parent = ThinkingSphinx::Association.new(nil, nil)
83
+ @parent.stub!(:join_to => true, :join => nil)
84
+ @base_join = Object.stub_instance(:joins => [:a, :b, :c])
85
+
86
+ ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_method(:new => @join)
87
+ end
88
+
89
+ it "should call the parent's join_to if parent has no join" do
90
+ @assoc = ThinkingSphinx::Association.new(@parent, :ref)
91
+ @parent.should_receive(:join_to).with(@base_join)
92
+
93
+ @assoc.join_to(@base_join)
94
+ end
95
+
96
+ it "should not call the parent's join_to if it already has a join" do
97
+ @assoc = ThinkingSphinx::Association.new(@parent, :ref)
98
+ @parent.stub_method(:join => @parent_join)
99
+ @parent.should_not_receive(:join_to)
100
+
101
+ @assoc.join_to(@base_join)
102
+ end
103
+
104
+ it "should define the join association with a JoinAssociation instance" do
105
+ @assoc = ThinkingSphinx::Association.new(@parent, :ref)
106
+
107
+ @assoc.join_to(@base_join).should == @join
108
+ @assoc.join.should == @join
109
+ end
110
+ end
111
+
112
+ describe "to_sql method" do
113
+ before :each do
114
+ @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
115
+ :klass => Person
116
+ )
117
+ @association = ThinkingSphinx::Association.new(nil, @reflection)
118
+ @parent = Object.stub_instance(:aliased_table_name => "ALIAS TABLE NAME")
119
+ @join = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_instance(
120
+ :association_join => "full association join SQL",
121
+ :parent => @parent
122
+ )
123
+ @association.join = @join
124
+ end
125
+
126
+ it "should return the join's association join value" do
127
+ @association.to_sql.should == "full association join SQL"
128
+ end
129
+
130
+ it "should replace ::ts_join_alias:: with the aliased table name" do
131
+ @join.stub_method(:association_join => "text with ::ts_join_alias:: gone")
132
+
133
+ @association.to_sql.should == "text with `ALIAS TABLE NAME` gone"
134
+ end
135
+ end
136
+
137
+ describe "is_many? method" do
138
+ before :each do
139
+ @parent = ThinkingSphinx::Association.stub_instance(
140
+ :is_many? => :parent_is_many
141
+ )
142
+ @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
143
+ :macro => :has_many
144
+ )
145
+ end
146
+
147
+ it "should return true if association is either a has_many or a habtm" do
148
+ association = ThinkingSphinx::Association.new(@parent, @reflection)
149
+ association.is_many?.should be_true
150
+
151
+ @reflection.stub_method(:macro => :has_and_belongs_to_many)
152
+ association.is_many?.should be_true
153
+ end
154
+
155
+ it "should return the parent value if not a has many or habtm and there is a parent" do
156
+ association = ThinkingSphinx::Association.new(@parent, @reflection)
157
+ @reflection.stub_method(:macro => :belongs_to)
158
+ association.is_many?.should == :parent_is_many
159
+ end
160
+
161
+ it "should return false if no parent and not a has many or habtm" do
162
+ association = ThinkingSphinx::Association.new(nil, @reflection)
163
+ @reflection.stub_method(:macro => :belongs_to)
164
+ association.is_many?.should be_false
165
+ end
166
+ end
167
+
168
+ describe "ancestors method" do
169
+ it "should return an array of associations - including all parents" do
170
+ parent = ThinkingSphinx::Association.stub_instance(:ancestors => [:all, :ancestors])
171
+ association = ThinkingSphinx::Association.new(parent, @reflection)
172
+ association.ancestors.should == [:all, :ancestors, association]
173
+ end
174
+ end
175
+
176
+ describe "polymorphic_classes method" do
177
+ it "should return all the polymorphic result types as classes" do
178
+ Person.connection.stub_method(:select_all => [
179
+ {"person_type" => "Person"},
180
+ {"person_type" => "Friendship"}
181
+ ])
182
+ ref = Object.stub_instance(
183
+ :active_record => Person,
184
+ :options => {:foreign_type => "person_type"}
185
+ )
186
+
187
+ ThinkingSphinx::Association.send(:polymorphic_classes, ref).should == [Person, Friendship]
188
+ end
189
+ end
190
+
191
+ describe "casted_options method" do
192
+ before :each do
193
+ @options = {
194
+ :foreign_key => "thing_id",
195
+ :foreign_type => "thing_type",
196
+ :polymorphic => true
197
+ }
198
+ @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
199
+ :options => @options
200
+ )
201
+ end
202
+
203
+ it "should return a new options set for a specific class" do
204
+ ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
205
+ :polymorphic => nil,
206
+ :class_name => "Person",
207
+ :foreign_key => "thing_id",
208
+ :foreign_type => "thing_type",
209
+ :conditions => "::ts_join_alias::.`thing_type` = 'Person'"
210
+ }
211
+ end
212
+
213
+ it "should append to existing Array of conditions" do
214
+ @options[:conditions] = ["first condition"]
215
+ ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
216
+ :polymorphic => nil,
217
+ :class_name => "Person",
218
+ :foreign_key => "thing_id",
219
+ :foreign_type => "thing_type",
220
+ :conditions => ["first condition", "::ts_join_alias::.`thing_type` = 'Person'"]
221
+ }
222
+ end
223
+
224
+ it "should merge to an existing Hash of conditions" do
225
+ @options[:conditions] = {"field" => "value"}
226
+ ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
227
+ :polymorphic => nil,
228
+ :class_name => "Person",
229
+ :foreign_key => "thing_id",
230
+ :foreign_type => "thing_type",
231
+ :conditions => {"field" => "value", "thing_type" => "Person"}
232
+ }
233
+ end
234
+
235
+ it "should append to an existing String of conditions" do
236
+ @options[:conditions] = "first condition"
237
+ ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
238
+ :polymorphic => nil,
239
+ :class_name => "Person",
240
+ :foreign_key => "thing_id",
241
+ :foreign_type => "thing_type",
242
+ :conditions => "first condition AND ::ts_join_alias::.`thing_type` = 'Person'"
243
+ }
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,338 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Attribute do
4
+ before :each do
5
+ @index = ThinkingSphinx::Index.new(Person)
6
+ @source = ThinkingSphinx::Source.new(@index)
7
+ end
8
+
9
+ describe '#initialize' do
10
+ it 'raises if no columns are provided so that configuration errors are easier to track down' do
11
+ lambda {
12
+ ThinkingSphinx::Attribute.new(@source, [])
13
+ }.should raise_error(RuntimeError)
14
+ end
15
+
16
+ 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
17
+ lambda {
18
+ ThinkingSphinx::Attribute.new(@source, [1234])
19
+ }.should raise_error(RuntimeError)
20
+ end
21
+ end
22
+
23
+ describe "unique_name method" do
24
+ before :each do
25
+ @attribute = ThinkingSphinx::Attribute.new @source, [
26
+ Object.stub_instance(:__stack => [], :__name => "col_name")
27
+ ]
28
+ end
29
+
30
+ it "should use the alias if there is one" do
31
+ @attribute.alias = "alias"
32
+ @attribute.unique_name.should == "alias"
33
+ end
34
+
35
+ it "should use the alias if there's multiple columns" do
36
+ @attribute.columns << Object.stub_instance(:__stack => [], :__name => "col_name")
37
+ @attribute.unique_name.should be_nil
38
+
39
+ @attribute.alias = "alias"
40
+ @attribute.unique_name.should == "alias"
41
+ end
42
+
43
+ it "should use the column name if there's no alias and just one column" do
44
+ @attribute.unique_name.should == "col_name"
45
+ end
46
+ end
47
+
48
+ describe "column_with_prefix method" do
49
+ before :each do
50
+ @attribute = ThinkingSphinx::Attribute.new @source, [
51
+ ThinkingSphinx::Index::FauxColumn.new(:col_name)
52
+ ]
53
+ @attribute.columns.each { |col| @attribute.associations[col] = [] }
54
+ @attribute.model = Person
55
+
56
+ @first_join = Object.new
57
+ @first_join.stub!(:aliased_table_name => "tabular")
58
+ @second_join = Object.new
59
+ @second_join.stub!(:aliased_table_name => "data")
60
+
61
+ @first_assoc = ThinkingSphinx::Association.new nil, nil
62
+ @first_assoc.stub!(:join => @first_join, :has_column? => true)
63
+ @second_assoc = ThinkingSphinx::Association.new nil, nil
64
+ @second_assoc.stub!(:join => @second_join, :has_column? => true)
65
+ end
66
+
67
+ it "should return the column name if the column is a string" do
68
+ @attribute.columns = [ThinkingSphinx::Index::FauxColumn.new("string")]
69
+ @attribute.send(:column_with_prefix, @attribute.columns.first).should == "string"
70
+ end
71
+
72
+ it "should return the column with model's table prefix if there's no associations for the column" do
73
+ @attribute.send(:column_with_prefix, @attribute.columns.first).should == "`people`.`col_name`"
74
+ end
75
+
76
+ it "should return the column with its join table prefix if an association exists" do
77
+ column = @attribute.columns.first
78
+ @attribute.associations[column] = [@first_assoc]
79
+ @attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
80
+ end
81
+
82
+ it "should return multiple columns concatenated if more than one association exists" do
83
+ column = @attribute.columns.first
84
+ @attribute.associations[column] = [@first_assoc, @second_assoc]
85
+ @attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
86
+ end
87
+ end
88
+
89
+ describe "is_many? method" do
90
+ before :each do
91
+ @assoc_a = Object.stub_instance(:is_many? => true)
92
+ @assoc_b = Object.stub_instance(:is_many? => true)
93
+ @assoc_c = Object.stub_instance(:is_many? => true)
94
+
95
+ @attribute = ThinkingSphinx::Attribute.new(
96
+ @source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
97
+ )
98
+ @attribute.associations = {
99
+ :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
100
+ }
101
+ end
102
+
103
+ it "should return true if all associations return true to is_many?" do
104
+ @attribute.send(:is_many?).should be_true
105
+ end
106
+
107
+ it "should return true if one association returns true to is_many?" do
108
+ @assoc_b.stub_method(:is_many? => false)
109
+ @assoc_c.stub_method(:is_many? => false)
110
+
111
+ @attribute.send(:is_many?).should be_true
112
+ end
113
+
114
+ it "should return false if all associations return false to is_many?" do
115
+ @assoc_a.stub_method(:is_many? => false)
116
+ @assoc_b.stub_method(:is_many? => false)
117
+ @assoc_c.stub_method(:is_many? => false)
118
+
119
+ @attribute.send(:is_many?).should be_false
120
+ end
121
+ end
122
+
123
+ describe "is_string? method" do
124
+ before :each do
125
+ @col_a = ThinkingSphinx::Index::FauxColumn.new("a")
126
+ @col_b = ThinkingSphinx::Index::FauxColumn.new("b")
127
+ @col_c = ThinkingSphinx::Index::FauxColumn.new("c")
128
+
129
+ @attribute = ThinkingSphinx::Attribute.new(
130
+ @source, [@col_a, @col_b, @col_c]
131
+ )
132
+ end
133
+
134
+ it "should return true if all columns return true to is_string?" do
135
+ @attribute.send(:is_string?).should be_true
136
+ end
137
+
138
+ it "should return false if one column returns true to is_string?" do
139
+ @col_a.send(:instance_variable_set, :@name, :a)
140
+ @attribute.send(:is_string?).should be_false
141
+ end
142
+
143
+ it "should return false if all columns return false to is_string?" do
144
+ @col_a.send(:instance_variable_set, :@name, :a)
145
+ @col_b.send(:instance_variable_set, :@name, :b)
146
+ @col_c.send(:instance_variable_set, :@name, :c)
147
+ @attribute.send(:is_string?).should be_false
148
+ end
149
+ end
150
+
151
+ describe "type method" do
152
+ before :each do
153
+ @column = ThinkingSphinx::Index::FauxColumn.new(:col_name)
154
+ @attribute = ThinkingSphinx::Attribute.new(@source, [@column])
155
+ @attribute.model = Person
156
+ @attribute.stub_method(:is_many? => false)
157
+ end
158
+
159
+ it "should return :multi if is_many? is true" do
160
+ @attribute.stub_method(:is_many? => true)
161
+ @attribute.send(:type).should == :multi
162
+ end
163
+
164
+ it "should return :string if there's more than one association" do
165
+ @attribute.associations = {:a => [:assoc], :b => [:assoc]}
166
+ @attribute.send(:type).should == :string
167
+ end
168
+
169
+ it "should return the column type from the database if not :multi or more than one association" do
170
+ @column.send(:instance_variable_set, :@name, "birthday")
171
+ @attribute.send(:type).should == :datetime
172
+
173
+ @attribute.send(:instance_variable_set, :@type, nil)
174
+ @column.send(:instance_variable_set, :@name, "first_name")
175
+ @attribute.send(:type).should == :string
176
+
177
+ @attribute.send(:instance_variable_set, :@type, nil)
178
+ @column.send(:instance_variable_set, :@name, "id")
179
+ @attribute.send(:type).should == :integer
180
+ end
181
+ end
182
+
183
+ describe "all_ints? method" do
184
+ it "should return true if all columns are integers" do
185
+ attribute = ThinkingSphinx::Attribute.new(@source,
186
+ [ ThinkingSphinx::Index::FauxColumn.new(:id),
187
+ ThinkingSphinx::Index::FauxColumn.new(:team_id) ]
188
+ )
189
+ attribute.model = Person
190
+ attribute.columns.each { |col| attribute.associations[col] = [] }
191
+
192
+ attribute.send(:all_ints?).should be_true
193
+ end
194
+
195
+ it "should return false if only some columns are integers" do
196
+ attribute = ThinkingSphinx::Attribute.new(@source,
197
+ [ ThinkingSphinx::Index::FauxColumn.new(:id),
198
+ ThinkingSphinx::Index::FauxColumn.new(:first_name) ]
199
+ )
200
+ attribute.model = Person
201
+ attribute.columns.each { |col| attribute.associations[col] = [] }
202
+
203
+ attribute.send(:all_ints?).should be_false
204
+ end
205
+
206
+ it "should return false if no columns are integers" do
207
+ attribute = ThinkingSphinx::Attribute.new(@source,
208
+ [ ThinkingSphinx::Index::FauxColumn.new(:first_name),
209
+ ThinkingSphinx::Index::FauxColumn.new(:last_name) ]
210
+ )
211
+ attribute.model = Person
212
+ attribute.columns.each { |col| attribute.associations[col] = [] }
213
+
214
+ attribute.send(:all_ints?).should be_false
215
+ end
216
+ end
217
+
218
+ describe "MVA with source query" do
219
+ before :each do
220
+ @attribute = ThinkingSphinx::Attribute.new(@source,
221
+ [ThinkingSphinx::Index::FauxColumn.new(:tags, :id)],
222
+ :as => :tag_ids, :source => :query
223
+ )
224
+ end
225
+
226
+ it "should use a query" do
227
+ @attribute.type_to_config.should == :sql_attr_multi
228
+
229
+ declaration, query = @attribute.config_value.split('; ')
230
+ declaration.should == "uint tag_ids from query"
231
+ query.should == "SELECT `tags`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `tags`.`id` AS `tag_ids` FROM `tags`"
232
+ end
233
+ end
234
+
235
+ describe "MVA via a HABTM association with a source query" do
236
+ before :each do
237
+ @attribute = ThinkingSphinx::Attribute.new(@source,
238
+ [ThinkingSphinx::Index::FauxColumn.new(:links, :id)],
239
+ :as => :link_ids, :source => :query
240
+ )
241
+ end
242
+
243
+ it "should use a ranged query" do
244
+ @attribute.type_to_config.should == :sql_attr_multi
245
+
246
+ declaration, query = @attribute.config_value.split('; ')
247
+ declaration.should == "uint link_ids from query"
248
+ query.should == "SELECT `links_people`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `links_people`.`link_id` AS `link_ids` FROM `links_people`"
249
+ end
250
+ end
251
+
252
+ describe "MVA with ranged source query" do
253
+ before :each do
254
+ @attribute = ThinkingSphinx::Attribute.new(@source,
255
+ [ThinkingSphinx::Index::FauxColumn.new(:tags, :id)],
256
+ :as => :tag_ids, :source => :ranged_query
257
+ )
258
+ end
259
+
260
+ it "should use a ranged query" do
261
+ @attribute.type_to_config.should == :sql_attr_multi
262
+
263
+ declaration, query, range_query = @attribute.config_value.split('; ')
264
+ declaration.should == "uint tag_ids from ranged-query"
265
+ 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"
266
+ range_query.should == "SELECT MIN(`tags`.`person_id`), MAX(`tags`.`person_id`) FROM `tags`"
267
+ end
268
+ end
269
+
270
+ describe "MVA via a has-many :through with a ranged source query" do
271
+ before :each do
272
+ @attribute = ThinkingSphinx::Attribute.new(@source,
273
+ [ThinkingSphinx::Index::FauxColumn.new(:football_teams, :id)],
274
+ :as => :football_team_ids, :source => :ranged_query
275
+ )
276
+ end
277
+
278
+ it "should use a ranged query" do
279
+ @attribute.type_to_config.should == :sql_attr_multi
280
+
281
+ declaration, query, range_query = @attribute.config_value.split('; ')
282
+ declaration.should == "uint football_team_ids from ranged-query"
283
+ query.should == "SELECT `tags`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `tags`.`football_team_id` AS `football_team_ids` FROM `tags` WHERE `tags`.`person_id` >= $start AND `tags`.`person_id` <= $end"
284
+ range_query.should == "SELECT MIN(`tags`.`person_id`), MAX(`tags`.`person_id`) FROM `tags`"
285
+ end
286
+ end
287
+
288
+ describe "MVA via a has-many :through using a foreign key with a ranged source query" do
289
+ before :each do
290
+ @attribute = ThinkingSphinx::Attribute.new(@source,
291
+ [ThinkingSphinx::Index::FauxColumn.new(:friends, :id)],
292
+ :as => :friend_ids, :source => :ranged_query
293
+ )
294
+ end
295
+
296
+ it "should use a ranged query" do
297
+ @attribute.type_to_config.should == :sql_attr_multi
298
+
299
+ declaration, query, range_query = @attribute.config_value.split('; ')
300
+ declaration.should == "uint friend_ids from ranged-query"
301
+ query.should == "SELECT `friendships`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `friendships`.`friend_id` AS `friend_ids` FROM `friendships` WHERE `friendships`.`person_id` >= $start AND `friendships`.`person_id` <= $end"
302
+ range_query.should == "SELECT MIN(`friendships`.`person_id`), MAX(`friendships`.`person_id`) FROM `friendships`"
303
+ end
304
+ end
305
+
306
+ describe "MVA via a HABTM with a ranged source query" do
307
+ before :each do
308
+ @attribute = ThinkingSphinx::Attribute.new(@source,
309
+ [ThinkingSphinx::Index::FauxColumn.new(:links, :id)],
310
+ :as => :link_ids, :source => :ranged_query
311
+ )
312
+ end
313
+
314
+ it "should use a ranged query" do
315
+ @attribute.type_to_config.should == :sql_attr_multi
316
+
317
+ declaration, query, range_query = @attribute.config_value.split('; ')
318
+ declaration.should == "uint link_ids from ranged-query"
319
+ query.should == "SELECT `links_people`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `links_people`.`link_id` AS `link_ids` FROM `links_people` WHERE `links_people`.`person_id` >= $start AND `links_people`.`person_id` <= $end"
320
+ range_query.should == "SELECT MIN(`links_people`.`person_id`), MAX(`links_people`.`person_id`) FROM `links_people`"
321
+ end
322
+ end
323
+
324
+ describe "with custom queries" do
325
+ before :each do
326
+ index = CricketTeam.sphinx_indexes.first
327
+ @statement = index.sources.first.to_riddle_for_core(0, 0).sql_attr_multi.last
328
+ end
329
+
330
+ it "should track the query type accordingly" do
331
+ @statement.should match(/uint tags from query/)
332
+ end
333
+
334
+ it "should include the SQL statement" do
335
+ @statement.should match(/SELECT cricket_team_id, id FROM tags/)
336
+ end
337
+ end
338
+ end