nixme-thinking-sphinx 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
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