angelf-thinking-sphinx 1.3.18

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 (159) hide show
  1. data/LICENCE +20 -0
  2. data/README.textile +170 -0
  3. data/VERSION +1 -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 +13 -0
  11. data/features/extensible_delta_indexing.feature +9 -0
  12. data/features/facets.feature +90 -0
  13. data/features/facets_across_model.feature +29 -0
  14. data/features/handling_edits.feature +92 -0
  15. data/features/retry_stale_indexes.feature +24 -0
  16. data/features/searching_across_models.feature +20 -0
  17. data/features/searching_by_index.feature +40 -0
  18. data/features/searching_by_model.feature +175 -0
  19. data/features/searching_with_find_arguments.feature +56 -0
  20. data/features/sphinx_detection.feature +25 -0
  21. data/features/sphinx_scopes.feature +42 -0
  22. data/features/step_definitions/alpha_steps.rb +16 -0
  23. data/features/step_definitions/beta_steps.rb +7 -0
  24. data/features/step_definitions/common_steps.rb +193 -0
  25. data/features/step_definitions/extensible_delta_indexing_steps.rb +7 -0
  26. data/features/step_definitions/facet_steps.rb +96 -0
  27. data/features/step_definitions/find_arguments_steps.rb +36 -0
  28. data/features/step_definitions/gamma_steps.rb +15 -0
  29. data/features/step_definitions/scope_steps.rb +15 -0
  30. data/features/step_definitions/search_steps.rb +89 -0
  31. data/features/step_definitions/sphinx_steps.rb +35 -0
  32. data/features/sti_searching.feature +19 -0
  33. data/features/support/env.rb +21 -0
  34. data/features/support/lib/generic_delta_handler.rb +8 -0
  35. data/features/thinking_sphinx/database.example.yml +3 -0
  36. data/features/thinking_sphinx/db/fixtures/alphas.rb +10 -0
  37. data/features/thinking_sphinx/db/fixtures/authors.rb +1 -0
  38. data/features/thinking_sphinx/db/fixtures/betas.rb +11 -0
  39. data/features/thinking_sphinx/db/fixtures/boxes.rb +9 -0
  40. data/features/thinking_sphinx/db/fixtures/categories.rb +1 -0
  41. data/features/thinking_sphinx/db/fixtures/cats.rb +3 -0
  42. data/features/thinking_sphinx/db/fixtures/comments.rb +24 -0
  43. data/features/thinking_sphinx/db/fixtures/developers.rb +31 -0
  44. data/features/thinking_sphinx/db/fixtures/dogs.rb +3 -0
  45. data/features/thinking_sphinx/db/fixtures/extensible_betas.rb +10 -0
  46. data/features/thinking_sphinx/db/fixtures/foxes.rb +3 -0
  47. data/features/thinking_sphinx/db/fixtures/gammas.rb +10 -0
  48. data/features/thinking_sphinx/db/fixtures/music.rb +4 -0
  49. data/features/thinking_sphinx/db/fixtures/people.rb +1001 -0
  50. data/features/thinking_sphinx/db/fixtures/posts.rb +6 -0
  51. data/features/thinking_sphinx/db/fixtures/robots.rb +14 -0
  52. data/features/thinking_sphinx/db/fixtures/tags.rb +27 -0
  53. data/features/thinking_sphinx/db/migrations/create_alphas.rb +8 -0
  54. data/features/thinking_sphinx/db/migrations/create_animals.rb +5 -0
  55. data/features/thinking_sphinx/db/migrations/create_authors.rb +3 -0
  56. data/features/thinking_sphinx/db/migrations/create_authors_posts.rb +6 -0
  57. data/features/thinking_sphinx/db/migrations/create_betas.rb +5 -0
  58. data/features/thinking_sphinx/db/migrations/create_boxes.rb +5 -0
  59. data/features/thinking_sphinx/db/migrations/create_categories.rb +3 -0
  60. data/features/thinking_sphinx/db/migrations/create_comments.rb +10 -0
  61. data/features/thinking_sphinx/db/migrations/create_developers.rb +7 -0
  62. data/features/thinking_sphinx/db/migrations/create_extensible_betas.rb +5 -0
  63. data/features/thinking_sphinx/db/migrations/create_gammas.rb +3 -0
  64. data/features/thinking_sphinx/db/migrations/create_genres.rb +3 -0
  65. data/features/thinking_sphinx/db/migrations/create_music.rb +6 -0
  66. data/features/thinking_sphinx/db/migrations/create_people.rb +13 -0
  67. data/features/thinking_sphinx/db/migrations/create_posts.rb +5 -0
  68. data/features/thinking_sphinx/db/migrations/create_robots.rb +4 -0
  69. data/features/thinking_sphinx/db/migrations/create_taggings.rb +5 -0
  70. data/features/thinking_sphinx/db/migrations/create_tags.rb +4 -0
  71. data/features/thinking_sphinx/models/alpha.rb +22 -0
  72. data/features/thinking_sphinx/models/animal.rb +5 -0
  73. data/features/thinking_sphinx/models/author.rb +3 -0
  74. data/features/thinking_sphinx/models/beta.rb +8 -0
  75. data/features/thinking_sphinx/models/box.rb +8 -0
  76. data/features/thinking_sphinx/models/cat.rb +3 -0
  77. data/features/thinking_sphinx/models/category.rb +4 -0
  78. data/features/thinking_sphinx/models/comment.rb +10 -0
  79. data/features/thinking_sphinx/models/developer.rb +16 -0
  80. data/features/thinking_sphinx/models/dog.rb +3 -0
  81. data/features/thinking_sphinx/models/extensible_beta.rb +9 -0
  82. data/features/thinking_sphinx/models/fox.rb +5 -0
  83. data/features/thinking_sphinx/models/gamma.rb +5 -0
  84. data/features/thinking_sphinx/models/genre.rb +3 -0
  85. data/features/thinking_sphinx/models/medium.rb +5 -0
  86. data/features/thinking_sphinx/models/music.rb +8 -0
  87. data/features/thinking_sphinx/models/person.rb +23 -0
  88. data/features/thinking_sphinx/models/post.rb +21 -0
  89. data/features/thinking_sphinx/models/robot.rb +12 -0
  90. data/features/thinking_sphinx/models/tag.rb +3 -0
  91. data/features/thinking_sphinx/models/tagging.rb +4 -0
  92. data/lib/cucumber/thinking_sphinx/external_world.rb +8 -0
  93. data/lib/cucumber/thinking_sphinx/internal_world.rb +127 -0
  94. data/lib/cucumber/thinking_sphinx/sql_logger.rb +20 -0
  95. data/lib/thinking_sphinx.rb +242 -0
  96. data/lib/thinking_sphinx/active_record.rb +380 -0
  97. data/lib/thinking_sphinx/active_record/attribute_updates.rb +50 -0
  98. data/lib/thinking_sphinx/active_record/delta.rb +61 -0
  99. data/lib/thinking_sphinx/active_record/has_many_association.rb +51 -0
  100. data/lib/thinking_sphinx/active_record/scopes.rb +75 -0
  101. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +47 -0
  102. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +58 -0
  103. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +147 -0
  104. data/lib/thinking_sphinx/association.rb +164 -0
  105. data/lib/thinking_sphinx/attribute.rb +380 -0
  106. data/lib/thinking_sphinx/auto_version.rb +22 -0
  107. data/lib/thinking_sphinx/class_facet.rb +15 -0
  108. data/lib/thinking_sphinx/configuration.rb +292 -0
  109. data/lib/thinking_sphinx/context.rb +74 -0
  110. data/lib/thinking_sphinx/core/array.rb +7 -0
  111. data/lib/thinking_sphinx/core/string.rb +15 -0
  112. data/lib/thinking_sphinx/deltas.rb +28 -0
  113. data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
  114. data/lib/thinking_sphinx/deploy/capistrano.rb +100 -0
  115. data/lib/thinking_sphinx/excerpter.rb +22 -0
  116. data/lib/thinking_sphinx/facet.rb +125 -0
  117. data/lib/thinking_sphinx/facet_search.rb +146 -0
  118. data/lib/thinking_sphinx/field.rb +80 -0
  119. data/lib/thinking_sphinx/index.rb +157 -0
  120. data/lib/thinking_sphinx/index/builder.rb +302 -0
  121. data/lib/thinking_sphinx/index/faux_column.rb +118 -0
  122. data/lib/thinking_sphinx/join.rb +37 -0
  123. data/lib/thinking_sphinx/property.rb +168 -0
  124. data/lib/thinking_sphinx/rails_additions.rb +150 -0
  125. data/lib/thinking_sphinx/search.rb +785 -0
  126. data/lib/thinking_sphinx/search_methods.rb +439 -0
  127. data/lib/thinking_sphinx/source.rb +164 -0
  128. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  129. data/lib/thinking_sphinx/source/sql.rb +130 -0
  130. data/lib/thinking_sphinx/tasks.rb +121 -0
  131. data/lib/thinking_sphinx/test.rb +55 -0
  132. data/rails/init.rb +16 -0
  133. data/spec/thinking_sphinx/active_record/delta_spec.rb +128 -0
  134. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +71 -0
  135. data/spec/thinking_sphinx/active_record/scopes_spec.rb +177 -0
  136. data/spec/thinking_sphinx/active_record_spec.rb +618 -0
  137. data/spec/thinking_sphinx/association_spec.rb +239 -0
  138. data/spec/thinking_sphinx/attribute_spec.rb +548 -0
  139. data/spec/thinking_sphinx/auto_version_spec.rb +39 -0
  140. data/spec/thinking_sphinx/configuration_spec.rb +271 -0
  141. data/spec/thinking_sphinx/context_spec.rb +126 -0
  142. data/spec/thinking_sphinx/core/array_spec.rb +9 -0
  143. data/spec/thinking_sphinx/core/string_spec.rb +9 -0
  144. data/spec/thinking_sphinx/excerpter_spec.rb +49 -0
  145. data/spec/thinking_sphinx/facet_search_spec.rb +176 -0
  146. data/spec/thinking_sphinx/facet_spec.rb +333 -0
  147. data/spec/thinking_sphinx/field_spec.rb +113 -0
  148. data/spec/thinking_sphinx/index/builder_spec.rb +495 -0
  149. data/spec/thinking_sphinx/index/faux_column_spec.rb +36 -0
  150. data/spec/thinking_sphinx/index_spec.rb +183 -0
  151. data/spec/thinking_sphinx/rails_additions_spec.rb +203 -0
  152. data/spec/thinking_sphinx/search_methods_spec.rb +152 -0
  153. data/spec/thinking_sphinx/search_spec.rb +1206 -0
  154. data/spec/thinking_sphinx/source_spec.rb +243 -0
  155. data/spec/thinking_sphinx_spec.rb +204 -0
  156. data/tasks/distribution.rb +46 -0
  157. data/tasks/rails.rake +1 -0
  158. data/tasks/testing.rb +76 -0
  159. metadata +342 -0
@@ -0,0 +1,113 @@
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 "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 "is_many? method" do
81
+ before :each do
82
+ @assoc_a = stub('assoc', :is_many? => true)
83
+ @assoc_b = stub('assoc', :is_many? => true)
84
+ @assoc_c = stub('assoc', :is_many? => true)
85
+
86
+ @field = ThinkingSphinx::Field.new(
87
+ @source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
88
+ )
89
+ @field.associations = {
90
+ :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
91
+ }
92
+ end
93
+
94
+ it "should return true if all associations return true to is_many?" do
95
+ @field.send(:is_many?).should be_true
96
+ end
97
+
98
+ it "should return true if one association returns true to is_many?" do
99
+ @assoc_b.stub!(:is_many? => false)
100
+ @assoc_c.stub!(:is_many? => false)
101
+
102
+ @field.send(:is_many?).should be_true
103
+ end
104
+
105
+ it "should return false if all associations return false to is_many?" do
106
+ @assoc_a.stub!(:is_many? => false)
107
+ @assoc_b.stub!(:is_many? => false)
108
+ @assoc_c.stub!(:is_many? => false)
109
+
110
+ @field.send(:is_many?).should be_false
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,495 @@
1
+ require 'spec_helper'
2
+
3
+ describe ThinkingSphinx::Index::Builder do
4
+ describe ".generate without source scope" do
5
+ before :each do
6
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
7
+ indexes first_name, last_name
8
+ has birthday
9
+ has id, :as => :internal_id
10
+
11
+ set_property :sql_range_step => 1000
12
+
13
+ where "birthday <= NOW()"
14
+ group_by "first_name"
15
+ end
16
+
17
+ @source = @index.sources.first
18
+ end
19
+
20
+ it "should return an index" do
21
+ @index.should be_a_kind_of(ThinkingSphinx::Index)
22
+ end
23
+
24
+ it "should have one source for the index" do
25
+ @index.sources.length.should == 1
26
+ end
27
+
28
+ it "should have two fields" do
29
+ @source.fields.length.should == 2
30
+ @source.fields[0].unique_name.should == :first_name
31
+ @source.fields[1].unique_name.should == :last_name
32
+ end
33
+
34
+ it "should have two attributes alongside the three internal ones" do
35
+ @source.attributes.length.should == 5
36
+ @source.attributes[3].unique_name.should == :birthday
37
+ @source.attributes[4].unique_name.should == :internal_id
38
+ end
39
+
40
+ it "should have one condition" do
41
+ @source.conditions.length.should == 1
42
+ @source.conditions.first.should == "birthday <= NOW()"
43
+ end
44
+
45
+ it "should have one grouping" do
46
+ @source.groupings.length.should == 1
47
+ @source.groupings.first.should == "first_name"
48
+ end
49
+
50
+ it "should have one option" do
51
+ @source.options.length.should == 1
52
+ @source.options[:sql_range_step].should == 1000
53
+ end
54
+ end
55
+
56
+ describe 'aliased field' do
57
+ before :each do
58
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
59
+ indexes first_name, :as => 'name'
60
+ end
61
+
62
+ @source = @index.sources.first
63
+ end
64
+
65
+ it "should store the alias as a symbol for consistency" do
66
+ @source.fields.last.unique_name.should == :name
67
+ end
68
+ end
69
+
70
+ describe 'aliased attribute' do
71
+ before :each do
72
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
73
+ indexes first_name
74
+ has :id, :as => 'real_id'
75
+ end
76
+
77
+ @source = @index.sources.first
78
+ end
79
+
80
+ it "should store the alias as a symbol for consistency" do
81
+ @source.attributes.last.unique_name.should == :real_id
82
+ end
83
+ end
84
+
85
+ describe "sortable field" do
86
+ before :each do
87
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
88
+ indexes first_name, :sortable => true
89
+ end
90
+
91
+ @source = @index.sources.first
92
+ end
93
+
94
+ it "should have one field" do
95
+ @source.fields.length.should == 1
96
+ end
97
+
98
+ it "should have one attribute alongside the three internal ones" do
99
+ @source.attributes.length.should == 4
100
+ end
101
+
102
+ it "should set the attribute name to have the _sort suffix" do
103
+ @source.attributes.last.unique_name.should == :first_name_sort
104
+ end
105
+
106
+ it "should set the attribute column to be the same as the field" do
107
+ @source.attributes.last.columns.length.should == 1
108
+ @source.attributes.last.columns.first.__name.should == :first_name
109
+ end
110
+ end
111
+
112
+ describe '#join' do
113
+ before :each do
114
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
115
+ indexes first_name
116
+
117
+ join contacts
118
+ end
119
+
120
+ @source = @index.sources.first
121
+ end
122
+
123
+ it "should include the explicit join" do
124
+ @source.joins.length.should == 1
125
+ end
126
+ end
127
+
128
+ describe "faceted field" do
129
+ before :each do
130
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
131
+ indexes first_name, :facet => true
132
+ end
133
+
134
+ @source = @index.sources.first
135
+ end
136
+
137
+ after :each do
138
+ Person.sphinx_facets.delete_at(-1)
139
+ end
140
+
141
+ it "should have one field" do
142
+ @source.fields.length.should == 1
143
+ end
144
+
145
+ it "should have one attribute alongside the three internal ones" do
146
+ @source.attributes.length.should == 4
147
+ end
148
+
149
+ it "should set the attribute name to have the _facet suffix" do
150
+ @source.attributes.last.unique_name.should == :first_name_facet
151
+ end
152
+
153
+ it "should set the attribute type to integer" do
154
+ @source.attributes.last.type.should == :integer
155
+ end
156
+
157
+ it "should set the attribute column to be the same as the field" do
158
+ @source.attributes.last.columns.length.should == 1
159
+ @source.attributes.last.columns.first.__name.should == :first_name
160
+ end
161
+ end
162
+
163
+ describe "faceted integer attribute" do
164
+ before :each do
165
+ @index = ThinkingSphinx::Index::Builder.generate(Alpha) do
166
+ indexes :name
167
+ has value, :facet => true
168
+ end
169
+
170
+ @source = @index.sources.first
171
+ end
172
+
173
+ after :each do
174
+ Alpha.sphinx_facets.delete_at(-1)
175
+ end
176
+
177
+ it "should have just one attribute alongside the three internal ones" do
178
+ @source.attributes.length.should == 4
179
+ end
180
+ end
181
+
182
+ describe "faceted timestamp attribute" do
183
+ before :each do
184
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
185
+ indexes first_name
186
+ has birthday, :facet => true
187
+ end
188
+
189
+ @source = @index.sources.first
190
+ end
191
+
192
+ after :each do
193
+ Person.sphinx_facets.delete_at(-1)
194
+ end
195
+
196
+ it "should have just one attribute alongside the three internal ones" do
197
+ @source.attributes.length.should == 4
198
+ end
199
+ end
200
+
201
+ describe "faceted boolean attribute" do
202
+ before :each do
203
+ @index = ThinkingSphinx::Index::Builder.generate(Beta) do
204
+ indexes :name
205
+ has delta, :facet => true
206
+ end
207
+
208
+ @source = @index.sources.first
209
+ end
210
+
211
+ after :each do
212
+ Beta.sphinx_facets.delete_at(-1)
213
+ end
214
+
215
+ it "should have just one attribute alongside the three internal ones" do
216
+ @source.attributes.length.should == 4
217
+ end
218
+ end
219
+
220
+ describe "faceted float attribute" do
221
+ before :each do
222
+ @index = ThinkingSphinx::Index::Builder.generate(Alpha) do
223
+ indexes :name
224
+ has cost, :facet => true
225
+ end
226
+
227
+ @source = @index.sources.first
228
+ end
229
+
230
+ after :each do
231
+ Alpha.sphinx_facets.delete_at(-1)
232
+ end
233
+
234
+ it "should have just one attribute alongside the three internal ones" do
235
+ @source.attributes.length.should == 4
236
+ end
237
+ end
238
+
239
+ describe "faceted string attribute" do
240
+ before :each do
241
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
242
+ indexes first_name
243
+ has last_name, :facet => true
244
+ end
245
+
246
+ @source = @index.sources.first
247
+ end
248
+
249
+ after :each do
250
+ Person.sphinx_facets.delete_at(-1)
251
+ end
252
+
253
+ it "should have two attributes alongside the three internal ones" do
254
+ @source.attributes.length.should == 5
255
+ end
256
+
257
+ it "should set the facet attribute name to have the _facet suffix" do
258
+ @source.attributes.last.unique_name.should == :last_name_facet
259
+ end
260
+
261
+ it "should set the attribute type to integer" do
262
+ @source.attributes.last.type.should == :integer
263
+ end
264
+
265
+ it "should set the attribute column to be the same as the field" do
266
+ @source.attributes.last.columns.length.should == 1
267
+ @source.attributes.last.columns.first.__name.should == :last_name
268
+ end
269
+ end
270
+
271
+ describe 'faceted manual MVA' do
272
+ before :each do
273
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
274
+ indexes first_name
275
+ has 'SQL STATEMENT', :type => :multi, :as => :sql, :facet => true
276
+ end
277
+
278
+ @source = @index.sources.first
279
+ end
280
+
281
+ after :each do
282
+ Person.sphinx_facets.delete_at(-1)
283
+ end
284
+
285
+ it "should have two attributes alongside the three internal ones" do
286
+ @source.attributes.length.should == 5
287
+ end
288
+
289
+ it "should set the facet attribute name to have the _facet suffix" do
290
+ @source.attributes.last.unique_name.should == :sql_facet
291
+ end
292
+
293
+ it "should keep the original attribute's name set as requested" do
294
+ @source.attributes[-2].unique_name.should == :sql
295
+ end
296
+
297
+ it "should set the attribute type to multi" do
298
+ @source.attributes.last.type.should == :multi
299
+ end
300
+
301
+ it "should set the attribute column to be the same as the field" do
302
+ @source.attributes.last.columns.length.should == 1
303
+ @source.attributes.last.columns.first.__name.should == 'SQL STATEMENT'
304
+ end
305
+ end
306
+
307
+ describe 'faceted MVA field' do
308
+ before :each do
309
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
310
+ indexes tags(:name), :as => :tags, :facet => true
311
+ end
312
+
313
+ @source = @index.sources.first
314
+ end
315
+
316
+ after :each do
317
+ Person.sphinx_facets.delete_at(-1)
318
+ end
319
+
320
+ it "should have one field" do
321
+ @source.fields.length.should == 1
322
+ end
323
+
324
+ it "should have one attribute alongside the three internal ones" do
325
+ @source.attributes.length.should == 4
326
+ end
327
+
328
+ it "should set the attribute name to have the _facet suffix" do
329
+ @source.attributes.last.unique_name.should == :tags_facet
330
+ end
331
+
332
+ it "should set the attribute type to multi" do
333
+ @source.attributes.last.type.should == :multi
334
+ end
335
+
336
+ it "should set the attribute column to be the same as the field" do
337
+ @source.attributes.last.columns.length.should == 1
338
+ @source.attributes.last.columns.first.__name.should == :name
339
+ end
340
+ end
341
+
342
+ describe "no fields" do
343
+ it "should raise an exception" do
344
+ lambda {
345
+ ThinkingSphinx::Index::Builder.generate(Person) do
346
+ #
347
+ end
348
+ }.should raise_error
349
+ end
350
+ end
351
+
352
+ describe "explicit source" do
353
+ before :each do
354
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
355
+ define_source do
356
+ indexes first_name, last_name
357
+ has birthday
358
+ has id, :as => :internal_id
359
+
360
+ set_property :delta => true
361
+
362
+ where "birthday <= NOW()"
363
+ group_by "first_name"
364
+ end
365
+ end
366
+
367
+ @source = @index.sources.first
368
+ end
369
+
370
+ it "should return an index" do
371
+ @index.should be_a_kind_of(ThinkingSphinx::Index)
372
+ end
373
+
374
+ it "should have one source for the index" do
375
+ @index.sources.length.should == 1
376
+ end
377
+
378
+ it "should have two fields" do
379
+ @source.fields.length.should == 2
380
+ @source.fields[0].unique_name.should == :first_name
381
+ @source.fields[1].unique_name.should == :last_name
382
+ end
383
+
384
+ it "should have two attributes alongside the three internal ones" do
385
+ @source.attributes.length.should == 5
386
+ @source.attributes[3].unique_name.should == :birthday
387
+ @source.attributes[4].unique_name.should == :internal_id
388
+ end
389
+ end
390
+
391
+ describe "multiple sources" do
392
+ before :each do
393
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
394
+ define_source do
395
+ indexes first_name
396
+ has birthday
397
+ end
398
+
399
+ define_source do
400
+ indexes last_name
401
+ has :id, :as => :internal_id
402
+ end
403
+ end
404
+ end
405
+
406
+ it "should have two sources" do
407
+ @index.sources.length.should == 2
408
+ end
409
+
410
+ it "should have two fields" do
411
+ @index.fields.length.should == 2
412
+ end
413
+
414
+ it "should have one field in each source" do
415
+ @index.sources.each do |source|
416
+ source.fields.length.should == 1
417
+ end
418
+ end
419
+
420
+ it "should have two attributes alongside the six internal ones" do
421
+ @index.attributes.length.should == 8
422
+ end
423
+
424
+ it "should have one attribute in each source alongside the three internal ones" do
425
+ @index.sources.each do |source|
426
+ source.attributes.length.should == 4
427
+ end
428
+ end
429
+ end
430
+
431
+ describe "index options" do
432
+ before :each do
433
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
434
+ indexes first_name
435
+
436
+ set_property :charset_type => "utf16"
437
+ set_property :group_concat_max_len => 1024
438
+ end
439
+ end
440
+
441
+ it "should store the index setting for the index" do
442
+ @index.local_options[:charset_type].should == "utf16"
443
+ end
444
+
445
+ it "should store non-Sphinx settings for the index" do
446
+ @index.local_options[:group_concat_max_len].should == 1024
447
+ end
448
+ end
449
+
450
+ describe "delta options" do
451
+ before :each do
452
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
453
+ indexes first_name
454
+
455
+ set_property :delta => true
456
+ end
457
+ end
458
+
459
+ it "should not keep the delta setting in source options" do
460
+ @index.sources.first.options.should be_empty
461
+ end
462
+
463
+ it "should not keep the delta setting in index options" do
464
+ @index.local_options.should be_empty
465
+ end
466
+
467
+ it "should set the index delta object set" do
468
+ @index.delta_object.should be_a_kind_of(ThinkingSphinx::Deltas::DefaultDelta)
469
+ end
470
+ end
471
+
472
+ context 'index options' do
473
+ before :each do
474
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
475
+ indexes first_name
476
+
477
+ set_property :index_exact_words => true
478
+ end
479
+ end
480
+
481
+ it "should track the index_exact_words option to the index" do
482
+ @index.local_options[:index_exact_words].should be_true
483
+ end
484
+ end
485
+
486
+ context 'with an explicit name' do
487
+ it "should set the index's name using the provided value" do
488
+ index = ThinkingSphinx::Index::Builder.generate(Person, 'custom') do
489
+ indexes first_name
490
+ end
491
+
492
+ index.name.should == 'custom'
493
+ end
494
+ end
495
+ end