nixme-thinking-sphinx 0.9.7

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 (38) hide show
  1. data/LICENCE +20 -0
  2. data/README +52 -0
  3. data/lib/riddle.rb +22 -0
  4. data/lib/riddle/client.rb +593 -0
  5. data/lib/riddle/client/filter.rb +44 -0
  6. data/lib/riddle/client/message.rb +65 -0
  7. data/lib/riddle/client/response.rb +84 -0
  8. data/lib/test.rb +46 -0
  9. data/lib/thinking_sphinx.rb +82 -0
  10. data/lib/thinking_sphinx/active_record.rb +138 -0
  11. data/lib/thinking_sphinx/active_record/delta.rb +90 -0
  12. data/lib/thinking_sphinx/active_record/has_many_association.rb +29 -0
  13. data/lib/thinking_sphinx/active_record/search.rb +43 -0
  14. data/lib/thinking_sphinx/association.rb +140 -0
  15. data/lib/thinking_sphinx/attribute.rb +282 -0
  16. data/lib/thinking_sphinx/configuration.rb +277 -0
  17. data/lib/thinking_sphinx/field.rb +198 -0
  18. data/lib/thinking_sphinx/index.rb +334 -0
  19. data/lib/thinking_sphinx/index/builder.rb +212 -0
  20. data/lib/thinking_sphinx/index/faux_column.rb +97 -0
  21. data/lib/thinking_sphinx/rails_additions.rb +56 -0
  22. data/lib/thinking_sphinx/search.rb +455 -0
  23. data/spec/unit/thinking_sphinx/active_record/delta_spec.rb +185 -0
  24. data/spec/unit/thinking_sphinx/active_record/has_many_association_spec.rb +53 -0
  25. data/spec/unit/thinking_sphinx/active_record/search_spec.rb +81 -0
  26. data/spec/unit/thinking_sphinx/active_record_spec.rb +201 -0
  27. data/spec/unit/thinking_sphinx/association_spec.rb +247 -0
  28. data/spec/unit/thinking_sphinx/attribute_spec.rb +356 -0
  29. data/spec/unit/thinking_sphinx/configuration_spec.rb +476 -0
  30. data/spec/unit/thinking_sphinx/field_spec.rb +215 -0
  31. data/spec/unit/thinking_sphinx/index/builder_spec.rb +33 -0
  32. data/spec/unit/thinking_sphinx/index/faux_column_spec.rb +41 -0
  33. data/spec/unit/thinking_sphinx/index_spec.rb +230 -0
  34. data/spec/unit/thinking_sphinx/search_spec.rb +163 -0
  35. data/spec/unit/thinking_sphinx_spec.rb +107 -0
  36. data/tasks/thinking_sphinx_tasks.rake +1 -0
  37. data/tasks/thinking_sphinx_tasks.rb +86 -0
  38. metadata +90 -0
@@ -0,0 +1,215 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Field do
4
+ describe '#initialize' do
5
+ it 'raises if no columns are provided so that configuration errors are easier to track down' do
6
+ lambda {
7
+ ThinkingSphinx::Field.new([])
8
+ }.should raise_error(RuntimeError)
9
+ end
10
+
11
+ 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
+ lambda {
13
+ ThinkingSphinx::Field.new([1234])
14
+ }.should raise_error(RuntimeError)
15
+ end
16
+ end
17
+
18
+ describe "to_select_sql method with MySQL" do
19
+ before :each do
20
+ @index = Person.indexes.first
21
+ @index.link!
22
+ end
23
+
24
+ it "should concat with spaces if there are multiple columns" do
25
+ @index.fields.first.to_select_sql.should match(/CONCAT_WS\(' ', /)
26
+ end
27
+
28
+ it "should concat with spaces if a column has more than one association" do
29
+ @index.fields[1].to_select_sql.should match(/CONCAT_WS\(' ', /)
30
+ end
31
+
32
+ it "should group if any association for any column is a has_many or has_and_belongs_to_many" do
33
+ @index.fields[2].to_select_sql.should match(/GROUP_CONCAT/)
34
+ end
35
+ end
36
+
37
+ describe "to_select_sql method with PostgreSQL" do
38
+ before :each do
39
+ @index = Person.indexes.first
40
+ Person.connection.class.stub_method(
41
+ :name => "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
42
+ )
43
+ @index.link!
44
+ end
45
+
46
+ it "should concat with spaces if there are multiple columns" do
47
+ @index.fields.first.to_select_sql.should match(/|| ' ' ||/)
48
+ end
49
+
50
+ it "should concat with spaces if a column has more than one association" do
51
+ @index.fields[1].to_select_sql.should match(/|| ' ' ||/)
52
+ end
53
+
54
+ it "should group if any association for any column is a has_many or has_and_belongs_to_many" do
55
+ @index.fields[2].to_select_sql.should match(/array_to_string\(array_accum\(/)
56
+ end
57
+ end
58
+
59
+ describe "to_group_sql method" do
60
+ before :each do
61
+ @field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
62
+ @field.stub_methods(:is_many? => false)
63
+
64
+ ThinkingSphinx.stub_method(:use_group_by_shortcut? => false)
65
+ end
66
+
67
+ it "should return nil if is_many?" do
68
+ @field.stub_method(:is_many? => true)
69
+
70
+ @field.to_group_sql.should be_nil
71
+ end
72
+
73
+ it "should return nil if group_by shortcut is allowed" do
74
+ ThinkingSphinx.stub_method(:use_group_by_shortcut? => true)
75
+
76
+ @field.to_group_sql.should be_nil
77
+ end
78
+
79
+ it "should return an array if neither is_many? or shortcut allowed" do
80
+ @field.stub_method(:column_with_prefix => 'hello')
81
+ @field.to_group_sql.should be_a_kind_of(Array)
82
+ end
83
+ end
84
+
85
+ describe "unique_name method" do
86
+ before :each do
87
+ @field = ThinkingSphinx::Field.new [
88
+ Object.stub_instance(:__stack => [], :__name => "col_name")
89
+ ]
90
+ end
91
+
92
+ it "should use the alias if there is one" do
93
+ @field.alias = "alias"
94
+ @field.unique_name.should == "alias"
95
+ end
96
+
97
+ it "should use the alias if there's multiple columns" do
98
+ @field.columns << Object.stub_instance(:__stack => [], :__name => "col_name")
99
+ @field.unique_name.should be_nil
100
+
101
+ @field.alias = "alias"
102
+ @field.unique_name.should == "alias"
103
+ end
104
+
105
+ it "should use the column name if there's no alias and just one column" do
106
+ @field.unique_name.should == "col_name"
107
+ end
108
+ end
109
+
110
+ describe "prefixes method" do
111
+ it "should default to false" do
112
+ @field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
113
+ @field.prefixes.should be_false
114
+ end
115
+
116
+ it "should be true if the corresponding option is set" do
117
+ @field = ThinkingSphinx::Field.new(
118
+ [Object.stub_instance(:__stack => [])], :prefixes => true
119
+ )
120
+ @field.prefixes.should be_true
121
+ end
122
+ end
123
+
124
+ describe "infixes method" do
125
+ it "should default to false" do
126
+ @field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
127
+ @field.infixes.should be_false
128
+ end
129
+
130
+ it "should be true if the corresponding option is set" do
131
+ @field = ThinkingSphinx::Field.new(
132
+ [Object.stub_instance(:__stack => [])], :infixes => true
133
+ )
134
+ @field.infixes.should be_true
135
+ end
136
+ end
137
+
138
+ describe "quote_column_name method" do
139
+ it "should delegate the call to the model's connection" do
140
+ @field = ThinkingSphinx::Field.new [
141
+ ThinkingSphinx::Index::FauxColumn.new(:col_name)
142
+ ]
143
+ @field.model = Person
144
+ Person.connection.stub_method(:quote_column_name => "quoted!")
145
+
146
+ @field.send(:quote_column, "blah").should == "quoted!"
147
+ end
148
+ end
149
+
150
+ describe "column_with_prefix method" do
151
+ before :each do
152
+ @field = ThinkingSphinx::Field.new [
153
+ ThinkingSphinx::Index::FauxColumn.new(:col_name)
154
+ ]
155
+ @field.columns.each { |col| @field.associations[col] = [] }
156
+ @field.model = Person
157
+
158
+ @first_join = Object.stub_instance(:aliased_table_name => "tabular")
159
+ @second_join = Object.stub_instance(:aliased_table_name => "data")
160
+
161
+ @first_assoc = ThinkingSphinx::Association.stub_instance(:join => @first_join)
162
+ @second_assoc = ThinkingSphinx::Association.stub_instance(:join => @second_join)
163
+ end
164
+
165
+ it "should return the column with model's table prefix if there's no associations for the column" do
166
+ @field.send(:column_with_prefix, @field.columns.first).should == "`people`.`col_name`"
167
+ end
168
+
169
+ it "should return the column with its join table prefix if an association exists" do
170
+ column = @field.columns.first
171
+ @field.associations[column] = [@first_assoc]
172
+ @field.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
173
+ end
174
+
175
+ it "should return multiple columns concatenated if more than one association exists" do
176
+ column = @field.columns.first
177
+ @field.associations[column] = [@first_assoc, @second_assoc]
178
+ @field.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
179
+ end
180
+ end
181
+
182
+ describe "is_many? method" do
183
+ before :each do
184
+ @assoc_a = Object.stub_instance(:is_many? => true)
185
+ @assoc_b = Object.stub_instance(:is_many? => true)
186
+ @assoc_c = Object.stub_instance(:is_many? => true)
187
+
188
+ @field = ThinkingSphinx::Field.new(
189
+ [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
190
+ )
191
+ @field.associations = {
192
+ :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
193
+ }
194
+ end
195
+
196
+ it "should return true if all associations return true to is_many?" do
197
+ @field.send(:is_many?).should be_true
198
+ end
199
+
200
+ it "should return true if one association returns true to is_many?" do
201
+ @assoc_b.stub_method(:is_many? => false)
202
+ @assoc_c.stub_method(:is_many? => false)
203
+
204
+ @field.send(:is_many?).should be_true
205
+ end
206
+
207
+ it "should return false if all associations return false to is_many?" do
208
+ @assoc_a.stub_method(:is_many? => false)
209
+ @assoc_b.stub_method(:is_many? => false)
210
+ @assoc_c.stub_method(:is_many? => false)
211
+
212
+ @field.send(:is_many?).should be_false
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Index::Builder do
4
+ before :each do
5
+ @builder = Class.new(ThinkingSphinx::Index::Builder)
6
+ @builder.setup
7
+ end
8
+
9
+ describe "setup method" do
10
+ it "should set up the information arrays and properties hash" do
11
+ @builder.fields.should == []
12
+ @builder.attributes.should == []
13
+ @builder.conditions.should == []
14
+ @builder.properties.should == {}
15
+ end
16
+ end
17
+
18
+ describe "indexes method" do
19
+
20
+ end
21
+
22
+ describe "has method" do
23
+
24
+ end
25
+
26
+ describe "where method" do
27
+
28
+ end
29
+
30
+ describe "set_property method" do
31
+
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Index::FauxColumn do
4
+ it "should use the last argument as the name, with preceeding ones going into the stack" do
5
+ #
6
+ end
7
+
8
+ it "should access the name through __name" do
9
+ #
10
+ end
11
+
12
+ it "should access the stack through __stack" do
13
+ #
14
+ end
15
+
16
+ it "should return true from is_string? if the name is a string and the stack is empty" do
17
+ #
18
+ end
19
+
20
+ describe "method_missing calls with no arguments" do
21
+ it "should push any further method calls into name, and the old name goes into the stack" do
22
+ #
23
+ end
24
+
25
+ it "should return itself" do
26
+ #
27
+ end
28
+ end
29
+
30
+ describe "method_missing calls with one argument" do
31
+ it "should act as if calling method missing with method, then argument" do
32
+ #
33
+ end
34
+ end
35
+
36
+ describe "method_missing calls with more than one argument" do
37
+ it "should return a collection of Faux Columns sharing the same stack, but with each argument as the name" do
38
+ #
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,230 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Index do
4
+ describe "to_config method" do
5
+ before :each do
6
+ @index = ThinkingSphinx::Index.new(Person)
7
+
8
+ @index.stub_methods(
9
+ :attributes => [
10
+ ThinkingSphinx::Attribute.stub_instance(:to_sphinx_clause => "attr a"),
11
+ ThinkingSphinx::Attribute.stub_instance(:to_sphinx_clause => "attr b")
12
+ ],
13
+ :link! => true,
14
+ :adapter => :mysql,
15
+ :to_sql_query_pre => "sql_query_pre",
16
+ :to_sql => "SQL",
17
+ :to_sql_query_range => "sql_query_range",
18
+ :to_sql_query_info => "sql_query_info",
19
+ :delta? => false
20
+ )
21
+
22
+ @database = {
23
+ :host => "localhost",
24
+ :username => "username",
25
+ :password => "blank",
26
+ :database => "db"
27
+ }
28
+ end
29
+
30
+ it "should call link!" do
31
+ @index.to_config(0, @database, "utf-8")
32
+
33
+ @index.should have_received(:link!)
34
+ end
35
+
36
+ it "should raise an exception if the adapter isn't mysql or postgres" do
37
+ @index.stub_method(:adapter => :sqlite)
38
+
39
+ lambda { @index.to_config(0, @database, "utf-8") }.should raise_error
40
+ end
41
+
42
+ it "should set the core source name to {model}_{index}_core" do
43
+ @index.to_config(0, @database, "utf-8").should match(
44
+ /source person_0_core/
45
+ )
46
+ end
47
+
48
+ it "should include the database config supplied" do
49
+ conf = @index.to_config(0, @database, "utf-8")
50
+ conf.should match(/type\s+= mysql/)
51
+ conf.should match(/sql_host\s+= localhost/)
52
+ conf.should match(/sql_user\s+= username/)
53
+ conf.should match(/sql_pass\s+= blank/)
54
+ conf.should match(/sql_db\s+= db/)
55
+ end
56
+
57
+ it "should have a pre query 'SET NAMES utf8' if using mysql and utf8 charset" do
58
+ @index.to_config(0, @database, "utf-8").should match(
59
+ /sql_query_pre\s+= SET NAMES utf8/
60
+ )
61
+
62
+ @index.stub_method(:delta? => true)
63
+ @index.to_config(0, @database, "utf-8").should match(
64
+ /source person_0_delta.+sql_query_pre\s+= SET NAMES utf8/m
65
+ )
66
+
67
+ @index.stub_method(:delta? => false)
68
+ @index.to_config(0, @database, "non-utf-8").should_not match(
69
+ /SET NAMES utf8/
70
+ )
71
+
72
+ @index.stub_method(:adapter => :postgres)
73
+ @index.to_config(0, @database, "utf-8").should_not match(
74
+ /SET NAMES utf8/
75
+ )
76
+ end
77
+
78
+ it "should use the pre query from the index" do
79
+ @index.to_config(0, @database, "utf-8").should match(
80
+ /sql_query_pre\s+= sql_query_pre/
81
+ )
82
+ end
83
+
84
+ it "should not set group_concat_max_len if not specified" do
85
+ @index.to_config(0, @database, "utf-8").should_not match(
86
+ /group_concat_max_len/
87
+ )
88
+ end
89
+
90
+ it "should set group_concat_max_len if specified" do
91
+ @index.options.merge! :group_concat_max_len => 2056
92
+ @index.to_config(0, @database, "utf-8").should match(
93
+ /sql_query_pre\s+= SET SESSION group_concat_max_len = 2056/
94
+ )
95
+
96
+ @index.stub_method(:delta? => true)
97
+ @index.to_config(0, @database, "utf-8").should match(
98
+ /source person_0_delta.+sql_query_pre\s+= SET SESSION group_concat_max_len = 2056/m
99
+ )
100
+ end
101
+
102
+ it "should use the main query from the index" do
103
+ @index.to_config(0, @database, "utf-8").should match(
104
+ /sql_query\s+= SQL/
105
+ )
106
+ end
107
+
108
+ it "should use the range query from the index" do
109
+ @index.to_config(0, @database, "utf-8").should match(
110
+ /sql_query_range\s+= sql_query_range/
111
+ )
112
+ end
113
+
114
+ it "should use the info query from the index" do
115
+ @index.to_config(0, @database, "utf-8").should match(
116
+ /sql_query_info\s+= sql_query_info/
117
+ )
118
+ end
119
+
120
+ it "should include the attribute sources" do
121
+ @index.to_config(0, @database, "utf-8").should match(
122
+ /attr a\n\s+attr b/
123
+ )
124
+ end
125
+
126
+ it "should add a delta index with name {model}_{index}_delta if requested" do
127
+ @index.stub_method(:delta? => true)
128
+
129
+ @index.to_config(0, @database, "utf-8").should match(
130
+ /source person_0_delta/
131
+ )
132
+ end
133
+
134
+ it "should not add a delta index unless requested" do
135
+ @index.to_config(0, @database, "utf-8").should_not match(
136
+ /source person_0_delta/
137
+ )
138
+ end
139
+
140
+ it "should have the delta index inherit from the core index" do
141
+ @index.stub_method(:delta? => true)
142
+
143
+ @index.to_config(0, @database, "utf-8").should match(
144
+ /source person_0_delta : person_0_core/
145
+ )
146
+ end
147
+
148
+ it "should redefine the main query for the delta index" do
149
+ @index.stub_method(:delta? => true)
150
+
151
+ @index.to_config(0, @database, "utf-8").should match(
152
+ /source person_0_delta.+sql_query\s+= SQL/m
153
+ )
154
+ end
155
+
156
+ it "should redefine the range query for the delta index" do
157
+ @index.stub_method(:delta? => true)
158
+
159
+ @index.to_config(0, @database, "utf-8").should match(
160
+ /source person_0_delta.+sql_query_range\s+= sql_query_range/m
161
+ )
162
+ end
163
+
164
+ it "should redefine the pre query for the delta index" do
165
+ @index.stub_method(:delta? => true)
166
+
167
+ @index.to_config(0, @database, "utf-8").should match(
168
+ /source person_0_delta.+sql_query_pre\s+=\s*\n/m
169
+ )
170
+ end
171
+ end
172
+
173
+ describe "to_sql_query_range method" do
174
+ before :each do
175
+ @index = ThinkingSphinx::Index.new(Person)
176
+ end
177
+
178
+ it "should add COALESCE around MIN and MAX calls if using PostgreSQL" do
179
+ @index.stub_method(:adapter => :postgres)
180
+
181
+ @index.to_sql_query_range.should match(/COALESCE\(MIN.+COALESCE\(MAX/)
182
+ end
183
+
184
+ it "shouldn't add COALESCE if using MySQL" do
185
+ @index.to_sql_query_range.should_not match(/COALESCE/)
186
+ end
187
+ end
188
+
189
+ describe "prefix_fields method" do
190
+ before :each do
191
+ @index = ThinkingSphinx::Index.new(Person)
192
+
193
+ @field_a = ThinkingSphinx::Field.stub_instance(:prefixes => true)
194
+ @field_b = ThinkingSphinx::Field.stub_instance(:prefixes => false)
195
+ @field_c = ThinkingSphinx::Field.stub_instance(:prefixes => true)
196
+
197
+ @index.fields = [@field_a, @field_b, @field_c]
198
+ end
199
+
200
+ it "should return fields that are flagged as prefixed" do
201
+ @index.prefix_fields.should include(@field_a)
202
+ @index.prefix_fields.should include(@field_c)
203
+ end
204
+
205
+ it "should not return fields that aren't flagged as prefixed" do
206
+ @index.prefix_fields.should_not include(@field_b)
207
+ end
208
+ end
209
+
210
+ describe "infix_fields" do
211
+ before :each do
212
+ @index = ThinkingSphinx::Index.new(Person)
213
+
214
+ @field_a = ThinkingSphinx::Field.stub_instance(:infixes => true)
215
+ @field_b = ThinkingSphinx::Field.stub_instance(:infixes => false)
216
+ @field_c = ThinkingSphinx::Field.stub_instance(:infixes => true)
217
+
218
+ @index.fields = [@field_a, @field_b, @field_c]
219
+ end
220
+
221
+ it "should return fields that are flagged as infixed" do
222
+ @index.infix_fields.should include(@field_a)
223
+ @index.infix_fields.should include(@field_c)
224
+ end
225
+
226
+ it "should not return fields that aren't flagged as infixed" do
227
+ @index.infix_fields.should_not include(@field_b)
228
+ end
229
+ end
230
+ end