thinking-sphinx 1.2.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/LICENCE +20 -0
  2. data/README.textile +157 -0
  3. data/VERSION.yml +4 -0
  4. data/lib/thinking_sphinx.rb +211 -0
  5. data/lib/thinking_sphinx/active_record.rb +307 -0
  6. data/lib/thinking_sphinx/active_record/attribute_updates.rb +48 -0
  7. data/lib/thinking_sphinx/active_record/delta.rb +87 -0
  8. data/lib/thinking_sphinx/active_record/has_many_association.rb +28 -0
  9. data/lib/thinking_sphinx/active_record/scopes.rb +39 -0
  10. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +42 -0
  11. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +54 -0
  12. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +136 -0
  13. data/lib/thinking_sphinx/association.rb +164 -0
  14. data/lib/thinking_sphinx/attribute.rb +342 -0
  15. data/lib/thinking_sphinx/class_facet.rb +15 -0
  16. data/lib/thinking_sphinx/configuration.rb +282 -0
  17. data/lib/thinking_sphinx/core/array.rb +7 -0
  18. data/lib/thinking_sphinx/core/string.rb +15 -0
  19. data/lib/thinking_sphinx/deltas.rb +30 -0
  20. data/lib/thinking_sphinx/deltas/datetime_delta.rb +50 -0
  21. data/lib/thinking_sphinx/deltas/default_delta.rb +68 -0
  22. data/lib/thinking_sphinx/deltas/delayed_delta.rb +30 -0
  23. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +24 -0
  24. data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +27 -0
  25. data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +26 -0
  26. data/lib/thinking_sphinx/deploy/capistrano.rb +100 -0
  27. data/lib/thinking_sphinx/excerpter.rb +22 -0
  28. data/lib/thinking_sphinx/facet.rb +125 -0
  29. data/lib/thinking_sphinx/facet_search.rb +134 -0
  30. data/lib/thinking_sphinx/field.rb +82 -0
  31. data/lib/thinking_sphinx/index.rb +99 -0
  32. data/lib/thinking_sphinx/index/builder.rb +286 -0
  33. data/lib/thinking_sphinx/index/faux_column.rb +110 -0
  34. data/lib/thinking_sphinx/property.rb +162 -0
  35. data/lib/thinking_sphinx/rails_additions.rb +150 -0
  36. data/lib/thinking_sphinx/search.rb +707 -0
  37. data/lib/thinking_sphinx/search_methods.rb +421 -0
  38. data/lib/thinking_sphinx/source.rb +150 -0
  39. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  40. data/lib/thinking_sphinx/source/sql.rb +128 -0
  41. data/lib/thinking_sphinx/tasks.rb +165 -0
  42. data/rails/init.rb +14 -0
  43. data/spec/lib/thinking_sphinx/active_record/delta_spec.rb +130 -0
  44. data/spec/lib/thinking_sphinx/active_record/has_many_association_spec.rb +49 -0
  45. data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +96 -0
  46. data/spec/lib/thinking_sphinx/active_record_spec.rb +364 -0
  47. data/spec/lib/thinking_sphinx/association_spec.rb +239 -0
  48. data/spec/lib/thinking_sphinx/attribute_spec.rb +500 -0
  49. data/spec/lib/thinking_sphinx/configuration_spec.rb +268 -0
  50. data/spec/lib/thinking_sphinx/core/array_spec.rb +9 -0
  51. data/spec/lib/thinking_sphinx/core/string_spec.rb +9 -0
  52. data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
  53. data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
  54. data/spec/lib/thinking_sphinx/facet_spec.rb +333 -0
  55. data/spec/lib/thinking_sphinx/field_spec.rb +154 -0
  56. data/spec/lib/thinking_sphinx/index/builder_spec.rb +455 -0
  57. data/spec/lib/thinking_sphinx/index/faux_column_spec.rb +30 -0
  58. data/spec/lib/thinking_sphinx/index_spec.rb +45 -0
  59. data/spec/lib/thinking_sphinx/rails_additions_spec.rb +203 -0
  60. data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
  61. data/spec/lib/thinking_sphinx/search_spec.rb +1092 -0
  62. data/spec/lib/thinking_sphinx/source_spec.rb +227 -0
  63. data/spec/lib/thinking_sphinx_spec.rb +162 -0
  64. data/tasks/distribution.rb +50 -0
  65. data/tasks/rails.rake +1 -0
  66. data/tasks/testing.rb +83 -0
  67. data/vendor/after_commit/LICENSE +20 -0
  68. data/vendor/after_commit/README +16 -0
  69. data/vendor/after_commit/Rakefile +22 -0
  70. data/vendor/after_commit/init.rb +8 -0
  71. data/vendor/after_commit/lib/after_commit.rb +45 -0
  72. data/vendor/after_commit/lib/after_commit/active_record.rb +114 -0
  73. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +103 -0
  74. data/vendor/after_commit/test/after_commit_test.rb +53 -0
  75. data/vendor/delayed_job/lib/delayed/job.rb +251 -0
  76. data/vendor/delayed_job/lib/delayed/message_sending.rb +7 -0
  77. data/vendor/delayed_job/lib/delayed/performable_method.rb +55 -0
  78. data/vendor/delayed_job/lib/delayed/worker.rb +54 -0
  79. data/vendor/riddle/lib/riddle.rb +30 -0
  80. data/vendor/riddle/lib/riddle/client.rb +635 -0
  81. data/vendor/riddle/lib/riddle/client/filter.rb +53 -0
  82. data/vendor/riddle/lib/riddle/client/message.rb +66 -0
  83. data/vendor/riddle/lib/riddle/client/response.rb +84 -0
  84. data/vendor/riddle/lib/riddle/configuration.rb +33 -0
  85. data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +48 -0
  86. data/vendor/riddle/lib/riddle/configuration/index.rb +142 -0
  87. data/vendor/riddle/lib/riddle/configuration/indexer.rb +19 -0
  88. data/vendor/riddle/lib/riddle/configuration/remote_index.rb +17 -0
  89. data/vendor/riddle/lib/riddle/configuration/searchd.rb +25 -0
  90. data/vendor/riddle/lib/riddle/configuration/section.rb +43 -0
  91. data/vendor/riddle/lib/riddle/configuration/source.rb +23 -0
  92. data/vendor/riddle/lib/riddle/configuration/sql_source.rb +34 -0
  93. data/vendor/riddle/lib/riddle/configuration/xml_source.rb +28 -0
  94. data/vendor/riddle/lib/riddle/controller.rb +53 -0
  95. metadata +172 -0
@@ -0,0 +1,333 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Facet do
4
+ describe ".name_for" do
5
+ it "should remove '_facet' from provided string and return a symbol" do
6
+ ThinkingSphinx::Facet.name_for('attribute_facet').should == :attribute
7
+ end
8
+
9
+ it "should remove '_facet' from provided symbol" do
10
+ ThinkingSphinx::Facet.name_for(:attribute_facet).should == :attribute
11
+ end
12
+
13
+ it "should return the name of the facet if a Facet is passed" do
14
+ facet = ThinkingSphinx::Facet.new(
15
+ stub('attribute', :unique_name => :attribute, :columns => ['attribute'])
16
+ )
17
+ ThinkingSphinx::Facet.name_for(facet).should == :attribute
18
+ end
19
+
20
+ it "should return 'class' for special case name 'class_crc'" do
21
+ ThinkingSphinx::Facet.name_for(:class_crc).should == :class
22
+ end
23
+
24
+ it "should cycle" do
25
+ ThinkingSphinx::Facet.name_for(ThinkingSphinx::Facet.attribute_name_for(:attribute)).should == :attribute
26
+ end
27
+ end
28
+
29
+ describe ".attribute_name_for" do
30
+ it "should append '_facet' to provided string" do
31
+ ThinkingSphinx::Facet.attribute_name_for('attribute').should == 'attribute_facet'
32
+ end
33
+
34
+ it "should append '_facet' to provided symbol and return a string" do
35
+ ThinkingSphinx::Facet.attribute_name_for(:attribute).should == 'attribute_facet'
36
+ end
37
+
38
+ it "should return 'class_crc' for special case attribute 'class'" do
39
+ ThinkingSphinx::Facet.attribute_name_for(:class).should == 'class_crc'
40
+ end
41
+
42
+ it "should cycle" do
43
+ ThinkingSphinx::Facet.attribute_name_for(ThinkingSphinx::Facet.name_for('attribute_facet')).should == 'attribute_facet'
44
+ end
45
+ end
46
+
47
+ describe ".attribute_name_from_value" do
48
+ it "should append _facet if the value is a string" do
49
+ ThinkingSphinx::Facet.attribute_name_from_value('attribute', 'string').
50
+ should == 'attribute_facet'
51
+ end
52
+
53
+ it "should not append _facet if the value isn't a string" do
54
+ ThinkingSphinx::Facet.attribute_name_from_value('attribute', 1).
55
+ should == 'attribute'
56
+ ThinkingSphinx::Facet.attribute_name_from_value('attribute', Time.now).
57
+ should == 'attribute'
58
+ ThinkingSphinx::Facet.attribute_name_from_value('attribute', true).
59
+ should == 'attribute'
60
+ ThinkingSphinx::Facet.attribute_name_from_value('attribute', 1.23).
61
+ should == 'attribute'
62
+ end
63
+
64
+ it "should append _facet is the value is an array of strings" do
65
+ ThinkingSphinx::Facet.attribute_name_from_value('attribute', ['a', 'b']).
66
+ should == 'attribute_facet'
67
+ end
68
+
69
+ it "should not append _facet if the value is an array of integers" do
70
+ ThinkingSphinx::Facet.attribute_name_from_value('attribute', [1, 2]).
71
+ should == 'attribute'
72
+ end
73
+ end
74
+
75
+ describe ".translate?" do
76
+ before :each do
77
+ @index = ThinkingSphinx::Index.new(Alpha)
78
+ @source = ThinkingSphinx::Source.new(@index)
79
+ @attribute = ThinkingSphinx::Attribute.new(
80
+ @source, ThinkingSphinx::Index::FauxColumn.new(:name)
81
+ )
82
+ end
83
+
84
+ it "should return true if the property is a field" do
85
+ field = ThinkingSphinx::Field.new(
86
+ @source, ThinkingSphinx::Index::FauxColumn.new(:name)
87
+ )
88
+
89
+ ThinkingSphinx::Facet.translate?(field).should be_true
90
+ end
91
+
92
+ it "should return true if the property is a string attribute" do
93
+ @attribute.stub!(:type => :string)
94
+
95
+ ThinkingSphinx::Facet.translate?(@attribute).should be_true
96
+ end
97
+
98
+ it "should return false if the property is an integer attribute" do
99
+ @attribute.stub!(:type => :integer)
100
+
101
+ ThinkingSphinx::Facet.translate?(@attribute).should be_false
102
+ end
103
+
104
+ it "should return false if the property is a boolean attribute" do
105
+ @attribute.stub!(:type => :boolean)
106
+
107
+ ThinkingSphinx::Facet.translate?(@attribute).should be_false
108
+ end
109
+
110
+ it "should return false if the property is a timestamp attribute" do
111
+ @attribute.stub!(:type => :datetime)
112
+
113
+ ThinkingSphinx::Facet.translate?(@attribute).should be_false
114
+ end
115
+
116
+ it "should return false if the property is a float attribute" do
117
+ @attribute.stub!(:type => :float)
118
+
119
+ ThinkingSphinx::Facet.translate?(@attribute).should be_false
120
+ end
121
+
122
+ it "should return false if the property is an MVA of integer values" do
123
+ @attribute.stub!(:type => :multi, :all_ints? => true)
124
+
125
+ ThinkingSphinx::Facet.translate?(@attribute).should be_false
126
+ end
127
+
128
+ it "should return true if the property is an MVA of string values" do
129
+ @attribute.stub!(:type => :multi, :all_ints? => false)
130
+
131
+ ThinkingSphinx::Facet.translate?(@attribute).should be_true
132
+ end
133
+ end
134
+
135
+ describe "#translate?" do
136
+ before :each do
137
+ @index = ThinkingSphinx::Index.new(Alpha)
138
+ @source = ThinkingSphinx::Source.new(@index)
139
+ @attribute = ThinkingSphinx::Attribute.new(
140
+ @source, ThinkingSphinx::Index::FauxColumn.new(:name)
141
+ )
142
+ end
143
+
144
+ it "should return true if the property is a field" do
145
+ field = ThinkingSphinx::Field.new(
146
+ @source, ThinkingSphinx::Index::FauxColumn.new(:name)
147
+ )
148
+
149
+ ThinkingSphinx::Facet.new(field).translate?.should be_true
150
+ end
151
+
152
+ it "should return true if the property is a string attribute" do
153
+ @attribute.stub!(:type => :string)
154
+
155
+ ThinkingSphinx::Facet.new(@attribute).translate?.should be_true
156
+ end
157
+
158
+ it "should return false if the property is an integer attribute" do
159
+ @attribute.stub!(:type => :integer)
160
+
161
+ ThinkingSphinx::Facet.new(@attribute).translate?.should be_false
162
+ end
163
+
164
+ it "should return false if the property is a boolean attribute" do
165
+ @attribute.stub!(:type => :boolean)
166
+
167
+ ThinkingSphinx::Facet.new(@attribute).translate?.should be_false
168
+ end
169
+
170
+ it "should return false if the property is a timestamp attribute" do
171
+ @attribute.stub!(:type => :datetime)
172
+
173
+ ThinkingSphinx::Facet.new(@attribute).translate?.should be_false
174
+ end
175
+
176
+ it "should return false if the property is a float attribute" do
177
+ @attribute.stub!(:type => :float)
178
+
179
+ ThinkingSphinx::Facet.new(@attribute).translate?.should be_false
180
+ end
181
+
182
+ it "should return false if the property is an MVA of integer values" do
183
+ @attribute.stub!(:type => :multi, :all_ints? => true)
184
+
185
+ ThinkingSphinx::Facet.new(@attribute).translate?.should be_false
186
+ end
187
+
188
+ it "should return true if the property is an MVA of string values" do
189
+ @attribute.stub!(:type => :multi, :all_ints? => false)
190
+
191
+ ThinkingSphinx::Facet.new(@attribute).translate?.should be_true
192
+ end
193
+ end
194
+
195
+ describe "#attribute_name" do
196
+ before :each do
197
+ @index = ThinkingSphinx::Index.new(Alpha)
198
+ @source = ThinkingSphinx::Source.new(@index)
199
+ @attribute = ThinkingSphinx::Attribute.new(
200
+ @source, ThinkingSphinx::Index::FauxColumn.new(:name)
201
+ )
202
+ end
203
+
204
+ it "should return the attribute name if built off an integer attribute" do
205
+ @attribute.stub!(:type => :integer)
206
+
207
+ ThinkingSphinx::Facet.new(@attribute).attribute_name.should == "name"
208
+ end
209
+
210
+ it "should return the attribute name if built off a boolean attribute" do
211
+ @attribute.stub!(:type => :boolean)
212
+
213
+ ThinkingSphinx::Facet.new(@attribute).attribute_name.should == "name"
214
+ end
215
+
216
+ it "should return the attribute name if built off a float attribute" do
217
+ @attribute.stub!(:type => :float)
218
+
219
+ ThinkingSphinx::Facet.new(@attribute).attribute_name.should == "name"
220
+ end
221
+
222
+ it "should return the attribute name if built off a timestamp attribute" do
223
+ @attribute.stub!(:type => :datetime)
224
+
225
+ ThinkingSphinx::Facet.new(@attribute).attribute_name.should == "name"
226
+ end
227
+
228
+ it "should return the attribute name with _facet suffix if built off a string attribute" do
229
+ @attribute.stub!(:type => :string)
230
+
231
+ ThinkingSphinx::Facet.new(@attribute).attribute_name.should == "name_facet"
232
+ end
233
+
234
+ it "should return the attribute name with _facet suffix if built off a field" do
235
+ field = ThinkingSphinx::Field.new(
236
+ @source, ThinkingSphinx::Index::FauxColumn.new(:name)
237
+ )
238
+
239
+ ThinkingSphinx::Facet.new(field).attribute_name.should == "name_facet"
240
+ end
241
+
242
+ it "should return the attribute name if build off an integer MVA" do
243
+ @attribute.stub!(:type => :multi, :all_ints? => true)
244
+
245
+ ThinkingSphinx::Facet.new(@attribute).attribute_name.should == "name"
246
+ end
247
+
248
+ it "should return the attribute name with the _facet suffix if build off an non-integer MVA" do
249
+ @attribute.stub!(:type => :multi, :all_ints? => false)
250
+
251
+ ThinkingSphinx::Facet.new(@attribute).attribute_name.should == "name_facet"
252
+ end
253
+ end
254
+
255
+ describe "#type" do
256
+ before :each do
257
+ @index = ThinkingSphinx::Index.new(Alpha)
258
+ @source = ThinkingSphinx::Source.new(@index)
259
+ end
260
+
261
+ it "should return :string if the property is a field" do
262
+ field = ThinkingSphinx::Field.new(
263
+ @source, ThinkingSphinx::Index::FauxColumn.new(:name)
264
+ )
265
+
266
+ ThinkingSphinx::Facet.new(field).type.should == :string
267
+ end
268
+
269
+ it "should return the attribute type if the property is an attribute" do
270
+ attribute = ThinkingSphinx::Attribute.new(
271
+ @source, ThinkingSphinx::Index::FauxColumn.new(:name)
272
+ )
273
+ attribute.stub!(:type => :anything)
274
+
275
+ ThinkingSphinx::Facet.new(attribute).type.should == :anything
276
+ end
277
+ end
278
+
279
+ describe "#value" do
280
+ describe 'for fields from associations' do
281
+ before :each do
282
+ @index = ThinkingSphinx::Index.new(Friendship)
283
+ @source = ThinkingSphinx::Source.new(@index)
284
+ @field = ThinkingSphinx::Field.new(
285
+ @source, ThinkingSphinx::Index::FauxColumn.new(:person, :first_name)
286
+ )
287
+ @facet = ThinkingSphinx::Facet.new(@field)
288
+ end
289
+
290
+ it "should return association values" do
291
+ person = Person.find(:first)
292
+ friendship = Friendship.new(:person => person)
293
+
294
+ @facet.value(friendship, 1).should == person.first_name
295
+ end
296
+
297
+ it "should return nil if the association is nil" do
298
+ friendship = Friendship.new(:person => nil)
299
+
300
+ @facet.value(friendship, 1).should be_nil
301
+ end
302
+
303
+ it "should return multi-level association values" do
304
+ person = Person.find(:first)
305
+ tag = person.tags.build(:name => 'buried')
306
+ friendship = Friendship.new(:person => person)
307
+
308
+ field = ThinkingSphinx::Field.new(
309
+ @source, ThinkingSphinx::Index::FauxColumn.new(:person, :tags, :name)
310
+ )
311
+ ThinkingSphinx::Facet.new(field).value(friendship, 'buried'.to_crc32).
312
+ should == 'buried'
313
+ end
314
+ end
315
+
316
+ describe 'for float attributes' do
317
+ before :each do
318
+ @index = ThinkingSphinx::Index.new(Alpha)
319
+ @source = ThinkingSphinx::Source.new(@index)
320
+ @attribute = ThinkingSphinx::Attribute.new(
321
+ @source, ThinkingSphinx::Index::FauxColumn.new(:cost)
322
+ )
323
+ @facet = ThinkingSphinx::Facet.new(@attribute)
324
+ end
325
+
326
+ it "should translate using the given model" do
327
+ alpha = Alpha.new(:cost => 10.5)
328
+
329
+ @facet.value(alpha, 1093140480).should == 10.5
330
+ end
331
+ end
332
+ end
333
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Field do
4
+ before :each do
5
+ @index = ThinkingSphinx::Index.new(Alpha)
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::Field.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::Field.new(@source, [1234])
19
+ }.should raise_error(RuntimeError)
20
+ end
21
+ end
22
+
23
+ describe "unique_name method" do
24
+ before :each do
25
+ @field = ThinkingSphinx::Field.new @source, [
26
+ stub('column', :__stack => [], :__name => "col_name")
27
+ ]
28
+ end
29
+
30
+ it "should use the alias if there is one" do
31
+ @field.alias = "alias"
32
+ @field.unique_name.should == "alias"
33
+ end
34
+
35
+ it "should use the alias if there's multiple columns" do
36
+ @field.columns << stub('column', :__stack => [], :__name => "col_name")
37
+ @field.unique_name.should be_nil
38
+
39
+ @field.alias = "alias"
40
+ @field.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
+ @field.unique_name.should == "col_name"
45
+ end
46
+ end
47
+
48
+ describe "prefixes method" do
49
+ it "should default to false" do
50
+ @field = ThinkingSphinx::Field.new(
51
+ @source, [stub('column', :__stack => [])]
52
+ )
53
+ @field.prefixes.should be_false
54
+ end
55
+
56
+ it "should be true if the corresponding option is set" do
57
+ @field = ThinkingSphinx::Field.new(
58
+ @source, [stub('column', :__stack => [])], :prefixes => true
59
+ )
60
+ @field.prefixes.should be_true
61
+ end
62
+ end
63
+
64
+ describe "infixes method" do
65
+ it "should default to false" do
66
+ @field = ThinkingSphinx::Field.new(
67
+ @source, [stub('column', :__stack => [])]
68
+ )
69
+ @field.infixes.should be_false
70
+ end
71
+
72
+ it "should be true if the corresponding option is set" do
73
+ @field = ThinkingSphinx::Field.new(
74
+ @source, [stub('column', :__stack => [])], :infixes => true
75
+ )
76
+ @field.infixes.should be_true
77
+ end
78
+ end
79
+
80
+ describe "column_with_prefix method" do
81
+ before :each do
82
+ @field = ThinkingSphinx::Field.new @source, [
83
+ ThinkingSphinx::Index::FauxColumn.new(:col_name)
84
+ ]
85
+ @field.columns.each { |col| @field.associations[col] = [] }
86
+ @field.model = Person
87
+
88
+ @first_join = Object.new
89
+ @first_join.stub!(:aliased_table_name => "tabular")
90
+ @second_join = Object.new
91
+ @second_join.stub!(:aliased_table_name => "data")
92
+
93
+ @first_assoc = ThinkingSphinx::Association.new nil, nil
94
+ @first_assoc.stub!(:join => @first_join, :has_column? => true)
95
+ @second_assoc = ThinkingSphinx::Association.new nil, nil
96
+ @second_assoc.stub!(:join => @second_join, :has_column? => true)
97
+ end
98
+
99
+ it "should return the column name if the column is a string" do
100
+ @field.columns = [ThinkingSphinx::Index::FauxColumn.new("string")]
101
+ @field.send(:column_with_prefix, @field.columns.first).should == "string"
102
+ end
103
+
104
+ it "should return the column with model's table prefix if there's no associations for the column" do
105
+ @field.send(:column_with_prefix, @field.columns.first).should == "`people`.`col_name`"
106
+ end
107
+
108
+ it "should return the column with its join table prefix if an association exists" do
109
+ column = @field.columns.first
110
+ @field.associations[column] = [@first_assoc]
111
+ @field.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
112
+ end
113
+
114
+ it "should return multiple columns concatenated if more than one association exists" do
115
+ column = @field.columns.first
116
+ @field.associations[column] = [@first_assoc, @second_assoc]
117
+ @field.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
118
+ end
119
+ end
120
+
121
+ describe "is_many? method" do
122
+ before :each do
123
+ @assoc_a = stub('assoc', :is_many? => true)
124
+ @assoc_b = stub('assoc', :is_many? => true)
125
+ @assoc_c = stub('assoc', :is_many? => true)
126
+
127
+ @field = ThinkingSphinx::Field.new(
128
+ @source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
129
+ )
130
+ @field.associations = {
131
+ :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
132
+ }
133
+ end
134
+
135
+ it "should return true if all associations return true to is_many?" do
136
+ @field.send(:is_many?).should be_true
137
+ end
138
+
139
+ it "should return true if one association returns true to is_many?" do
140
+ @assoc_b.stub!(:is_many? => false)
141
+ @assoc_c.stub!(:is_many? => false)
142
+
143
+ @field.send(:is_many?).should be_true
144
+ end
145
+
146
+ it "should return false if all associations return false to is_many?" do
147
+ @assoc_a.stub!(:is_many? => false)
148
+ @assoc_b.stub!(:is_many? => false)
149
+ @assoc_c.stub!(:is_many? => false)
150
+
151
+ @field.send(:is_many?).should be_false
152
+ end
153
+ end
154
+ end