skalee-thinking-sphinx 1.3.14.1

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 (199) hide show
  1. data/LICENCE +20 -0
  2. data/README.textile +201 -0
  3. data/Rakefile +3 -0
  4. data/VERSION +1 -0
  5. data/contribute.rb +385 -0
  6. data/cucumber.yml +1 -0
  7. data/features/abstract_inheritance.feature +10 -0
  8. data/features/alternate_primary_key.feature +27 -0
  9. data/features/attribute_transformation.feature +22 -0
  10. data/features/attribute_updates.feature +51 -0
  11. data/features/deleting_instances.feature +67 -0
  12. data/features/direct_attributes.feature +11 -0
  13. data/features/excerpts.feature +13 -0
  14. data/features/extensible_delta_indexing.feature +9 -0
  15. data/features/facets.feature +82 -0
  16. data/features/facets_across_model.feature +29 -0
  17. data/features/handling_edits.feature +92 -0
  18. data/features/retry_stale_indexes.feature +24 -0
  19. data/features/searching_across_models.feature +20 -0
  20. data/features/searching_by_index.feature +40 -0
  21. data/features/searching_by_model.feature +175 -0
  22. data/features/searching_with_find_arguments.feature +56 -0
  23. data/features/sphinx_detection.feature +25 -0
  24. data/features/sphinx_scopes.feature +42 -0
  25. data/features/step_definitions/alpha_steps.rb +16 -0
  26. data/features/step_definitions/beta_steps.rb +7 -0
  27. data/features/step_definitions/common_steps.rb +188 -0
  28. data/features/step_definitions/extensible_delta_indexing_steps.rb +7 -0
  29. data/features/step_definitions/facet_steps.rb +96 -0
  30. data/features/step_definitions/find_arguments_steps.rb +36 -0
  31. data/features/step_definitions/gamma_steps.rb +15 -0
  32. data/features/step_definitions/scope_steps.rb +15 -0
  33. data/features/step_definitions/search_steps.rb +89 -0
  34. data/features/step_definitions/sphinx_steps.rb +35 -0
  35. data/features/sti_searching.feature +19 -0
  36. data/features/support/database.example.yml +3 -0
  37. data/features/support/db/.gitignore +1 -0
  38. data/features/support/db/fixtures/alphas.rb +10 -0
  39. data/features/support/db/fixtures/authors.rb +1 -0
  40. data/features/support/db/fixtures/betas.rb +10 -0
  41. data/features/support/db/fixtures/boxes.rb +9 -0
  42. data/features/support/db/fixtures/categories.rb +1 -0
  43. data/features/support/db/fixtures/cats.rb +3 -0
  44. data/features/support/db/fixtures/comments.rb +24 -0
  45. data/features/support/db/fixtures/developers.rb +29 -0
  46. data/features/support/db/fixtures/dogs.rb +3 -0
  47. data/features/support/db/fixtures/extensible_betas.rb +10 -0
  48. data/features/support/db/fixtures/foxes.rb +3 -0
  49. data/features/support/db/fixtures/gammas.rb +10 -0
  50. data/features/support/db/fixtures/music.rb +4 -0
  51. data/features/support/db/fixtures/people.rb +1001 -0
  52. data/features/support/db/fixtures/posts.rb +6 -0
  53. data/features/support/db/fixtures/robots.rb +14 -0
  54. data/features/support/db/fixtures/tags.rb +27 -0
  55. data/features/support/db/migrations/create_alphas.rb +8 -0
  56. data/features/support/db/migrations/create_animals.rb +5 -0
  57. data/features/support/db/migrations/create_authors.rb +3 -0
  58. data/features/support/db/migrations/create_authors_posts.rb +6 -0
  59. data/features/support/db/migrations/create_betas.rb +5 -0
  60. data/features/support/db/migrations/create_boxes.rb +5 -0
  61. data/features/support/db/migrations/create_categories.rb +3 -0
  62. data/features/support/db/migrations/create_comments.rb +10 -0
  63. data/features/support/db/migrations/create_developers.rb +9 -0
  64. data/features/support/db/migrations/create_extensible_betas.rb +5 -0
  65. data/features/support/db/migrations/create_gammas.rb +3 -0
  66. data/features/support/db/migrations/create_genres.rb +3 -0
  67. data/features/support/db/migrations/create_music.rb +6 -0
  68. data/features/support/db/migrations/create_people.rb +13 -0
  69. data/features/support/db/migrations/create_posts.rb +5 -0
  70. data/features/support/db/migrations/create_robots.rb +4 -0
  71. data/features/support/db/migrations/create_taggings.rb +5 -0
  72. data/features/support/db/migrations/create_tags.rb +4 -0
  73. data/features/support/env.rb +21 -0
  74. data/features/support/lib/generic_delta_handler.rb +8 -0
  75. data/features/support/models/alpha.rb +22 -0
  76. data/features/support/models/animal.rb +5 -0
  77. data/features/support/models/author.rb +3 -0
  78. data/features/support/models/beta.rb +8 -0
  79. data/features/support/models/box.rb +8 -0
  80. data/features/support/models/cat.rb +3 -0
  81. data/features/support/models/category.rb +4 -0
  82. data/features/support/models/comment.rb +10 -0
  83. data/features/support/models/developer.rb +16 -0
  84. data/features/support/models/dog.rb +3 -0
  85. data/features/support/models/extensible_beta.rb +9 -0
  86. data/features/support/models/fox.rb +5 -0
  87. data/features/support/models/gamma.rb +5 -0
  88. data/features/support/models/genre.rb +3 -0
  89. data/features/support/models/medium.rb +5 -0
  90. data/features/support/models/music.rb +8 -0
  91. data/features/support/models/person.rb +23 -0
  92. data/features/support/models/post.rb +21 -0
  93. data/features/support/models/robot.rb +12 -0
  94. data/features/support/models/tag.rb +3 -0
  95. data/features/support/models/tagging.rb +4 -0
  96. data/ginger_scenarios.rb +28 -0
  97. data/init.rb +5 -0
  98. data/install.rb +5 -0
  99. data/lib/cucumber/thinking_sphinx/external_world.rb +8 -0
  100. data/lib/cucumber/thinking_sphinx/internal_world.rb +126 -0
  101. data/lib/cucumber/thinking_sphinx/sql_logger.rb +20 -0
  102. data/lib/thinking_sphinx/active_record/attribute_updates.rb +19 -0
  103. data/lib/thinking_sphinx/active_record/delta.rb +47 -0
  104. data/lib/thinking_sphinx/active_record/has_many_association.rb +29 -0
  105. data/lib/thinking_sphinx/active_record/scopes.rb +75 -0
  106. data/lib/thinking_sphinx/active_record.rb +348 -0
  107. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +42 -0
  108. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +54 -0
  109. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +143 -0
  110. data/lib/thinking_sphinx/association.rb +164 -0
  111. data/lib/thinking_sphinx/attribute.rb +362 -0
  112. data/lib/thinking_sphinx/auto_version.rb +22 -0
  113. data/lib/thinking_sphinx/class_facet.rb +15 -0
  114. data/lib/thinking_sphinx/configuration.rb +300 -0
  115. data/lib/thinking_sphinx/context.rb +68 -0
  116. data/lib/thinking_sphinx/core/array.rb +7 -0
  117. data/lib/thinking_sphinx/core/string.rb +15 -0
  118. data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
  119. data/lib/thinking_sphinx/deltas.rb +28 -0
  120. data/lib/thinking_sphinx/deploy/capistrano.rb +100 -0
  121. data/lib/thinking_sphinx/excerpter.rb +22 -0
  122. data/lib/thinking_sphinx/facet.rb +125 -0
  123. data/lib/thinking_sphinx/facet_search.rb +136 -0
  124. data/lib/thinking_sphinx/field.rb +82 -0
  125. data/lib/thinking_sphinx/index/builder.rb +296 -0
  126. data/lib/thinking_sphinx/index/faux_column.rb +110 -0
  127. data/lib/thinking_sphinx/index.rb +157 -0
  128. data/lib/thinking_sphinx/property.rb +162 -0
  129. data/lib/thinking_sphinx/rails_additions.rb +150 -0
  130. data/lib/thinking_sphinx/search.rb +769 -0
  131. data/lib/thinking_sphinx/search_methods.rb +439 -0
  132. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  133. data/lib/thinking_sphinx/source/sql.rb +130 -0
  134. data/lib/thinking_sphinx/source.rb +153 -0
  135. data/lib/thinking_sphinx/tasks.rb +131 -0
  136. data/lib/thinking_sphinx/test.rb +52 -0
  137. data/lib/thinking_sphinx.rb +225 -0
  138. data/rails/init.rb +16 -0
  139. data/recipes/thinking_sphinx.rb +3 -0
  140. data/spec/fixtures/data.sql +32 -0
  141. data/spec/fixtures/database.yml.default +3 -0
  142. data/spec/fixtures/models.rb +145 -0
  143. data/spec/fixtures/structure.sql +125 -0
  144. data/spec/spec_helper.rb +60 -0
  145. data/spec/sphinx_helper.rb +81 -0
  146. data/spec/thinking_sphinx/active_record/delta_spec.rb +128 -0
  147. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +55 -0
  148. data/spec/thinking_sphinx/active_record/scopes_spec.rb +177 -0
  149. data/spec/thinking_sphinx/active_record_spec.rb +622 -0
  150. data/spec/thinking_sphinx/association_spec.rb +239 -0
  151. data/spec/thinking_sphinx/attribute_spec.rb +570 -0
  152. data/spec/thinking_sphinx/auto_version_spec.rb +39 -0
  153. data/spec/thinking_sphinx/configuration_spec.rb +234 -0
  154. data/spec/thinking_sphinx/context_spec.rb +119 -0
  155. data/spec/thinking_sphinx/core/array_spec.rb +9 -0
  156. data/spec/thinking_sphinx/core/string_spec.rb +9 -0
  157. data/spec/thinking_sphinx/excerpter_spec.rb +57 -0
  158. data/spec/thinking_sphinx/facet_search_spec.rb +176 -0
  159. data/spec/thinking_sphinx/facet_spec.rb +333 -0
  160. data/spec/thinking_sphinx/field_spec.rb +154 -0
  161. data/spec/thinking_sphinx/index/builder_spec.rb +479 -0
  162. data/spec/thinking_sphinx/index/faux_column_spec.rb +30 -0
  163. data/spec/thinking_sphinx/index_spec.rb +183 -0
  164. data/spec/thinking_sphinx/rails_additions_spec.rb +203 -0
  165. data/spec/thinking_sphinx/search_methods_spec.rb +152 -0
  166. data/spec/thinking_sphinx/search_spec.rb +1181 -0
  167. data/spec/thinking_sphinx/source_spec.rb +235 -0
  168. data/spec/thinking_sphinx_spec.rb +204 -0
  169. data/tasks/distribution.rb +41 -0
  170. data/tasks/rails.rake +1 -0
  171. data/tasks/testing.rb +72 -0
  172. data/vendor/after_commit/.gitignore +1 -0
  173. data/vendor/after_commit/lib/after_commit/active_record.rb +122 -0
  174. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +168 -0
  175. data/vendor/after_commit/lib/after_commit/test_bypass.rb +30 -0
  176. data/vendor/after_commit/lib/after_commit.rb +70 -0
  177. data/vendor/riddle/lib/riddle/0.9.8.rb +1 -0
  178. data/vendor/riddle/lib/riddle/0.9.9/client/filter.rb +22 -0
  179. data/vendor/riddle/lib/riddle/0.9.9/client.rb +49 -0
  180. data/vendor/riddle/lib/riddle/0.9.9/configuration/searchd.rb +28 -0
  181. data/vendor/riddle/lib/riddle/0.9.9.rb +7 -0
  182. data/vendor/riddle/lib/riddle/auto_version.rb +11 -0
  183. data/vendor/riddle/lib/riddle/client/filter.rb +62 -0
  184. data/vendor/riddle/lib/riddle/client/message.rb +70 -0
  185. data/vendor/riddle/lib/riddle/client/response.rb +94 -0
  186. data/vendor/riddle/lib/riddle/client.rb +745 -0
  187. data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +49 -0
  188. data/vendor/riddle/lib/riddle/configuration/index.rb +149 -0
  189. data/vendor/riddle/lib/riddle/configuration/indexer.rb +20 -0
  190. data/vendor/riddle/lib/riddle/configuration/remote_index.rb +17 -0
  191. data/vendor/riddle/lib/riddle/configuration/searchd.rb +28 -0
  192. data/vendor/riddle/lib/riddle/configuration/section.rb +43 -0
  193. data/vendor/riddle/lib/riddle/configuration/source.rb +23 -0
  194. data/vendor/riddle/lib/riddle/configuration/sql_source.rb +53 -0
  195. data/vendor/riddle/lib/riddle/configuration/xml_source.rb +29 -0
  196. data/vendor/riddle/lib/riddle/configuration.rb +33 -0
  197. data/vendor/riddle/lib/riddle/controller.rb +78 -0
  198. data/vendor/riddle/lib/riddle.rb +51 -0
  199. metadata +312 -0
@@ -0,0 +1,235 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Source do
4
+ before :each do
5
+ @index = ThinkingSphinx::Index.new(Person)
6
+ @source = ThinkingSphinx::Source.new(@index, :sql_range_step => 1000)
7
+ end
8
+
9
+ describe '#initialize' do
10
+ it "should store the current connection details" do
11
+ config = Person.connection.instance_variable_get(:@config)
12
+ @source.database_configuration.should == config
13
+ end
14
+ end
15
+
16
+ it "should generate the name from the model" do
17
+ @source.name.should == "person"
18
+ end
19
+
20
+ it "should handle namespaced models for name generation" do
21
+ index = ThinkingSphinx::Index.new(Admin::Person)
22
+ source = ThinkingSphinx::Source.new(index)
23
+ source.name.should == "admin_person"
24
+ end
25
+
26
+ describe "#to_riddle_for_core" do
27
+ before :each do
28
+ config = ThinkingSphinx::Configuration.instance
29
+ config.source_options[:sql_ranged_throttle] = 100
30
+
31
+ ThinkingSphinx::Field.new(
32
+ @source, ThinkingSphinx::Index::FauxColumn.new(:first_name)
33
+ )
34
+ ThinkingSphinx::Field.new(
35
+ @source, ThinkingSphinx::Index::FauxColumn.new(:last_name)
36
+ )
37
+
38
+ ThinkingSphinx::Attribute.new(
39
+ @source, ThinkingSphinx::Index::FauxColumn.new(:id), :as => :internal_id
40
+ )
41
+ ThinkingSphinx::Attribute.new(
42
+ @source, ThinkingSphinx::Index::FauxColumn.new(:birthday)
43
+ )
44
+ ThinkingSphinx::Attribute.new(
45
+ @source, ThinkingSphinx::Index::FauxColumn.new(:tags, :id), :as => :tag_ids
46
+ )
47
+ ThinkingSphinx::Attribute.new(
48
+ @source, ThinkingSphinx::Index::FauxColumn.new(:contacts, :id),
49
+ :as => :contact_ids, :source => :query
50
+ )
51
+
52
+ @source.conditions << "`birthday` <= NOW()"
53
+ @source.groupings << "`first_name`"
54
+
55
+ @index.local_options[:group_concat_max_len] = 1024
56
+
57
+ @riddle = @source.to_riddle_for_core(1, 0)
58
+ end
59
+
60
+ it "should generate a Riddle Source object" do
61
+ @riddle.should be_a_kind_of(Riddle::Configuration::SQLSource)
62
+ end
63
+
64
+ it "should use the index and name its own name" do
65
+ @riddle.name.should == "person_core_0"
66
+ end
67
+
68
+ it "should use the model's database connection to determine type" do
69
+ @riddle.type.should == "mysql"
70
+ end
71
+
72
+ it "should match the model's database settings" do
73
+ config = Person.connection.instance_variable_get(:@config)
74
+ @riddle.sql_db.should == config[:database]
75
+ @riddle.sql_user.should == config[:username]
76
+ @riddle.sql_pass.should == config[:password].to_s
77
+ @riddle.sql_host.should == config[:host]
78
+ @riddle.sql_port.should == config[:port]
79
+ @riddle.sql_sock.should == config[:socket]
80
+ end
81
+
82
+ it "should use a default username of root if nothing else is provided" do
83
+ Person.connection.stub!(:instance_variable_get => {
84
+ :user => nil,
85
+ :username => nil
86
+ })
87
+ @source = ThinkingSphinx::Source.new(@index)
88
+
89
+ riddle = @source.to_riddle_for_core(1, 0)
90
+ riddle.sql_user.should == 'root'
91
+ end
92
+
93
+ it "should assign attributes" do
94
+ # 3 internal attributes plus the one requested
95
+ @riddle.sql_attr_uint.length.should == 4
96
+ @riddle.sql_attr_uint.last.should == :internal_id
97
+
98
+ @riddle.sql_attr_timestamp.length.should == 1
99
+ @riddle.sql_attr_timestamp.first.should == :birthday
100
+ end
101
+
102
+ it "should set Sphinx Source options" do
103
+ @riddle.sql_range_step.should == 1000
104
+ @riddle.sql_ranged_throttle.should == 100
105
+ end
106
+
107
+ describe "#sql_query" do
108
+ before :each do
109
+ @query = @riddle.sql_query
110
+ end
111
+
112
+ it "should select data from the model table" do
113
+ @query.should match(/FROM `people`/)
114
+ end
115
+
116
+ it "should select each of the fields" do
117
+ @query.should match(/`first_name`.+FROM/)
118
+ @query.should match(/`last_name`.+FROM/)
119
+ end
120
+
121
+ it "should select each of the attributes" do
122
+ @query.should match(/`id` AS `internal_id`.+FROM/)
123
+ @query.should match(/`birthday`.+FROM/)
124
+ @query.should match(/`tags`.`id`.+ AS `tag_ids`.+FROM/)
125
+ end
126
+
127
+ it "should not match the sourced MVA attribute" do
128
+ @query.should_not match(/contact_ids/)
129
+ end
130
+
131
+ it "should include joins for required associations" do
132
+ @query.should match(/LEFT OUTER JOIN `tags`/)
133
+ end
134
+
135
+ it "should not include joins for the sourced MVA attribute" do
136
+ @query.should_not match(/LEFT OUTER JOIN `contacts`/)
137
+ end
138
+
139
+ it "should include any defined conditions" do
140
+ @query.should match(/WHERE.+`birthday` <= NOW()/)
141
+ end
142
+
143
+ it "should include any defined groupings" do
144
+ @query.should match(/GROUP BY.+`first_name`/)
145
+ end
146
+ end
147
+
148
+ describe "#sql_query_range" do
149
+ before :each do
150
+ @query = @riddle.sql_query_range
151
+ end
152
+
153
+ it "should select data from the model table" do
154
+ @query.should match(/FROM `people`/)
155
+ end
156
+
157
+ it "should select the minimum and the maximum ids" do
158
+ @query.should match(/SELECT.+MIN.+MAX.+FROM/)
159
+ end
160
+ end
161
+
162
+ describe "#sql_query_info" do
163
+ before :each do
164
+ @query = @riddle.sql_query_info
165
+ end
166
+
167
+ it "should select all fields from the model table" do
168
+ @query.should match(/SELECT \* FROM `people`/)
169
+ end
170
+
171
+ it "should filter the primary key with the offset" do
172
+ model_count = ThinkingSphinx.context.indexed_models.size
173
+ @query.should match(/WHERE `id` = \(\(\$id - 1\) \/ #{model_count}\)/)
174
+ end
175
+ end
176
+
177
+ describe "#sql_query_pre" do
178
+ before :each do
179
+ @queries = @riddle.sql_query_pre
180
+ end
181
+
182
+ it "should default to just the UTF8 statement" do
183
+ @queries.detect { |query|
184
+ query == "SET NAMES utf8"
185
+ }.should_not be_nil
186
+ end
187
+
188
+ it "should set the group_concat_max_len session value for MySQL if requested" do
189
+ @queries.detect { |query|
190
+ query == "SET SESSION group_concat_max_len = 1024"
191
+ }.should_not be_nil
192
+ end
193
+ end
194
+ end
195
+
196
+ describe "#to_riddle_for_core with range disabled" do
197
+ before :each do
198
+ ThinkingSphinx::Field.new(
199
+ @source, ThinkingSphinx::Index::FauxColumn.new(:first_name)
200
+ )
201
+ end
202
+
203
+ describe "set per-index" do
204
+ before :each do
205
+ @index.local_options[:disable_range] = true
206
+ @riddle = @source.to_riddle_for_core(1, 0)
207
+ end
208
+
209
+ it "should not have the range in the sql_query" do
210
+ @riddle.sql_query.should_not match(/`people`.`id` >= \$start/)
211
+ @riddle.sql_query.should_not match(/`people`.`id` <= \$end/)
212
+ end
213
+
214
+ it "should not have a sql_query_range" do
215
+ @riddle.sql_query_range.should be_nil
216
+ end
217
+ end
218
+
219
+ describe "set globally" do
220
+ before :each do
221
+ ThinkingSphinx::Configuration.instance.index_options[:disable_range] = true
222
+ @riddle = @source.to_riddle_for_core(1, 0)
223
+ end
224
+
225
+ it "should not have the range in the sql_query" do
226
+ @riddle.sql_query.should_not match(/`people`.`id` >= \$start/)
227
+ @riddle.sql_query.should_not match(/`people`.`id` <= \$end/)
228
+ end
229
+
230
+ it "should not have a sql_query_range" do
231
+ @riddle.sql_query_range.should be_nil
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,204 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx do
4
+ describe '.context' do
5
+ it "should return a Context instance" do
6
+ ThinkingSphinx.context.should be_a(ThinkingSphinx::Context)
7
+ end
8
+
9
+ it "should remember changes to the Context instance" do
10
+ models = ThinkingSphinx.context.indexed_models
11
+
12
+ ThinkingSphinx.context.indexed_models.replace([:model])
13
+ ThinkingSphinx.context.indexed_models.should == [:model]
14
+
15
+ ThinkingSphinx.context.indexed_models.replace(models)
16
+ end
17
+ end
18
+
19
+ describe '.reset_context!' do
20
+ it "should remove the existing Context instance" do
21
+ existing = ThinkingSphinx.context
22
+
23
+ ThinkingSphinx.reset_context!
24
+ ThinkingSphinx.context.should_not == existing
25
+
26
+ Thread.current[:thinking_sphinx_context] = existing
27
+ end
28
+ end
29
+
30
+ describe '.define_indexes?' do
31
+ it "should define indexes by default" do
32
+ ThinkingSphinx.define_indexes?.should be_true
33
+ end
34
+ end
35
+
36
+ describe '.define_indexes=' do
37
+ it "should disable index definition" do
38
+ ThinkingSphinx.define_indexes = false
39
+ ThinkingSphinx.define_indexes?.should be_false
40
+ end
41
+
42
+ it "should enable index definition" do
43
+ ThinkingSphinx.define_indexes = false
44
+ ThinkingSphinx.define_indexes?.should be_false
45
+ ThinkingSphinx.define_indexes = true
46
+ ThinkingSphinx.define_indexes?.should be_true
47
+ end
48
+ end
49
+
50
+ describe '.deltas_enabled?' do
51
+ it "should index deltas by default" do
52
+ ThinkingSphinx.deltas_enabled = nil
53
+ ThinkingSphinx.deltas_enabled?.should be_true
54
+ end
55
+ end
56
+
57
+ describe '.deltas_enabled=' do
58
+ it "should disable delta indexing" do
59
+ ThinkingSphinx.deltas_enabled = false
60
+ ThinkingSphinx.deltas_enabled?.should be_false
61
+ end
62
+
63
+ it "should enable delta indexing" do
64
+ ThinkingSphinx.deltas_enabled = false
65
+ ThinkingSphinx.deltas_enabled?.should be_false
66
+ ThinkingSphinx.deltas_enabled = true
67
+ ThinkingSphinx.deltas_enabled?.should be_true
68
+ end
69
+ end
70
+
71
+ describe '.updates_enabled?' do
72
+ it "should update indexes by default" do
73
+ ThinkingSphinx.updates_enabled = nil
74
+ ThinkingSphinx.updates_enabled?.should be_true
75
+ end
76
+ end
77
+
78
+ describe '.updates_enabled=' do
79
+ it "should disable index updating" do
80
+ ThinkingSphinx.updates_enabled = false
81
+ ThinkingSphinx.updates_enabled?.should be_false
82
+ end
83
+
84
+ it "should enable index updating" do
85
+ ThinkingSphinx.updates_enabled = false
86
+ ThinkingSphinx.updates_enabled?.should be_false
87
+ ThinkingSphinx.updates_enabled = true
88
+ ThinkingSphinx.updates_enabled?.should be_true
89
+ end
90
+ end
91
+
92
+ describe '.sphinx_running?' do
93
+ it "should always say Sphinx is running if flagged as being on a remote machine" do
94
+ ThinkingSphinx.remote_sphinx = true
95
+ ThinkingSphinx.stub!(:sphinx_running_by_pid? => false)
96
+
97
+ ThinkingSphinx.sphinx_running?.should be_true
98
+ end
99
+
100
+ it "should actually pay attention to Sphinx if not on a remote machine" do
101
+ ThinkingSphinx.remote_sphinx = false
102
+ ThinkingSphinx.stub!(:sphinx_running_by_pid? => false)
103
+ ThinkingSphinx.sphinx_running?.should be_false
104
+
105
+ ThinkingSphinx.stub!(:sphinx_running_by_pid? => true)
106
+ ThinkingSphinx.sphinx_running?.should be_true
107
+ end
108
+ end
109
+
110
+ describe '.version' do
111
+ it "should return the version from the stored YAML file" do
112
+ version = Jeweler::VersionHelper.new(
113
+ File.join(File.dirname(__FILE__), '..')
114
+ ).to_s
115
+
116
+ ThinkingSphinx.version.should == version
117
+ end
118
+ end
119
+
120
+ describe "use_group_by_shortcut? method" do
121
+ before :each do
122
+ adapter = defined?(JRUBY_VERSION) ? :JdbcAdapter : :MysqlAdapter
123
+ unless ::ActiveRecord::ConnectionAdapters.const_defined?(adapter)
124
+ pending "No MySQL"
125
+ return
126
+ end
127
+
128
+ @connection = stub('adapter',
129
+ :select_all => true,
130
+ :class => ActiveRecord::ConnectionAdapters::MysqlAdapter,
131
+ :config => {:adapter => defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql'}
132
+ )
133
+ ::ActiveRecord::Base.stub!(
134
+ :connection => @connection
135
+ )
136
+
137
+ Thread.current[:thinking_sphinx_use_group_by_shortcut] = nil
138
+ end
139
+
140
+ it "should return true if no ONLY_FULL_GROUP_BY" do
141
+ @connection.stub!(
142
+ :select_all => {:a => "OTHER SETTINGS"}
143
+ )
144
+
145
+ ThinkingSphinx.use_group_by_shortcut?.should be_true
146
+ end
147
+
148
+ it "should return true if NULL value" do
149
+ @connection.stub!(
150
+ :select_all => {:a => nil}
151
+ )
152
+
153
+ ThinkingSphinx.use_group_by_shortcut?.should be_true
154
+ end
155
+
156
+ it "should return false if ONLY_FULL_GROUP_BY is set" do
157
+ @connection.stub!(
158
+ :select_all => {:a => "OTHER SETTINGS,ONLY_FULL_GROUP_BY,blah"}
159
+ )
160
+
161
+ ThinkingSphinx.use_group_by_shortcut?.should be_false
162
+ end
163
+
164
+ it "should return false if ONLY_FULL_GROUP_BY is set in any of the values" do
165
+ @connection.stub!(
166
+ :select_all => {
167
+ :a => "OTHER SETTINGS",
168
+ :b => "ONLY_FULL_GROUP_BY"
169
+ }
170
+ )
171
+
172
+ ThinkingSphinx.use_group_by_shortcut?.should be_false
173
+ end
174
+
175
+ describe "if not using MySQL" do
176
+ before :each do
177
+ adapter = defined?(JRUBY_VERSION) ? 'JdbcAdapter' : 'PostgreSQLAdapter'
178
+ unless ::ActiveRecord::ConnectionAdapters.const_defined?(adapter)
179
+ pending "No PostgreSQL"
180
+ return
181
+ end
182
+
183
+ @connection = stub(adapter).as_null_object
184
+ @connection.stub!(
185
+ :select_all => true,
186
+ :config => {:adapter => defined?(JRUBY_VERSION) ? 'jdbcpostgresql' : 'postgresql'}
187
+ )
188
+ ::ActiveRecord::Base.stub!(
189
+ :connection => @connection
190
+ )
191
+ end
192
+
193
+ it "should return false" do
194
+ ThinkingSphinx.use_group_by_shortcut?.should be_false
195
+ end
196
+
197
+ it "should not call select_all" do
198
+ @connection.should_not_receive(:select_all)
199
+
200
+ ThinkingSphinx.use_group_by_shortcut?
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,41 @@
1
+ require 'yard'
2
+ require 'jeweler'
3
+
4
+ desc 'Generate documentation'
5
+ YARD::Rake::YardocTask.new
6
+
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "hawkerb-thinking-sphinx"
9
+ gem.summary = "ActiveRecord/Rails Sphinx library"
10
+ gem.description = "A concise and easy-to-use Ruby library that connects ActiveRecord to the Sphinx search daemon, managing configuration, indexing and searching."
11
+ gem.authors = ["Pat Allan", "Jaroslaw Skrzypek"]
12
+ gem.email = "hawk@zenbe.com"
13
+ gem.homepage = "http://github.com/hawkerb/thinking-sphinx"
14
+
15
+ # s.rubyforge_project = "thinking-sphinx"
16
+ gem.files = FileList[
17
+ "rails/*.rb",
18
+ "lib/**/*.rb",
19
+ "LICENCE",
20
+ "README.textile",
21
+ "tasks/**/*.rb",
22
+ "tasks/**/*.rake",
23
+ "VERSION"
24
+ ]
25
+ gem.test_files = FileList[
26
+ "features/**/*",
27
+ "spec/**/*_spec.rb"
28
+ ]
29
+
30
+ gem.add_dependency 'activerecord', '>= 1.15.6'
31
+ gem.add_dependency 'riddle', '>= 1.0.8'
32
+ gem.add_dependency 'after_commit', '>= 1.0.5'
33
+
34
+ gem.post_install_message = <<-MESSAGE
35
+ If you're upgrading, you should read this:
36
+ http://freelancing-god.github.com/ts/en/upgrading.html
37
+
38
+ MESSAGE
39
+ end
40
+ Jeweler::GemcutterTasks.new
41
+
data/tasks/rails.rake ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), '/../lib/thinking_sphinx/tasks')
data/tasks/testing.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'rubygems'
2
+ require 'spec/rake/spectask'
3
+ require 'cucumber/rake/task'
4
+
5
+ desc "Run the specs under spec"
6
+ Spec::Rake::SpecTask.new do |t|
7
+ t.spec_files = FileList['spec/**/*_spec.rb']
8
+ t.spec_opts << "-c"
9
+ end
10
+
11
+ desc "Run all feature-set configurations"
12
+ task :features do |t|
13
+ databases = ENV['DATABASES'] || 'mysql,postgresql'
14
+ databases.split(',').each do |database|
15
+ puts "rake features:#{database}"
16
+ system "rake features:#{database}"
17
+ end
18
+ end
19
+
20
+ namespace :features do
21
+ def add_task(name, description)
22
+ Cucumber::Rake::Task.new(name, description) do |t|
23
+ t.cucumber_opts = "--format pretty features/*.feature DATABASE=#{name}"
24
+ end
25
+ end
26
+
27
+ add_task :mysql, "Run feature-set against MySQL"
28
+ add_task :postgresql, "Run feature-set against PostgreSQL"
29
+ end
30
+
31
+ desc "Generate RCov reports"
32
+ Spec::Rake::SpecTask.new(:rcov) do |t|
33
+ t.libs << 'lib'
34
+ t.spec_files = FileList['spec/**/*_spec.rb']
35
+ t.rcov = true
36
+ t.rcov_opts = [
37
+ '--exclude', 'spec',
38
+ '--exclude', 'gems',
39
+ '--exclude', 'riddle',
40
+ '--exclude', 'ruby'
41
+ ]
42
+ end
43
+
44
+ namespace :rcov do
45
+ def add_task(name, description)
46
+ Cucumber::Rake::Task.new(name, description) do |t|
47
+ t.cucumber_opts = "--format pretty"
48
+ t.profile = name
49
+ t.rcov = true
50
+ t.rcov_opts = [
51
+ '--exclude', 'spec',
52
+ '--exclude', 'gems',
53
+ '--exclude', 'riddle',
54
+ '--exclude', 'features'
55
+ ]
56
+ end
57
+ end
58
+
59
+ add_task :mysql, "Run feature-set against MySQL with rcov"
60
+ add_task :postgresql, "Run feature-set against PostgreSQL with rcov"
61
+ end
62
+
63
+ desc "Build cucumber.yml file"
64
+ task :cucumber_defaults do
65
+ steps = FileList["features/step_definitions/**.rb"].collect { |path|
66
+ "--require #{path}"
67
+ }.join(" ")
68
+
69
+ File.open('cucumber.yml', 'w') { |f|
70
+ f.write "default: \"--require features/support/env.rb #{steps}\"\n"
71
+ }
72
+ end
@@ -0,0 +1 @@
1
+ test.sqlite3
@@ -0,0 +1,122 @@
1
+ module AfterCommit
2
+ module ActiveRecord
3
+ def self.included(base)
4
+ base.class_eval do
5
+ class << self
6
+ def establish_connection_with_after_commit(spec = nil)
7
+ establish_connection_without_after_commit spec
8
+ include_after_commit_extensions
9
+ end
10
+ alias_method_chain :establish_connection, :after_commit
11
+
12
+ def include_after_commit_extensions
13
+ base = ::ActiveRecord::ConnectionAdapters::AbstractAdapter
14
+ Object.subclasses_of(base).each do |klass|
15
+ include_after_commit_extension klass
16
+ end
17
+
18
+ if defined?(JRUBY_VERSION) and defined?(JdbcSpec::MySQL)
19
+ include_after_commit_extension JdbcSpec::MySQL
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def include_after_commit_extension(adapter)
26
+ additions = AfterCommit::ConnectionAdapters
27
+ unless adapter.included_modules.include?(additions)
28
+ adapter.send :include, additions
29
+ end
30
+ end
31
+ end
32
+
33
+ # The define_callbacks method was added post Rails 2.0.2 - if it
34
+ # doesn't exist, we define the callback manually
35
+ if respond_to?(:define_callbacks)
36
+ define_callbacks :after_commit,
37
+ :after_commit_on_create,
38
+ :after_commit_on_update,
39
+ :after_commit_on_destroy,
40
+ :after_rollback,
41
+ :before_commit,
42
+ :before_commit_on_create,
43
+ :before_commit_on_update,
44
+ :before_commit_on_destroy,
45
+ :before_rollback
46
+ else
47
+ class << self
48
+ # Handle after_commit callbacks - call all the registered callbacks.
49
+ def after_commit(*callbacks, &block)
50
+ callbacks << block if block_given?
51
+ write_inheritable_array(:after_commit, callbacks)
52
+ end
53
+
54
+ def after_commit_on_create(*callbacks, &block)
55
+ callbacks << block if block_given?
56
+ write_inheritable_array(:after_commit_on_create, callbacks)
57
+ end
58
+
59
+ def after_commit_on_update(*callbacks, &block)
60
+ callbacks << block if block_given?
61
+ write_inheritable_array(:after_commit_on_update, callbacks)
62
+ end
63
+
64
+ def after_commit_on_destroy(*callbacks, &block)
65
+ callbacks << block if block_given?
66
+ write_inheritable_array(:after_commit_on_destroy, callbacks)
67
+ end
68
+
69
+ def after_rollback(*callbacks, &block)
70
+ callbacks << block if block_given?
71
+ write_inheritable_array(:after_commit, callbacks)
72
+ end
73
+
74
+ def before_commit(*callbacks, &block)
75
+ callbacks << block if block_given?
76
+ write_inheritable_array(:before_commit, callbacks)
77
+ end
78
+
79
+ def before_commit_on_create(*callbacks, &block)
80
+ callbacks << block if block_given?
81
+ write_inheritable_array(:before_commit_on_create, callbacks)
82
+ end
83
+
84
+ def before_commit_on_update(*callbacks, &block)
85
+ callbacks << block if block_given?
86
+ write_inheritable_array(:before_commit_on_update, callbacks)
87
+ end
88
+
89
+ def before_commit_on_destroy(*callbacks, &block)
90
+ callbacks << block if block_given?
91
+ write_inheritable_array(:before_commit_on_destroy, callbacks)
92
+ end
93
+
94
+ def before_rollback(*callbacks, &block)
95
+ callbacks << block if block_given?
96
+ write_inheritable_array(:before_commit, callbacks)
97
+ end
98
+ end
99
+ end
100
+
101
+ after_create :add_committed_record_on_create
102
+ after_update :add_committed_record_on_update
103
+ after_destroy :add_committed_record_on_destroy
104
+
105
+ def add_committed_record_on_create
106
+ AfterCommit.record(self.class.connection, self)
107
+ AfterCommit.record_created(self.class.connection, self)
108
+ end
109
+
110
+ def add_committed_record_on_update
111
+ AfterCommit.record(self.class.connection, self)
112
+ AfterCommit.record_updated(self.class.connection, self)
113
+ end
114
+
115
+ def add_committed_record_on_destroy
116
+ AfterCommit.record(self.class.connection, self)
117
+ AfterCommit.record_destroyed(self.class.connection, self)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end