DrMark-thinking-sphinx 1.1.6 → 1.1.14

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 (40) hide show
  1. data/{README → README.textile} +84 -84
  2. data/lib/thinking_sphinx/active_record/attribute_updates.rb +48 -0
  3. data/lib/thinking_sphinx/active_record/delta.rb +10 -1
  4. data/lib/thinking_sphinx/active_record.rb +10 -3
  5. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +1 -1
  6. data/lib/thinking_sphinx/attribute.rb +44 -134
  7. data/lib/thinking_sphinx/class_facet.rb +15 -0
  8. data/lib/thinking_sphinx/collection.rb +1 -0
  9. data/lib/thinking_sphinx/configuration.rb +7 -3
  10. data/lib/thinking_sphinx/deltas/datetime_delta.rb +1 -1
  11. data/lib/thinking_sphinx/deltas/default_delta.rb +3 -2
  12. data/lib/thinking_sphinx/deltas/delayed_delta.rb +4 -2
  13. data/lib/thinking_sphinx/deltas.rb +9 -6
  14. data/lib/thinking_sphinx/deploy/capistrano.rb +82 -0
  15. data/lib/thinking_sphinx/facet.rb +68 -18
  16. data/lib/thinking_sphinx/facet_collection.rb +16 -17
  17. data/lib/thinking_sphinx/field.rb +7 -97
  18. data/lib/thinking_sphinx/index/builder.rb +255 -232
  19. data/lib/thinking_sphinx/index.rb +37 -349
  20. data/lib/thinking_sphinx/property.rb +160 -0
  21. data/lib/thinking_sphinx/search/facets.rb +98 -0
  22. data/lib/thinking_sphinx/search.rb +4 -73
  23. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  24. data/lib/thinking_sphinx/source/sql.rb +124 -0
  25. data/lib/thinking_sphinx/source.rb +150 -0
  26. data/lib/thinking_sphinx/tasks.rb +1 -1
  27. data/lib/thinking_sphinx.rb +3 -1
  28. data/spec/unit/thinking_sphinx/active_record_spec.rb +14 -12
  29. data/spec/unit/thinking_sphinx/attribute_spec.rb +16 -11
  30. data/spec/unit/thinking_sphinx/facet_collection_spec.rb +64 -0
  31. data/spec/unit/thinking_sphinx/facet_spec.rb +278 -0
  32. data/spec/unit/thinking_sphinx/field_spec.rb +18 -9
  33. data/spec/unit/thinking_sphinx/index/builder_spec.rb +347 -1
  34. data/spec/unit/thinking_sphinx/index_spec.rb +22 -27
  35. data/spec/unit/thinking_sphinx/rails_additions_spec.rb +183 -0
  36. data/spec/unit/thinking_sphinx/search_spec.rb +71 -0
  37. data/spec/unit/thinking_sphinx/source_spec.rb +156 -0
  38. data/tasks/distribution.rb +1 -1
  39. data/tasks/testing.rb +7 -15
  40. metadata +19 -3
@@ -0,0 +1,278 @@
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
+ ThinkingSphinx::Attribute.stub_instance(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(: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_method(:type => :anything)
274
+
275
+ ThinkingSphinx::Facet.new(attribute).type.should == :anything
276
+ end
277
+ end
278
+ end
@@ -1,23 +1,28 @@
1
1
  require 'spec/spec_helper'
2
2
 
3
3
  describe ThinkingSphinx::Field do
4
+ before :each do
5
+ @index = ThinkingSphinx::Index.new(Alpha)
6
+ @source = ThinkingSphinx::Source.new(@index)
7
+ end
8
+
4
9
  describe '#initialize' do
5
10
  it 'raises if no columns are provided so that configuration errors are easier to track down' do
6
11
  lambda {
7
- ThinkingSphinx::Field.new([])
12
+ ThinkingSphinx::Field.new(@source, [])
8
13
  }.should raise_error(RuntimeError)
9
14
  end
10
15
 
11
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
12
17
  lambda {
13
- ThinkingSphinx::Field.new([1234])
18
+ ThinkingSphinx::Field.new(@source, [1234])
14
19
  }.should raise_error(RuntimeError)
15
20
  end
16
21
  end
17
22
 
18
23
  describe "unique_name method" do
19
24
  before :each do
20
- @field = ThinkingSphinx::Field.new [
25
+ @field = ThinkingSphinx::Field.new @source, [
21
26
  Object.stub_instance(:__stack => [], :__name => "col_name")
22
27
  ]
23
28
  end
@@ -42,13 +47,15 @@ describe ThinkingSphinx::Field do
42
47
 
43
48
  describe "prefixes method" do
44
49
  it "should default to false" do
45
- @field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
50
+ @field = ThinkingSphinx::Field.new(
51
+ @source, [Object.stub_instance(:__stack => [])]
52
+ )
46
53
  @field.prefixes.should be_false
47
54
  end
48
55
 
49
56
  it "should be true if the corresponding option is set" do
50
57
  @field = ThinkingSphinx::Field.new(
51
- [Object.stub_instance(:__stack => [])], :prefixes => true
58
+ @source, [Object.stub_instance(:__stack => [])], :prefixes => true
52
59
  )
53
60
  @field.prefixes.should be_true
54
61
  end
@@ -56,13 +63,15 @@ describe ThinkingSphinx::Field do
56
63
 
57
64
  describe "infixes method" do
58
65
  it "should default to false" do
59
- @field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
66
+ @field = ThinkingSphinx::Field.new(
67
+ @source, [Object.stub_instance(:__stack => [])]
68
+ )
60
69
  @field.infixes.should be_false
61
70
  end
62
71
 
63
72
  it "should be true if the corresponding option is set" do
64
73
  @field = ThinkingSphinx::Field.new(
65
- [Object.stub_instance(:__stack => [])], :infixes => true
74
+ @source, [Object.stub_instance(:__stack => [])], :infixes => true
66
75
  )
67
76
  @field.infixes.should be_true
68
77
  end
@@ -70,7 +79,7 @@ describe ThinkingSphinx::Field do
70
79
 
71
80
  describe "column_with_prefix method" do
72
81
  before :each do
73
- @field = ThinkingSphinx::Field.new [
82
+ @field = ThinkingSphinx::Field.new @source, [
74
83
  ThinkingSphinx::Index::FauxColumn.new(:col_name)
75
84
  ]
76
85
  @field.columns.each { |col| @field.associations[col] = [] }
@@ -116,7 +125,7 @@ describe ThinkingSphinx::Field do
116
125
  @assoc_c = Object.stub_instance(:is_many? => true)
117
126
 
118
127
  @field = ThinkingSphinx::Field.new(
119
- [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
128
+ @source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
120
129
  )
121
130
  @field.associations = {
122
131
  :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
@@ -1,5 +1,351 @@
1
1
  require 'spec/spec_helper'
2
2
 
3
3
  describe ThinkingSphinx::Index::Builder do
4
- #
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 four internal ones" do
35
+ @source.attributes.length.should == 6
36
+ @source.attributes[4].unique_name.should == :birthday
37
+ @source.attributes[5].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 "sortable field" do
57
+ before :each do
58
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
59
+ indexes first_name, :sortable => true
60
+ end
61
+
62
+ @source = @index.sources.first
63
+ end
64
+
65
+ it "should have one field" do
66
+ @source.fields.length.should == 1
67
+ end
68
+
69
+ it "should have one attribute alongside the four internal ones" do
70
+ @source.attributes.length.should == 5
71
+ end
72
+
73
+ it "should set the attribute name to have the _sort suffix" do
74
+ @source.attributes.last.unique_name.should == :first_name_sort
75
+ end
76
+
77
+ it "should set the attribute column to be the same as the field" do
78
+ @source.attributes.last.columns.length.should == 1
79
+ @source.attributes.last.columns.first.__name.should == :first_name
80
+ end
81
+ end
82
+
83
+ describe "faceted field" do
84
+ before :each do
85
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
86
+ indexes first_name, :facet => true
87
+ end
88
+
89
+ @source = @index.sources.first
90
+ end
91
+
92
+ after :each do
93
+ Person.sphinx_facets.delete_at(-1)
94
+ end
95
+
96
+ it "should have one field" do
97
+ @source.fields.length.should == 1
98
+ end
99
+
100
+ it "should have one attribute alongside the four internal ones" do
101
+ @source.attributes.length.should == 5
102
+ end
103
+
104
+ it "should set the attribute name to have the _facet suffix" do
105
+ @source.attributes.last.unique_name.should == :first_name_facet
106
+ end
107
+
108
+ it "should set the attribute type to integer" do
109
+ @source.attributes.last.type.should == :integer
110
+ end
111
+
112
+ it "should set the attribute column to be the same as the field" do
113
+ @source.attributes.last.columns.length.should == 1
114
+ @source.attributes.last.columns.first.__name.should == :first_name
115
+ end
116
+ end
117
+
118
+ describe "faceted integer attribute" do
119
+ before :each do
120
+ @index = ThinkingSphinx::Index::Builder.generate(Alpha) do
121
+ indexes :name
122
+ has value, :facet => true
123
+ end
124
+
125
+ @source = @index.sources.first
126
+ end
127
+
128
+ after :each do
129
+ Alpha.sphinx_facets.delete_at(-1)
130
+ end
131
+
132
+ it "should have just one attribute alongside the four internal ones" do
133
+ @source.attributes.length.should == 5
134
+ end
135
+ end
136
+
137
+ describe "faceted timestamp attribute" do
138
+ before :each do
139
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
140
+ indexes first_name
141
+ has birthday, :facet => true
142
+ end
143
+
144
+ @source = @index.sources.first
145
+ end
146
+
147
+ after :each do
148
+ Person.sphinx_facets.delete_at(-1)
149
+ end
150
+
151
+ it "should have just one attribute alongside the four internal ones" do
152
+ @source.attributes.length.should == 5
153
+ end
154
+ end
155
+
156
+ describe "faceted boolean attribute" do
157
+ before :each do
158
+ @index = ThinkingSphinx::Index::Builder.generate(Beta) do
159
+ indexes :name
160
+ has delta, :facet => true
161
+ end
162
+
163
+ @source = @index.sources.first
164
+ end
165
+
166
+ after :each do
167
+ Beta.sphinx_facets.delete_at(-1)
168
+ end
169
+
170
+ it "should have just one attribute alongside the four internal ones" do
171
+ @source.attributes.length.should == 5
172
+ end
173
+ end
174
+
175
+ describe "faceted float attribute" do
176
+ before :each do
177
+ @index = ThinkingSphinx::Index::Builder.generate(Alpha) do
178
+ indexes :name
179
+ has cost, :facet => true
180
+ end
181
+
182
+ @source = @index.sources.first
183
+ end
184
+
185
+ after :each do
186
+ Alpha.sphinx_facets.delete_at(-1)
187
+ end
188
+
189
+ it "should have just one attribute alongside the four internal ones" do
190
+ @source.attributes.length.should == 5
191
+ end
192
+ end
193
+
194
+ describe "faceted string attribute" do
195
+ before :each do
196
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
197
+ indexes first_name
198
+ has last_name, :facet => true
199
+ end
200
+
201
+ @source = @index.sources.first
202
+ end
203
+
204
+ after :each do
205
+ Person.sphinx_facets.delete_at(-1)
206
+ end
207
+
208
+ it "should have two attributes alongside the four internal ones" do
209
+ @source.attributes.length.should == 6
210
+ end
211
+
212
+ it "should set the facet attribute name to have the _facet suffix" do
213
+ @source.attributes.last.unique_name.should == :last_name_facet
214
+ end
215
+
216
+ it "should set the attribute type to integer" do
217
+ @source.attributes.last.type.should == :integer
218
+ end
219
+
220
+ it "should set the attribute column to be the same as the field" do
221
+ @source.attributes.last.columns.length.should == 1
222
+ @source.attributes.last.columns.first.__name.should == :last_name
223
+ end
224
+ end
225
+
226
+ describe "no fields" do
227
+ it "should raise an exception" do
228
+ lambda {
229
+ ThinkingSphinx::Index::Builder.generate(Person) do
230
+ #
231
+ end
232
+ }.should raise_error
233
+ end
234
+ end
235
+
236
+ describe "explicit source" do
237
+ before :each do
238
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
239
+ define_source do
240
+ indexes first_name, last_name
241
+ has birthday
242
+ has id, :as => :internal_id
243
+
244
+ set_property :delta => true
245
+
246
+ where "birthday <= NOW()"
247
+ group_by "first_name"
248
+ end
249
+ end
250
+
251
+ @source = @index.sources.first
252
+ end
253
+
254
+ it "should return an index" do
255
+ @index.should be_a_kind_of(ThinkingSphinx::Index)
256
+ end
257
+
258
+ it "should have one source for the index" do
259
+ @index.sources.length.should == 1
260
+ end
261
+
262
+ it "should have two fields" do
263
+ @source.fields.length.should == 2
264
+ @source.fields[0].unique_name.should == :first_name
265
+ @source.fields[1].unique_name.should == :last_name
266
+ end
267
+
268
+ it "should have two attributes alongside the four internal ones" do
269
+ @source.attributes.length.should == 6
270
+ @source.attributes[4].unique_name.should == :birthday
271
+ @source.attributes[5].unique_name.should == :internal_id
272
+ end
273
+ end
274
+
275
+ describe "multiple sources" do
276
+ before :each do
277
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
278
+ define_source do
279
+ indexes first_name
280
+ has birthday
281
+ end
282
+
283
+ define_source do
284
+ indexes last_name
285
+ has :id, :as => :internal_id
286
+ end
287
+ end
288
+ end
289
+
290
+ it "should have two sources" do
291
+ @index.sources.length.should == 2
292
+ end
293
+
294
+ it "should have two fields" do
295
+ @index.fields.length.should == 2
296
+ end
297
+
298
+ it "should have one field in each source" do
299
+ @index.sources.each do |source|
300
+ source.fields.length.should == 1
301
+ end
302
+ end
303
+
304
+ it "should have two attributes alongside the eight internal ones" do
305
+ @index.attributes.length.should == 10
306
+ end
307
+
308
+ it "should have one attribute in each source alongside the four internal ones" do
309
+ @index.sources.each do |source|
310
+ source.attributes.length.should == 5
311
+ end
312
+ end
313
+ end
314
+
315
+ describe "index options" do
316
+ before :each do
317
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
318
+ indexes first_name
319
+
320
+ set_property :charset_type => "utf16"
321
+ end
322
+ end
323
+
324
+ it "should store the setting for the index" do
325
+ @index.local_options.length.should == 1
326
+ @index.local_options[:charset_type].should == "utf16"
327
+ end
328
+ end
329
+
330
+ describe "delta options" do
331
+ before :each do
332
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
333
+ indexes first_name
334
+
335
+ set_property :delta => true
336
+ end
337
+ end
338
+
339
+ it "should not keep the delta setting in source options" do
340
+ @index.sources.first.options.should be_empty
341
+ end
342
+
343
+ it "should not keep the delta setting in index options" do
344
+ @index.local_options.should be_empty
345
+ end
346
+
347
+ it "should set the index delta object set" do
348
+ @index.delta_object.should be_a_kind_of(ThinkingSphinx::Deltas::DefaultDelta)
349
+ end
350
+ end
5
351
  end