thinking-sphinx 2.1.0 → 3.0.0.pre

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 (352) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +13 -0
  3. data/Appraisals +7 -0
  4. data/Gemfile +10 -0
  5. data/HISTORY +2 -267
  6. data/LICENCE +1 -1
  7. data/README.textile +194 -226
  8. data/Rakefile +24 -0
  9. data/gemfiles/.gitignore +1 -0
  10. data/gemfiles/rails_3_1.gemfile +11 -0
  11. data/gemfiles/rails_3_2.gemfile +11 -0
  12. data/lib/thinking-sphinx.rb +1 -1
  13. data/lib/thinking_sphinx.rb +34 -292
  14. data/lib/thinking_sphinx/active_record.rb +22 -383
  15. data/lib/thinking_sphinx/active_record/association.rb +9 -0
  16. data/lib/thinking_sphinx/active_record/association_proxy.rb +68 -0
  17. data/lib/thinking_sphinx/active_record/associations.rb +68 -0
  18. data/lib/thinking_sphinx/active_record/attribute.rb +20 -0
  19. data/lib/thinking_sphinx/active_record/attribute/sphinx_presenter.rb +32 -0
  20. data/lib/thinking_sphinx/active_record/attribute/type.rb +79 -0
  21. data/lib/thinking_sphinx/active_record/attribute/values.rb +18 -0
  22. data/lib/thinking_sphinx/active_record/base.rb +36 -0
  23. data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +31 -0
  24. data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +55 -0
  25. data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +59 -0
  26. data/lib/thinking_sphinx/active_record/column.rb +30 -0
  27. data/lib/thinking_sphinx/active_record/database_adapters.rb +51 -0
  28. data/lib/thinking_sphinx/active_record/database_adapters/abstract_adapter.rb +13 -0
  29. data/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb +23 -0
  30. data/lib/thinking_sphinx/active_record/database_adapters/postgresql_adapter.rb +25 -0
  31. data/lib/thinking_sphinx/active_record/field.rb +11 -0
  32. data/lib/thinking_sphinx/active_record/index.rb +55 -0
  33. data/lib/thinking_sphinx/active_record/interpreter.rb +47 -0
  34. data/lib/thinking_sphinx/active_record/log_subscriber.rb +10 -58
  35. data/lib/thinking_sphinx/active_record/property.rb +28 -0
  36. data/lib/thinking_sphinx/active_record/property_sql_presenter.rb +60 -0
  37. data/lib/thinking_sphinx/active_record/sql_builder.rb +159 -0
  38. data/lib/thinking_sphinx/active_record/sql_source.rb +138 -0
  39. data/lib/thinking_sphinx/active_record/sql_source/template.rb +46 -0
  40. data/lib/thinking_sphinx/batched_search.rb +26 -0
  41. data/lib/thinking_sphinx/callbacks.rb +15 -0
  42. data/lib/thinking_sphinx/configuration.rb +80 -331
  43. data/lib/thinking_sphinx/configuration/consistent_ids.rb +31 -0
  44. data/lib/thinking_sphinx/configuration/defaults.rb +5 -0
  45. data/lib/thinking_sphinx/core.rb +6 -0
  46. data/lib/thinking_sphinx/core/index.rb +68 -0
  47. data/lib/thinking_sphinx/core/interpreter.rb +19 -0
  48. data/lib/thinking_sphinx/deltas.rb +35 -26
  49. data/lib/thinking_sphinx/deltas/default_delta.rb +56 -56
  50. data/lib/thinking_sphinx/excerpter.rb +23 -21
  51. data/lib/thinking_sphinx/facet.rb +22 -127
  52. data/lib/thinking_sphinx/facet_search.rb +95 -162
  53. data/lib/thinking_sphinx/index.rb +39 -143
  54. data/lib/thinking_sphinx/index_set.rb +51 -0
  55. data/lib/thinking_sphinx/masks.rb +8 -0
  56. data/lib/thinking_sphinx/masks/group_enumerators_mask.rb +23 -0
  57. data/lib/thinking_sphinx/masks/pagination_mask.rb +60 -0
  58. data/lib/thinking_sphinx/masks/scopes_mask.rb +35 -0
  59. data/lib/thinking_sphinx/masks/weight_enumerator_mask.rb +11 -0
  60. data/lib/thinking_sphinx/middlewares.rb +36 -0
  61. data/lib/thinking_sphinx/middlewares/active_record_translator.rb +73 -0
  62. data/lib/thinking_sphinx/middlewares/geographer.rb +53 -0
  63. data/lib/thinking_sphinx/middlewares/glazier.rb +39 -0
  64. data/lib/thinking_sphinx/middlewares/ids_only.rb +13 -0
  65. data/lib/thinking_sphinx/middlewares/inquirer.rb +62 -0
  66. data/lib/thinking_sphinx/middlewares/middleware.rb +9 -0
  67. data/lib/thinking_sphinx/middlewares/sphinxql.rb +149 -0
  68. data/lib/thinking_sphinx/middlewares/stale_id_checker.rb +45 -0
  69. data/lib/thinking_sphinx/middlewares/stale_id_filter.rb +46 -0
  70. data/lib/thinking_sphinx/panes.rb +8 -0
  71. data/lib/thinking_sphinx/panes/attributes_pane.rb +9 -0
  72. data/lib/thinking_sphinx/panes/distance_pane.rb +13 -0
  73. data/lib/thinking_sphinx/panes/excerpts_pane.rb +37 -0
  74. data/lib/thinking_sphinx/panes/weight_pane.rb +9 -0
  75. data/lib/thinking_sphinx/railtie.rb +6 -40
  76. data/lib/thinking_sphinx/rake_interface.rb +47 -0
  77. data/lib/thinking_sphinx/real_time.rb +11 -0
  78. data/lib/thinking_sphinx/real_time/attribute.rb +5 -0
  79. data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +48 -0
  80. data/lib/thinking_sphinx/real_time/field.rb +3 -0
  81. data/lib/thinking_sphinx/real_time/index.rb +47 -0
  82. data/lib/thinking_sphinx/real_time/index/template.rb +33 -0
  83. data/lib/thinking_sphinx/real_time/interpreter.rb +23 -0
  84. data/lib/thinking_sphinx/real_time/property.rb +16 -0
  85. data/lib/thinking_sphinx/scopes.rb +22 -0
  86. data/lib/thinking_sphinx/search.rb +90 -1028
  87. data/lib/thinking_sphinx/search/batch_inquirer.rb +27 -0
  88. data/lib/thinking_sphinx/search/context.rb +26 -0
  89. data/lib/thinking_sphinx/search/glaze.rb +32 -0
  90. data/lib/thinking_sphinx/search/merger.rb +24 -0
  91. data/lib/thinking_sphinx/search/query.rb +43 -0
  92. data/lib/thinking_sphinx/search/stale_ids_exception.rb +11 -0
  93. data/lib/thinking_sphinx/search/translator.rb +50 -0
  94. data/lib/thinking_sphinx/tasks.rb +22 -125
  95. data/lib/thinking_sphinx/test.rb +9 -19
  96. data/sketchpad.rb +58 -0
  97. data/spec/acceptance/association_scoping_spec.rb +23 -0
  98. data/spec/acceptance/attribute_access_spec.rb +39 -0
  99. data/spec/acceptance/attribute_updates_spec.rb +16 -0
  100. data/spec/acceptance/batch_searching_spec.rb +21 -0
  101. data/spec/acceptance/big_integers_spec.rb +27 -0
  102. data/spec/acceptance/excerpts_spec.rb +14 -0
  103. data/spec/acceptance/facets_spec.rb +122 -0
  104. data/spec/acceptance/geosearching_spec.rb +39 -0
  105. data/spec/acceptance/grouping_by_attributes_spec.rb +77 -0
  106. data/spec/acceptance/paginating_search_results_spec.rb +24 -0
  107. data/spec/acceptance/remove_deleted_records_spec.rb +23 -0
  108. data/spec/acceptance/search_counts_spec.rb +18 -0
  109. data/spec/acceptance/search_for_just_ids_spec.rb +19 -0
  110. data/spec/acceptance/searching_across_models_spec.rb +28 -0
  111. data/spec/acceptance/searching_on_fields_spec.rb +56 -0
  112. data/spec/acceptance/searching_with_filters_spec.rb +109 -0
  113. data/spec/acceptance/searching_with_sti_spec.rb +55 -0
  114. data/spec/acceptance/searching_within_a_model_spec.rb +52 -0
  115. data/spec/acceptance/sorting_search_results_spec.rb +41 -0
  116. data/spec/acceptance/spec_helper.rb +4 -0
  117. data/spec/acceptance/specifying_sql_spec.rb +62 -0
  118. data/spec/acceptance/sphinx_scopes_spec.rb +49 -0
  119. data/spec/acceptance/sql_deltas_spec.rb +43 -0
  120. data/spec/acceptance/support/database_cleaner.rb +11 -0
  121. data/spec/acceptance/support/sphinx_controller.rb +39 -0
  122. data/spec/acceptance/support/sphinx_helpers.rb +24 -0
  123. data/spec/acceptance/suspended_deltas_spec.rb +20 -0
  124. data/spec/internal/.gitignore +1 -0
  125. data/spec/internal/app/indices/animal_index.rb +3 -0
  126. data/spec/internal/app/indices/article_index.rb +24 -0
  127. data/spec/internal/app/indices/book_index.rb +8 -0
  128. data/spec/internal/app/indices/city_index.rb +6 -0
  129. data/spec/internal/app/indices/product_index.rb +3 -0
  130. data/spec/internal/app/indices/tee_index.rb +4 -0
  131. data/spec/internal/app/indices/user_index.rb +5 -0
  132. data/spec/internal/app/models/animal.rb +2 -0
  133. data/spec/internal/app/models/article.rb +5 -0
  134. data/spec/internal/app/models/bird.rb +2 -0
  135. data/spec/internal/app/models/book.rb +11 -0
  136. data/spec/internal/app/models/city.rb +2 -0
  137. data/spec/internal/app/models/colour.rb +3 -0
  138. data/spec/internal/app/models/flightless_bird.rb +2 -0
  139. data/spec/internal/app/models/mammal.rb +2 -0
  140. data/spec/internal/app/models/product.rb +3 -0
  141. data/spec/internal/app/models/tag.rb +4 -0
  142. data/{features/thinking_sphinx → spec/internal/app}/models/tagging.rb +1 -1
  143. data/spec/internal/app/models/tee.rb +3 -0
  144. data/spec/internal/app/models/tweet.rb +3 -0
  145. data/spec/internal/app/models/user.rb +3 -0
  146. data/spec/internal/config/database.yml +5 -0
  147. data/spec/internal/db/schema.rb +65 -0
  148. data/spec/internal/log/.gitignore +1 -0
  149. data/spec/spec_helper.rb +8 -49
  150. data/spec/support/sphinx_yaml_helpers.rb +9 -0
  151. data/spec/thinking_sphinx/active_record/association_spec.rb +12 -0
  152. data/spec/thinking_sphinx/active_record/associations_spec.rb +184 -0
  153. data/spec/thinking_sphinx/active_record/attribute/type_spec.rb +147 -0
  154. data/spec/thinking_sphinx/active_record/base_spec.rb +61 -0
  155. data/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +80 -0
  156. data/spec/thinking_sphinx/active_record/callbacks/delta_callbacks_spec.rb +147 -0
  157. data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +69 -0
  158. data/spec/thinking_sphinx/active_record/column_spec.rb +47 -0
  159. data/spec/thinking_sphinx/active_record/database_adapters/abstract_adapter_spec.rb +31 -0
  160. data/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +43 -0
  161. data/spec/thinking_sphinx/active_record/database_adapters/postgresql_adapter_spec.rb +45 -0
  162. data/spec/thinking_sphinx/active_record/database_adapters_spec.rb +108 -0
  163. data/spec/thinking_sphinx/active_record/field_spec.rb +36 -0
  164. data/spec/thinking_sphinx/active_record/index_spec.rb +208 -0
  165. data/spec/thinking_sphinx/active_record/interpreter_spec.rb +293 -0
  166. data/spec/thinking_sphinx/active_record/property_sql_presenter_spec.rb +162 -0
  167. data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +666 -0
  168. data/spec/thinking_sphinx/active_record/sql_source_spec.rb +401 -0
  169. data/spec/thinking_sphinx/configuration_spec.rb +264 -171
  170. data/spec/thinking_sphinx/deltas/default_delta_spec.rb +116 -0
  171. data/spec/thinking_sphinx/deltas_spec.rb +58 -0
  172. data/spec/thinking_sphinx/excerpter_spec.rb +40 -38
  173. data/spec/thinking_sphinx/facet_search_spec.rb +49 -151
  174. data/spec/thinking_sphinx/index_set_spec.rb +68 -0
  175. data/spec/thinking_sphinx/index_spec.rb +91 -155
  176. data/spec/thinking_sphinx/masks/pagination_mask_spec.rb +121 -0
  177. data/spec/thinking_sphinx/masks/scopes_mask_spec.rb +68 -0
  178. data/spec/thinking_sphinx/middlewares/active_record_translator_spec.rb +132 -0
  179. data/spec/thinking_sphinx/middlewares/geographer_spec.rb +89 -0
  180. data/spec/thinking_sphinx/middlewares/glazier_spec.rb +62 -0
  181. data/spec/thinking_sphinx/middlewares/inquirer_spec.rb +55 -0
  182. data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +271 -0
  183. data/spec/thinking_sphinx/middlewares/stale_id_checker_spec.rb +47 -0
  184. data/spec/thinking_sphinx/middlewares/stale_id_filter_spec.rb +91 -0
  185. data/spec/thinking_sphinx/panes/attributes_pane_spec.rb +21 -0
  186. data/spec/thinking_sphinx/panes/distance_pane_spec.rb +41 -0
  187. data/spec/thinking_sphinx/panes/excerpts_pane_spec.rb +53 -0
  188. data/spec/thinking_sphinx/panes/weight_pane_spec.rb +20 -0
  189. data/spec/thinking_sphinx/rake_interface_spec.rb +147 -0
  190. data/spec/thinking_sphinx/real_time/attribute_spec.rb +62 -0
  191. data/spec/thinking_sphinx/real_time/callbacks/real_time_callbacks_spec.rb +76 -0
  192. data/spec/thinking_sphinx/real_time/field_spec.rb +54 -0
  193. data/spec/thinking_sphinx/real_time/index_spec.rb +154 -0
  194. data/spec/thinking_sphinx/real_time/interpreter_spec.rb +147 -0
  195. data/spec/thinking_sphinx/scopes_spec.rb +38 -0
  196. data/spec/thinking_sphinx/search/glaze_spec.rb +55 -0
  197. data/spec/thinking_sphinx/search/query_spec.rb +46 -0
  198. data/spec/thinking_sphinx/search_spec.rb +65 -1357
  199. data/spec/thinking_sphinx_spec.rb +19 -182
  200. data/thinking-sphinx.gemspec +33 -0
  201. metadata +318 -431
  202. data/features/abstract_inheritance.feature +0 -10
  203. data/features/alternate_primary_key.feature +0 -27
  204. data/features/attribute_transformation.feature +0 -22
  205. data/features/attribute_updates.feature +0 -79
  206. data/features/deleting_instances.feature +0 -70
  207. data/features/direct_attributes.feature +0 -11
  208. data/features/excerpts.feature +0 -21
  209. data/features/extensible_delta_indexing.feature +0 -9
  210. data/features/facets.feature +0 -88
  211. data/features/facets_across_model.feature +0 -29
  212. data/features/field_sorting.feature +0 -18
  213. data/features/handling_edits.feature +0 -97
  214. data/features/retry_stale_indexes.feature +0 -24
  215. data/features/searching_across_models.feature +0 -20
  216. data/features/searching_by_index.feature +0 -41
  217. data/features/searching_by_model.feature +0 -175
  218. data/features/searching_with_find_arguments.feature +0 -56
  219. data/features/sphinx_detection.feature +0 -25
  220. data/features/sphinx_scopes.feature +0 -68
  221. data/features/step_definitions/alpha_steps.rb +0 -16
  222. data/features/step_definitions/beta_steps.rb +0 -7
  223. data/features/step_definitions/common_steps.rb +0 -205
  224. data/features/step_definitions/extensible_delta_indexing_steps.rb +0 -7
  225. data/features/step_definitions/facet_steps.rb +0 -96
  226. data/features/step_definitions/find_arguments_steps.rb +0 -36
  227. data/features/step_definitions/gamma_steps.rb +0 -15
  228. data/features/step_definitions/scope_steps.rb +0 -19
  229. data/features/step_definitions/search_steps.rb +0 -94
  230. data/features/step_definitions/sphinx_steps.rb +0 -35
  231. data/features/sti_searching.feature +0 -19
  232. data/features/support/env.rb +0 -24
  233. data/features/support/lib/generic_delta_handler.rb +0 -8
  234. data/features/thinking_sphinx/database.example.yml +0 -3
  235. data/features/thinking_sphinx/db/.gitignore +0 -1
  236. data/features/thinking_sphinx/db/fixtures/alphas.rb +0 -8
  237. data/features/thinking_sphinx/db/fixtures/authors.rb +0 -1
  238. data/features/thinking_sphinx/db/fixtures/betas.rb +0 -11
  239. data/features/thinking_sphinx/db/fixtures/boxes.rb +0 -9
  240. data/features/thinking_sphinx/db/fixtures/categories.rb +0 -1
  241. data/features/thinking_sphinx/db/fixtures/cats.rb +0 -3
  242. data/features/thinking_sphinx/db/fixtures/comments.rb +0 -24
  243. data/features/thinking_sphinx/db/fixtures/developers.rb +0 -31
  244. data/features/thinking_sphinx/db/fixtures/dogs.rb +0 -3
  245. data/features/thinking_sphinx/db/fixtures/extensible_betas.rb +0 -10
  246. data/features/thinking_sphinx/db/fixtures/foxes.rb +0 -3
  247. data/features/thinking_sphinx/db/fixtures/gammas.rb +0 -10
  248. data/features/thinking_sphinx/db/fixtures/music.rb +0 -4
  249. data/features/thinking_sphinx/db/fixtures/people.rb +0 -1001
  250. data/features/thinking_sphinx/db/fixtures/post_keywords.txt +0 -1
  251. data/features/thinking_sphinx/db/fixtures/posts.rb +0 -10
  252. data/features/thinking_sphinx/db/fixtures/robots.rb +0 -8
  253. data/features/thinking_sphinx/db/fixtures/tags.rb +0 -27
  254. data/features/thinking_sphinx/db/migrations/create_alphas.rb +0 -8
  255. data/features/thinking_sphinx/db/migrations/create_animals.rb +0 -5
  256. data/features/thinking_sphinx/db/migrations/create_authors.rb +0 -3
  257. data/features/thinking_sphinx/db/migrations/create_authors_posts.rb +0 -6
  258. data/features/thinking_sphinx/db/migrations/create_betas.rb +0 -5
  259. data/features/thinking_sphinx/db/migrations/create_boxes.rb +0 -5
  260. data/features/thinking_sphinx/db/migrations/create_categories.rb +0 -3
  261. data/features/thinking_sphinx/db/migrations/create_comments.rb +0 -10
  262. data/features/thinking_sphinx/db/migrations/create_developers.rb +0 -7
  263. data/features/thinking_sphinx/db/migrations/create_extensible_betas.rb +0 -5
  264. data/features/thinking_sphinx/db/migrations/create_gammas.rb +0 -3
  265. data/features/thinking_sphinx/db/migrations/create_genres.rb +0 -3
  266. data/features/thinking_sphinx/db/migrations/create_music.rb +0 -6
  267. data/features/thinking_sphinx/db/migrations/create_people.rb +0 -13
  268. data/features/thinking_sphinx/db/migrations/create_posts.rb +0 -6
  269. data/features/thinking_sphinx/db/migrations/create_robots.rb +0 -4
  270. data/features/thinking_sphinx/db/migrations/create_taggings.rb +0 -5
  271. data/features/thinking_sphinx/db/migrations/create_tags.rb +0 -4
  272. data/features/thinking_sphinx/models/alpha.rb +0 -23
  273. data/features/thinking_sphinx/models/andrew.rb +0 -17
  274. data/features/thinking_sphinx/models/animal.rb +0 -5
  275. data/features/thinking_sphinx/models/author.rb +0 -3
  276. data/features/thinking_sphinx/models/beta.rb +0 -13
  277. data/features/thinking_sphinx/models/box.rb +0 -8
  278. data/features/thinking_sphinx/models/cat.rb +0 -3
  279. data/features/thinking_sphinx/models/category.rb +0 -4
  280. data/features/thinking_sphinx/models/comment.rb +0 -10
  281. data/features/thinking_sphinx/models/developer.rb +0 -21
  282. data/features/thinking_sphinx/models/dog.rb +0 -3
  283. data/features/thinking_sphinx/models/extensible_beta.rb +0 -9
  284. data/features/thinking_sphinx/models/fox.rb +0 -5
  285. data/features/thinking_sphinx/models/gamma.rb +0 -5
  286. data/features/thinking_sphinx/models/genre.rb +0 -3
  287. data/features/thinking_sphinx/models/medium.rb +0 -5
  288. data/features/thinking_sphinx/models/music.rb +0 -10
  289. data/features/thinking_sphinx/models/person.rb +0 -24
  290. data/features/thinking_sphinx/models/post.rb +0 -22
  291. data/features/thinking_sphinx/models/robot.rb +0 -12
  292. data/features/thinking_sphinx/models/tag.rb +0 -3
  293. data/lib/cucumber/thinking_sphinx/external_world.rb +0 -12
  294. data/lib/cucumber/thinking_sphinx/internal_world.rb +0 -137
  295. data/lib/cucumber/thinking_sphinx/sql_logger.rb +0 -28
  296. data/lib/thinking_sphinx/action_controller.rb +0 -31
  297. data/lib/thinking_sphinx/active_record/attribute_updates.rb +0 -54
  298. data/lib/thinking_sphinx/active_record/collection_proxy.rb +0 -47
  299. data/lib/thinking_sphinx/active_record/collection_proxy_with_scopes.rb +0 -27
  300. data/lib/thinking_sphinx/active_record/delta.rb +0 -67
  301. data/lib/thinking_sphinx/active_record/has_many_association.rb +0 -44
  302. data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +0 -21
  303. data/lib/thinking_sphinx/active_record/scopes.rb +0 -110
  304. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +0 -94
  305. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +0 -62
  306. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +0 -188
  307. data/lib/thinking_sphinx/association.rb +0 -230
  308. data/lib/thinking_sphinx/attribute.rb +0 -405
  309. data/lib/thinking_sphinx/auto_version.rb +0 -40
  310. data/lib/thinking_sphinx/bundled_search.rb +0 -40
  311. data/lib/thinking_sphinx/class_facet.rb +0 -20
  312. data/lib/thinking_sphinx/connection.rb +0 -71
  313. data/lib/thinking_sphinx/context.rb +0 -81
  314. data/lib/thinking_sphinx/core/string.rb +0 -15
  315. data/lib/thinking_sphinx/deltas/delete_job.rb +0 -16
  316. data/lib/thinking_sphinx/deltas/index_job.rb +0 -17
  317. data/lib/thinking_sphinx/deploy/capistrano.rb +0 -99
  318. data/lib/thinking_sphinx/field.rb +0 -98
  319. data/lib/thinking_sphinx/index/builder.rb +0 -315
  320. data/lib/thinking_sphinx/index/faux_column.rb +0 -118
  321. data/lib/thinking_sphinx/join.rb +0 -37
  322. data/lib/thinking_sphinx/property.rb +0 -187
  323. data/lib/thinking_sphinx/search_methods.rb +0 -439
  324. data/lib/thinking_sphinx/sinatra.rb +0 -7
  325. data/lib/thinking_sphinx/source.rb +0 -194
  326. data/lib/thinking_sphinx/source/internal_properties.rb +0 -51
  327. data/lib/thinking_sphinx/source/sql.rb +0 -174
  328. data/spec/fixtures/data.sql +0 -32
  329. data/spec/fixtures/database.yml.default +0 -3
  330. data/spec/fixtures/models.rb +0 -164
  331. data/spec/fixtures/structure.sql +0 -146
  332. data/spec/sphinx_helper.rb +0 -60
  333. data/spec/support/rails.rb +0 -25
  334. data/spec/thinking_sphinx/active_record/delta_spec.rb +0 -123
  335. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +0 -173
  336. data/spec/thinking_sphinx/active_record/scopes_spec.rb +0 -177
  337. data/spec/thinking_sphinx/active_record_spec.rb +0 -573
  338. data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +0 -163
  339. data/spec/thinking_sphinx/association_spec.rb +0 -250
  340. data/spec/thinking_sphinx/attribute_spec.rb +0 -552
  341. data/spec/thinking_sphinx/auto_version_spec.rb +0 -103
  342. data/spec/thinking_sphinx/connection_spec.rb +0 -77
  343. data/spec/thinking_sphinx/context_spec.rb +0 -127
  344. data/spec/thinking_sphinx/core/array_spec.rb +0 -9
  345. data/spec/thinking_sphinx/core/string_spec.rb +0 -9
  346. data/spec/thinking_sphinx/facet_spec.rb +0 -359
  347. data/spec/thinking_sphinx/field_spec.rb +0 -127
  348. data/spec/thinking_sphinx/index/builder_spec.rb +0 -532
  349. data/spec/thinking_sphinx/index/faux_column_spec.rb +0 -36
  350. data/spec/thinking_sphinx/search_methods_spec.rb +0 -156
  351. data/spec/thinking_sphinx/source_spec.rb +0 -267
  352. data/spec/thinking_sphinx/test_spec.rb +0 -20
@@ -1,230 +0,0 @@
1
- module ThinkingSphinx
2
- # Association tracks a specific reflection and join to reference data that
3
- # isn't in the base model. Very much an internal class for Thinking Sphinx -
4
- # perhaps because I feel it's not as strong (or simple) as most of the rest.
5
- #
6
- class Association
7
- attr_accessor :parent, :reflection, :join
8
-
9
- # Create a new association by passing in the parent association, and the
10
- # corresponding reflection instance. If there is no parent, pass in nil.
11
- #
12
- # top = Association.new nil, top_reflection
13
- # child = Association.new top, child_reflection
14
- #
15
- def initialize(parent, reflection)
16
- @parent, @reflection = parent, reflection
17
- @children = {}
18
- end
19
-
20
- # Get the children associations for a given association name. The only time
21
- # that there'll actually be more than one association is when the
22
- # relationship is polymorphic. To keep things simple though, it will always
23
- # be an Array that gets returned (an empty one if no matches).
24
- #
25
- # # where pages is an association on the class tied to the reflection.
26
- # association.children(:pages)
27
- #
28
- def children(assoc)
29
- @children[assoc] ||= Association.children(@reflection.klass, assoc, self)
30
- end
31
-
32
- # Get the children associations for a given class, association name and
33
- # parent association. Much like the instance method of the same name, it
34
- # will return an empty array if no associations have the name, and only
35
- # have multiple association instances if the underlying relationship is
36
- # polymorphic.
37
- #
38
- # Association.children(User, :pages, user_association)
39
- #
40
- def self.children(klass, assoc, parent=nil)
41
- ref = klass.reflect_on_association(assoc)
42
-
43
- return [] if ref.nil?
44
- return [Association.new(parent, ref)] unless ref.options[:polymorphic]
45
-
46
- # association is polymorphic - create associations for each
47
- # non-polymorphic reflection.
48
- polymorphic_classes(ref).collect { |poly_class|
49
- Association.new parent, depolymorphic_reflection(ref, klass, poly_class)
50
- }
51
- end
52
-
53
- # Link up the join for this model from a base join - and set parent
54
- # associations' joins recursively.
55
- #
56
- def join_to(base_join)
57
- parent.join_to(base_join) if parent && parent.join.nil?
58
-
59
- @join ||= join_association_class.new(
60
- @reflection, base_join, parent ? parent.join : join_parent(base_join)
61
- )
62
- end
63
-
64
- def arel_join
65
- @join.join_type = Arel::OuterJoin
66
- rewrite_conditions
67
-
68
- @join
69
- end
70
-
71
- # Returns true if the association - or a parent - is a has_many or
72
- # has_and_belongs_to_many.
73
- #
74
- def is_many?
75
- case @reflection.macro
76
- when :has_many, :has_and_belongs_to_many
77
- true
78
- else
79
- @parent ? @parent.is_many? : false
80
- end
81
- end
82
-
83
- # Returns an array of all the associations that lead to this one - starting
84
- # with the top level all the way to the current association object.
85
- #
86
- def ancestors
87
- (parent ? parent.ancestors : []) << self
88
- end
89
-
90
- def has_column?(column)
91
- @reflection.klass.column_names.include?(column.to_s)
92
- end
93
-
94
- def primary_key_from_reflection
95
- if @reflection.options[:through]
96
- if ThinkingSphinx.rails_3_1?
97
- @reflection.source_reflection.foreign_key
98
- else
99
- @reflection.source_reflection.options[:foreign_key] ||
100
- @reflection.source_reflection.primary_key_name
101
- end
102
- elsif @reflection.macro == :has_and_belongs_to_many
103
- @reflection.association_foreign_key
104
- else
105
- nil
106
- end
107
- end
108
-
109
- def table
110
- if @reflection.options[:through] ||
111
- @reflection.macro == :has_and_belongs_to_many
112
- if ThinkingSphinx.rails_3_1?
113
- @join.tables.first.name
114
- else
115
- @join.aliased_join_table_name
116
- end
117
- else
118
- @join.aliased_table_name
119
- end
120
- end
121
-
122
- private
123
-
124
- def self.depolymorphic_reflection(reflection, source_class, poly_class)
125
- name = "#{reflection.name}_#{poly_class.name}".to_sym
126
-
127
- source_class.reflections[name] ||=
128
- ::ActiveRecord::Reflection::AssociationReflection.new(
129
- reflection.macro, name, casted_options(poly_class, reflection),
130
- reflection.active_record
131
- )
132
- end
133
-
134
- # Returns all the objects that could be currently instantiated from a
135
- # polymorphic association. This is pretty damn fast if there's an index on
136
- # the foreign type column - but if there isn't, it can take a while if you
137
- # have a lot of data.
138
- #
139
- def self.polymorphic_classes(ref)
140
- ref.active_record.connection.select_all(
141
- "SELECT DISTINCT #{foreign_type(ref)} " +
142
- "FROM #{ref.active_record.table_name} " +
143
- "WHERE #{foreign_type(ref)} IS NOT NULL"
144
- ).collect { |row|
145
- row[foreign_type(ref)].constantize
146
- }
147
- end
148
-
149
- # Returns a new set of options for an association that mimics an existing
150
- # polymorphic relationship for a specific class. It adds a condition to
151
- # filter by the appropriate object.
152
- #
153
- def self.casted_options(klass, ref)
154
- options = ref.options.clone
155
- options[:polymorphic] = nil
156
- options[:class_name] = klass.name
157
- options[:foreign_key] ||= "#{ref.name}_id"
158
-
159
- quoted_foreign_type = klass.connection.quote_column_name foreign_type(ref)
160
- case options[:conditions]
161
- when nil
162
- options[:conditions] = "::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'"
163
- when Array
164
- options[:conditions] << "::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'"
165
- when Hash
166
- options[:conditions].merge!(foreign_type(ref) => klass.name)
167
- else
168
- options[:conditions] << " AND ::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'"
169
- end
170
-
171
- options
172
- end
173
-
174
- def join_association_class
175
- if ThinkingSphinx.rails_3_1?
176
- ::ActiveRecord::Associations::JoinDependency::JoinAssociation
177
- else
178
- ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation
179
- end
180
- end
181
-
182
- def join_parent(join)
183
- if ThinkingSphinx.rails_3_1?
184
- join.join_parts.first
185
- else
186
- join.joins.first
187
- end
188
- end
189
-
190
- def self.foreign_type(ref)
191
- if ThinkingSphinx.rails_3_1?
192
- ref.foreign_type
193
- else
194
- ref.options[:foreign_type]
195
- end
196
- end
197
-
198
- def rewrite_conditions
199
- @join.options[:conditions] = case @join.options[:conditions]
200
- when String
201
- rewrite_condition @join.options[:conditions]
202
- when Array
203
- @join.options[:conditions].collect { |condition|
204
- rewrite_condition condition
205
- }
206
- else
207
- @join.options[:conditions]
208
- end
209
- end
210
-
211
- def rewrite_condition(condition)
212
- return condition unless condition.is_a?(String)
213
-
214
- if defined?(ActsAsTaggableOn) &&
215
- @reflection.klass == ActsAsTaggableOn::Tagging &&
216
- @reflection.name.to_s[/_taggings$/]
217
- condition.gsub! /taggings\.tag_id = tags\.id AND/, "" if ThinkingSphinx.rails_3_1?
218
- condition = condition.gsub /taggings\./, "#{quoted_alias @join}."
219
- end
220
-
221
- condition.gsub /::ts_join_alias::/, quoted_alias(@join.parent)
222
- end
223
-
224
- def quoted_alias(join)
225
- @reflection.klass.connection.quote_table_name(
226
- join.aliased_table_name
227
- )
228
- end
229
- end
230
- end
@@ -1,405 +0,0 @@
1
- module ThinkingSphinx
2
- # Attributes - eternally useful when it comes to filtering, sorting or
3
- # grouping. This class isn't really useful to you unless you're hacking
4
- # around with the internals of Thinking Sphinx - but hey, don't let that
5
- # stop you.
6
- #
7
- # One key thing to remember - if you're using the attribute manually to
8
- # generate SQL statements, you'll need to set the base model, and all the
9
- # associations. Which can get messy. Use Index.link!, it really helps.
10
- #
11
- class Attribute < ThinkingSphinx::Property
12
- attr_accessor :query_source
13
-
14
- SphinxTypeMappings = {
15
- :multi => :sql_attr_multi,
16
- :datetime => :sql_attr_timestamp,
17
- :string => :sql_attr_str2ordinal,
18
- :float => :sql_attr_float,
19
- :boolean => :sql_attr_bool,
20
- :integer => :sql_attr_uint,
21
- :bigint => :sql_attr_bigint,
22
- :wordcount => :sql_attr_str2wordcount
23
- }
24
-
25
- # To create a new attribute, you'll need to pass in either a single Column
26
- # or an array of them, and some (optional) options.
27
- #
28
- # Valid options are:
29
- # - :as => :alias_name
30
- # - :type => :attribute_type
31
- # - :source => :field, :query, :ranged_query
32
- #
33
- # Alias is only required in three circumstances: when there's
34
- # another attribute or field with the same name, when the column name is
35
- # 'id', or when there's more than one column.
36
- #
37
- # Type is not required, unless you want to force a column to be a certain
38
- # type (but keep in mind the value will not be CASTed in the SQL
39
- # statements). The only time you really need to use this is when the type
40
- # can't be figured out by the column - ie: when not actually using a
41
- # database column as your source.
42
- #
43
- # Source is only used for multi-value attributes (MVA). By default this will
44
- # use a left-join and a group_concat to obtain the values. For better performance
45
- # during indexing it can be beneficial to let Sphinx use a separate query to retrieve
46
- # all document,value-pairs.
47
- # Either :query or :ranged_query will enable this feature, where :ranged_query will cause
48
- # the query to be executed incremental.
49
- #
50
- # Example usage:
51
- #
52
- # Attribute.new(
53
- # Column.new(:created_at)
54
- # )
55
- #
56
- # Attribute.new(
57
- # Column.new(:posts, :id),
58
- # :as => :post_ids
59
- # )
60
- #
61
- # Attribute.new(
62
- # Column.new(:posts, :id),
63
- # :as => :post_ids,
64
- # :source => :ranged_query
65
- # )
66
- #
67
- # Attribute.new(
68
- # [Column.new(:pages, :id), Column.new(:articles, :id)],
69
- # :as => :content_ids
70
- # )
71
- #
72
- # Attribute.new(
73
- # Column.new("NOW()"),
74
- # :as => :indexed_at,
75
- # :type => :datetime
76
- # )
77
- #
78
- # If you're creating attributes for latitude and longitude, don't forget
79
- # that Sphinx expects these values to be in radians.
80
- #
81
- def initialize(source, columns, options = {})
82
- super
83
-
84
- @type = options[:type]
85
- @query_source = options[:source]
86
- @crc = options[:crc]
87
- @all_ints = options[:all_ints]
88
-
89
- @type ||= :multi unless @query_source.nil?
90
- if @type == :string && @crc
91
- @type = is_many? ? :multi : :integer
92
- end
93
-
94
- source.attributes << self
95
- end
96
-
97
- # Get the part of the SELECT clause related to this attribute. Don't forget
98
- # to set your model and associations first though.
99
- #
100
- # This will concatenate strings and arrays of integers, and convert
101
- # datetimes to timestamps, as needed.
102
- #
103
- def to_select_sql
104
- return nil unless include_as_association? && available?
105
-
106
- separator = all_ints? || all_datetimes? || @crc ? ',' : ' '
107
-
108
- clause = columns_with_prefixes.collect { |column|
109
- case type
110
- when :string
111
- adapter.convert_nulls(column)
112
- when :datetime
113
- adapter.cast_to_datetime(column)
114
- when :multi
115
- column = adapter.cast_to_datetime(column) if is_many_datetimes?
116
- column = adapter.convert_nulls(column, '0') if is_many_ints?
117
- column
118
- else
119
- column
120
- end
121
- }.join(', ')
122
-
123
- clause = adapter.crc(clause) if @crc
124
- clause = adapter.concatenate(clause, separator) if concat_ws?
125
- clause = adapter.group_concatenate(clause, separator) if is_many?
126
- clause = adapter.downcase(clause) if insensitive?
127
-
128
- "#{clause} AS #{quote_column(unique_name)}"
129
- end
130
-
131
- def type_to_config
132
- SphinxTypeMappings[type]
133
- end
134
-
135
- def include_as_association?
136
- ! (type == :multi && (query_source == :query || query_source == :ranged_query))
137
- end
138
-
139
- # Returns the configuration value that should be used for
140
- # the attribute.
141
- # Special case is the multi-valued attribute that needs some
142
- # extra configuration.
143
- #
144
- def config_value(offset = nil, delta = false)
145
- if type == :multi
146
- multi_config = include_as_association? ? "field" :
147
- source_value(offset, delta).gsub(/\s+/m, " ").strip
148
- "uint #{unique_name} from #{multi_config}"
149
- else
150
- unique_name
151
- end
152
- end
153
-
154
- # Returns the type of the column. If that's not already set, it returns
155
- # :multi if there's the possibility of more than one value, :string if
156
- # there's more than one association, otherwise it figures out what the
157
- # actual column's datatype is and returns that.
158
- #
159
- def type
160
- @type ||= begin
161
- base_type = case
162
- when is_many?, is_many_ints?
163
- :multi
164
- when @associations.values.flatten.length > 1
165
- :string
166
- else
167
- translated_type_from_database
168
- end
169
-
170
- if base_type == :string && @crc
171
- base_type = :integer
172
- else
173
- @crc = false unless base_type == :multi && is_many_strings? && @crc
174
- end
175
-
176
- base_type
177
- end
178
- end
179
-
180
- def updatable?
181
- [:integer, :datetime, :boolean].include?(type) &&
182
- unique_name != :sphinx_internal_id &&
183
- !is_string?
184
- end
185
-
186
- def live_value(instance)
187
- object = instance
188
- column = @columns.first
189
- column.__stack.each { |method|
190
- object = object.send(method)
191
- return sphinx_value(nil) if object.nil?
192
- }
193
-
194
- sphinx_value object.send(column.__name)
195
- end
196
-
197
- def all_ints?
198
- @all_ints || all_of_type?(:integer)
199
- end
200
-
201
- def all_datetimes?
202
- all_of_type?(:datetime, :date, :timestamp)
203
- end
204
-
205
- def all_strings?
206
- all_of_type?(:string, :text)
207
- end
208
-
209
- private
210
-
211
- def source_value(offset, delta)
212
- if is_string?
213
- return "#{query_source.to_s.dasherize}; #{columns.first.__name}"
214
- end
215
-
216
- query = query(offset)
217
-
218
- if query_source == :ranged_query
219
- query += query_clause
220
- query += " AND #{query_delta.strip}" if delta
221
- "ranged-query; #{query}; #{range_query}"
222
- else
223
- query += " WHERE #{query_delta.strip}" if delta
224
- "query; #{query}"
225
- end
226
- end
227
-
228
- def query(offset)
229
- base_assoc = base_association_for_mva
230
- end_assoc = end_association_for_mva
231
- raise "Could not determine SQL for MVA" if base_assoc.nil?
232
-
233
- relation = ::ActiveRecord::Relation.new(
234
- base_assoc.reflection.klass, Arel::Table.new(base_assoc.table)
235
- )
236
-
237
- association_joins.each do |join|
238
- join.join_type = Arel::OuterJoin
239
- relation = relation.joins(join)
240
- end
241
-
242
- relation = relation.select "#{foreign_key_for_mva base_assoc} #{ThinkingSphinx.unique_id_expression(adapter, offset)} AS #{quote_column('id')}, #{primary_key_for_mva(end_assoc)} AS #{quote_column(unique_name)}"
243
-
244
- relation.to_sql
245
- end
246
-
247
- def query_clause
248
- foreign_key = foreign_key_for_mva base_association_for_mva
249
- " WHERE #{foreign_key} >= $start AND #{foreign_key} <= $end"
250
- end
251
-
252
- def query_delta
253
- foreign_key = foreign_key_for_mva base_association_for_mva
254
- <<-SQL
255
- #{foreign_key} IN (SELECT #{quote_column model.primary_key}
256
- FROM #{model.quoted_table_name}
257
- WHERE #{@source.index.delta_object.clause(model, true)})
258
- SQL
259
- end
260
-
261
- def range_query
262
- assoc = base_association_for_mva
263
- foreign_key = foreign_key_for_mva assoc
264
- "SELECT MIN(#{foreign_key}), MAX(#{foreign_key}) FROM #{quote_table_name assoc.table}"
265
- end
266
-
267
- def primary_key_for_mva(assoc)
268
- quote_with_table(
269
- assoc.table, assoc.primary_key_from_reflection || columns.first.__name
270
- )
271
- end
272
-
273
- def foreign_key_for_mva(assoc)
274
- if ThinkingSphinx.rails_3_1?
275
- if assoc.reflection.through_reflection
276
- quote_with_table assoc.table, assoc.reflection.through_reflection.foreign_key
277
- else
278
- quote_with_table assoc.table, assoc.reflection.foreign_key
279
- end
280
- else
281
- quote_with_table assoc.table, assoc.reflection.primary_key_name
282
- end
283
- end
284
-
285
- def end_association_for_mva
286
- @association_for_mva ||= associations[columns.first.__stack].detect { |assoc|
287
- assoc.has_column?(columns.first.__name)
288
- }
289
- end
290
-
291
- def base_association_for_mva
292
- @first_association_for_mva ||= begin
293
- assoc = end_association_for_mva
294
- while !assoc.parent.nil?
295
- assoc = assoc.parent
296
- end
297
-
298
- assoc
299
- end
300
- end
301
-
302
- def association_joins
303
- joins = []
304
- assoc = end_association_for_mva
305
- while assoc != base_association_for_mva
306
- joins << assoc.join
307
- assoc = assoc.parent
308
- end
309
-
310
- joins
311
- end
312
-
313
- def is_many_ints?
314
- concat_ws? && all_ints?
315
- end
316
-
317
- def is_many_datetimes?
318
- is_many? && all_datetimes?
319
- end
320
-
321
- def is_many_strings?
322
- is_many? && all_strings?
323
- end
324
-
325
- def translated_type_from_database
326
- case type_from_db = type_from_database
327
- when :integer
328
- integer_type_from_db
329
- when :datetime, :string, :float, :boolean
330
- type_from_db
331
- when :decimal
332
- :float
333
- when :timestamp, :date
334
- :datetime
335
- else
336
- raise <<-MESSAGE
337
-
338
- Cannot automatically map attribute #{unique_name} in #{@model.name} to an
339
- equivalent Sphinx type (integer, float, boolean, datetime, string as ordinal).
340
- You could try to explicitly convert the column's value in your define_index
341
- block:
342
- has "CAST(column AS INT)", :type => :integer, :as => :column
343
- MESSAGE
344
- end
345
- end
346
-
347
- def type_from_database
348
- column = column_from_db
349
- column.nil? ? nil : column.type
350
- end
351
-
352
- def integer_type_from_db
353
- column = column_from_db
354
- return nil if column.nil?
355
-
356
- case column.sql_type
357
- when adapter.bigint_pattern
358
- :bigint
359
- else
360
- :integer
361
- end
362
- end
363
-
364
- def column_from_db
365
- klass = @associations.values.flatten.first ?
366
- @associations.values.flatten.first.reflection.klass : @model
367
-
368
- klass.columns.detect { |col|
369
- @columns.collect { |c| c.__name.to_s }.include? col.name
370
- }
371
- end
372
-
373
- def all_of_type?(*column_types)
374
- @columns.all? { |col|
375
- klasses = @associations[col.__stack].empty? ? [@model] :
376
- @associations[col.__stack].collect { |assoc| assoc.reflection.klass }
377
- klasses.all? { |klass|
378
- column = klass.columns.detect { |column| column.name == col.__name.to_s }
379
- !column.nil? && column_types.include?(column.type)
380
- }
381
- }
382
- end
383
-
384
- def sphinx_value(value)
385
- case value
386
- when TrueClass
387
- 1
388
- when FalseClass, NilClass
389
- 0
390
- when Time
391
- value.to_i
392
- when Date
393
- value.to_time.to_i
394
- when String
395
- value.to_crc32
396
- else
397
- value
398
- end
399
- end
400
-
401
- def insensitive?
402
- @sortable == :insensitive
403
- end
404
- end
405
- end