thinking-sphinx 1.2.13 → 6.0.0

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 (517) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +99 -0
  3. data/.github/actions/test/action.yml +46 -0
  4. data/.github/workflows/ci.yml +75 -0
  5. data/.gitignore +18 -0
  6. data/.travis.yml +36 -0
  7. data/Appraisals +71 -0
  8. data/CHANGELOG.markdown +782 -0
  9. data/Gemfile +18 -0
  10. data/LICENCE +1 -1
  11. data/Procfile.support +2 -0
  12. data/README.textile +91 -136
  13. data/Rakefile +26 -0
  14. data/bin/console +15 -0
  15. data/bin/loadsphinx +99 -0
  16. data/bin/testmatrix +48 -0
  17. data/lib/thinking/sphinx.rb +3 -0
  18. data/lib/thinking-sphinx.rb +3 -0
  19. data/lib/thinking_sphinx/active_record/association.rb +19 -0
  20. data/lib/thinking_sphinx/active_record/association_proxy/attribute_finder.rb +44 -0
  21. data/lib/thinking_sphinx/active_record/association_proxy/attribute_matcher.rb +40 -0
  22. data/lib/thinking_sphinx/active_record/association_proxy.rb +34 -0
  23. data/lib/thinking_sphinx/active_record/attribute/sphinx_presenter.rb +52 -0
  24. data/lib/thinking_sphinx/active_record/attribute/type.rb +106 -0
  25. data/lib/thinking_sphinx/active_record/attribute/values.rb +20 -0
  26. data/lib/thinking_sphinx/active_record/attribute.rb +22 -0
  27. data/lib/thinking_sphinx/active_record/base.rb +91 -0
  28. data/lib/thinking_sphinx/active_record/callbacks/association_delta_callbacks.rb +21 -0
  29. data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +27 -0
  30. data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +66 -0
  31. data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +78 -0
  32. data/lib/thinking_sphinx/active_record/column.rb +44 -0
  33. data/lib/thinking_sphinx/active_record/column_sql_presenter.rb +54 -0
  34. data/lib/thinking_sphinx/active_record/database_adapters/abstract_adapter.rb +19 -0
  35. data/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb +51 -0
  36. data/lib/thinking_sphinx/active_record/database_adapters/postgresql_adapter.rb +47 -0
  37. data/lib/thinking_sphinx/active_record/database_adapters.rb +59 -0
  38. data/lib/thinking_sphinx/active_record/depolymorph/association_reflection.rb +32 -0
  39. data/lib/thinking_sphinx/active_record/depolymorph/base_reflection.rb +32 -0
  40. data/lib/thinking_sphinx/active_record/depolymorph/conditions_reflection.rb +40 -0
  41. data/lib/thinking_sphinx/active_record/depolymorph/overridden_reflection.rb +50 -0
  42. data/lib/thinking_sphinx/active_record/depolymorph/scoped_reflection.rb +26 -0
  43. data/lib/thinking_sphinx/active_record/field.rb +18 -0
  44. data/lib/thinking_sphinx/active_record/filter_reflection.rb +18 -0
  45. data/lib/thinking_sphinx/active_record/index.rb +71 -0
  46. data/lib/thinking_sphinx/active_record/interpreter.rb +77 -0
  47. data/lib/thinking_sphinx/active_record/join_association.rb +17 -0
  48. data/lib/thinking_sphinx/active_record/log_subscriber.rb +37 -0
  49. data/lib/thinking_sphinx/active_record/polymorpher.rb +64 -0
  50. data/lib/thinking_sphinx/active_record/property.rb +30 -0
  51. data/lib/thinking_sphinx/active_record/property_query.rb +149 -0
  52. data/lib/thinking_sphinx/active_record/property_sql_presenter.rb +89 -0
  53. data/lib/thinking_sphinx/active_record/simple_many_query.rb +37 -0
  54. data/lib/thinking_sphinx/active_record/source_joins.rb +68 -0
  55. data/lib/thinking_sphinx/active_record/sql_builder/clause_builder.rb +29 -0
  56. data/lib/thinking_sphinx/active_record/sql_builder/query.rb +59 -0
  57. data/lib/thinking_sphinx/active_record/sql_builder/statement.rb +147 -0
  58. data/lib/thinking_sphinx/active_record/sql_builder.rb +107 -0
  59. data/lib/thinking_sphinx/active_record/sql_source/template.rb +55 -0
  60. data/lib/thinking_sphinx/active_record/sql_source.rb +173 -0
  61. data/lib/thinking_sphinx/active_record.rb +39 -301
  62. data/lib/thinking_sphinx/attribute_types.rb +72 -0
  63. data/lib/thinking_sphinx/batched_search.rb +28 -0
  64. data/lib/thinking_sphinx/callbacks/appender.rb +63 -0
  65. data/lib/thinking_sphinx/callbacks.rb +44 -0
  66. data/lib/thinking_sphinx/capistrano/v2.rb +60 -0
  67. data/lib/thinking_sphinx/capistrano/v3.rb +104 -0
  68. data/lib/thinking_sphinx/capistrano.rb +10 -0
  69. data/lib/thinking_sphinx/commander.rb +27 -0
  70. data/lib/thinking_sphinx/commands/base.rb +53 -0
  71. data/lib/thinking_sphinx/commands/clear_real_time.rb +22 -0
  72. data/lib/thinking_sphinx/commands/clear_sql.rb +18 -0
  73. data/lib/thinking_sphinx/commands/configure.rb +15 -0
  74. data/lib/thinking_sphinx/commands/index_real_time.rb +15 -0
  75. data/lib/thinking_sphinx/commands/index_sql.rb +25 -0
  76. data/lib/thinking_sphinx/commands/merge.rb +27 -0
  77. data/lib/thinking_sphinx/commands/merge_and_update.rb +57 -0
  78. data/lib/thinking_sphinx/commands/prepare.rb +15 -0
  79. data/lib/thinking_sphinx/commands/rotate.rb +13 -0
  80. data/lib/thinking_sphinx/commands/running.rb +15 -0
  81. data/lib/thinking_sphinx/commands/start_attached.rb +22 -0
  82. data/lib/thinking_sphinx/commands/start_detached.rb +21 -0
  83. data/lib/thinking_sphinx/commands/stop.rb +24 -0
  84. data/lib/thinking_sphinx/commands.rb +20 -0
  85. data/lib/thinking_sphinx/configuration/consistent_ids.rb +35 -0
  86. data/lib/thinking_sphinx/configuration/defaults.rb +7 -0
  87. data/lib/thinking_sphinx/configuration/distributed_indices.rb +31 -0
  88. data/lib/thinking_sphinx/configuration/duplicate_names.rb +36 -0
  89. data/lib/thinking_sphinx/configuration/minimum_fields.rb +36 -0
  90. data/lib/thinking_sphinx/configuration.rb +196 -269
  91. data/lib/thinking_sphinx/connection/client.rb +74 -0
  92. data/lib/thinking_sphinx/connection/jruby.rb +58 -0
  93. data/lib/thinking_sphinx/connection/mri.rb +26 -0
  94. data/lib/thinking_sphinx/connection.rb +73 -0
  95. data/lib/thinking_sphinx/core/field.rb +11 -0
  96. data/lib/thinking_sphinx/core/index.rb +110 -0
  97. data/lib/thinking_sphinx/core/interpreter.rb +25 -0
  98. data/lib/thinking_sphinx/core/property.rb +15 -0
  99. data/lib/thinking_sphinx/core/settings.rb +11 -0
  100. data/lib/thinking_sphinx/core.rb +11 -0
  101. data/lib/thinking_sphinx/deletion.rb +70 -0
  102. data/lib/thinking_sphinx/deltas/default_delta.rb +57 -66
  103. data/lib/thinking_sphinx/deltas/delete_job.rb +27 -0
  104. data/lib/thinking_sphinx/deltas/index_job.rb +28 -0
  105. data/lib/thinking_sphinx/deltas.rb +52 -27
  106. data/lib/thinking_sphinx/distributed/index.rb +46 -0
  107. data/lib/thinking_sphinx/distributed.rb +7 -0
  108. data/lib/thinking_sphinx/errors.rb +96 -0
  109. data/lib/thinking_sphinx/excerpter.rb +36 -19
  110. data/lib/thinking_sphinx/facet.rb +29 -122
  111. data/lib/thinking_sphinx/facet_search.rb +132 -125
  112. data/lib/thinking_sphinx/float_formatter.rb +35 -0
  113. data/lib/thinking_sphinx/frameworks/plain.rb +10 -0
  114. data/lib/thinking_sphinx/frameworks/rails.rb +11 -0
  115. data/lib/thinking_sphinx/frameworks.rb +11 -0
  116. data/lib/thinking_sphinx/guard/file.rb +28 -0
  117. data/lib/thinking_sphinx/guard/files.rb +40 -0
  118. data/lib/thinking_sphinx/guard/none.rb +7 -0
  119. data/lib/thinking_sphinx/guard.rb +9 -0
  120. data/lib/thinking_sphinx/hooks/guard_presence.rb +34 -0
  121. data/lib/thinking_sphinx/index.rb +50 -92
  122. data/lib/thinking_sphinx/index_set.rb +96 -0
  123. data/lib/thinking_sphinx/indexing_strategies/all_at_once.rb +9 -0
  124. data/lib/thinking_sphinx/indexing_strategies/one_at_a_time.rb +16 -0
  125. data/lib/thinking_sphinx/interfaces/base.rb +13 -0
  126. data/lib/thinking_sphinx/interfaces/daemon.rb +27 -0
  127. data/lib/thinking_sphinx/interfaces/real_time.rb +46 -0
  128. data/lib/thinking_sphinx/interfaces/sql.rb +53 -0
  129. data/lib/thinking_sphinx/interfaces.rb +10 -0
  130. data/lib/thinking_sphinx/logger.rb +9 -0
  131. data/lib/thinking_sphinx/masks/group_enumerators_mask.rb +30 -0
  132. data/lib/thinking_sphinx/masks/pagination_mask.rb +63 -0
  133. data/lib/thinking_sphinx/masks/scopes_mask.rb +56 -0
  134. data/lib/thinking_sphinx/masks/weight_enumerator_mask.rb +17 -0
  135. data/lib/thinking_sphinx/masks.rb +10 -0
  136. data/lib/thinking_sphinx/middlewares/active_record_translator.rb +103 -0
  137. data/lib/thinking_sphinx/middlewares/geographer.rb +94 -0
  138. data/lib/thinking_sphinx/middlewares/glazier.rb +52 -0
  139. data/lib/thinking_sphinx/middlewares/ids_only.rb +15 -0
  140. data/lib/thinking_sphinx/middlewares/inquirer.rb +64 -0
  141. data/lib/thinking_sphinx/middlewares/middleware.rb +11 -0
  142. data/lib/thinking_sphinx/middlewares/sphinxql.rb +256 -0
  143. data/lib/thinking_sphinx/middlewares/stale_id_checker.rb +47 -0
  144. data/lib/thinking_sphinx/middlewares/stale_id_filter.rb +48 -0
  145. data/lib/thinking_sphinx/middlewares/valid_options.rb +25 -0
  146. data/lib/thinking_sphinx/middlewares.rb +35 -0
  147. data/lib/thinking_sphinx/panes/attributes_pane.rb +11 -0
  148. data/lib/thinking_sphinx/panes/distance_pane.rb +15 -0
  149. data/lib/thinking_sphinx/panes/excerpts_pane.rb +43 -0
  150. data/lib/thinking_sphinx/panes/weight_pane.rb +11 -0
  151. data/lib/thinking_sphinx/panes.rb +10 -0
  152. data/lib/thinking_sphinx/processor.rb +71 -0
  153. data/lib/thinking_sphinx/query.rb +11 -0
  154. data/lib/thinking_sphinx/railtie.rb +38 -0
  155. data/lib/thinking_sphinx/rake_interface.rb +34 -0
  156. data/lib/thinking_sphinx/real_time/attribute.rb +27 -0
  157. data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +60 -0
  158. data/lib/thinking_sphinx/real_time/field.rb +9 -0
  159. data/lib/thinking_sphinx/real_time/index/template.rb +52 -0
  160. data/lib/thinking_sphinx/real_time/index.rb +102 -0
  161. data/lib/thinking_sphinx/real_time/interpreter.rb +54 -0
  162. data/lib/thinking_sphinx/real_time/populator.rb +46 -0
  163. data/lib/thinking_sphinx/real_time/processor.rb +36 -0
  164. data/lib/thinking_sphinx/real_time/property.rb +21 -0
  165. data/lib/thinking_sphinx/real_time/transcribe_instance.rb +38 -0
  166. data/lib/thinking_sphinx/real_time/transcriber.rb +89 -0
  167. data/lib/thinking_sphinx/real_time/translator.rb +39 -0
  168. data/lib/thinking_sphinx/real_time.rb +40 -0
  169. data/lib/thinking_sphinx/scopes.rb +34 -0
  170. data/lib/thinking_sphinx/search/batch_inquirer.rb +23 -0
  171. data/lib/thinking_sphinx/search/context.rb +31 -0
  172. data/lib/thinking_sphinx/search/glaze.rb +39 -0
  173. data/lib/thinking_sphinx/search/merger.rb +34 -0
  174. data/lib/thinking_sphinx/search/query.rb +33 -0
  175. data/lib/thinking_sphinx/search/stale_ids_exception.rb +15 -0
  176. data/lib/thinking_sphinx/search.rb +166 -704
  177. data/lib/thinking_sphinx/settings.rb +128 -0
  178. data/lib/thinking_sphinx/sinatra.rb +7 -0
  179. data/lib/thinking_sphinx/subscribers/populator_subscriber.rb +48 -0
  180. data/lib/thinking_sphinx/tasks.rb +70 -150
  181. data/lib/thinking_sphinx/test.rb +56 -0
  182. data/lib/thinking_sphinx/utf8.rb +18 -0
  183. data/lib/thinking_sphinx/wildcard.rb +42 -0
  184. data/lib/thinking_sphinx/with_output.rb +13 -0
  185. data/lib/thinking_sphinx.rb +83 -185
  186. data/spec/acceptance/association_scoping_spec.rb +65 -0
  187. data/spec/acceptance/attribute_access_spec.rb +58 -0
  188. data/spec/acceptance/attribute_updates_spec.rb +18 -0
  189. data/spec/acceptance/batch_searching_spec.rb +23 -0
  190. data/spec/acceptance/big_integers_spec.rb +61 -0
  191. data/spec/acceptance/excerpts_spec.rb +50 -0
  192. data/spec/acceptance/facets_spec.rb +141 -0
  193. data/spec/acceptance/geosearching_spec.rb +70 -0
  194. data/spec/acceptance/grouping_by_attributes_spec.rb +79 -0
  195. data/spec/acceptance/index_options_spec.rb +154 -0
  196. data/spec/acceptance/indexing_spec.rb +38 -0
  197. data/spec/acceptance/merging_spec.rb +90 -0
  198. data/spec/acceptance/paginating_search_results_spec.rb +42 -0
  199. data/spec/acceptance/real_time_updates_spec.rb +115 -0
  200. data/spec/acceptance/remove_deleted_records_spec.rb +99 -0
  201. data/spec/acceptance/search_counts_spec.rb +20 -0
  202. data/spec/acceptance/search_for_just_ids_spec.rb +21 -0
  203. data/spec/acceptance/searching_across_models_spec.rb +47 -0
  204. data/spec/acceptance/searching_across_schemas_spec.rb +40 -0
  205. data/spec/acceptance/searching_on_fields_spec.rb +59 -0
  206. data/spec/acceptance/searching_with_filters_spec.rb +159 -0
  207. data/spec/acceptance/searching_with_sti_spec.rb +76 -0
  208. data/spec/acceptance/searching_within_a_model_spec.rb +117 -0
  209. data/spec/acceptance/sorting_search_results_spec.rb +50 -0
  210. data/spec/acceptance/spec_helper.rb +6 -0
  211. data/spec/acceptance/specifying_sql_spec.rb +516 -0
  212. data/spec/acceptance/sphinx_scopes_spec.rb +87 -0
  213. data/spec/acceptance/sql_deltas_spec.rb +78 -0
  214. data/spec/acceptance/support/database_cleaner.rb +13 -0
  215. data/spec/acceptance/support/sphinx_controller.rb +62 -0
  216. data/spec/acceptance/support/sphinx_helpers.rb +45 -0
  217. data/spec/acceptance/suspended_deltas_spec.rb +56 -0
  218. data/spec/fixtures/database.yml +4 -0
  219. data/spec/internal/app/indices/admin_person_index.rb +9 -0
  220. data/spec/internal/app/indices/album_index.rb +9 -0
  221. data/spec/internal/app/indices/animal_index.rb +5 -0
  222. data/spec/internal/app/indices/article_index.rb +31 -0
  223. data/spec/internal/app/indices/bird_index.rb +6 -0
  224. data/spec/internal/app/indices/book_index.rb +11 -0
  225. data/spec/internal/app/indices/car_index.rb +7 -0
  226. data/spec/internal/app/indices/city_index.rb +9 -0
  227. data/spec/internal/app/indices/colour_index.rb +7 -0
  228. data/spec/internal/app/indices/product_index.rb +27 -0
  229. data/spec/internal/app/indices/tee_index.rb +6 -0
  230. data/spec/internal/app/indices/user_index.rb +9 -0
  231. data/spec/internal/app/models/admin/person.rb +9 -0
  232. data/spec/internal/app/models/album.rb +25 -0
  233. data/spec/internal/app/models/animal.rb +5 -0
  234. data/spec/internal/app/models/article.rb +9 -0
  235. data/spec/internal/app/models/bird.rb +5 -0
  236. data/spec/internal/app/models/book.rb +18 -0
  237. data/spec/internal/app/models/car.rb +7 -0
  238. data/spec/internal/app/models/categorisation.rb +15 -0
  239. data/spec/internal/app/models/category.rb +6 -0
  240. data/spec/internal/app/models/city.rb +7 -0
  241. data/spec/internal/app/models/colour.rb +7 -0
  242. data/spec/internal/app/models/event.rb +5 -0
  243. data/spec/internal/app/models/flightless_bird.rb +4 -0
  244. data/spec/internal/app/models/genre.rb +5 -0
  245. data/spec/internal/app/models/hardcover.rb +5 -0
  246. data/spec/internal/app/models/mammal.rb +4 -0
  247. data/spec/internal/app/models/manufacturer.rb +5 -0
  248. data/spec/internal/app/models/product.rb +8 -0
  249. data/spec/internal/app/models/tag.rb +6 -0
  250. data/{features/support → spec/internal/app}/models/tagging.rb +3 -1
  251. data/spec/internal/app/models/tee.rb +10 -0
  252. data/spec/internal/app/models/tweet.rb +5 -0
  253. data/spec/internal/app/models/user.rb +10 -0
  254. data/spec/internal/config/database.yml +17 -0
  255. data/spec/internal/db/schema.rb +115 -0
  256. data/spec/internal/tmp/.gitkeep +0 -0
  257. data/spec/spec_helper.rb +29 -0
  258. data/spec/support/json_column.rb +35 -0
  259. data/spec/support/multi_schema.rb +50 -0
  260. data/spec/support/mysql.rb +25 -0
  261. data/spec/support/sphinx_yaml_helpers.rb +16 -0
  262. data/spec/thinking_sphinx/active_record/association_spec.rb +14 -0
  263. data/spec/thinking_sphinx/active_record/attribute/type_spec.rb +165 -0
  264. data/spec/thinking_sphinx/active_record/base_spec.rb +131 -0
  265. data/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +128 -0
  266. data/spec/thinking_sphinx/active_record/callbacks/delta_callbacks_spec.rb +176 -0
  267. data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +91 -0
  268. data/spec/thinking_sphinx/active_record/column_spec.rb +72 -0
  269. data/spec/thinking_sphinx/active_record/column_sql_presenter_spec.rb +39 -0
  270. data/spec/thinking_sphinx/active_record/database_adapters/abstract_adapter_spec.rb +33 -0
  271. data/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +70 -0
  272. data/spec/thinking_sphinx/active_record/database_adapters/postgresql_adapter_spec.rb +66 -0
  273. data/spec/thinking_sphinx/active_record/database_adapters_spec.rb +128 -0
  274. data/spec/thinking_sphinx/active_record/field_spec.rb +51 -0
  275. data/spec/thinking_sphinx/active_record/filter_reflection_spec.rb +207 -0
  276. data/spec/thinking_sphinx/active_record/index_spec.rb +220 -0
  277. data/spec/thinking_sphinx/active_record/interpreter_spec.rb +329 -0
  278. data/spec/thinking_sphinx/active_record/polymorpher_spec.rb +87 -0
  279. data/spec/thinking_sphinx/active_record/property_sql_presenter_spec.rb +264 -0
  280. data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +662 -0
  281. data/spec/thinking_sphinx/active_record/sql_source_spec.rb +507 -0
  282. data/spec/thinking_sphinx/attribute_types_spec.rb +52 -0
  283. data/spec/thinking_sphinx/commands/clear_real_time_spec.rb +46 -0
  284. data/spec/thinking_sphinx/commands/clear_sql_spec.rb +52 -0
  285. data/spec/thinking_sphinx/commands/configure_spec.rb +31 -0
  286. data/spec/thinking_sphinx/commands/index_real_time_spec.rb +33 -0
  287. data/spec/thinking_sphinx/commands/index_sql_spec.rb +86 -0
  288. data/spec/thinking_sphinx/commands/merge_and_update_spec.rb +106 -0
  289. data/spec/thinking_sphinx/commands/merge_spec.rb +48 -0
  290. data/spec/thinking_sphinx/commands/prepare_spec.rb +31 -0
  291. data/spec/thinking_sphinx/commands/running_spec.rb +30 -0
  292. data/spec/thinking_sphinx/commands/start_detached_spec.rb +67 -0
  293. data/spec/thinking_sphinx/commands/stop_spec.rb +63 -0
  294. data/spec/thinking_sphinx/configuration/minimum_fields_spec.rb +60 -0
  295. data/spec/thinking_sphinx/configuration_spec.rb +582 -0
  296. data/spec/thinking_sphinx/connection/mri_spec.rb +49 -0
  297. data/spec/thinking_sphinx/connection_spec.rb +87 -0
  298. data/spec/thinking_sphinx/deletion_spec.rb +57 -0
  299. data/spec/thinking_sphinx/deltas/default_delta_spec.rb +123 -0
  300. data/spec/thinking_sphinx/deltas_spec.rb +77 -0
  301. data/spec/thinking_sphinx/errors_spec.rb +103 -0
  302. data/spec/thinking_sphinx/excerpter_spec.rb +53 -0
  303. data/spec/thinking_sphinx/facet_search_spec.rb +133 -0
  304. data/spec/thinking_sphinx/hooks/guard_presence_spec.rb +30 -0
  305. data/spec/thinking_sphinx/index_set_spec.rb +132 -0
  306. data/spec/thinking_sphinx/index_spec.rb +140 -0
  307. data/spec/thinking_sphinx/interfaces/daemon_spec.rb +60 -0
  308. data/spec/thinking_sphinx/interfaces/real_time_spec.rb +109 -0
  309. data/spec/thinking_sphinx/interfaces/sql_spec.rb +122 -0
  310. data/spec/thinking_sphinx/masks/pagination_mask_spec.rb +123 -0
  311. data/spec/thinking_sphinx/masks/scopes_mask_spec.rb +139 -0
  312. data/spec/thinking_sphinx/middlewares/active_record_translator_spec.rb +180 -0
  313. data/spec/thinking_sphinx/middlewares/geographer_spec.rb +102 -0
  314. data/spec/thinking_sphinx/middlewares/glazier_spec.rb +65 -0
  315. data/spec/thinking_sphinx/middlewares/inquirer_spec.rb +72 -0
  316. data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +401 -0
  317. data/spec/thinking_sphinx/middlewares/stale_id_checker_spec.rb +50 -0
  318. data/spec/thinking_sphinx/middlewares/stale_id_filter_spec.rb +113 -0
  319. data/spec/thinking_sphinx/middlewares/valid_options_spec.rb +51 -0
  320. data/spec/thinking_sphinx/panes/attributes_pane_spec.rb +23 -0
  321. data/spec/thinking_sphinx/panes/distance_pane_spec.rb +43 -0
  322. data/spec/thinking_sphinx/panes/excerpts_pane_spec.rb +53 -0
  323. data/spec/thinking_sphinx/panes/weight_pane_spec.rb +22 -0
  324. data/spec/thinking_sphinx/rake_interface_spec.rb +39 -0
  325. data/spec/thinking_sphinx/real_time/attribute_spec.rb +64 -0
  326. data/spec/thinking_sphinx/real_time/callbacks/real_time_callbacks_spec.rb +238 -0
  327. data/spec/thinking_sphinx/real_time/field_spec.rb +69 -0
  328. data/spec/thinking_sphinx/real_time/index_spec.rb +230 -0
  329. data/spec/thinking_sphinx/real_time/interpreter_spec.rb +203 -0
  330. data/spec/thinking_sphinx/real_time/transcribe_instance_spec.rb +35 -0
  331. data/spec/thinking_sphinx/real_time/transcriber_spec.rb +109 -0
  332. data/spec/thinking_sphinx/real_time/translator_spec.rb +17 -0
  333. data/spec/thinking_sphinx/scopes_spec.rb +51 -0
  334. data/spec/thinking_sphinx/search/glaze_spec.rb +79 -0
  335. data/spec/thinking_sphinx/search/query_spec.rb +87 -0
  336. data/spec/thinking_sphinx/search_spec.rb +214 -0
  337. data/spec/thinking_sphinx/wildcard_spec.rb +53 -0
  338. data/spec/thinking_sphinx_spec.rb +44 -0
  339. data/thinking-sphinx.gemspec +42 -0
  340. metadata +656 -243
  341. data/VERSION.yml +0 -5
  342. data/features/alternate_primary_key.feature +0 -27
  343. data/features/attribute_transformation.feature +0 -22
  344. data/features/attribute_updates.feature +0 -33
  345. data/features/datetime_deltas.feature +0 -66
  346. data/features/delayed_delta_indexing.feature +0 -37
  347. data/features/deleting_instances.feature +0 -64
  348. data/features/direct_attributes.feature +0 -11
  349. data/features/excerpts.feature +0 -13
  350. data/features/extensible_delta_indexing.feature +0 -9
  351. data/features/facets.feature +0 -76
  352. data/features/facets_across_model.feature +0 -29
  353. data/features/handling_edits.feature +0 -92
  354. data/features/retry_stale_indexes.feature +0 -24
  355. data/features/searching_across_models.feature +0 -20
  356. data/features/searching_by_model.feature +0 -175
  357. data/features/searching_with_find_arguments.feature +0 -56
  358. data/features/sphinx_detection.feature +0 -25
  359. data/features/sphinx_scopes.feature +0 -35
  360. data/features/step_definitions/alpha_steps.rb +0 -3
  361. data/features/step_definitions/beta_steps.rb +0 -7
  362. data/features/step_definitions/common_steps.rb +0 -178
  363. data/features/step_definitions/datetime_delta_steps.rb +0 -15
  364. data/features/step_definitions/delayed_delta_indexing_steps.rb +0 -7
  365. data/features/step_definitions/extensible_delta_indexing_steps.rb +0 -7
  366. data/features/step_definitions/facet_steps.rb +0 -92
  367. data/features/step_definitions/find_arguments_steps.rb +0 -36
  368. data/features/step_definitions/gamma_steps.rb +0 -15
  369. data/features/step_definitions/scope_steps.rb +0 -11
  370. data/features/step_definitions/search_steps.rb +0 -89
  371. data/features/step_definitions/sphinx_steps.rb +0 -31
  372. data/features/sti_searching.feature +0 -14
  373. data/features/support/database.example.yml +0 -3
  374. data/features/support/database.yml +0 -5
  375. data/features/support/db/active_record.rb +0 -40
  376. data/features/support/db/database.yml +0 -5
  377. data/features/support/db/fixtures/alphas.rb +0 -10
  378. data/features/support/db/fixtures/authors.rb +0 -1
  379. data/features/support/db/fixtures/betas.rb +0 -10
  380. data/features/support/db/fixtures/boxes.rb +0 -9
  381. data/features/support/db/fixtures/categories.rb +0 -1
  382. data/features/support/db/fixtures/cats.rb +0 -3
  383. data/features/support/db/fixtures/comments.rb +0 -24
  384. data/features/support/db/fixtures/delayed_betas.rb +0 -10
  385. data/features/support/db/fixtures/developers.rb +0 -29
  386. data/features/support/db/fixtures/dogs.rb +0 -3
  387. data/features/support/db/fixtures/extensible_betas.rb +0 -10
  388. data/features/support/db/fixtures/gammas.rb +0 -10
  389. data/features/support/db/fixtures/people.rb +0 -1001
  390. data/features/support/db/fixtures/posts.rb +0 -6
  391. data/features/support/db/fixtures/robots.rb +0 -14
  392. data/features/support/db/fixtures/tags.rb +0 -27
  393. data/features/support/db/fixtures/thetas.rb +0 -10
  394. data/features/support/db/migrations/create_alphas.rb +0 -7
  395. data/features/support/db/migrations/create_animals.rb +0 -5
  396. data/features/support/db/migrations/create_authors.rb +0 -3
  397. data/features/support/db/migrations/create_authors_posts.rb +0 -6
  398. data/features/support/db/migrations/create_betas.rb +0 -5
  399. data/features/support/db/migrations/create_boxes.rb +0 -5
  400. data/features/support/db/migrations/create_categories.rb +0 -3
  401. data/features/support/db/migrations/create_comments.rb +0 -10
  402. data/features/support/db/migrations/create_delayed_betas.rb +0 -17
  403. data/features/support/db/migrations/create_developers.rb +0 -9
  404. data/features/support/db/migrations/create_extensible_betas.rb +0 -5
  405. data/features/support/db/migrations/create_gammas.rb +0 -3
  406. data/features/support/db/migrations/create_people.rb +0 -13
  407. data/features/support/db/migrations/create_posts.rb +0 -5
  408. data/features/support/db/migrations/create_robots.rb +0 -4
  409. data/features/support/db/migrations/create_taggings.rb +0 -5
  410. data/features/support/db/migrations/create_tags.rb +0 -4
  411. data/features/support/db/migrations/create_thetas.rb +0 -5
  412. data/features/support/db/mysql.rb +0 -3
  413. data/features/support/db/postgresql.rb +0 -3
  414. data/features/support/env.rb +0 -18
  415. data/features/support/lib/generic_delta_handler.rb +0 -8
  416. data/features/support/models/alpha.rb +0 -10
  417. data/features/support/models/animal.rb +0 -5
  418. data/features/support/models/author.rb +0 -3
  419. data/features/support/models/beta.rb +0 -8
  420. data/features/support/models/box.rb +0 -8
  421. data/features/support/models/cat.rb +0 -3
  422. data/features/support/models/category.rb +0 -4
  423. data/features/support/models/comment.rb +0 -10
  424. data/features/support/models/delayed_beta.rb +0 -7
  425. data/features/support/models/developer.rb +0 -16
  426. data/features/support/models/dog.rb +0 -3
  427. data/features/support/models/extensible_beta.rb +0 -9
  428. data/features/support/models/gamma.rb +0 -5
  429. data/features/support/models/person.rb +0 -23
  430. data/features/support/models/post.rb +0 -20
  431. data/features/support/models/robot.rb +0 -12
  432. data/features/support/models/tag.rb +0 -3
  433. data/features/support/models/theta.rb +0 -7
  434. data/features/support/post_database.rb +0 -43
  435. data/lib/cucumber/thinking_sphinx/internal_world.rb +0 -125
  436. data/lib/cucumber/thinking_sphinx/sql_logger.rb +0 -20
  437. data/lib/thinking_sphinx/active_record/attribute_updates.rb +0 -48
  438. data/lib/thinking_sphinx/active_record/delta.rb +0 -87
  439. data/lib/thinking_sphinx/active_record/has_many_association.rb +0 -28
  440. data/lib/thinking_sphinx/active_record/scopes.rb +0 -39
  441. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +0 -42
  442. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +0 -54
  443. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +0 -143
  444. data/lib/thinking_sphinx/association.rb +0 -164
  445. data/lib/thinking_sphinx/attribute.rb +0 -341
  446. data/lib/thinking_sphinx/class_facet.rb +0 -15
  447. data/lib/thinking_sphinx/core/array.rb +0 -7
  448. data/lib/thinking_sphinx/core/string.rb +0 -15
  449. data/lib/thinking_sphinx/deltas/datetime_delta.rb +0 -50
  450. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +0 -24
  451. data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +0 -27
  452. data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +0 -26
  453. data/lib/thinking_sphinx/deltas/delayed_delta.rb +0 -30
  454. data/lib/thinking_sphinx/deploy/capistrano.rb +0 -100
  455. data/lib/thinking_sphinx/field.rb +0 -82
  456. data/lib/thinking_sphinx/index/builder.rb +0 -286
  457. data/lib/thinking_sphinx/index/faux_column.rb +0 -110
  458. data/lib/thinking_sphinx/property.rb +0 -162
  459. data/lib/thinking_sphinx/rails_additions.rb +0 -150
  460. data/lib/thinking_sphinx/search_methods.rb +0 -421
  461. data/lib/thinking_sphinx/source/internal_properties.rb +0 -46
  462. data/lib/thinking_sphinx/source/sql.rb +0 -128
  463. data/lib/thinking_sphinx/source.rb +0 -150
  464. data/rails/init.rb +0 -14
  465. data/spec/lib/thinking_sphinx/active_record/delta_spec.rb +0 -130
  466. data/spec/lib/thinking_sphinx/active_record/has_many_association_spec.rb +0 -49
  467. data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +0 -96
  468. data/spec/lib/thinking_sphinx/active_record_spec.rb +0 -353
  469. data/spec/lib/thinking_sphinx/association_spec.rb +0 -239
  470. data/spec/lib/thinking_sphinx/attribute_spec.rb +0 -507
  471. data/spec/lib/thinking_sphinx/configuration_spec.rb +0 -268
  472. data/spec/lib/thinking_sphinx/core/array_spec.rb +0 -9
  473. data/spec/lib/thinking_sphinx/core/string_spec.rb +0 -9
  474. data/spec/lib/thinking_sphinx/deltas/job_spec.rb +0 -32
  475. data/spec/lib/thinking_sphinx/excerpter_spec.rb +0 -57
  476. data/spec/lib/thinking_sphinx/facet_search_spec.rb +0 -176
  477. data/spec/lib/thinking_sphinx/facet_spec.rb +0 -333
  478. data/spec/lib/thinking_sphinx/field_spec.rb +0 -154
  479. data/spec/lib/thinking_sphinx/index/builder_spec.rb +0 -455
  480. data/spec/lib/thinking_sphinx/index/faux_column_spec.rb +0 -30
  481. data/spec/lib/thinking_sphinx/index_spec.rb +0 -45
  482. data/spec/lib/thinking_sphinx/rails_additions_spec.rb +0 -203
  483. data/spec/lib/thinking_sphinx/search_methods_spec.rb +0 -152
  484. data/spec/lib/thinking_sphinx/search_spec.rb +0 -1101
  485. data/spec/lib/thinking_sphinx/source_spec.rb +0 -227
  486. data/spec/lib/thinking_sphinx_spec.rb +0 -162
  487. data/tasks/distribution.rb +0 -53
  488. data/tasks/rails.rake +0 -1
  489. data/tasks/testing.rb +0 -72
  490. data/vendor/after_commit/LICENSE +0 -20
  491. data/vendor/after_commit/README +0 -16
  492. data/vendor/after_commit/Rakefile +0 -22
  493. data/vendor/after_commit/init.rb +0 -8
  494. data/vendor/after_commit/lib/after_commit/active_record.rb +0 -114
  495. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +0 -103
  496. data/vendor/after_commit/lib/after_commit.rb +0 -45
  497. data/vendor/after_commit/test/after_commit_test.rb +0 -53
  498. data/vendor/delayed_job/lib/delayed/job.rb +0 -251
  499. data/vendor/delayed_job/lib/delayed/message_sending.rb +0 -7
  500. data/vendor/delayed_job/lib/delayed/performable_method.rb +0 -55
  501. data/vendor/delayed_job/lib/delayed/worker.rb +0 -54
  502. data/vendor/riddle/lib/riddle/client/filter.rb +0 -53
  503. data/vendor/riddle/lib/riddle/client/message.rb +0 -66
  504. data/vendor/riddle/lib/riddle/client/response.rb +0 -84
  505. data/vendor/riddle/lib/riddle/client.rb +0 -635
  506. data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +0 -48
  507. data/vendor/riddle/lib/riddle/configuration/index.rb +0 -142
  508. data/vendor/riddle/lib/riddle/configuration/indexer.rb +0 -19
  509. data/vendor/riddle/lib/riddle/configuration/remote_index.rb +0 -17
  510. data/vendor/riddle/lib/riddle/configuration/searchd.rb +0 -25
  511. data/vendor/riddle/lib/riddle/configuration/section.rb +0 -43
  512. data/vendor/riddle/lib/riddle/configuration/source.rb +0 -23
  513. data/vendor/riddle/lib/riddle/configuration/sql_source.rb +0 -34
  514. data/vendor/riddle/lib/riddle/configuration/xml_source.rb +0 -28
  515. data/vendor/riddle/lib/riddle/configuration.rb +0 -33
  516. data/vendor/riddle/lib/riddle/controller.rb +0 -53
  517. data/vendor/riddle/lib/riddle.rb +0 -30
@@ -0,0 +1,117 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ require 'acceptance/spec_helper'
5
+
6
+ describe 'Searching within a model', :live => true do
7
+ it "returns results" do
8
+ article = Article.create! :title => 'Pancakes'
9
+ index
10
+
11
+ expect(Article.search.first).to eq(article)
12
+ end
13
+
14
+ it "returns results matching the given query" do
15
+ pancakes = Article.create! :title => 'Pancakes'
16
+ waffles = Article.create! :title => 'Waffles'
17
+ index
18
+
19
+ articles = Article.search 'pancakes'
20
+ expect(articles).to include(pancakes)
21
+ expect(articles).not_to include(waffles)
22
+ end
23
+
24
+ it "handles unicode characters" do
25
+ istanbul = City.create! :name => 'İstanbul'
26
+ index
27
+
28
+ expect(City.search('İstanbul').to_a).to eq([istanbul])
29
+ end
30
+
31
+ it "will star provided queries on request" do
32
+ article = Article.create! :title => 'Pancakes'
33
+ index
34
+
35
+ expect(Article.search('cake', :star => true).first).to eq(article)
36
+ end
37
+
38
+ it "allows for searching on specific indices" do
39
+ article = Article.create :title => 'Pancakes'
40
+ index
41
+
42
+ articles = Article.search('pancake', :indices => ['stemmed_article_core'])
43
+ expect(articles.to_a).to eq([article])
44
+ end
45
+
46
+ it "allows for searching on distributed indices" do
47
+ article = Article.create :title => 'Pancakes'
48
+ index
49
+
50
+ articles = Article.search('pancake', :indices => ['article'])
51
+ expect(articles.to_a).to eq([article])
52
+ end
53
+
54
+ it "can search on namespaced models" do
55
+ person = Admin::Person.create :name => 'James Bond'
56
+ index
57
+
58
+ expect(Admin::Person.search('Bond').to_a).to eq([person])
59
+ end
60
+
61
+ it "raises an error if searching through an ActiveRecord scope" do
62
+ expect {
63
+ City.ordered.search
64
+ }.to raise_error(ThinkingSphinx::MixedScopesError)
65
+ end
66
+
67
+ it "does not raise an error when searching with a default ActiveRecord scope" do
68
+ expect {
69
+ User.search
70
+ }.not_to raise_error
71
+ end
72
+
73
+ it "raises an error when searching with default and applied AR scopes" do
74
+ expect {
75
+ User.recent.search
76
+ }.to raise_error(ThinkingSphinx::MixedScopesError)
77
+ end
78
+
79
+ it "raises an error if the model has no indices defined" do
80
+ expect {
81
+ Category.search.to_a
82
+ }.to raise_error(ThinkingSphinx::NoIndicesError)
83
+ end
84
+
85
+ it "handles models with alternative id columns" do
86
+ album = Album.create! :name => 'The Seldom Seen Kid', :artist => 'Elbow'
87
+ index
88
+
89
+ expect(Album.search(:indices => ['album_core', 'album_delta']).first).
90
+ to eq(album)
91
+
92
+ expect(Album.search(:indices => ['album_real_core']).first).
93
+ to eq(album)
94
+ end
95
+
96
+ it "is available via a sphinx-prefixed method" do
97
+ article = Article.create! :title => 'Pancakes'
98
+ index
99
+
100
+ expect(Article.sphinx_search.first).to eq(article)
101
+ end
102
+
103
+ it "has a 'none' default scope" do
104
+ article = Article.create! :title => 'Pancakes'
105
+ index
106
+
107
+ expect(Article.search_none).to be_empty
108
+ end
109
+ end
110
+
111
+ describe 'Searching within a model with a realtime index', :live => true do
112
+ it "returns results" do
113
+ product = Product.create! :name => 'Widget'
114
+
115
+ expect(Product.search.first).to eq(product)
116
+ end
117
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'acceptance/spec_helper'
4
+
5
+ describe 'Sorting search results', :live => true do
6
+ it "sorts by a given clause" do
7
+ gods = Book.create! :title => 'American Gods', :publishing_year => 2001
8
+ grave = Book.create! :title => 'The Graveyard Book', :publishing_year => 2009
9
+ boys = Book.create! :title => 'Anansi Boys', :publishing_year => 2005
10
+ index
11
+
12
+ expect(Book.search(:order => 'publishing_year ASC').to_a).to eq([gods, boys, grave])
13
+ end
14
+
15
+ it "sorts by a given attribute in ascending order" do
16
+ gods = Book.create! :title => 'American Gods', :publishing_year => 2001
17
+ grave = Book.create! :title => 'The Graveyard Book', :publishing_year => 2009
18
+ boys = Book.create! :title => 'Anansi Boys', :publishing_year => 2005
19
+ index
20
+
21
+ expect(Book.search(:order => :publishing_year).to_a).to eq([gods, boys, grave])
22
+ end
23
+
24
+ it "sorts by a given sortable field" do
25
+ gods = Book.create! :title => 'American Gods', :publishing_year => 2001
26
+ grave = Book.create! :title => 'The Graveyard Book', :publishing_year => 2009
27
+ boys = Book.create! :title => 'Anansi Boys', :publishing_year => 2005
28
+ index
29
+
30
+ expect(Book.search(:order => :title).to_a).to eq([gods, boys, grave])
31
+ end
32
+
33
+ it "sorts by a given sortable field with real-time indices" do
34
+ widgets = Product.create! :name => 'Widgets'
35
+ gadgets = Product.create! :name => 'Gadgets'
36
+
37
+ expect(Product.search(:order => "name_sort ASC").to_a).to eq([gadgets, widgets])
38
+ end
39
+
40
+ it "can sort with a provided expression" do
41
+ gods = Book.create! :title => 'American Gods', :publishing_year => 2001
42
+ grave = Book.create! :title => 'The Graveyard Book', :publishing_year => 2009
43
+ boys = Book.create! :title => 'Anansi Boys', :publishing_year => 2005
44
+ index
45
+
46
+ expect(Book.search(
47
+ :select => '*, publishing_year MOD 2004 as mod_year', :order => 'mod_year ASC'
48
+ ).to_a).to eq([boys, grave, gods])
49
+ end
50
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ root = File.expand_path File.dirname(__FILE__)
6
+ Dir["#{root}/support/**/*.rb"].each { |file| require file }
@@ -0,0 +1,516 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'acceptance/spec_helper'
4
+
5
+ describe 'specifying SQL for index definitions' do
6
+ it "renders the SQL with the join" do
7
+ index = ThinkingSphinx::ActiveRecord::Index.new(:article)
8
+ index.definition_block = Proc.new {
9
+ indexes title
10
+ join user
11
+ }
12
+ index.render
13
+ expect(index.sources.first.sql_query).to match(/LEFT OUTER JOIN .users./)
14
+ end
15
+
16
+ it "handles deep joins" do
17
+ index = ThinkingSphinx::ActiveRecord::Index.new(:article)
18
+ index.definition_block = Proc.new {
19
+ indexes title
20
+ join user.articles
21
+ }
22
+ index.render
23
+
24
+ query = index.sources.first.sql_query
25
+ expect(query).to match(/LEFT OUTER JOIN .users./)
26
+ expect(query).to match(/LEFT OUTER JOIN .articles./)
27
+ end
28
+
29
+ it "handles has-many :through joins" do
30
+ index = ThinkingSphinx::ActiveRecord::Index.new(:article)
31
+ index.definition_block = Proc.new {
32
+ indexes tags.name
33
+ }
34
+ index.render
35
+
36
+ query = index.sources.first.sql_query
37
+ expect(query).to match(/LEFT OUTER JOIN .taggings./)
38
+ expect(query).to match(/LEFT OUTER JOIN .tags./)
39
+ end
40
+
41
+ it "handles custom join SQL statements" do
42
+ index = ThinkingSphinx::ActiveRecord::Index.new(:article)
43
+ index.definition_block = Proc.new {
44
+ indexes title
45
+ join "INNER JOIN foo ON foo.x = bar.y"
46
+ }
47
+ index.render
48
+
49
+ query = index.sources.first.sql_query
50
+ expect(query).to match(/INNER JOIN foo ON foo.x = bar.y/)
51
+ end
52
+
53
+ it "handles GROUP BY clauses" do
54
+ index = ThinkingSphinx::ActiveRecord::Index.new(:article)
55
+ index.definition_block = Proc.new {
56
+ indexes title
57
+ group_by 'lat'
58
+ }
59
+ index.render
60
+
61
+ query = index.sources.first.sql_query
62
+ expect(query).to match(/GROUP BY .articles.\..id., .?articles.?\..title., .?articles.?\..id., lat/)
63
+ end
64
+
65
+ it "handles WHERE clauses" do
66
+ index = ThinkingSphinx::ActiveRecord::Index.new(:article)
67
+ index.definition_block = Proc.new {
68
+ indexes title
69
+ where "title != 'secret'"
70
+ }
71
+ index.render
72
+
73
+ query = index.sources.first.sql_query
74
+ expect(query).to match(/WHERE .+title != 'secret'.+ GROUP BY/)
75
+ end
76
+
77
+ it "handles manual MVA declarations" do
78
+ index = ThinkingSphinx::ActiveRecord::Index.new(:article)
79
+ index.definition_block = Proc.new {
80
+ indexes title
81
+ has "taggings.tag_ids", :as => :tag_ids, :type => :integer,
82
+ :multi => true
83
+ }
84
+ index.render
85
+
86
+ expect(index.sources.first.sql_attr_multi).to eq(['uint tag_ids from field'])
87
+ end
88
+
89
+ it "provides the sanitize_sql helper within the index definition block" do
90
+ index = ThinkingSphinx::ActiveRecord::Index.new(:article)
91
+ index.definition_block = Proc.new {
92
+ indexes title
93
+ where sanitize_sql(["title != ?", 'secret'])
94
+ }
95
+ index.render
96
+
97
+ query = index.sources.first.sql_query
98
+ expect(query).to match(/WHERE .+title != 'secret'.+ GROUP BY/)
99
+ end
100
+
101
+ it "escapes new lines in SQL snippets" do
102
+ index = ThinkingSphinx::ActiveRecord::Index.new(:article)
103
+ index.definition_block = Proc.new {
104
+ indexes title
105
+ has <<-SQL, as: :custom_attribute, type: :integer
106
+ ARRAY_AGG(
107
+ CONCAT(
108
+ something
109
+ )
110
+ )
111
+ SQL
112
+ }
113
+ index.render
114
+
115
+ query = index.sources.first.sql_query
116
+ expect(query).to match(/\\\n/)
117
+ end
118
+
119
+ it "joins each polymorphic relation" do
120
+ index = ThinkingSphinx::ActiveRecord::Index.new(:event)
121
+ index.definition_block = Proc.new {
122
+ indexes eventable.title, :as => :title
123
+ polymorphs eventable, :to => %w(Article Book)
124
+ }
125
+ index.render
126
+
127
+ query = index.sources.first.sql_query
128
+ expect(query).to match(/LEFT OUTER JOIN .articles. ON .articles.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Article'/)
129
+ expect(query).to match(/LEFT OUTER JOIN .books. ON .books.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Book'/)
130
+ expect(query).to match(/.articles.\..title., .books.\..title./)
131
+ end if ActiveRecord::VERSION::MAJOR > 3
132
+
133
+ it "concatenates references that have column" do
134
+ index = ThinkingSphinx::ActiveRecord::Index.new(:event)
135
+ index.definition_block = Proc.new {
136
+ indexes eventable.title, :as => :title
137
+ polymorphs eventable, :to => %w(Article User)
138
+ }
139
+ index.render
140
+
141
+ query = index.sources.first.sql_query
142
+ expect(query).to match(/LEFT OUTER JOIN .articles. ON .articles.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Article'/)
143
+ expect(query).not_to match(/articles\..title., users\..title./)
144
+ expect(query).to match(/.articles.\..title./)
145
+ end if ActiveRecord::VERSION::MAJOR > 3
146
+
147
+ it "respects deeper associations through polymorphic joins" do
148
+ index = ThinkingSphinx::ActiveRecord::Index.new(:event)
149
+ index.definition_block = Proc.new {
150
+ indexes eventable.user.name, :as => :user_name
151
+ polymorphs eventable, :to => %w(Article Book)
152
+ }
153
+ index.render
154
+
155
+ query = index.sources.first.sql_query
156
+ expect(query).to match(/LEFT OUTER JOIN .articles. ON .articles.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Article'/)
157
+ expect(query).to match(/LEFT OUTER JOIN .users. ON .users.\..id. = .articles.\..user_id./)
158
+ expect(query).to match(/.users.\..name./)
159
+ end
160
+
161
+ it "allows for STI mixed with polymorphic joins" do
162
+ index = ThinkingSphinx::ActiveRecord::Index.new(:event)
163
+ index.definition_block = Proc.new {
164
+ indexes eventable.name, :as => :name
165
+ polymorphs eventable, :to => %w(Bird Car)
166
+ }
167
+ index.render
168
+
169
+ query = index.sources.first.sql_query
170
+ expect(query).to match(/LEFT OUTER JOIN .animals. ON .animals.\..id. = .events.\..eventable_id. .* AND .events.\..eventable_type. = 'Animal'/)
171
+ expect(query).to match(/LEFT OUTER JOIN .cars. ON .cars.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Car'/)
172
+ expect(query).to match(/.animals.\..name., .cars.\..name./)
173
+ end
174
+ end if ActiveRecord::VERSION::MAJOR > 3
175
+
176
+ describe 'separate queries for MVAs' do
177
+ def id_type
178
+ ActiveRecord::VERSION::STRING.to_f > 5.0 ? 'bigint' : 'uint'
179
+ end
180
+
181
+ let(:index) { ThinkingSphinx::ActiveRecord::Index.new(:article) }
182
+ let(:count) { ThinkingSphinx::Configuration.instance.indices.count }
183
+ let(:source) { index.sources.first }
184
+
185
+ it "generates an appropriate SQL query for an MVA" do
186
+ index.definition_block = Proc.new {
187
+ indexes title
188
+ has taggings.tag_id, :as => :tag_ids, :source => :query
189
+ }
190
+ index.render
191
+
192
+ attribute = source.sql_attr_multi.detect { |attribute|
193
+ attribute[/tag_ids/]
194
+ }
195
+ declaration, query = attribute.split(/;\s+/)
196
+
197
+ expect(declaration).to eq("uint tag_ids from query")
198
+ expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)$/)
199
+ end
200
+
201
+ it "does not include attributes sourced via separate queries" do
202
+ index.definition_block = Proc.new {
203
+ indexes title
204
+ has taggings.tag_id, :as => :tag_ids, :source => :query
205
+ }
206
+ index.render
207
+
208
+ # We don't want it in the SELECT, JOIN or GROUP clauses. This should catch
209
+ # them all.
210
+ expect(source.sql_query).not_to include('taggings')
211
+ end
212
+
213
+ it "keeps the joins in for separately queried tables if they're used elsewhere" do
214
+ index.definition_block = Proc.new {
215
+ indexes taggings.tag.name, :as => :tag_names
216
+ has taggings.tag.created_at, :as => :tag_dates, :source => :query
217
+ }
218
+ index.render
219
+
220
+ expect(source.sql_query).to include('taggings')
221
+ expect(source.sql_query).to include('tags')
222
+ expect(source.sql_query).to_not match(/.tags.\..created_at./)
223
+ expect(source.sql_query).to match(/.tags.\..name./)
224
+ end
225
+
226
+ it "generates a SQL query with joins when appropriate for MVAs" do
227
+ index.definition_block = Proc.new {
228
+ indexes title
229
+ has taggings.tag.id, :as => :tag_ids, :source => :query
230
+ }
231
+ index.render
232
+
233
+ attribute = source.sql_attr_multi.detect { |attribute|
234
+ attribute[/tag_ids/]
235
+ }
236
+ declaration, query = attribute.split(/;\s+/)
237
+
238
+ expect(declaration).to eq("#{id_type} tag_ids from query")
239
+ expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.taggings.\..article_id. IS NOT NULL\)\s?$/)
240
+ end
241
+
242
+ it "respects has_many :through joins for MVA queries" do
243
+ index.definition_block = Proc.new {
244
+ indexes title
245
+ has tags.id, :as => :tag_ids, :source => :query
246
+ }
247
+ index.render
248
+
249
+ attribute = source.sql_attr_multi.detect { |attribute|
250
+ attribute[/tag_ids/]
251
+ }
252
+ declaration, query = attribute.split(/;\s+/)
253
+
254
+ expect(declaration).to eq("#{id_type} tag_ids from query")
255
+ expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.taggings.\..article_id. IS NOT NULL\)\s?$/)
256
+ end
257
+
258
+ it "can handle multiple joins for MVA queries" do
259
+ index = ThinkingSphinx::ActiveRecord::Index.new(:user)
260
+ index.definition_block = Proc.new {
261
+ indexes name
262
+ has articles.tags.id, :as => :tag_ids, :source => :query
263
+ }
264
+ index.render
265
+ source = index.sources.first
266
+
267
+ attribute = source.sql_attr_multi.detect { |attribute|
268
+ attribute[/tag_ids/]
269
+ }
270
+ declaration, query = attribute.split(/;\s+/)
271
+
272
+ expect(declaration).to eq("#{id_type} tag_ids from query")
273
+ expect(query).to match(/^SELECT .articles.\..user_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .articles. INNER JOIN .taggings. ON .taggings.\..article_id. = .articles.\..id. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.articles.\..user_id. IS NOT NULL\)\s?$/)
274
+ end
275
+
276
+ it "can handle simple HABTM joins for MVA queries" do
277
+ index = ThinkingSphinx::ActiveRecord::Index.new(:book)
278
+ index.definition_block = Proc.new {
279
+ indexes title
280
+ has genres.id, :as => :genre_ids, :source => :query
281
+ }
282
+ index.render
283
+ source = index.sources.first
284
+
285
+ attribute = source.sql_attr_multi.detect { |attribute|
286
+ attribute[/genre_ids/]
287
+ }
288
+ declaration, query = attribute.split(/;\s+/)
289
+
290
+ expect(declaration).to eq("#{id_type} genre_ids from query")
291
+ expect(query).to match(/^SELECT .books_genres.\..book_id. \* #{count} \+ #{source.offset} AS .id., .books_genres.\..genre_id. AS .genre_ids. FROM .books_genres.\s?$/)
292
+ end if ActiveRecord::VERSION::MAJOR > 3
293
+
294
+ it "generates an appropriate range SQL queries for an MVA" do
295
+ index.definition_block = Proc.new {
296
+ indexes title
297
+ has taggings.tag_id, :as => :tag_ids, :source => :ranged_query
298
+ }
299
+ index.render
300
+
301
+ attribute = source.sql_attr_multi.detect { |attribute|
302
+ attribute[/tag_ids/]
303
+ }
304
+ declaration, query, range = attribute.split(/;\s+/)
305
+
306
+ expect(declaration).to eq("uint tag_ids from ranged-query")
307
+ expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)$/)
308
+ expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
309
+ end
310
+
311
+ it "generates a SQL query with joins when appropriate for MVAs" do
312
+ index.definition_block = Proc.new {
313
+ indexes title
314
+ has taggings.tag.id, :as => :tag_ids, :source => :ranged_query
315
+ }
316
+ index.render
317
+
318
+ attribute = source.sql_attr_multi.detect { |attribute|
319
+ attribute[/tag_ids/]
320
+ }
321
+ declaration, query, range = attribute.split(/;\s+/)
322
+
323
+ expect(declaration).to eq("#{id_type} tag_ids from ranged-query")
324
+ expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)$/)
325
+ expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
326
+ end
327
+
328
+ it "can handle ranged queries for simple HABTM joins for MVA queries" do
329
+ index = ThinkingSphinx::ActiveRecord::Index.new(:book)
330
+ index.definition_block = Proc.new {
331
+ indexes title
332
+ has genres.id, :as => :genre_ids, :source => :ranged_query
333
+ }
334
+ index.render
335
+ source = index.sources.first
336
+
337
+ attribute = source.sql_attr_multi.detect { |attribute|
338
+ attribute[/genre_ids/]
339
+ }
340
+ declaration, query, range = attribute.split(/;\s+/)
341
+
342
+ expect(declaration).to eq("#{id_type} genre_ids from ranged-query")
343
+ expect(query).to match(/^SELECT .books_genres.\..book_id. \* #{count} \+ #{source.offset} AS .id., .books_genres.\..genre_id. AS .genre_ids. FROM .books_genres. WHERE \(.books_genres.\..book_id. BETWEEN \$start AND \$end\)$/)
344
+ expect(range).to match(/^SELECT MIN\(.books_genres.\..book_id.\), MAX\(.books_genres.\..book_id.\) FROM .books_genres.$/)
345
+ end if ActiveRecord::VERSION::MAJOR > 3
346
+
347
+ it "respects custom SQL snippets as the query value" do
348
+ index.definition_block = Proc.new {
349
+ indexes title
350
+ has 'My Custom SQL Query', :as => :tag_ids, :source => :query,
351
+ :type => :integer, :multi => true
352
+ }
353
+ index.render
354
+
355
+ attribute = source.sql_attr_multi.detect { |attribute|
356
+ attribute[/tag_ids/]
357
+ }
358
+ declaration, query = attribute.split(/;\s+/)
359
+
360
+ expect(declaration).to eq('uint tag_ids from query')
361
+ expect(query).to eq('My Custom SQL Query')
362
+ end
363
+
364
+ it "respects custom SQL snippets as the ranged query value" do
365
+ index.definition_block = Proc.new {
366
+ indexes title
367
+ has 'My Custom SQL Query; And a Range', :as => :tag_ids,
368
+ :source => :ranged_query, :type => :integer, :multi => true
369
+ }
370
+ index.render
371
+
372
+ attribute = source.sql_attr_multi.detect { |attribute|
373
+ attribute[/tag_ids/]
374
+ }
375
+ declaration, query, range = attribute.split(/;\s+/)
376
+
377
+ expect(declaration).to eq('uint tag_ids from ranged-query')
378
+ expect(query).to eq('My Custom SQL Query')
379
+ expect(range).to eq('And a Range')
380
+ end
381
+
382
+ it "escapes new lines in custom SQL snippets" do
383
+ index.definition_block = Proc.new {
384
+ indexes title
385
+ has <<-SQL, :as => :tag_ids, :source => :query, :type => :integer, :multi => true
386
+ My Custom
387
+ SQL Query
388
+ SQL
389
+ }
390
+ index.render
391
+
392
+ attribute = source.sql_attr_multi.detect { |attribute|
393
+ attribute[/tag_ids/]
394
+ }
395
+ declaration, query = attribute.split(/;\s+/)
396
+
397
+ expect(declaration).to eq('uint tag_ids from query')
398
+ expect(query).to eq("My Custom\\\nSQL Query")
399
+ end
400
+ end
401
+
402
+ describe 'separate queries for field' do
403
+ let(:index) { ThinkingSphinx::ActiveRecord::Index.new(:article) }
404
+ let(:count) { ThinkingSphinx::Configuration.instance.indices.count }
405
+ let(:source) { index.sources.first }
406
+
407
+ it "generates a SQL query with joins when appropriate for MVF" do
408
+ index.definition_block = Proc.new {
409
+ indexes taggings.tag.name, :as => :tags, :source => :query
410
+ }
411
+ index.render
412
+
413
+ field = source.sql_joined_field.detect { |field| field[/tags/] }
414
+ declaration, query = field.split(/;\s+/)
415
+
416
+ expect(declaration).to eq('tags from query')
417
+ expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)\s? ORDER BY .taggings.\..article_id. ASC\s?$/)
418
+ end
419
+
420
+ it "respects has_many :through joins for MVF queries" do
421
+ index.definition_block = Proc.new {
422
+ indexes tags.name, :as => :tags, :source => :query
423
+ }
424
+ index.render
425
+
426
+ field = source.sql_joined_field.detect { |field| field[/tags/] }
427
+ declaration, query = field.split(/;\s+/)
428
+
429
+ expect(declaration).to eq('tags from query')
430
+ expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)\s? ORDER BY .taggings.\..article_id. ASC\s?$/)
431
+ end
432
+
433
+ it "can handle multiple joins for MVF queries" do
434
+ index = ThinkingSphinx::ActiveRecord::Index.new(:user)
435
+ index.definition_block = Proc.new {
436
+ indexes articles.tags.name, :as => :tags, :source => :query
437
+ }
438
+ index.render
439
+ source = index.sources.first
440
+
441
+ field = source.sql_joined_field.detect { |field| field[/tags/] }
442
+ declaration, query = field.split(/;\s+/)
443
+
444
+ expect(declaration).to eq('tags from query')
445
+ expect(query).to match(/^SELECT .articles.\..user_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .articles. INNER JOIN .taggings. ON .taggings.\..article_id. = .articles.\..id. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? WHERE \(.articles.\..user_id. IS NOT NULL\)\s? ORDER BY .articles.\..user_id. ASC\s?$/)
446
+ end
447
+
448
+ it "generates a SQL query with joins when appropriate for MVFs" do
449
+ index.definition_block = Proc.new {
450
+ indexes taggings.tag.name, :as => :tags, :source => :ranged_query
451
+ }
452
+ index.render
453
+
454
+ field = source.sql_joined_field.detect { |field| field[/tags/] }
455
+ declaration, query, range = field.split(/;\s+/)
456
+
457
+ expect(declaration).to eq('tags from ranged-query')
458
+ expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)\s? ORDER BY .taggings.\..article_id. ASC$/)
459
+ expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
460
+ end
461
+
462
+ it "does not include fields sourced via separate queries" do
463
+ index.definition_block = Proc.new {
464
+ indexes taggings.tag.name, :as => :tags, :source => :query
465
+ }
466
+ index.render
467
+
468
+ # We don't want it in the SELECT, JOIN or GROUP clauses. This should catch
469
+ # them all.
470
+ expect(source.sql_query).not_to include('tags')
471
+ end
472
+
473
+ it "respects custom SQL snippets as the query value" do
474
+ index.definition_block = Proc.new {
475
+ indexes 'My Custom SQL Query', :as => :tags, :source => :query
476
+ }
477
+ index.render
478
+
479
+ field = source.sql_joined_field.detect { |field| field[/tags/] }
480
+ declaration, query = field.split(/;\s+/)
481
+
482
+ expect(declaration).to eq('tags from query')
483
+ expect(query).to eq('My Custom SQL Query')
484
+ end
485
+
486
+ it "respects custom SQL snippets as the ranged query value" do
487
+ index.definition_block = Proc.new {
488
+ indexes 'My Custom SQL Query; And a Range', :as => :tags,
489
+ :source => :ranged_query
490
+ }
491
+ index.render
492
+
493
+ field = source.sql_joined_field.detect { |field| field[/tags/] }
494
+ declaration, query, range = field.split(/;\s+/)
495
+
496
+ expect(declaration).to eq('tags from ranged-query')
497
+ expect(query).to eq('My Custom SQL Query')
498
+ expect(range).to eq('And a Range')
499
+ end
500
+
501
+ it "escapes new lines in custom SQL snippets" do
502
+ index.definition_block = Proc.new {
503
+ indexes <<-SQL, :as => :tags, :source => :query
504
+ My Custom
505
+ SQL Query
506
+ SQL
507
+ }
508
+ index.render
509
+
510
+ field = source.sql_joined_field.detect { |field| field[/tags/] }
511
+ declaration, query = field.split(/;\s+/)
512
+
513
+ expect(declaration).to eq('tags from query')
514
+ expect(query).to eq("My Custom\\\nSQL Query")
515
+ end
516
+ end