thinking-sphinx 2.1.0 → 3.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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,187 +0,0 @@
1
- module ThinkingSphinx
2
- class Property
3
- attr_accessor :alias, :columns, :associations, :model, :faceted, :admin
4
-
5
- def initialize(source, columns, options = {})
6
- @source = source
7
- @model = source.model
8
- @columns = Array(columns)
9
- @associations = {}
10
-
11
- raise "Cannot define a field or attribute in #{source.model.name} with no columns. Maybe you are trying to index a field with a reserved name (id, name). You can fix this error by using a symbol rather than a bare name (:id instead of id)." if @columns.empty? || @columns.any? { |column| !column.respond_to?(:__stack) }
12
-
13
- @alias = options[:as]
14
- @faceted = options[:facet]
15
- @admin = options[:admin]
16
- @sortable = options[:sortable] || false
17
- @value_source = options[:value]
18
-
19
- @alias = @alias.to_sym unless @alias.blank?
20
-
21
- @columns.each { |col|
22
- @associations[col.__stack] = association_stack(col.__stack.clone).each { |assoc|
23
- assoc.join_to(source.base)
24
- }
25
- }
26
- end
27
-
28
- # Returns the unique name of the attribute - which is either the alias of
29
- # the attribute, or the name of the only column - if there is only one. If
30
- # there isn't, there should be an alias. Else things probably won't work.
31
- # Consider yourself warned.
32
- #
33
- def unique_name
34
- if @columns.length == 1
35
- @alias || @columns.first.__name
36
- else
37
- @alias
38
- end
39
- end
40
-
41
- def to_facet
42
- return nil unless @faceted
43
-
44
- ThinkingSphinx::Facet.new(self, @value_source)
45
- end
46
-
47
- # Get the part of the GROUP BY clause related to this attribute - if one is
48
- # needed. If not, all you'll get back is nil. The latter will happen if
49
- # there isn't actually a real column to get data from, or if there's
50
- # multiple data values (read: a has_many or has_and_belongs_to_many
51
- # association).
52
- #
53
- def to_group_sql
54
- case
55
- when is_many?, is_string?, ThinkingSphinx.use_group_by_shortcut?
56
- nil
57
- else
58
- @columns.collect { |column|
59
- column_with_prefix(column)
60
- }
61
- end
62
- end
63
-
64
- def changed?(instance)
65
- return true if is_string? || @columns.any? { |col| !col.__stack.empty? }
66
-
67
- @columns.any? { |col|
68
- instance.send("#{col.__name.to_s}_changed?")
69
- }
70
- end
71
-
72
- def admin?
73
- admin
74
- end
75
-
76
- def public?
77
- !admin
78
- end
79
-
80
- def available?
81
- columns.any? { |column| column_available?(column) }
82
- end
83
-
84
- private
85
-
86
- # Could there be more than one value related to the parent record? If so,
87
- # then this will return true. If not, false. It's that simple.
88
- #
89
- def is_many?
90
- associations.values.flatten.any? { |assoc| assoc.is_many? }
91
- end
92
-
93
- # Returns true if any of the columns are string values, instead of database
94
- # column references.
95
- def is_string?
96
- columns.all? { |col| col.is_string? }
97
- end
98
-
99
- def adapter
100
- @adapter ||= @model.sphinx_database_adapter
101
- end
102
-
103
- def quote_with_table(table, column)
104
- "#{quote_table_name(table)}.#{quote_column(column)}"
105
- end
106
-
107
- def quote_column(column)
108
- @model.connection.quote_column_name(column)
109
- end
110
-
111
- def quote_table_name(table_name)
112
- @model.connection.quote_table_name(table_name)
113
- end
114
-
115
- # Indication of whether the columns should be concatenated with a space
116
- # between each value. True if there's either multiple sources or multiple
117
- # associations.
118
- #
119
- def concat_ws?
120
- multiple_associations? || @columns.length > 1
121
- end
122
-
123
- # Checks whether any column requires multiple associations (which only
124
- # happens for polymorphic situations).
125
- #
126
- def multiple_associations?
127
- associations.values.any? { |assocs| assocs.length > 1 }
128
- end
129
-
130
- # Builds a column reference tied to the appropriate associations. This
131
- # dives into the associations hash and their corresponding joins to
132
- # figure out how to correctly reference a column in SQL.
133
- #
134
- def column_with_prefix(column)
135
- return nil unless column_available?(column)
136
-
137
- if column.is_string?
138
- column.__name
139
- elsif column.__stack.empty?
140
- "#{@model.quoted_table_name}.#{quote_column(column.__name)}"
141
- else
142
- associations[column.__stack].collect { |assoc|
143
- assoc.has_column?(column.__name) ?
144
- "#{quote_with_table(assoc.join.aliased_table_name, column.__name)}" :
145
- nil
146
- }.compact
147
- end
148
- end
149
-
150
- def columns_with_prefixes
151
- @columns.collect { |column|
152
- column_with_prefix column
153
- }.flatten.compact
154
- end
155
-
156
- def column_available?(column)
157
- if column.is_string?
158
- true
159
- elsif column.__stack.empty?
160
- @model.column_names.include?(column.__name.to_s)
161
- else
162
- associations[column.__stack].any? { |assoc|
163
- assoc.has_column?(column.__name)
164
- }
165
- end
166
- end
167
-
168
- # Gets a stack of associations for a specific path.
169
- #
170
- def association_stack(path, parent = nil)
171
- assocs = []
172
-
173
- if parent.nil?
174
- assocs = @source.association(path.shift)
175
- else
176
- assocs = parent.children(path.shift)
177
- end
178
-
179
- until path.empty?
180
- point = path.shift
181
- assocs = assocs.collect { |assoc| assoc.children(point) }.flatten
182
- end
183
-
184
- assocs
185
- end
186
- end
187
- end
@@ -1,439 +0,0 @@
1
- module ThinkingSphinx
2
- module SearchMethods
3
- def self.included(base)
4
- base.class_eval do
5
- extend ThinkingSphinx::SearchMethods::ClassMethods
6
- end
7
- end
8
-
9
- module ClassMethods
10
- def search_context
11
- # Comparing to name string to avoid class inheritance complications
12
- case self.class.name
13
- when 'Class'
14
- self
15
- else
16
- nil
17
- end
18
- end
19
-
20
- # Searches through the Sphinx indexes for relevant matches. There's
21
- # various ways to search, sort, group and filter - which are covered
22
- # below.
23
- #
24
- # Also, if you have WillPaginate installed, the search method can be used
25
- # just like paginate. The same parameters - :page and :per_page - work as
26
- # expected, and the returned result set can be used by the will_paginate
27
- # helper.
28
- #
29
- # == Basic Searching
30
- #
31
- # The simplest way of searching is straight text.
32
- #
33
- # ThinkingSphinx.search "pat"
34
- # ThinkingSphinx.search "google"
35
- # User.search "pat", :page => (params[:page] || 1)
36
- # Article.search "relevant news issue of the day"
37
- #
38
- # If you specify :include, like in an #find call, this will be respected
39
- # when loading the relevant models from the search results.
40
- #
41
- # User.search "pat", :include => :posts
42
- #
43
- # == Match Modes
44
- #
45
- # Sphinx supports 5 different matching modes. By default Thinking Sphinx
46
- # uses :all, which unsurprisingly requires all the supplied search terms
47
- # to match a result.
48
- #
49
- # Alternative modes include:
50
- #
51
- # User.search "pat allan", :match_mode => :any
52
- # User.search "pat allan", :match_mode => :phrase
53
- # User.search "pat | allan", :match_mode => :boolean
54
- # User.search "@name pat | @username pat", :match_mode => :extended
55
- #
56
- # Any will find results with any of the search terms. Phrase treats the
57
- # search terms a single phrase instead of individual words. Boolean and
58
- # extended allow for more complex query syntax, refer to the sphinx
59
- # documentation for further details.
60
- #
61
- # == Weighting
62
- #
63
- # Sphinx has support for weighting, where matches in one field can be
64
- # considered more important than in another. Weights are integers, with 1
65
- # as the default. They can be set per-search like this:
66
- #
67
- # User.search "pat allan", :field_weights => { :alias => 4, :aka => 2 }
68
- #
69
- # If you're searching multiple models, you can set per-index weights:
70
- #
71
- # ThinkingSphinx.search "pat", :index_weights => { User => 10 }
72
- #
73
- # See http://sphinxsearch.com/doc.html#weighting for further details.
74
- #
75
- # == Searching by Fields
76
- #
77
- # If you want to step it up a level, you can limit your search terms to
78
- # specific fields:
79
- #
80
- # User.search :conditions => {:name => "pat"}
81
- #
82
- # This uses Sphinx's extended match mode, unless you specify a different
83
- # match mode explicitly (but then this way of searching won't work). Also
84
- # note that you don't need to put in a search string.
85
- #
86
- # == Searching by Attributes
87
- #
88
- # Also known as filters, you can limit your searches to documents that
89
- # have specific values for their attributes. There are three ways to do
90
- # this. The first two techniques work in all scenarios - using the :with
91
- # or :with_all options.
92
- #
93
- # ThinkingSphinx.search :with => {:tag_ids => 10}
94
- # ThinkingSphinx.search :with => {:tag_ids => [10,12]}
95
- # ThinkingSphinx.search :with_all => {:tag_ids => [10,12]}
96
- #
97
- # The first :with search will match records with a tag_id attribute of 10.
98
- # The second :with will match records with a tag_id attribute of 10 OR 12.
99
- # If you need to find records that are tagged with ids 10 AND 12, you
100
- # will need to use the :with_all search parameter. This is particuarly
101
- # useful in conjunction with Multi Value Attributes (MVAs).
102
- #
103
- # The third filtering technique is only viable if you're searching with a
104
- # specific model (not multi-model searching). With a single model,
105
- # Thinking Sphinx can figure out what attributes and fields are available,
106
- # so you can put it all in the :conditions hash, and it will sort it out.
107
- #
108
- # Node.search :conditions => {:parent_id => 10}
109
- #
110
- # Filters can be single values, arrays of values, or ranges.
111
- #
112
- # Article.search "East Timor", :conditions => {:rating => 3..5}
113
- #
114
- # == Excluding by Attributes
115
- #
116
- # Sphinx also supports negative filtering - where the filters are of
117
- # attribute values to exclude. This is done with the :without option:
118
- #
119
- # User.search :without => {:role_id => 1}
120
- #
121
- # == Excluding by Primary Key
122
- #
123
- # There is a shortcut to exclude records by their ActiveRecord primary
124
- # key:
125
- #
126
- # User.search :without_ids => 1
127
- #
128
- # Pass an array or a single value.
129
- #
130
- # The primary key must be an integer as a negative filter is used. Note
131
- # that for multi-model search, an id may occur in more than one model.
132
- #
133
- # == Infix (Star) Searching
134
- #
135
- # Enable infix searching by something like this in config/sphinx.yml:
136
- #
137
- # development:
138
- # enable_star: 1
139
- # min_infix_len: 2
140
- #
141
- # Note that this will make indexing take longer.
142
- #
143
- # With those settings (and after reindexing), wildcard asterisks can be
144
- # used in queries:
145
- #
146
- # Location.search "*elbourn*"
147
- #
148
- # To automatically add asterisks around every token (but not operators),
149
- # pass the :star option:
150
- #
151
- # Location.search "elbourn -ustrali", :star => true,
152
- # :match_mode => :boolean
153
- #
154
- # This would become "*elbourn* -*ustrali*". The :star option only adds the
155
- # asterisks. You need to make the config/sphinx.yml changes yourself.
156
- #
157
- # By default, the tokens are assumed to match the regular expression
158
- # /\w\+/u\+. If you've modified the charset_table, pass another regular
159
- # expression, e.g.
160
- #
161
- # User.search("oo@bar.c", :star => /[\w@.]+/u)
162
- #
163
- # to search for "*oo@bar.c*" and not "*oo*@*bar*.*c*".
164
- #
165
- # == Sorting
166
- #
167
- # Sphinx can only sort by attributes, so generally you will need to avoid
168
- # using field names in your :order option. However, if you're searching
169
- # on a single model, and have specified some fields as sortable, you can
170
- # use those field names and Thinking Sphinx will interpret accordingly.
171
- # Remember: this will only happen for single-model searches, and only
172
- # through the :order option.
173
- #
174
- # Location.search "Melbourne", :order => :state
175
- # User.search :conditions => {:role_id => 2}, :order => "name ASC"
176
- #
177
- # Keep in mind that if you use a string, you *must* specify the direction
178
- # (ASC or DESC) else Sphinx won't return any results. If you use a symbol
179
- # then Thinking Sphinx assumes ASC, but if you wish to state otherwise,
180
- # use the :sort_mode option:
181
- #
182
- # Location.search "Melbourne", :order => :state, :sort_mode => :desc
183
- #
184
- # Of course, there are other sort modes - check out the Sphinx
185
- # documentation[http://sphinxsearch.com/doc.html] for that level of
186
- # detail though.
187
- #
188
- # If desired, you can sort by a column in your model instead of a sphinx
189
- # field or attribute. This sort only applies to the current page, so is
190
- # most useful when performing a search with a single page of results.
191
- #
192
- # User.search("pat", :sql_order => "name")
193
- #
194
- # == Grouping
195
- #
196
- # For this you can use the group_by, group_clause and group_function
197
- # options - which are all directly linked to Sphinx's expectations. No
198
- # magic from Thinking Sphinx. It can get a little tricky, so make sure
199
- # you read all the relevant
200
- # documentation[http://sphinxsearch.com/doc.html#clustering] first.
201
- #
202
- # Grouping is done via three parameters within the options hash
203
- # * <tt>:group_function</tt> determines the way grouping is done
204
- # * <tt>:group_by</tt> determines the field which is used for grouping
205
- # * <tt>:group_clause</tt> determines the sorting order
206
- #
207
- # As a convenience, you can also use
208
- # * <tt>:group</tt>
209
- # which sets :group_by and defaults to :group_function of :attr
210
- #
211
- # === group_function
212
- #
213
- # Valid values for :group_function are
214
- # * <tt>:day</tt>, <tt>:week</tt>, <tt>:month</tt>, <tt>:year</tt> - Grouping is done by the respective timeframes.
215
- # * <tt>:attr</tt>, <tt>:attrpair</tt> - Grouping is done by the specified attributes(s)
216
- #
217
- # === group_by
218
- #
219
- # This parameter denotes the field by which grouping is done. Note that
220
- # the specified field must be a sphinx attribute or index.
221
- #
222
- # === group_clause
223
- #
224
- # This determines the sorting order of the groups. In a grouping search,
225
- # the matches within a group will sorted by the <tt>:sort_mode</tt> and
226
- # <tt>:order</tt> parameters. The group matches themselves however, will
227
- # be sorted by <tt>:group_clause</tt>.
228
- #
229
- # The syntax for this is the same as an order parameter in extended sort
230
- # mode. Namely, you can specify an SQL-like sort expression with up to 5
231
- # attributes (including internal attributes), eg: "@relevance DESC, price
232
- # ASC, @id DESC"
233
- #
234
- # === Grouping by timestamp
235
- #
236
- # Timestamp grouping groups off items by the day, week, month or year of
237
- # the attribute given. In order to do this you need to define a timestamp
238
- # attribute, which pretty much looks like the standard defintion for any
239
- # attribute.
240
- #
241
- # define_index do
242
- # #
243
- # # All your other stuff
244
- # #
245
- # has :created_at
246
- # end
247
- #
248
- # When you need to fire off your search, it'll go something to the tune of
249
- #
250
- # Fruit.search "apricot", :group_function => :day,
251
- # :group_by => 'created_at'
252
- #
253
- # The <tt>@groupby</tt> special attribute will contain the date for that
254
- # group. Depending on the <tt>:group_function</tt> parameter, the date
255
- # format will be:
256
- #
257
- # * <tt>:day</tt> - YYYYMMDD
258
- # * <tt>:week</tt> - YYYYNNN (NNN is the first day of the week in question,
259
- # counting from the start of the year )
260
- # * <tt>:month</tt> - YYYYMM
261
- # * <tt>:year</tt> - YYYY
262
- #
263
- # === Grouping by attribute
264
- #
265
- # The syntax is the same as grouping by timestamp, except for the fact
266
- # that the <tt>:group_function</tt> parameter is changed.
267
- #
268
- # Fruit.search "apricot", :group_function => :attr, :group_by => 'size'
269
- #
270
- # == Geo/Location Searching
271
- #
272
- # Sphinx - and therefore Thinking Sphinx - has the facility to search
273
- # around a geographical point, using a given latitude and longitude. To
274
- # take advantage of this, you will need to have both of those values in
275
- # attributes. To search with that point, you can then use one of the
276
- # following syntax examples:
277
- #
278
- # Address.search "Melbourne", :geo => [1.4, -2.217],
279
- # :order => "@geodist asc"
280
- # Address.search "Australia", :geo => [-0.55, 3.108],
281
- # :order => "@geodist asc" :latitude_attr => "latit",
282
- # :longitude_attr => "longit"
283
- #
284
- # The first example applies when your latitude and longitude attributes
285
- # are named any of lat, latitude, lon, long or longitude. If that's not
286
- # the case, you will need to explicitly state them in your search, _or_
287
- # you can do so in your model:
288
- #
289
- # define_index do
290
- # has :latit # Float column, stored in radians
291
- # has :longit # Float column, stored in radians
292
- #
293
- # set_property :latitude_attr => "latit"
294
- # set_property :longitude_attr => "longit"
295
- # end
296
- #
297
- # Now, geo-location searching really only has an affect if you have a
298
- # filter, sort or grouping clause related to it - otherwise it's just a
299
- # normal search, and _will not_ return a distance value otherwise. To
300
- # make use of the positioning difference, use the special attribute
301
- # "@geodist" in any of your filters or sorting or grouping clauses.
302
- #
303
- # And don't forget - both the latitude and longitude you use in your
304
- # search, and the values in your indexes, need to be stored as a float in
305
- # radians, _not_ degrees. Keep in mind that if you do this conversion in
306
- # SQL you will need to explicitly declare a column type of :float.
307
- #
308
- # define_index do
309
- # has 'RADIANS(lat)', :as => :lat, :type => :float
310
- # # ...
311
- # end
312
- #
313
- # Once you've got your results set, you can access the distances as
314
- # follows:
315
- #
316
- # @results.each_with_geodist do |result, distance|
317
- # # ...
318
- # end
319
- #
320
- # The distance value is returned as a float, representing the distance in
321
- # metres.
322
- #
323
- # == Filtering by custom attributes
324
- #
325
- # Do note that this applies only to sphinx 0.9.9
326
- #
327
- # Should you find yourself in desperate need of a filter that involves
328
- # selecting either one of multiple conditions, one solution could be
329
- # provided by the :sphinx_select option within the search.
330
- # This handles which fields are selected by sphinx from its store.
331
- #
332
- # The default value is "*", and you can add custom fields using syntax
333
- # similar to sql:
334
- #
335
- # Flower.search "foo",
336
- # :sphinx_select => "*, petals < 1 or color = 2 as grass"
337
- #
338
- # This will add the 'grass' attribute, which will now be usable in your
339
- # filters.
340
- #
341
- # == Handling a Stale Index
342
- #
343
- # Especially if you don't use delta indexing, you risk having records in
344
- # the Sphinx index that are no longer in the database. By default, those
345
- # will simply come back as nils:
346
- #
347
- # >> pat_user.delete
348
- # >> User.search("pat")
349
- # Sphinx Result: [1,2]
350
- # => [nil, <#User id: 2>]
351
- #
352
- # (If you search across multiple models, you'll get
353
- # ActiveRecord::RecordNotFound.)
354
- #
355
- # You can simply Array#compact these results or handle the nils in some
356
- # other way, but Sphinx will still report two results, and the missing
357
- # records may upset your layout.
358
- #
359
- # If you pass :retry_stale => true to a single-model search, missing
360
- # records will cause Thinking Sphinx to retry the query but excluding
361
- # those records. Since search is paginated, the new search could
362
- # potentially include missing records as well, so by default Thinking
363
- # Sphinx will retry three times. Pass :retry_stale => 5 to retry five
364
- # times, and so on. If there are still missing ids on the last retry, they
365
- # are shown as nils.
366
- #
367
- def search(*args)
368
- ThinkingSphinx::Search.new *search_options(args)
369
- end
370
-
371
- # Searches for results that match the parameters provided. Will only
372
- # return the ids for the matching objects. See #search for syntax
373
- # examples.
374
- #
375
- # Note that this only searches the Sphinx index, with no ActiveRecord
376
- # queries. Thus, if your index is not in sync with the database, this
377
- # method may return ids that no longer exist there.
378
- #
379
- def search_for_ids(*args)
380
- ThinkingSphinx::Search.new *search_options(args, :ids_only => true)
381
- end
382
-
383
- # Checks if a document with the given id exists within a specific index.
384
- # Expected parameters:
385
- #
386
- # - ID of the document
387
- # - Index to check within
388
- # - Options hash (defaults to {})
389
- #
390
- # Example:
391
- #
392
- # ThinkingSphinx.search_for_id(10, "user_core", :class => User)
393
- #
394
- def search_for_id(id, index, options = {})
395
- ThinkingSphinx::Search.new(
396
- *search_options([],
397
- :ids_only => true,
398
- :index => index,
399
- :id_range => id..id
400
- )
401
- ).any?
402
- end
403
-
404
- def count(*args)
405
- search_context ? super : search_count(*args)
406
- end
407
-
408
- def search_count(*args)
409
- search = ThinkingSphinx::Search.new(
410
- *search_options(args, :ids_only => true)
411
- )
412
- search.first # forces the query
413
- search.total_entries
414
- end
415
-
416
- # Model.facets *args
417
- # ThinkingSphinx.facets *args
418
- # ThinkingSphinx.facets *args, :all_facets => true
419
- # ThinkingSphinx.facets *args, :class_facet => false
420
- #
421
- def facets(*args)
422
- ThinkingSphinx::FacetSearch.new *search_options(args)
423
- end
424
-
425
- private
426
-
427
- def search_options(args, options = {})
428
- options = args.extract_options!.merge(options)
429
- options[:classes] ||= classes_option
430
- args << options
431
- end
432
-
433
- def classes_option
434
- classes_option = [search_context].compact
435
- classes_option.empty? ? nil : classes_option
436
- end
437
- end
438
- end
439
- end