dpickett-thinking-sphinx 1.1.4

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 (79) hide show
  1. data/LICENCE +20 -0
  2. data/README +107 -0
  3. data/lib/thinking_sphinx/active_record/delta.rb +74 -0
  4. data/lib/thinking_sphinx/active_record/has_many_association.rb +29 -0
  5. data/lib/thinking_sphinx/active_record/search.rb +57 -0
  6. data/lib/thinking_sphinx/active_record.rb +245 -0
  7. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +34 -0
  8. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +53 -0
  9. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +129 -0
  10. data/lib/thinking_sphinx/association.rb +144 -0
  11. data/lib/thinking_sphinx/attribute.rb +254 -0
  12. data/lib/thinking_sphinx/class_facet.rb +20 -0
  13. data/lib/thinking_sphinx/collection.rb +142 -0
  14. data/lib/thinking_sphinx/configuration.rb +236 -0
  15. data/lib/thinking_sphinx/core/string.rb +22 -0
  16. data/lib/thinking_sphinx/deltas/datetime_delta.rb +50 -0
  17. data/lib/thinking_sphinx/deltas/default_delta.rb +65 -0
  18. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +24 -0
  19. data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +27 -0
  20. data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +26 -0
  21. data/lib/thinking_sphinx/deltas/delayed_delta.rb +25 -0
  22. data/lib/thinking_sphinx/deltas.rb +22 -0
  23. data/lib/thinking_sphinx/facet.rb +58 -0
  24. data/lib/thinking_sphinx/facet_collection.rb +45 -0
  25. data/lib/thinking_sphinx/field.rb +172 -0
  26. data/lib/thinking_sphinx/index/builder.rb +233 -0
  27. data/lib/thinking_sphinx/index/faux_column.rb +110 -0
  28. data/lib/thinking_sphinx/index.rb +432 -0
  29. data/lib/thinking_sphinx/rails_additions.rb +133 -0
  30. data/lib/thinking_sphinx/search.rb +654 -0
  31. data/lib/thinking_sphinx/tasks.rb +128 -0
  32. data/lib/thinking_sphinx.rb +145 -0
  33. data/spec/unit/thinking_sphinx/active_record/delta_spec.rb +136 -0
  34. data/spec/unit/thinking_sphinx/active_record/has_many_association_spec.rb +53 -0
  35. data/spec/unit/thinking_sphinx/active_record/search_spec.rb +107 -0
  36. data/spec/unit/thinking_sphinx/active_record_spec.rb +256 -0
  37. data/spec/unit/thinking_sphinx/association_spec.rb +247 -0
  38. data/spec/unit/thinking_sphinx/attribute_spec.rb +212 -0
  39. data/spec/unit/thinking_sphinx/collection_spec.rb +14 -0
  40. data/spec/unit/thinking_sphinx/configuration_spec.rb +136 -0
  41. data/spec/unit/thinking_sphinx/core/string_spec.rb +9 -0
  42. data/spec/unit/thinking_sphinx/field_spec.rb +145 -0
  43. data/spec/unit/thinking_sphinx/index/builder_spec.rb +5 -0
  44. data/spec/unit/thinking_sphinx/index/faux_column_spec.rb +30 -0
  45. data/spec/unit/thinking_sphinx/index_spec.rb +54 -0
  46. data/spec/unit/thinking_sphinx/search_spec.rb +59 -0
  47. data/spec/unit/thinking_sphinx_spec.rb +129 -0
  48. data/tasks/distribution.rb +48 -0
  49. data/tasks/rails.rake +1 -0
  50. data/tasks/testing.rb +86 -0
  51. data/vendor/after_commit/LICENSE +20 -0
  52. data/vendor/after_commit/README +16 -0
  53. data/vendor/after_commit/Rakefile +22 -0
  54. data/vendor/after_commit/init.rb +5 -0
  55. data/vendor/after_commit/lib/after_commit/active_record.rb +91 -0
  56. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +103 -0
  57. data/vendor/after_commit/lib/after_commit.rb +42 -0
  58. data/vendor/after_commit/test/after_commit_test.rb +53 -0
  59. data/vendor/delayed_job/lib/delayed/job.rb +251 -0
  60. data/vendor/delayed_job/lib/delayed/message_sending.rb +7 -0
  61. data/vendor/delayed_job/lib/delayed/performable_method.rb +55 -0
  62. data/vendor/delayed_job/lib/delayed/worker.rb +54 -0
  63. data/vendor/riddle/lib/riddle/client/filter.rb +53 -0
  64. data/vendor/riddle/lib/riddle/client/message.rb +65 -0
  65. data/vendor/riddle/lib/riddle/client/response.rb +84 -0
  66. data/vendor/riddle/lib/riddle/client.rb +619 -0
  67. data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +48 -0
  68. data/vendor/riddle/lib/riddle/configuration/index.rb +142 -0
  69. data/vendor/riddle/lib/riddle/configuration/indexer.rb +19 -0
  70. data/vendor/riddle/lib/riddle/configuration/remote_index.rb +17 -0
  71. data/vendor/riddle/lib/riddle/configuration/searchd.rb +25 -0
  72. data/vendor/riddle/lib/riddle/configuration/section.rb +37 -0
  73. data/vendor/riddle/lib/riddle/configuration/source.rb +23 -0
  74. data/vendor/riddle/lib/riddle/configuration/sql_source.rb +34 -0
  75. data/vendor/riddle/lib/riddle/configuration/xml_source.rb +28 -0
  76. data/vendor/riddle/lib/riddle/configuration.rb +33 -0
  77. data/vendor/riddle/lib/riddle/controller.rb +44 -0
  78. data/vendor/riddle/lib/riddle.rb +30 -0
  79. metadata +158 -0
@@ -0,0 +1,212 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Attribute 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::Attribute.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::Attribute.new([1234])
14
+ }.should raise_error(RuntimeError)
15
+ end
16
+ end
17
+
18
+ describe "unique_name method" do
19
+ before :each do
20
+ @attribute = ThinkingSphinx::Attribute.new [
21
+ Object.stub_instance(:__stack => [], :__name => "col_name")
22
+ ]
23
+ end
24
+
25
+ it "should use the alias if there is one" do
26
+ @attribute.alias = "alias"
27
+ @attribute.unique_name.should == "alias"
28
+ end
29
+
30
+ it "should use the alias if there's multiple columns" do
31
+ @attribute.columns << Object.stub_instance(:__stack => [], :__name => "col_name")
32
+ @attribute.unique_name.should be_nil
33
+
34
+ @attribute.alias = "alias"
35
+ @attribute.unique_name.should == "alias"
36
+ end
37
+
38
+ it "should use the column name if there's no alias and just one column" do
39
+ @attribute.unique_name.should == "col_name"
40
+ end
41
+ end
42
+
43
+ describe "column_with_prefix method" do
44
+ before :each do
45
+ @attribute = ThinkingSphinx::Attribute.new [
46
+ ThinkingSphinx::Index::FauxColumn.new(:col_name)
47
+ ]
48
+ @attribute.columns.each { |col| @attribute.associations[col] = [] }
49
+ @attribute.model = Person
50
+
51
+ @first_join = Object.stub_instance(:aliased_table_name => "tabular")
52
+ @second_join = Object.stub_instance(:aliased_table_name => "data")
53
+
54
+ @first_assoc = ThinkingSphinx::Association.stub_instance(
55
+ :join => @first_join, :has_column? => true
56
+ )
57
+ @second_assoc = ThinkingSphinx::Association.stub_instance(
58
+ :join => @second_join, :has_column? => true
59
+ )
60
+ end
61
+
62
+ it "should return the column name if the column is a string" do
63
+ @attribute.columns = [ThinkingSphinx::Index::FauxColumn.new("string")]
64
+ @attribute.send(:column_with_prefix, @attribute.columns.first).should == "string"
65
+ end
66
+
67
+ it "should return the column with model's table prefix if there's no associations for the column" do
68
+ @attribute.send(:column_with_prefix, @attribute.columns.first).should == "`people`.`col_name`"
69
+ end
70
+
71
+ it "should return the column with its join table prefix if an association exists" do
72
+ column = @attribute.columns.first
73
+ @attribute.associations[column] = [@first_assoc]
74
+ @attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
75
+ end
76
+
77
+ it "should return multiple columns concatenated if more than one association exists" do
78
+ column = @attribute.columns.first
79
+ @attribute.associations[column] = [@first_assoc, @second_assoc]
80
+ @attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
81
+ end
82
+ end
83
+
84
+ describe "is_many? method" do
85
+ before :each do
86
+ @assoc_a = Object.stub_instance(:is_many? => true)
87
+ @assoc_b = Object.stub_instance(:is_many? => true)
88
+ @assoc_c = Object.stub_instance(:is_many? => true)
89
+
90
+ @attribute = ThinkingSphinx::Attribute.new(
91
+ [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
92
+ )
93
+ @attribute.associations = {
94
+ :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
95
+ }
96
+ end
97
+
98
+ it "should return true if all associations return true to is_many?" do
99
+ @attribute.send(:is_many?).should be_true
100
+ end
101
+
102
+ it "should return true if one association returns true to is_many?" do
103
+ @assoc_b.stub_method(:is_many? => false)
104
+ @assoc_c.stub_method(:is_many? => false)
105
+
106
+ @attribute.send(:is_many?).should be_true
107
+ end
108
+
109
+ it "should return false if all associations return false to is_many?" do
110
+ @assoc_a.stub_method(:is_many? => false)
111
+ @assoc_b.stub_method(:is_many? => false)
112
+ @assoc_c.stub_method(:is_many? => false)
113
+
114
+ @attribute.send(:is_many?).should be_false
115
+ end
116
+ end
117
+
118
+ describe "is_string? method" do
119
+ before :each do
120
+ @col_a = ThinkingSphinx::Index::FauxColumn.new("a")
121
+ @col_b = ThinkingSphinx::Index::FauxColumn.new("b")
122
+ @col_c = ThinkingSphinx::Index::FauxColumn.new("c")
123
+
124
+ @attribute = ThinkingSphinx::Attribute.new(
125
+ [@col_a, @col_b, @col_c]
126
+ )
127
+ end
128
+
129
+ it "should return true if all columns return true to is_string?" do
130
+ @attribute.send(:is_string?).should be_true
131
+ end
132
+
133
+ it "should return false if one column returns true to is_string?" do
134
+ @col_a.send(:instance_variable_set, :@name, :a)
135
+ @attribute.send(:is_string?).should be_false
136
+ end
137
+
138
+ it "should return false if all columns return false to is_string?" do
139
+ @col_a.send(:instance_variable_set, :@name, :a)
140
+ @col_b.send(:instance_variable_set, :@name, :b)
141
+ @col_c.send(:instance_variable_set, :@name, :c)
142
+ @attribute.send(:is_string?).should be_false
143
+ end
144
+ end
145
+
146
+ describe "type method" do
147
+ before :each do
148
+ @column = ThinkingSphinx::Index::FauxColumn.new(:col_name)
149
+ @attribute = ThinkingSphinx::Attribute.new([@column])
150
+ @attribute.model = Person
151
+ @attribute.stub_method(:is_many? => false)
152
+ end
153
+
154
+ it "should return :multi if is_many? is true" do
155
+ @attribute.stub_method(:is_many? => true)
156
+ @attribute.send(:type).should == :multi
157
+ end
158
+
159
+ it "should return :string if there's more than one association" do
160
+ @attribute.associations = {:a => :assoc, :b => :assoc}
161
+ @attribute.send(:type).should == :string
162
+ end
163
+
164
+ it "should return the column type from the database if not :multi or more than one association" do
165
+ @column.send(:instance_variable_set, :@name, "birthday")
166
+ @attribute.send(:type).should == :datetime
167
+
168
+ @attribute.send(:instance_variable_set, :@type, nil)
169
+ @column.send(:instance_variable_set, :@name, "first_name")
170
+ @attribute.send(:type).should == :string
171
+
172
+ @attribute.send(:instance_variable_set, :@type, nil)
173
+ @column.send(:instance_variable_set, :@name, "id")
174
+ @attribute.send(:type).should == :integer
175
+ end
176
+ end
177
+
178
+ describe "all_ints? method" do
179
+ it "should return true if all columns are integers" do
180
+ attribute = ThinkingSphinx::Attribute.new(
181
+ [ ThinkingSphinx::Index::FauxColumn.new(:id),
182
+ ThinkingSphinx::Index::FauxColumn.new(:team_id) ]
183
+ )
184
+ attribute.model = Person
185
+ attribute.columns.each { |col| attribute.associations[col] = [] }
186
+
187
+ attribute.send(:all_ints?).should be_true
188
+ end
189
+
190
+ it "should return false if only some columns are integers" do
191
+ attribute = ThinkingSphinx::Attribute.new(
192
+ [ ThinkingSphinx::Index::FauxColumn.new(:id),
193
+ ThinkingSphinx::Index::FauxColumn.new(:first_name) ]
194
+ )
195
+ attribute.model = Person
196
+ attribute.columns.each { |col| attribute.associations[col] = [] }
197
+
198
+ attribute.send(:all_ints?).should be_false
199
+ end
200
+
201
+ it "should return false if no columns are integers" do
202
+ attribute = ThinkingSphinx::Attribute.new(
203
+ [ ThinkingSphinx::Index::FauxColumn.new(:first_name),
204
+ ThinkingSphinx::Index::FauxColumn.new(:last_name) ]
205
+ )
206
+ attribute.model = Person
207
+ attribute.columns.each { |col| attribute.associations[col] = [] }
208
+
209
+ attribute.send(:all_ints?).should be_false
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Collection do
4
+ it "should behave like WillPaginate::Collection" do
5
+ ThinkingSphinx::Collection.instance_methods.should include("previous_page")
6
+ ThinkingSphinx::Collection.instance_methods.should include("next_page")
7
+ ThinkingSphinx::Collection.instance_methods.should include("current_page")
8
+ ThinkingSphinx::Collection.instance_methods.should include("total_pages")
9
+ ThinkingSphinx::Collection.instance_methods.should include("total_entries")
10
+ ThinkingSphinx::Collection.instance_methods.should include("offset")
11
+
12
+ ThinkingSphinx::Collection.ancestors.should include(Array)
13
+ end
14
+ end
@@ -0,0 +1,136 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Configuration do
4
+ describe "environment class method" do
5
+ before :each do
6
+ ThinkingSphinx::Configuration.send(:class_variable_set, :@@environment, nil)
7
+
8
+ ENV["RAILS_ENV"] = nil
9
+ end
10
+
11
+ it "should use the Merb environment value if set" do
12
+ unless defined?(Merb)
13
+ module Merb; end
14
+ end
15
+
16
+ ThinkingSphinx::Configuration.stub_method(:defined? => true)
17
+ Merb.stub_method(:environment => "merb_production")
18
+ ThinkingSphinx::Configuration.environment.should == "merb_production"
19
+
20
+ Object.send(:remove_const, :Merb)
21
+ end
22
+
23
+ it "should use the Rails environment value if set" do
24
+ ENV["RAILS_ENV"] = "rails_production"
25
+ ThinkingSphinx::Configuration.environment.should == "rails_production"
26
+ end
27
+
28
+ it "should default to development" do
29
+ ThinkingSphinx::Configuration.environment.should == "development"
30
+ end
31
+ end
32
+
33
+ describe "parse_config method" do
34
+ before :each do
35
+ @settings = {
36
+ "development" => {
37
+ "config_file" => "tmp/config/development.sphinx.conf",
38
+ "searchd_log_file" => "searchd_log_file.log",
39
+ "query_log_file" => "query_log_file.log",
40
+ "pid_file" => "pid_file.pid",
41
+ "searchd_file_path" => "searchd/file/path",
42
+ "address" => "127.0.0.1",
43
+ "port" => 3333,
44
+ "min_prefix_len" => 2,
45
+ "min_infix_len" => 3,
46
+ "mem_limit" => "128M",
47
+ "max_matches" => 1001,
48
+ "morphology" => "stem_ru",
49
+ "charset_type" => "latin1",
50
+ "charset_table" => "table",
51
+ "ignore_chars" => "e"
52
+ }
53
+ }
54
+
55
+ open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
56
+ f.write YAML.dump(@settings)
57
+ end
58
+ end
59
+
60
+ it "should use the accessors to set the configuration values" do
61
+ config = ThinkingSphinx::Configuration.instance
62
+ config.send(:parse_config)
63
+
64
+ %w(config_file searchd_log_file query_log_file pid_file searchd_file_path
65
+ address port).each do |key|
66
+ config.send(key).should == @settings["development"][key]
67
+ end
68
+ end
69
+
70
+ after :each do
71
+ FileUtils.rm "#{RAILS_ROOT}/config/sphinx.yml"
72
+ end
73
+ end
74
+
75
+ describe "initialisation" do
76
+ it "should have a default bin_path of nothing" do
77
+ ThinkingSphinx::Configuration.instance.bin_path.should == ""
78
+ end
79
+
80
+ it "should append a / to bin_path if one is supplied" do
81
+ @settings = {
82
+ "development" => {
83
+ "bin_path" => "path/to/somewhere"
84
+ }
85
+ }
86
+
87
+ open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
88
+ f.write YAML.dump(@settings)
89
+ end
90
+
91
+ ThinkingSphinx::Configuration.instance.send(:parse_config)
92
+ ThinkingSphinx::Configuration.instance.bin_path.should match(/\/$/)
93
+ end
94
+ end
95
+
96
+ it "should insert set index options into the configuration file" do
97
+ config = ThinkingSphinx::Configuration.instance
98
+ ThinkingSphinx::Configuration::IndexOptions.each do |option|
99
+ config.index_options[option.to_sym] = "something"
100
+ config.build
101
+
102
+ file = open(config.config_file) { |f| f.read }
103
+ file.should match(/#{option}\s+= something/)
104
+
105
+ config.index_options[option.to_sym] = nil
106
+ end
107
+ end
108
+
109
+ it "should insert set source options into the configuration file" do
110
+ config = ThinkingSphinx::Configuration.instance
111
+ ThinkingSphinx::Configuration::SourceOptions.each do |option|
112
+ config.source_options[option.to_sym] = "something"
113
+ config.build
114
+
115
+ file = open(config.config_file) { |f| f.read }
116
+ file.should match(/#{option}\s+= something/)
117
+
118
+ config.source_options[option.to_sym] = nil
119
+ end
120
+ end
121
+
122
+ it "should set any explicit prefixed or infixed fields" do
123
+ file = open(ThinkingSphinx::Configuration.instance.config_file) { |f|
124
+ f.read
125
+ }
126
+ file.should match(/prefix_fields\s+= city/)
127
+ file.should match(/infix_fields\s+= state/)
128
+ end
129
+
130
+ it "should not have prefix fields in indexes where nothing is set" do
131
+ file = open(ThinkingSphinx::Configuration.instance.config_file) { |f|
132
+ f.read
133
+ }
134
+ file.should_not match(/index alpha_core\s+\{\s+[^\}]*prefix_fields\s+=[^\}]*\}/m)
135
+ end
136
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe String do
4
+ describe "to_crc32 instance method" do
5
+ it "should return an integer" do
6
+ 'to_crc32'.to_crc32.should be_a_kind_of(Integer)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,145 @@
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 "unique_name method" do
19
+ before :each do
20
+ @field = ThinkingSphinx::Field.new [
21
+ Object.stub_instance(:__stack => [], :__name => "col_name")
22
+ ]
23
+ end
24
+
25
+ it "should use the alias if there is one" do
26
+ @field.alias = "alias"
27
+ @field.unique_name.should == "alias"
28
+ end
29
+
30
+ it "should use the alias if there's multiple columns" do
31
+ @field.columns << Object.stub_instance(:__stack => [], :__name => "col_name")
32
+ @field.unique_name.should be_nil
33
+
34
+ @field.alias = "alias"
35
+ @field.unique_name.should == "alias"
36
+ end
37
+
38
+ it "should use the column name if there's no alias and just one column" do
39
+ @field.unique_name.should == "col_name"
40
+ end
41
+ end
42
+
43
+ describe "prefixes method" do
44
+ it "should default to false" do
45
+ @field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
46
+ @field.prefixes.should be_false
47
+ end
48
+
49
+ it "should be true if the corresponding option is set" do
50
+ @field = ThinkingSphinx::Field.new(
51
+ [Object.stub_instance(:__stack => [])], :prefixes => true
52
+ )
53
+ @field.prefixes.should be_true
54
+ end
55
+ end
56
+
57
+ describe "infixes method" do
58
+ it "should default to false" do
59
+ @field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
60
+ @field.infixes.should be_false
61
+ end
62
+
63
+ it "should be true if the corresponding option is set" do
64
+ @field = ThinkingSphinx::Field.new(
65
+ [Object.stub_instance(:__stack => [])], :infixes => true
66
+ )
67
+ @field.infixes.should be_true
68
+ end
69
+ end
70
+
71
+ describe "column_with_prefix method" do
72
+ before :each do
73
+ @field = ThinkingSphinx::Field.new [
74
+ ThinkingSphinx::Index::FauxColumn.new(:col_name)
75
+ ]
76
+ @field.columns.each { |col| @field.associations[col] = [] }
77
+ @field.model = Person
78
+
79
+ @first_join = Object.stub_instance(:aliased_table_name => "tabular")
80
+ @second_join = Object.stub_instance(:aliased_table_name => "data")
81
+
82
+ @first_assoc = ThinkingSphinx::Association.stub_instance(
83
+ :join => @first_join, :has_column? => true
84
+ )
85
+ @second_assoc = ThinkingSphinx::Association.stub_instance(
86
+ :join => @second_join, :has_column? => true
87
+ )
88
+ end
89
+
90
+ it "should return the column name if the column is a string" do
91
+ @field.columns = [ThinkingSphinx::Index::FauxColumn.new("string")]
92
+ @field.send(:column_with_prefix, @field.columns.first).should == "string"
93
+ end
94
+
95
+ it "should return the column with model's table prefix if there's no associations for the column" do
96
+ @field.send(:column_with_prefix, @field.columns.first).should == "`people`.`col_name`"
97
+ end
98
+
99
+ it "should return the column with its join table prefix if an association exists" do
100
+ column = @field.columns.first
101
+ @field.associations[column] = [@first_assoc]
102
+ @field.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
103
+ end
104
+
105
+ it "should return multiple columns concatenated if more than one association exists" do
106
+ column = @field.columns.first
107
+ @field.associations[column] = [@first_assoc, @second_assoc]
108
+ @field.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
109
+ end
110
+ end
111
+
112
+ describe "is_many? method" do
113
+ before :each do
114
+ @assoc_a = Object.stub_instance(:is_many? => true)
115
+ @assoc_b = Object.stub_instance(:is_many? => true)
116
+ @assoc_c = Object.stub_instance(:is_many? => true)
117
+
118
+ @field = ThinkingSphinx::Field.new(
119
+ [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
120
+ )
121
+ @field.associations = {
122
+ :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
123
+ }
124
+ end
125
+
126
+ it "should return true if all associations return true to is_many?" do
127
+ @field.send(:is_many?).should be_true
128
+ end
129
+
130
+ it "should return true if one association returns true to is_many?" do
131
+ @assoc_b.stub_method(:is_many? => false)
132
+ @assoc_c.stub_method(:is_many? => false)
133
+
134
+ @field.send(:is_many?).should be_true
135
+ end
136
+
137
+ it "should return false if all associations return false to is_many?" do
138
+ @assoc_a.stub_method(:is_many? => false)
139
+ @assoc_b.stub_method(:is_many? => false)
140
+ @assoc_c.stub_method(:is_many? => false)
141
+
142
+ @field.send(:is_many?).should be_false
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Index::Builder do
4
+ #
5
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Index::FauxColumn do
4
+ describe "coerce class method" do
5
+ before :each do
6
+ @column = ThinkingSphinx::Index::FauxColumn.stub_instance
7
+ ThinkingSphinx::Index::FauxColumn.stub_method(:new => @column)
8
+ end
9
+
10
+ it "should return a single faux column if passed a string" do
11
+ ThinkingSphinx::Index::FauxColumn.coerce("string").should == @column
12
+ end
13
+
14
+ it "should return a single faux column if passed a symbol" do
15
+ ThinkingSphinx::Index::FauxColumn.coerce(:string).should == @column
16
+ end
17
+
18
+ it "should return an array of faux columns if passed an array of strings" do
19
+ ThinkingSphinx::Index::FauxColumn.coerce(["one", "two"]).should == [
20
+ @column, @column
21
+ ]
22
+ end
23
+
24
+ it "should return an array of faux columns if passed an array of symbols" do
25
+ ThinkingSphinx::Index::FauxColumn.coerce([:one, :two]).should == [
26
+ @column, @column
27
+ ]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Index do
4
+ describe "generated sql_query" do
5
+ it "should include explicit groupings if requested" do
6
+ @index = ThinkingSphinx::Index.new(Person)
7
+
8
+ @index.groupings << "custom_sql"
9
+ @index.to_riddle_for_core(0, 0).sql_query.should match(/GROUP BY.+custom_sql/)
10
+ end
11
+ end
12
+
13
+ describe "prefix_fields method" do
14
+ before :each do
15
+ @index = ThinkingSphinx::Index.new(Person)
16
+
17
+ @field_a = ThinkingSphinx::Field.stub_instance(:prefixes => true)
18
+ @field_b = ThinkingSphinx::Field.stub_instance(:prefixes => false)
19
+ @field_c = ThinkingSphinx::Field.stub_instance(:prefixes => true)
20
+
21
+ @index.fields = [@field_a, @field_b, @field_c]
22
+ end
23
+
24
+ it "should return fields that are flagged as prefixed" do
25
+ @index.prefix_fields.should include(@field_a)
26
+ @index.prefix_fields.should include(@field_c)
27
+ end
28
+
29
+ it "should not return fields that aren't flagged as prefixed" do
30
+ @index.prefix_fields.should_not include(@field_b)
31
+ end
32
+ end
33
+
34
+ describe "infix_fields method" do
35
+ before :each do
36
+ @index = ThinkingSphinx::Index.new(Person)
37
+
38
+ @field_a = ThinkingSphinx::Field.stub_instance(:infixes => true)
39
+ @field_b = ThinkingSphinx::Field.stub_instance(:infixes => false)
40
+ @field_c = ThinkingSphinx::Field.stub_instance(:infixes => true)
41
+
42
+ @index.fields = [@field_a, @field_b, @field_c]
43
+ end
44
+
45
+ it "should return fields that are flagged as infixed" do
46
+ @index.infix_fields.should include(@field_a)
47
+ @index.infix_fields.should include(@field_c)
48
+ end
49
+
50
+ it "should not return fields that aren't flagged as infixed" do
51
+ @index.infix_fields.should_not include(@field_b)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec/spec_helper'
2
+ require 'will_paginate/collection'
3
+
4
+ describe ThinkingSphinx::Search do
5
+ describe "search method" do
6
+ before :each do
7
+ @client = Riddle::Client.stub_instance(
8
+ :filters => [],
9
+ :filters= => true,
10
+ :id_range= => true,
11
+ :sort_mode => :asc,
12
+ :limit => 5,
13
+ :offset= => 0,
14
+ :sort_mode= => true,
15
+ :query => {
16
+ :matches => [],
17
+ :total => 50
18
+ }
19
+ )
20
+
21
+ ThinkingSphinx::Search.stub_methods(
22
+ :client_from_options => @client,
23
+ :search_conditions => ["", []]
24
+ )
25
+ end
26
+
27
+ describe ":star option" do
28
+
29
+ it "should not apply by default" do
30
+ ThinkingSphinx::Search.search "foo bar"
31
+ @client.should have_received(:query).with("foo bar")
32
+ end
33
+
34
+ it "should apply when passed, and handle full extended syntax" do
35
+ input = %{a b* c (d | e) 123 5&6 (f_f g) !h "i j" "k l"~10 "m n"/3 @o p -(q|r)}
36
+ expected = %{*a* b* *c* (*d* | *e*) *123* *5*&*6* (*f_f* *g*) !*h* "i j" "k l"~10 "m n"/3 @o *p* -(*q*|*r*)}
37
+ ThinkingSphinx::Search.search input, :star => true
38
+ @client.should have_received(:query).with(expected)
39
+ end
40
+
41
+ it "should default to /\w+/ as token" do
42
+ ThinkingSphinx::Search.search "foo@bar.com", :star => true
43
+ @client.should have_received(:query).with("*foo*@*bar*.*com*")
44
+ end
45
+
46
+ it "should honour custom token" do
47
+ ThinkingSphinx::Search.search "foo@bar.com -foo-bar", :star => /[\w@.-]+/u
48
+ @client.should have_received(:query).with("*foo@bar.com* -*foo-bar*")
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+
55
+ describe ThinkingSphinx::Search, "playing nice with Search model" do
56
+ it "should not conflict with models called Search" do
57
+ lambda { Search.find(:all) }.should_not raise_error
58
+ end
59
+ end