friendlyfashion-thinking-sphinx 2.0.13

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 (175) hide show
  1. data/HISTORY +244 -0
  2. data/LICENCE +20 -0
  3. data/README.textile +235 -0
  4. data/features/abstract_inheritance.feature +10 -0
  5. data/features/alternate_primary_key.feature +27 -0
  6. data/features/attribute_transformation.feature +22 -0
  7. data/features/attribute_updates.feature +77 -0
  8. data/features/deleting_instances.feature +67 -0
  9. data/features/direct_attributes.feature +11 -0
  10. data/features/excerpts.feature +21 -0
  11. data/features/extensible_delta_indexing.feature +9 -0
  12. data/features/facets.feature +88 -0
  13. data/features/facets_across_model.feature +29 -0
  14. data/features/field_sorting.feature +18 -0
  15. data/features/handling_edits.feature +94 -0
  16. data/features/retry_stale_indexes.feature +24 -0
  17. data/features/searching_across_models.feature +20 -0
  18. data/features/searching_by_index.feature +40 -0
  19. data/features/searching_by_model.feature +175 -0
  20. data/features/searching_with_find_arguments.feature +56 -0
  21. data/features/sphinx_detection.feature +25 -0
  22. data/features/sphinx_scopes.feature +68 -0
  23. data/features/step_definitions/alpha_steps.rb +16 -0
  24. data/features/step_definitions/beta_steps.rb +7 -0
  25. data/features/step_definitions/common_steps.rb +201 -0
  26. data/features/step_definitions/extensible_delta_indexing_steps.rb +7 -0
  27. data/features/step_definitions/facet_steps.rb +96 -0
  28. data/features/step_definitions/find_arguments_steps.rb +36 -0
  29. data/features/step_definitions/gamma_steps.rb +15 -0
  30. data/features/step_definitions/scope_steps.rb +19 -0
  31. data/features/step_definitions/search_steps.rb +94 -0
  32. data/features/step_definitions/sphinx_steps.rb +35 -0
  33. data/features/sti_searching.feature +19 -0
  34. data/features/support/env.rb +27 -0
  35. data/features/support/lib/generic_delta_handler.rb +8 -0
  36. data/features/thinking_sphinx/database.example.yml +3 -0
  37. data/features/thinking_sphinx/db/.gitignore +1 -0
  38. data/features/thinking_sphinx/db/fixtures/alphas.rb +8 -0
  39. data/features/thinking_sphinx/db/fixtures/authors.rb +1 -0
  40. data/features/thinking_sphinx/db/fixtures/betas.rb +11 -0
  41. data/features/thinking_sphinx/db/fixtures/boxes.rb +9 -0
  42. data/features/thinking_sphinx/db/fixtures/categories.rb +1 -0
  43. data/features/thinking_sphinx/db/fixtures/cats.rb +3 -0
  44. data/features/thinking_sphinx/db/fixtures/comments.rb +24 -0
  45. data/features/thinking_sphinx/db/fixtures/developers.rb +31 -0
  46. data/features/thinking_sphinx/db/fixtures/dogs.rb +3 -0
  47. data/features/thinking_sphinx/db/fixtures/extensible_betas.rb +10 -0
  48. data/features/thinking_sphinx/db/fixtures/foxes.rb +3 -0
  49. data/features/thinking_sphinx/db/fixtures/gammas.rb +10 -0
  50. data/features/thinking_sphinx/db/fixtures/music.rb +4 -0
  51. data/features/thinking_sphinx/db/fixtures/people.rb +1001 -0
  52. data/features/thinking_sphinx/db/fixtures/post_keywords.txt +1 -0
  53. data/features/thinking_sphinx/db/fixtures/posts.rb +10 -0
  54. data/features/thinking_sphinx/db/fixtures/robots.rb +8 -0
  55. data/features/thinking_sphinx/db/fixtures/tags.rb +27 -0
  56. data/features/thinking_sphinx/db/migrations/create_alphas.rb +8 -0
  57. data/features/thinking_sphinx/db/migrations/create_animals.rb +5 -0
  58. data/features/thinking_sphinx/db/migrations/create_authors.rb +3 -0
  59. data/features/thinking_sphinx/db/migrations/create_authors_posts.rb +6 -0
  60. data/features/thinking_sphinx/db/migrations/create_betas.rb +5 -0
  61. data/features/thinking_sphinx/db/migrations/create_boxes.rb +5 -0
  62. data/features/thinking_sphinx/db/migrations/create_categories.rb +3 -0
  63. data/features/thinking_sphinx/db/migrations/create_comments.rb +10 -0
  64. data/features/thinking_sphinx/db/migrations/create_developers.rb +7 -0
  65. data/features/thinking_sphinx/db/migrations/create_extensible_betas.rb +5 -0
  66. data/features/thinking_sphinx/db/migrations/create_gammas.rb +3 -0
  67. data/features/thinking_sphinx/db/migrations/create_genres.rb +3 -0
  68. data/features/thinking_sphinx/db/migrations/create_music.rb +6 -0
  69. data/features/thinking_sphinx/db/migrations/create_people.rb +13 -0
  70. data/features/thinking_sphinx/db/migrations/create_posts.rb +6 -0
  71. data/features/thinking_sphinx/db/migrations/create_robots.rb +4 -0
  72. data/features/thinking_sphinx/db/migrations/create_taggings.rb +5 -0
  73. data/features/thinking_sphinx/db/migrations/create_tags.rb +4 -0
  74. data/features/thinking_sphinx/models/alpha.rb +23 -0
  75. data/features/thinking_sphinx/models/andrew.rb +17 -0
  76. data/features/thinking_sphinx/models/animal.rb +5 -0
  77. data/features/thinking_sphinx/models/author.rb +3 -0
  78. data/features/thinking_sphinx/models/beta.rb +13 -0
  79. data/features/thinking_sphinx/models/box.rb +8 -0
  80. data/features/thinking_sphinx/models/cat.rb +3 -0
  81. data/features/thinking_sphinx/models/category.rb +4 -0
  82. data/features/thinking_sphinx/models/comment.rb +10 -0
  83. data/features/thinking_sphinx/models/developer.rb +21 -0
  84. data/features/thinking_sphinx/models/dog.rb +3 -0
  85. data/features/thinking_sphinx/models/extensible_beta.rb +9 -0
  86. data/features/thinking_sphinx/models/fox.rb +5 -0
  87. data/features/thinking_sphinx/models/gamma.rb +5 -0
  88. data/features/thinking_sphinx/models/genre.rb +3 -0
  89. data/features/thinking_sphinx/models/medium.rb +5 -0
  90. data/features/thinking_sphinx/models/music.rb +10 -0
  91. data/features/thinking_sphinx/models/person.rb +24 -0
  92. data/features/thinking_sphinx/models/post.rb +22 -0
  93. data/features/thinking_sphinx/models/robot.rb +12 -0
  94. data/features/thinking_sphinx/models/tag.rb +3 -0
  95. data/features/thinking_sphinx/models/tagging.rb +4 -0
  96. data/lib/cucumber/thinking_sphinx/external_world.rb +12 -0
  97. data/lib/cucumber/thinking_sphinx/internal_world.rb +137 -0
  98. data/lib/cucumber/thinking_sphinx/sql_logger.rb +28 -0
  99. data/lib/thinking-sphinx.rb +1 -0
  100. data/lib/thinking_sphinx/action_controller.rb +31 -0
  101. data/lib/thinking_sphinx/active_record/attribute_updates.rb +53 -0
  102. data/lib/thinking_sphinx/active_record/collection_proxy.rb +47 -0
  103. data/lib/thinking_sphinx/active_record/collection_proxy_with_scopes.rb +27 -0
  104. data/lib/thinking_sphinx/active_record/delta.rb +67 -0
  105. data/lib/thinking_sphinx/active_record/has_many_association.rb +44 -0
  106. data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +21 -0
  107. data/lib/thinking_sphinx/active_record/log_subscriber.rb +61 -0
  108. data/lib/thinking_sphinx/active_record/scopes.rb +110 -0
  109. data/lib/thinking_sphinx/active_record.rb +386 -0
  110. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +87 -0
  111. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +62 -0
  112. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +188 -0
  113. data/lib/thinking_sphinx/association.rb +230 -0
  114. data/lib/thinking_sphinx/attribute.rb +405 -0
  115. data/lib/thinking_sphinx/auto_version.rb +40 -0
  116. data/lib/thinking_sphinx/bundled_search.rb +44 -0
  117. data/lib/thinking_sphinx/class_facet.rb +20 -0
  118. data/lib/thinking_sphinx/configuration.rb +375 -0
  119. data/lib/thinking_sphinx/context.rb +76 -0
  120. data/lib/thinking_sphinx/core/string.rb +15 -0
  121. data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
  122. data/lib/thinking_sphinx/deltas.rb +28 -0
  123. data/lib/thinking_sphinx/deploy/capistrano.rb +99 -0
  124. data/lib/thinking_sphinx/excerpter.rb +23 -0
  125. data/lib/thinking_sphinx/facet.rb +135 -0
  126. data/lib/thinking_sphinx/facet_search.rb +170 -0
  127. data/lib/thinking_sphinx/field.rb +98 -0
  128. data/lib/thinking_sphinx/index/builder.rb +315 -0
  129. data/lib/thinking_sphinx/index/faux_column.rb +118 -0
  130. data/lib/thinking_sphinx/index.rb +159 -0
  131. data/lib/thinking_sphinx/join.rb +37 -0
  132. data/lib/thinking_sphinx/property.rb +187 -0
  133. data/lib/thinking_sphinx/railtie.rb +43 -0
  134. data/lib/thinking_sphinx/search.rb +1061 -0
  135. data/lib/thinking_sphinx/search_methods.rb +439 -0
  136. data/lib/thinking_sphinx/sinatra.rb +7 -0
  137. data/lib/thinking_sphinx/source/internal_properties.rb +51 -0
  138. data/lib/thinking_sphinx/source/sql.rb +174 -0
  139. data/lib/thinking_sphinx/source.rb +194 -0
  140. data/lib/thinking_sphinx/tasks.rb +142 -0
  141. data/lib/thinking_sphinx/test.rb +55 -0
  142. data/lib/thinking_sphinx/version.rb +3 -0
  143. data/lib/thinking_sphinx.rb +297 -0
  144. data/spec/fixtures/data.sql +32 -0
  145. data/spec/fixtures/database.yml.default +3 -0
  146. data/spec/fixtures/models.rb +164 -0
  147. data/spec/fixtures/structure.sql +146 -0
  148. data/spec/spec_helper.rb +61 -0
  149. data/spec/sphinx_helper.rb +60 -0
  150. data/spec/support/rails.rb +25 -0
  151. data/spec/thinking_sphinx/active_record/delta_spec.rb +122 -0
  152. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +173 -0
  153. data/spec/thinking_sphinx/active_record/scopes_spec.rb +176 -0
  154. data/spec/thinking_sphinx/active_record_spec.rb +573 -0
  155. data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +145 -0
  156. data/spec/thinking_sphinx/association_spec.rb +250 -0
  157. data/spec/thinking_sphinx/attribute_spec.rb +552 -0
  158. data/spec/thinking_sphinx/auto_version_spec.rb +103 -0
  159. data/spec/thinking_sphinx/configuration_spec.rb +326 -0
  160. data/spec/thinking_sphinx/context_spec.rb +126 -0
  161. data/spec/thinking_sphinx/core/array_spec.rb +9 -0
  162. data/spec/thinking_sphinx/core/string_spec.rb +9 -0
  163. data/spec/thinking_sphinx/excerpter_spec.rb +49 -0
  164. data/spec/thinking_sphinx/facet_search_spec.rb +176 -0
  165. data/spec/thinking_sphinx/facet_spec.rb +359 -0
  166. data/spec/thinking_sphinx/field_spec.rb +127 -0
  167. data/spec/thinking_sphinx/index/builder_spec.rb +532 -0
  168. data/spec/thinking_sphinx/index/faux_column_spec.rb +36 -0
  169. data/spec/thinking_sphinx/index_spec.rb +189 -0
  170. data/spec/thinking_sphinx/search_methods_spec.rb +156 -0
  171. data/spec/thinking_sphinx/search_spec.rb +1455 -0
  172. data/spec/thinking_sphinx/source_spec.rb +267 -0
  173. data/spec/thinking_sphinx/test_spec.rb +20 -0
  174. data/spec/thinking_sphinx_spec.rb +204 -0
  175. metadata +524 -0
@@ -0,0 +1,359 @@
1
+ require '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, {'first_name_facet' => 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, {'first_name_facet' => 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, {'name_facet' => 'buried'.to_crc32}).
312
+ should == 'buried'
313
+ end
314
+
315
+ it "should not error with multi-level association values containing a nil value" do
316
+ person = Person.find(:first)
317
+ tag = person.tags.build(:name => nil)
318
+ tag = person.tags.build(:name => "buried")
319
+ friendship = Friendship.new(:person => person)
320
+
321
+ field = ThinkingSphinx::Field.new(
322
+ @source, ThinkingSphinx::Index::FauxColumn.new(:person, :tags, :name)
323
+ )
324
+ lambda{ThinkingSphinx::Facet.new(field).value(friendship, {'name_facet' => 'buried'.to_crc32})}.should_not raise_error
325
+ end
326
+ end
327
+
328
+ describe 'for float attributes' do
329
+ before :each do
330
+ @index = ThinkingSphinx::Index.new(Alpha)
331
+ @source = ThinkingSphinx::Source.new(@index)
332
+ @attribute = ThinkingSphinx::Attribute.new(
333
+ @source, ThinkingSphinx::Index::FauxColumn.new(:cost)
334
+ )
335
+ @facet = ThinkingSphinx::Facet.new(@attribute)
336
+ end
337
+
338
+ it "should translate using the given model" do
339
+ alpha = Alpha.new(:cost => 10.5)
340
+
341
+ @facet.value(alpha, {'cost' => 1093140480}).should == 10.5
342
+ end
343
+ end
344
+
345
+ context 'manual value source' do
346
+ let(:index) { ThinkingSphinx::Index.new(Alpha) }
347
+ let(:source) { ThinkingSphinx::Source.new(index) }
348
+ let(:column) { ThinkingSphinx::Index::FauxColumn.new('LOWER(name)') }
349
+ let(:field) { ThinkingSphinx::Field.new(source, column) }
350
+ let(:facet) { ThinkingSphinx::Facet.new(field, :name) }
351
+
352
+ it "should use the given value source to figure out the value" do
353
+ alpha = Alpha.new(:name => 'Foo')
354
+
355
+ facet.value(alpha, {'foo_facet' => 'foo'.to_crc32}).should == 'Foo'
356
+ end
357
+ end
358
+ end
359
+ end
@@ -0,0 +1,127 @@
1
+ require '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 '#to_select_sql' do
49
+ it "should return nil if polymorphic association data does not exist" do
50
+ field = ThinkingSphinx::Field.new(@source,
51
+ [ThinkingSphinx::Index::FauxColumn.new(:source, :name)],
52
+ :as => :source_name
53
+ )
54
+
55
+ field.to_select_sql.should be_nil
56
+ end
57
+ end
58
+
59
+ describe "prefixes method" do
60
+ it "should default to false" do
61
+ @field = ThinkingSphinx::Field.new(
62
+ @source, [stub('column', :__stack => [])]
63
+ )
64
+ @field.prefixes.should be_false
65
+ end
66
+
67
+ it "should be true if the corresponding option is set" do
68
+ @field = ThinkingSphinx::Field.new(
69
+ @source, [stub('column', :__stack => [])], :prefixes => true
70
+ )
71
+ @field.prefixes.should be_true
72
+ end
73
+ end
74
+
75
+ describe "infixes method" do
76
+ it "should default to false" do
77
+ @field = ThinkingSphinx::Field.new(
78
+ @source, [stub('column', :__stack => [])]
79
+ )
80
+ @field.infixes.should be_false
81
+ end
82
+
83
+ it "should be true if the corresponding option is set" do
84
+ @field = ThinkingSphinx::Field.new(
85
+ @source, [stub('column', :__stack => [])], :infixes => true
86
+ )
87
+ @field.infixes.should be_true
88
+ end
89
+ end
90
+
91
+ describe "is_many? method" do
92
+ before :each do
93
+ @assoc_a = ThinkingSphinx::Association.new(nil, nil)
94
+ @assoc_b = ThinkingSphinx::Association.new(nil, nil)
95
+ @assoc_c = ThinkingSphinx::Association.new(nil, nil)
96
+
97
+ @field = ThinkingSphinx::Field.new(
98
+ @source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
99
+ )
100
+ @field.associations = {
101
+ :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
102
+ }
103
+ @field.associations.values.each { |assoc|
104
+ assoc.stub!(:is_many? => true)
105
+ }
106
+ end
107
+
108
+ it "should return true if all associations return true to is_many?" do
109
+ @field.send(:is_many?).should be_true
110
+ end
111
+
112
+ it "should return true if one association returns true to is_many?" do
113
+ @assoc_b.stub!(:is_many? => false)
114
+ @assoc_c.stub!(:is_many? => false)
115
+
116
+ @field.send(:is_many?).should be_true
117
+ end
118
+
119
+ it "should return false if all associations return false to is_many?" do
120
+ @assoc_a.stub!(:is_many? => false)
121
+ @assoc_b.stub!(:is_many? => false)
122
+ @assoc_c.stub!(:is_many? => false)
123
+
124
+ @field.send(:is_many?).should be_false
125
+ end
126
+ end
127
+ end