thinking-sphinx 2.1.0 → 3.0.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +13 -0
  3. data/Appraisals +7 -0
  4. data/Gemfile +10 -0
  5. data/HISTORY +2 -267
  6. data/LICENCE +1 -1
  7. data/README.textile +194 -226
  8. data/Rakefile +24 -0
  9. data/gemfiles/.gitignore +1 -0
  10. data/gemfiles/rails_3_1.gemfile +11 -0
  11. data/gemfiles/rails_3_2.gemfile +11 -0
  12. data/lib/thinking-sphinx.rb +1 -1
  13. data/lib/thinking_sphinx.rb +34 -292
  14. data/lib/thinking_sphinx/active_record.rb +22 -383
  15. data/lib/thinking_sphinx/active_record/association.rb +9 -0
  16. data/lib/thinking_sphinx/active_record/association_proxy.rb +68 -0
  17. data/lib/thinking_sphinx/active_record/associations.rb +68 -0
  18. data/lib/thinking_sphinx/active_record/attribute.rb +20 -0
  19. data/lib/thinking_sphinx/active_record/attribute/sphinx_presenter.rb +32 -0
  20. data/lib/thinking_sphinx/active_record/attribute/type.rb +79 -0
  21. data/lib/thinking_sphinx/active_record/attribute/values.rb +18 -0
  22. data/lib/thinking_sphinx/active_record/base.rb +36 -0
  23. data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +31 -0
  24. data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +55 -0
  25. data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +59 -0
  26. data/lib/thinking_sphinx/active_record/column.rb +30 -0
  27. data/lib/thinking_sphinx/active_record/database_adapters.rb +51 -0
  28. data/lib/thinking_sphinx/active_record/database_adapters/abstract_adapter.rb +13 -0
  29. data/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb +23 -0
  30. data/lib/thinking_sphinx/active_record/database_adapters/postgresql_adapter.rb +25 -0
  31. data/lib/thinking_sphinx/active_record/field.rb +11 -0
  32. data/lib/thinking_sphinx/active_record/index.rb +55 -0
  33. data/lib/thinking_sphinx/active_record/interpreter.rb +47 -0
  34. data/lib/thinking_sphinx/active_record/log_subscriber.rb +10 -58
  35. data/lib/thinking_sphinx/active_record/property.rb +28 -0
  36. data/lib/thinking_sphinx/active_record/property_sql_presenter.rb +60 -0
  37. data/lib/thinking_sphinx/active_record/sql_builder.rb +159 -0
  38. data/lib/thinking_sphinx/active_record/sql_source.rb +138 -0
  39. data/lib/thinking_sphinx/active_record/sql_source/template.rb +46 -0
  40. data/lib/thinking_sphinx/batched_search.rb +26 -0
  41. data/lib/thinking_sphinx/callbacks.rb +15 -0
  42. data/lib/thinking_sphinx/configuration.rb +80 -331
  43. data/lib/thinking_sphinx/configuration/consistent_ids.rb +31 -0
  44. data/lib/thinking_sphinx/configuration/defaults.rb +5 -0
  45. data/lib/thinking_sphinx/core.rb +6 -0
  46. data/lib/thinking_sphinx/core/index.rb +68 -0
  47. data/lib/thinking_sphinx/core/interpreter.rb +19 -0
  48. data/lib/thinking_sphinx/deltas.rb +35 -26
  49. data/lib/thinking_sphinx/deltas/default_delta.rb +56 -56
  50. data/lib/thinking_sphinx/excerpter.rb +23 -21
  51. data/lib/thinking_sphinx/facet.rb +22 -127
  52. data/lib/thinking_sphinx/facet_search.rb +95 -162
  53. data/lib/thinking_sphinx/index.rb +39 -143
  54. data/lib/thinking_sphinx/index_set.rb +51 -0
  55. data/lib/thinking_sphinx/masks.rb +8 -0
  56. data/lib/thinking_sphinx/masks/group_enumerators_mask.rb +23 -0
  57. data/lib/thinking_sphinx/masks/pagination_mask.rb +60 -0
  58. data/lib/thinking_sphinx/masks/scopes_mask.rb +35 -0
  59. data/lib/thinking_sphinx/masks/weight_enumerator_mask.rb +11 -0
  60. data/lib/thinking_sphinx/middlewares.rb +36 -0
  61. data/lib/thinking_sphinx/middlewares/active_record_translator.rb +73 -0
  62. data/lib/thinking_sphinx/middlewares/geographer.rb +53 -0
  63. data/lib/thinking_sphinx/middlewares/glazier.rb +39 -0
  64. data/lib/thinking_sphinx/middlewares/ids_only.rb +13 -0
  65. data/lib/thinking_sphinx/middlewares/inquirer.rb +62 -0
  66. data/lib/thinking_sphinx/middlewares/middleware.rb +9 -0
  67. data/lib/thinking_sphinx/middlewares/sphinxql.rb +149 -0
  68. data/lib/thinking_sphinx/middlewares/stale_id_checker.rb +45 -0
  69. data/lib/thinking_sphinx/middlewares/stale_id_filter.rb +46 -0
  70. data/lib/thinking_sphinx/panes.rb +8 -0
  71. data/lib/thinking_sphinx/panes/attributes_pane.rb +9 -0
  72. data/lib/thinking_sphinx/panes/distance_pane.rb +13 -0
  73. data/lib/thinking_sphinx/panes/excerpts_pane.rb +37 -0
  74. data/lib/thinking_sphinx/panes/weight_pane.rb +9 -0
  75. data/lib/thinking_sphinx/railtie.rb +6 -40
  76. data/lib/thinking_sphinx/rake_interface.rb +47 -0
  77. data/lib/thinking_sphinx/real_time.rb +11 -0
  78. data/lib/thinking_sphinx/real_time/attribute.rb +5 -0
  79. data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +48 -0
  80. data/lib/thinking_sphinx/real_time/field.rb +3 -0
  81. data/lib/thinking_sphinx/real_time/index.rb +47 -0
  82. data/lib/thinking_sphinx/real_time/index/template.rb +33 -0
  83. data/lib/thinking_sphinx/real_time/interpreter.rb +23 -0
  84. data/lib/thinking_sphinx/real_time/property.rb +16 -0
  85. data/lib/thinking_sphinx/scopes.rb +22 -0
  86. data/lib/thinking_sphinx/search.rb +90 -1028
  87. data/lib/thinking_sphinx/search/batch_inquirer.rb +27 -0
  88. data/lib/thinking_sphinx/search/context.rb +26 -0
  89. data/lib/thinking_sphinx/search/glaze.rb +32 -0
  90. data/lib/thinking_sphinx/search/merger.rb +24 -0
  91. data/lib/thinking_sphinx/search/query.rb +43 -0
  92. data/lib/thinking_sphinx/search/stale_ids_exception.rb +11 -0
  93. data/lib/thinking_sphinx/search/translator.rb +50 -0
  94. data/lib/thinking_sphinx/tasks.rb +22 -125
  95. data/lib/thinking_sphinx/test.rb +9 -19
  96. data/sketchpad.rb +58 -0
  97. data/spec/acceptance/association_scoping_spec.rb +23 -0
  98. data/spec/acceptance/attribute_access_spec.rb +39 -0
  99. data/spec/acceptance/attribute_updates_spec.rb +16 -0
  100. data/spec/acceptance/batch_searching_spec.rb +21 -0
  101. data/spec/acceptance/big_integers_spec.rb +27 -0
  102. data/spec/acceptance/excerpts_spec.rb +14 -0
  103. data/spec/acceptance/facets_spec.rb +122 -0
  104. data/spec/acceptance/geosearching_spec.rb +39 -0
  105. data/spec/acceptance/grouping_by_attributes_spec.rb +77 -0
  106. data/spec/acceptance/paginating_search_results_spec.rb +24 -0
  107. data/spec/acceptance/remove_deleted_records_spec.rb +23 -0
  108. data/spec/acceptance/search_counts_spec.rb +18 -0
  109. data/spec/acceptance/search_for_just_ids_spec.rb +19 -0
  110. data/spec/acceptance/searching_across_models_spec.rb +28 -0
  111. data/spec/acceptance/searching_on_fields_spec.rb +56 -0
  112. data/spec/acceptance/searching_with_filters_spec.rb +109 -0
  113. data/spec/acceptance/searching_with_sti_spec.rb +55 -0
  114. data/spec/acceptance/searching_within_a_model_spec.rb +52 -0
  115. data/spec/acceptance/sorting_search_results_spec.rb +41 -0
  116. data/spec/acceptance/spec_helper.rb +4 -0
  117. data/spec/acceptance/specifying_sql_spec.rb +62 -0
  118. data/spec/acceptance/sphinx_scopes_spec.rb +49 -0
  119. data/spec/acceptance/sql_deltas_spec.rb +43 -0
  120. data/spec/acceptance/support/database_cleaner.rb +11 -0
  121. data/spec/acceptance/support/sphinx_controller.rb +39 -0
  122. data/spec/acceptance/support/sphinx_helpers.rb +24 -0
  123. data/spec/acceptance/suspended_deltas_spec.rb +20 -0
  124. data/spec/internal/.gitignore +1 -0
  125. data/spec/internal/app/indices/animal_index.rb +3 -0
  126. data/spec/internal/app/indices/article_index.rb +24 -0
  127. data/spec/internal/app/indices/book_index.rb +8 -0
  128. data/spec/internal/app/indices/city_index.rb +6 -0
  129. data/spec/internal/app/indices/product_index.rb +3 -0
  130. data/spec/internal/app/indices/tee_index.rb +4 -0
  131. data/spec/internal/app/indices/user_index.rb +5 -0
  132. data/spec/internal/app/models/animal.rb +2 -0
  133. data/spec/internal/app/models/article.rb +5 -0
  134. data/spec/internal/app/models/bird.rb +2 -0
  135. data/spec/internal/app/models/book.rb +11 -0
  136. data/spec/internal/app/models/city.rb +2 -0
  137. data/spec/internal/app/models/colour.rb +3 -0
  138. data/spec/internal/app/models/flightless_bird.rb +2 -0
  139. data/spec/internal/app/models/mammal.rb +2 -0
  140. data/spec/internal/app/models/product.rb +3 -0
  141. data/spec/internal/app/models/tag.rb +4 -0
  142. data/{features/thinking_sphinx → spec/internal/app}/models/tagging.rb +1 -1
  143. data/spec/internal/app/models/tee.rb +3 -0
  144. data/spec/internal/app/models/tweet.rb +3 -0
  145. data/spec/internal/app/models/user.rb +3 -0
  146. data/spec/internal/config/database.yml +5 -0
  147. data/spec/internal/db/schema.rb +65 -0
  148. data/spec/internal/log/.gitignore +1 -0
  149. data/spec/spec_helper.rb +8 -49
  150. data/spec/support/sphinx_yaml_helpers.rb +9 -0
  151. data/spec/thinking_sphinx/active_record/association_spec.rb +12 -0
  152. data/spec/thinking_sphinx/active_record/associations_spec.rb +184 -0
  153. data/spec/thinking_sphinx/active_record/attribute/type_spec.rb +147 -0
  154. data/spec/thinking_sphinx/active_record/base_spec.rb +61 -0
  155. data/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +80 -0
  156. data/spec/thinking_sphinx/active_record/callbacks/delta_callbacks_spec.rb +147 -0
  157. data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +69 -0
  158. data/spec/thinking_sphinx/active_record/column_spec.rb +47 -0
  159. data/spec/thinking_sphinx/active_record/database_adapters/abstract_adapter_spec.rb +31 -0
  160. data/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +43 -0
  161. data/spec/thinking_sphinx/active_record/database_adapters/postgresql_adapter_spec.rb +45 -0
  162. data/spec/thinking_sphinx/active_record/database_adapters_spec.rb +108 -0
  163. data/spec/thinking_sphinx/active_record/field_spec.rb +36 -0
  164. data/spec/thinking_sphinx/active_record/index_spec.rb +208 -0
  165. data/spec/thinking_sphinx/active_record/interpreter_spec.rb +293 -0
  166. data/spec/thinking_sphinx/active_record/property_sql_presenter_spec.rb +162 -0
  167. data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +666 -0
  168. data/spec/thinking_sphinx/active_record/sql_source_spec.rb +401 -0
  169. data/spec/thinking_sphinx/configuration_spec.rb +264 -171
  170. data/spec/thinking_sphinx/deltas/default_delta_spec.rb +116 -0
  171. data/spec/thinking_sphinx/deltas_spec.rb +58 -0
  172. data/spec/thinking_sphinx/excerpter_spec.rb +40 -38
  173. data/spec/thinking_sphinx/facet_search_spec.rb +49 -151
  174. data/spec/thinking_sphinx/index_set_spec.rb +68 -0
  175. data/spec/thinking_sphinx/index_spec.rb +91 -155
  176. data/spec/thinking_sphinx/masks/pagination_mask_spec.rb +121 -0
  177. data/spec/thinking_sphinx/masks/scopes_mask_spec.rb +68 -0
  178. data/spec/thinking_sphinx/middlewares/active_record_translator_spec.rb +132 -0
  179. data/spec/thinking_sphinx/middlewares/geographer_spec.rb +89 -0
  180. data/spec/thinking_sphinx/middlewares/glazier_spec.rb +62 -0
  181. data/spec/thinking_sphinx/middlewares/inquirer_spec.rb +55 -0
  182. data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +271 -0
  183. data/spec/thinking_sphinx/middlewares/stale_id_checker_spec.rb +47 -0
  184. data/spec/thinking_sphinx/middlewares/stale_id_filter_spec.rb +91 -0
  185. data/spec/thinking_sphinx/panes/attributes_pane_spec.rb +21 -0
  186. data/spec/thinking_sphinx/panes/distance_pane_spec.rb +41 -0
  187. data/spec/thinking_sphinx/panes/excerpts_pane_spec.rb +53 -0
  188. data/spec/thinking_sphinx/panes/weight_pane_spec.rb +20 -0
  189. data/spec/thinking_sphinx/rake_interface_spec.rb +147 -0
  190. data/spec/thinking_sphinx/real_time/attribute_spec.rb +62 -0
  191. data/spec/thinking_sphinx/real_time/callbacks/real_time_callbacks_spec.rb +76 -0
  192. data/spec/thinking_sphinx/real_time/field_spec.rb +54 -0
  193. data/spec/thinking_sphinx/real_time/index_spec.rb +154 -0
  194. data/spec/thinking_sphinx/real_time/interpreter_spec.rb +147 -0
  195. data/spec/thinking_sphinx/scopes_spec.rb +38 -0
  196. data/spec/thinking_sphinx/search/glaze_spec.rb +55 -0
  197. data/spec/thinking_sphinx/search/query_spec.rb +46 -0
  198. data/spec/thinking_sphinx/search_spec.rb +65 -1357
  199. data/spec/thinking_sphinx_spec.rb +19 -182
  200. data/thinking-sphinx.gemspec +33 -0
  201. metadata +318 -431
  202. data/features/abstract_inheritance.feature +0 -10
  203. data/features/alternate_primary_key.feature +0 -27
  204. data/features/attribute_transformation.feature +0 -22
  205. data/features/attribute_updates.feature +0 -79
  206. data/features/deleting_instances.feature +0 -70
  207. data/features/direct_attributes.feature +0 -11
  208. data/features/excerpts.feature +0 -21
  209. data/features/extensible_delta_indexing.feature +0 -9
  210. data/features/facets.feature +0 -88
  211. data/features/facets_across_model.feature +0 -29
  212. data/features/field_sorting.feature +0 -18
  213. data/features/handling_edits.feature +0 -97
  214. data/features/retry_stale_indexes.feature +0 -24
  215. data/features/searching_across_models.feature +0 -20
  216. data/features/searching_by_index.feature +0 -41
  217. data/features/searching_by_model.feature +0 -175
  218. data/features/searching_with_find_arguments.feature +0 -56
  219. data/features/sphinx_detection.feature +0 -25
  220. data/features/sphinx_scopes.feature +0 -68
  221. data/features/step_definitions/alpha_steps.rb +0 -16
  222. data/features/step_definitions/beta_steps.rb +0 -7
  223. data/features/step_definitions/common_steps.rb +0 -205
  224. data/features/step_definitions/extensible_delta_indexing_steps.rb +0 -7
  225. data/features/step_definitions/facet_steps.rb +0 -96
  226. data/features/step_definitions/find_arguments_steps.rb +0 -36
  227. data/features/step_definitions/gamma_steps.rb +0 -15
  228. data/features/step_definitions/scope_steps.rb +0 -19
  229. data/features/step_definitions/search_steps.rb +0 -94
  230. data/features/step_definitions/sphinx_steps.rb +0 -35
  231. data/features/sti_searching.feature +0 -19
  232. data/features/support/env.rb +0 -24
  233. data/features/support/lib/generic_delta_handler.rb +0 -8
  234. data/features/thinking_sphinx/database.example.yml +0 -3
  235. data/features/thinking_sphinx/db/.gitignore +0 -1
  236. data/features/thinking_sphinx/db/fixtures/alphas.rb +0 -8
  237. data/features/thinking_sphinx/db/fixtures/authors.rb +0 -1
  238. data/features/thinking_sphinx/db/fixtures/betas.rb +0 -11
  239. data/features/thinking_sphinx/db/fixtures/boxes.rb +0 -9
  240. data/features/thinking_sphinx/db/fixtures/categories.rb +0 -1
  241. data/features/thinking_sphinx/db/fixtures/cats.rb +0 -3
  242. data/features/thinking_sphinx/db/fixtures/comments.rb +0 -24
  243. data/features/thinking_sphinx/db/fixtures/developers.rb +0 -31
  244. data/features/thinking_sphinx/db/fixtures/dogs.rb +0 -3
  245. data/features/thinking_sphinx/db/fixtures/extensible_betas.rb +0 -10
  246. data/features/thinking_sphinx/db/fixtures/foxes.rb +0 -3
  247. data/features/thinking_sphinx/db/fixtures/gammas.rb +0 -10
  248. data/features/thinking_sphinx/db/fixtures/music.rb +0 -4
  249. data/features/thinking_sphinx/db/fixtures/people.rb +0 -1001
  250. data/features/thinking_sphinx/db/fixtures/post_keywords.txt +0 -1
  251. data/features/thinking_sphinx/db/fixtures/posts.rb +0 -10
  252. data/features/thinking_sphinx/db/fixtures/robots.rb +0 -8
  253. data/features/thinking_sphinx/db/fixtures/tags.rb +0 -27
  254. data/features/thinking_sphinx/db/migrations/create_alphas.rb +0 -8
  255. data/features/thinking_sphinx/db/migrations/create_animals.rb +0 -5
  256. data/features/thinking_sphinx/db/migrations/create_authors.rb +0 -3
  257. data/features/thinking_sphinx/db/migrations/create_authors_posts.rb +0 -6
  258. data/features/thinking_sphinx/db/migrations/create_betas.rb +0 -5
  259. data/features/thinking_sphinx/db/migrations/create_boxes.rb +0 -5
  260. data/features/thinking_sphinx/db/migrations/create_categories.rb +0 -3
  261. data/features/thinking_sphinx/db/migrations/create_comments.rb +0 -10
  262. data/features/thinking_sphinx/db/migrations/create_developers.rb +0 -7
  263. data/features/thinking_sphinx/db/migrations/create_extensible_betas.rb +0 -5
  264. data/features/thinking_sphinx/db/migrations/create_gammas.rb +0 -3
  265. data/features/thinking_sphinx/db/migrations/create_genres.rb +0 -3
  266. data/features/thinking_sphinx/db/migrations/create_music.rb +0 -6
  267. data/features/thinking_sphinx/db/migrations/create_people.rb +0 -13
  268. data/features/thinking_sphinx/db/migrations/create_posts.rb +0 -6
  269. data/features/thinking_sphinx/db/migrations/create_robots.rb +0 -4
  270. data/features/thinking_sphinx/db/migrations/create_taggings.rb +0 -5
  271. data/features/thinking_sphinx/db/migrations/create_tags.rb +0 -4
  272. data/features/thinking_sphinx/models/alpha.rb +0 -23
  273. data/features/thinking_sphinx/models/andrew.rb +0 -17
  274. data/features/thinking_sphinx/models/animal.rb +0 -5
  275. data/features/thinking_sphinx/models/author.rb +0 -3
  276. data/features/thinking_sphinx/models/beta.rb +0 -13
  277. data/features/thinking_sphinx/models/box.rb +0 -8
  278. data/features/thinking_sphinx/models/cat.rb +0 -3
  279. data/features/thinking_sphinx/models/category.rb +0 -4
  280. data/features/thinking_sphinx/models/comment.rb +0 -10
  281. data/features/thinking_sphinx/models/developer.rb +0 -21
  282. data/features/thinking_sphinx/models/dog.rb +0 -3
  283. data/features/thinking_sphinx/models/extensible_beta.rb +0 -9
  284. data/features/thinking_sphinx/models/fox.rb +0 -5
  285. data/features/thinking_sphinx/models/gamma.rb +0 -5
  286. data/features/thinking_sphinx/models/genre.rb +0 -3
  287. data/features/thinking_sphinx/models/medium.rb +0 -5
  288. data/features/thinking_sphinx/models/music.rb +0 -10
  289. data/features/thinking_sphinx/models/person.rb +0 -24
  290. data/features/thinking_sphinx/models/post.rb +0 -22
  291. data/features/thinking_sphinx/models/robot.rb +0 -12
  292. data/features/thinking_sphinx/models/tag.rb +0 -3
  293. data/lib/cucumber/thinking_sphinx/external_world.rb +0 -12
  294. data/lib/cucumber/thinking_sphinx/internal_world.rb +0 -137
  295. data/lib/cucumber/thinking_sphinx/sql_logger.rb +0 -28
  296. data/lib/thinking_sphinx/action_controller.rb +0 -31
  297. data/lib/thinking_sphinx/active_record/attribute_updates.rb +0 -54
  298. data/lib/thinking_sphinx/active_record/collection_proxy.rb +0 -47
  299. data/lib/thinking_sphinx/active_record/collection_proxy_with_scopes.rb +0 -27
  300. data/lib/thinking_sphinx/active_record/delta.rb +0 -67
  301. data/lib/thinking_sphinx/active_record/has_many_association.rb +0 -44
  302. data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +0 -21
  303. data/lib/thinking_sphinx/active_record/scopes.rb +0 -110
  304. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +0 -94
  305. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +0 -62
  306. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +0 -188
  307. data/lib/thinking_sphinx/association.rb +0 -230
  308. data/lib/thinking_sphinx/attribute.rb +0 -405
  309. data/lib/thinking_sphinx/auto_version.rb +0 -40
  310. data/lib/thinking_sphinx/bundled_search.rb +0 -40
  311. data/lib/thinking_sphinx/class_facet.rb +0 -20
  312. data/lib/thinking_sphinx/connection.rb +0 -71
  313. data/lib/thinking_sphinx/context.rb +0 -81
  314. data/lib/thinking_sphinx/core/string.rb +0 -15
  315. data/lib/thinking_sphinx/deltas/delete_job.rb +0 -16
  316. data/lib/thinking_sphinx/deltas/index_job.rb +0 -17
  317. data/lib/thinking_sphinx/deploy/capistrano.rb +0 -99
  318. data/lib/thinking_sphinx/field.rb +0 -98
  319. data/lib/thinking_sphinx/index/builder.rb +0 -315
  320. data/lib/thinking_sphinx/index/faux_column.rb +0 -118
  321. data/lib/thinking_sphinx/join.rb +0 -37
  322. data/lib/thinking_sphinx/property.rb +0 -187
  323. data/lib/thinking_sphinx/search_methods.rb +0 -439
  324. data/lib/thinking_sphinx/sinatra.rb +0 -7
  325. data/lib/thinking_sphinx/source.rb +0 -194
  326. data/lib/thinking_sphinx/source/internal_properties.rb +0 -51
  327. data/lib/thinking_sphinx/source/sql.rb +0 -174
  328. data/spec/fixtures/data.sql +0 -32
  329. data/spec/fixtures/database.yml.default +0 -3
  330. data/spec/fixtures/models.rb +0 -164
  331. data/spec/fixtures/structure.sql +0 -146
  332. data/spec/sphinx_helper.rb +0 -60
  333. data/spec/support/rails.rb +0 -25
  334. data/spec/thinking_sphinx/active_record/delta_spec.rb +0 -123
  335. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +0 -173
  336. data/spec/thinking_sphinx/active_record/scopes_spec.rb +0 -177
  337. data/spec/thinking_sphinx/active_record_spec.rb +0 -573
  338. data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +0 -163
  339. data/spec/thinking_sphinx/association_spec.rb +0 -250
  340. data/spec/thinking_sphinx/attribute_spec.rb +0 -552
  341. data/spec/thinking_sphinx/auto_version_spec.rb +0 -103
  342. data/spec/thinking_sphinx/connection_spec.rb +0 -77
  343. data/spec/thinking_sphinx/context_spec.rb +0 -127
  344. data/spec/thinking_sphinx/core/array_spec.rb +0 -9
  345. data/spec/thinking_sphinx/core/string_spec.rb +0 -9
  346. data/spec/thinking_sphinx/facet_spec.rb +0 -359
  347. data/spec/thinking_sphinx/field_spec.rb +0 -127
  348. data/spec/thinking_sphinx/index/builder_spec.rb +0 -532
  349. data/spec/thinking_sphinx/index/faux_column_spec.rb +0 -36
  350. data/spec/thinking_sphinx/search_methods_spec.rb +0 -156
  351. data/spec/thinking_sphinx/source_spec.rb +0 -267
  352. data/spec/thinking_sphinx/test_spec.rb +0 -20
@@ -0,0 +1,55 @@
1
+ module ThinkingSphinx
2
+ class Search; end
3
+ end
4
+
5
+ require 'thinking_sphinx/search/glaze'
6
+
7
+ describe ThinkingSphinx::Search::Glaze do
8
+ let(:glaze) { ThinkingSphinx::Search::Glaze.new context, object, raw, [] }
9
+ let(:object) { double('object') }
10
+ let(:raw) { {} }
11
+ let(:context) { {} }
12
+
13
+ describe '#!=' do
14
+ it "is true for objects that don't match" do
15
+ (glaze != double('foo')).should be_true
16
+ end
17
+
18
+ it "is false when the underlying object is a match" do
19
+ (glaze != object).should be_false
20
+ end
21
+ end
22
+
23
+ describe '#method_missing' do
24
+ let(:glaze) {
25
+ ThinkingSphinx::Search::Glaze.new context, object, raw, [klass, klass] }
26
+ let(:klass) { double('pane class') }
27
+ let(:pane_one) { double('pane one', :foo => 'one') }
28
+ let(:pane_two) { double('pane two', :foo => 'two', :bar => 'two') }
29
+
30
+ before :each do
31
+ klass.stub(:new).and_return(pane_one, pane_two)
32
+ end
33
+
34
+ it "respects objects existing methods" do
35
+ object.stub :foo => 'original'
36
+
37
+ glaze.foo.should == 'original'
38
+ end
39
+
40
+ it "uses the first pane that responds to the method" do
41
+ glaze.foo.should == 'one'
42
+ glaze.bar.should == 'two'
43
+ end
44
+
45
+ it "raises the method missing error otherwise" do
46
+ lambda { glaze.baz }.should raise_error(NoMethodError)
47
+ end
48
+ end
49
+
50
+ describe '#unglazed' do
51
+ it "returns the original object" do
52
+ glaze.unglazed.should == object
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,46 @@
1
+ module ThinkingSphinx
2
+ class Search; end
3
+ end
4
+
5
+ require './lib/thinking_sphinx/search/query'
6
+
7
+ describe ThinkingSphinx::Search::Query do
8
+ describe '#to_s' do
9
+ it "passes through the keyword as provided" do
10
+ query = ThinkingSphinx::Search::Query.new 'pancakes'
11
+
12
+ query.to_s.should == 'pancakes'
13
+ end
14
+
15
+ it "pairs fields and keywords for given conditions" do
16
+ query = ThinkingSphinx::Search::Query.new '', :title => 'pancakes'
17
+
18
+ query.to_s.should == '@title pancakes'
19
+ end
20
+
21
+ it "combines both keywords and conditions" do
22
+ query = ThinkingSphinx::Search::Query.new 'tasty', :title => 'pancakes'
23
+
24
+ query.to_s.should == 'tasty @title pancakes'
25
+ end
26
+
27
+ it "automatically stars keywords if requested" do
28
+ query = ThinkingSphinx::Search::Query.new 'cake', {}, true
29
+
30
+ query.to_s.should == '*cake*'
31
+ end
32
+
33
+ it "automatically stars condition keywords if requested" do
34
+ query = ThinkingSphinx::Search::Query.new '', {:title => 'pan'}, true
35
+
36
+ query.to_s.should == '@title *pan*'
37
+ end
38
+
39
+ it "does not star the sphinx_internal_class field keyword" do
40
+ query = ThinkingSphinx::Search::Query.new '',
41
+ {:sphinx_internal_class => 'article'}, true
42
+
43
+ query.to_s.should == '@sphinx_internal_class article'
44
+ end
45
+ end
46
+ end
@@ -1,1063 +1,19 @@
1
1
  require 'spec_helper'
2
- require 'will_paginate/collection'
3
2
 
4
3
  describe ThinkingSphinx::Search do
5
- before :each do
6
- @config = ThinkingSphinx::Configuration.instance
7
- @client = Riddle::Client.new
8
-
9
- ThinkingSphinx::Connection.stub(:take).and_yield(@client)
10
-
11
- @client.stub!(:query => {:matches => [], :total_found => 41, :total => 41})
12
- end
13
-
14
- it "not request results from the client if not accessing items" do
15
- ThinkingSphinx::Connection.should_not_receive(:take)
16
-
17
- ThinkingSphinx::Search.new.class
18
- end
19
-
20
- it "should request results if access is required" do
21
- ThinkingSphinx::Connection.should_receive(:take).and_yield(@client)
22
-
23
- ThinkingSphinx::Search.new.first
24
- end
25
-
26
- describe '#respond_to?' do
27
- it "should respond to Array methods" do
28
- ThinkingSphinx::Search.new.respond_to?(:each).should be_true
29
- end
30
-
31
- it "should respond to Search methods" do
32
- ThinkingSphinx::Search.new.respond_to?(:per_page).should be_true
33
- end
34
- end
35
-
36
- describe '#==' do
37
- it "populates the search results when checking equality" do
38
- search = ThinkingSphinx::Search.new
39
- search == []
40
-
41
- search.should be_populated
42
- end
43
- end
44
-
45
- describe '#populated?' do
46
- before :each do
47
- @search = ThinkingSphinx::Search.new
48
- end
49
-
50
- it "should be false if the client request has not been made" do
51
- @search.populated?.should be_false
52
- end
53
-
54
- it "should be true once the client request has been made" do
55
- @search.first
56
- @search.should be_populated
57
- end
58
-
59
- it "should be populated if :populate is set to true" do
60
- search = ThinkingSphinx::Search.new(:populate => true)
61
- search.should be_populated
62
- end
63
- end
64
-
65
- describe '#error?' do
66
- before :each do
67
- @search = ThinkingSphinx::Search.new
68
- end
69
-
70
- it "should be false if client requests have not resulted in an error" do
71
- @search.should_receive(:error).and_return(nil)
72
- @search.error?.should_not be_true
73
- end
74
-
75
- it "should be true when client requests result in an error" do
76
- @search.should_receive(:error).and_return("error message")
77
- @search.error?.should be_true
78
- end
79
- end
80
-
81
- describe '#warning?' do
82
- before :each do
83
- @search = ThinkingSphinx::Search.new
84
- end
85
-
86
- it "should be false if client requests have not resulted in a warning" do
87
- @search.should_receive(:warning).and_return(nil)
88
- @search.warning?.should_not be_true
89
- end
90
-
91
- it "should be true when client requests result in an error" do
92
- @search.should_receive(:warning).and_return("warning message")
93
- @search.warning?.should be_true
94
- end
95
- end
96
-
97
- describe '#results' do
98
- it "should populate search results before returning" do
99
- @search = ThinkingSphinx::Search.new
100
- @search.populated?.should be_false
101
-
102
- @search.results
103
- @search.populated?.should be_true
104
- end
105
- end
106
-
107
- describe '#method_missing' do
108
- before :each do
109
- Alpha.sphinx_scope(:by_name) { |name|
110
- {:conditions => {:name => name}}
111
- }
112
- Alpha.sphinx_scope(:ids_only) { {:ids_only => true} }
113
- end
114
-
115
- after :each do
116
- Alpha.remove_sphinx_scopes
117
- end
118
-
119
- it "should handle Array methods" do
120
- ThinkingSphinx::Search.new.private_methods.should be_an(Array)
121
- end
122
-
123
- it "should raise a NoMethodError exception if unknown method" do
124
- lambda {
125
- ThinkingSphinx::Search.new.foo
126
- }.should raise_error(NoMethodError)
127
- end
128
-
129
- it "should not request results from client if method does not exist" do
130
- @client.should_not_receive(:query)
131
-
132
- lambda {
133
- ThinkingSphinx::Search.new.foo
134
- }.should raise_error(NoMethodError)
135
- end
136
-
137
- it "should accept sphinx scopes" do
138
- search = ThinkingSphinx::Search.new(:classes => [Alpha])
139
-
140
- lambda {
141
- search.by_name('Pat')
142
- }.should_not raise_error(NoMethodError)
143
- end
144
-
145
- it "should return itself when using a sphinx scope" do
146
- search = ThinkingSphinx::Search.new(:classes => [Alpha])
147
- search.by_name('Pat').object_id.should == search.object_id
148
- end
149
-
150
- it "should keep the same search object when chaining multiple scopes" do
151
- search = ThinkingSphinx::Search.new(:classes => [Alpha])
152
- search.by_name('Pat').ids_only.object_id.should == search.object_id
153
- end
154
- end
155
-
156
- describe '.search' do
157
- it "return the output of ThinkingSphinx.search" do
158
- @results = [] # to confirm same object
159
- ThinkingSphinx.stub!(:search => @results)
160
-
161
- ThinkingSphinx.search.object_id.should == @results.object_id
162
- end
163
- end
164
-
165
- describe '.search_for_ids' do
166
- it "return the output of ThinkingSphinx.search_for_ids" do
167
- @results = [] # to confirm same object
168
- ThinkingSphinx.stub!(:search_for_ids => @results)
169
-
170
- ThinkingSphinx.search_for_ids.object_id.
171
- should == @results.object_id
172
- end
173
- end
174
-
175
- describe '.search_for_id' do
176
- it "return the output of ThinkingSphinx.search_for_ids" do
177
- @results = [] # to confirm same object
178
- ThinkingSphinx.stub!(:search_for_id => @results)
179
-
180
- ThinkingSphinx.search_for_id.object_id.
181
- should == @results.object_id
182
- end
183
- end
184
-
185
- describe '.count' do
186
- it "return the output of ThinkingSphinx.search" do
187
- @results = [] # to confirm same object
188
- ThinkingSphinx.stub!(:count => @results)
189
-
190
- ThinkingSphinx.count.object_id.should == @results.object_id
191
- end
192
- end
193
-
194
- describe '.facets' do
195
- it "return the output of ThinkingSphinx.facets" do
196
- @results = [] # to confirm same object
197
- ThinkingSphinx.stub!(:facets => @results)
198
-
199
- ThinkingSphinx.facets.object_id.should == @results.object_id
200
- end
201
- end
202
-
203
- describe '.matching_fields' do
204
- it "should return objects with indexes matching 1's in the bitmask" do
205
- fields = ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta']
206
- ThinkingSphinx::Search.matching_fields(fields, 85).
207
- should == ['alpha', 'gamma', 'epsilon', 'eta']
208
-
209
- ThinkingSphinx::Search.matching_fields(fields, 42).
210
- should == ['beta', 'delta', 'zeta']
211
- end
212
- end
213
-
214
- describe '#populate' do
215
- before :each do
216
- @alpha_a, @alpha_b = Alpha.new, Alpha.new
217
- @beta_a, @beta_b = Beta.new, Beta.new
218
-
219
- @alpha_a.stub! :id => 1, :read_attribute => 1
220
- @alpha_b.stub! :id => 2, :read_attribute => 2
221
- @beta_a.stub! :id => 1, :read_attribute => 1
222
- @beta_b.stub! :id => 2, :read_attribute => 2
223
-
224
- @client.stub! :query => {
225
- :matches => minimal_result_hashes(@alpha_a, @beta_b, @alpha_b, @beta_a),
226
- :fields => ["one", "two", "three", "four", "five"]
227
- }
228
- Alpha.stub! :find => [@alpha_a, @alpha_b], :unscoped => Alpha
229
- Beta.stub! :find => [@beta_a, @beta_b], :unscoped => Beta
230
- end
231
-
232
- it "should issue only one select per model" do
233
- Alpha.should_receive(:find).once.and_return([@alpha_a, @alpha_b])
234
- Beta.should_receive(:find).once.and_return([@beta_a, @beta_b])
235
-
236
- ThinkingSphinx::Search.new.first
237
- end
238
-
239
- it "should mix the results from different models" do
240
- search = ThinkingSphinx::Search.new
241
- search[0].should be_a(Alpha)
242
- search[1].should be_a(Beta)
243
- search[2].should be_a(Alpha)
244
- search[3].should be_a(Beta)
245
- end
246
-
247
- it "should maintain the Xoopit ordering for results" do
248
- search = ThinkingSphinx::Search.new
249
- search[0].id.should == 1
250
- search[1].id.should == 2
251
- search[2].id.should == 2
252
- search[3].id.should == 1
253
- end
254
-
255
- it "should use the requested classes to generate the index argument" do
256
- @client.should_receive(:query) do |query, index, comment|
257
- index.should == 'alpha_core,beta_core,beta_delta'
258
- end
259
-
260
- ThinkingSphinx::Search.new(:classes => [Alpha, Beta]).first
261
- end
262
-
263
- it "should restrict includes to the relevant classes" do
264
- Alpha.should_receive(:find) do |type, options|
265
- options[:include].should == [:betas]
266
- [@alpha_a, @alpha_b]
267
- end
268
-
269
- Beta.should_receive(:find) do |type, options|
270
- options[:include].should == [:gammas]
271
- [@beta_a, @beta_b]
272
- end
273
-
274
- ThinkingSphinx::Search.new(:include => [:betas, :gammas]).first
275
- end
276
-
277
- it "should restrict single includes to the relevant classes" do
278
- Alpha.should_receive(:find) do |type, options|
279
- options[:include].should == :betas
280
- [@alpha_a, @alpha_b]
281
- end
282
-
283
- Beta.should_receive(:find) do |type, options|
284
- options[:include].should be_nil
285
- [@beta_a, @beta_b]
286
- end
287
-
288
- ThinkingSphinx::Search.new(:include => :betas).first
289
- end
290
-
291
- it "should respect complex includes" do
292
- Alpha.should_receive(:find) do |type, options|
293
- options[:include].should == [:thetas, {:betas => :gammas}]
294
- [@alpha_a, @alpha_b]
295
- end
296
-
297
- Beta.should_receive(:find) do |type, options|
298
- options[:include].should be_nil
299
- [@beta_a, @beta_b]
300
- end
301
-
302
- ThinkingSphinx::Search.new(:include => [:thetas, {:betas => :gammas}]).first
303
- end
304
-
305
- it "should respect hash includes" do
306
- Alpha.should_receive(:find) do |type, options|
307
- options[:include].should == {:betas => :gammas}
308
- [@alpha_a, @alpha_b]
309
- end
310
-
311
- Beta.should_receive(:find) do |type, options|
312
- options[:include].should be_nil
313
- [@beta_a, @beta_b]
314
- end
315
-
316
- ThinkingSphinx::Search.new(:include => {:betas => :gammas}).first
317
- end
318
-
319
- it "should respect includes for single class searches" do
320
- Alpha.should_receive(:find) do |type, options|
321
- options[:include].should == {:betas => :gammas}
322
- [@alpha_a, @alpha_b]
323
- end
324
-
325
- ThinkingSphinx::Search.new(
326
- :include => {:betas => :gammas},
327
- :classes => [Alpha]
328
- ).first
329
- end
330
-
331
- describe 'query' do
332
- it "should concatenate arguments with spaces" do
333
- @client.should_receive(:query) do |query, index, comment|
334
- query.should == 'two words'
335
- end
336
-
337
- ThinkingSphinx::Search.new('two', 'words').first
338
- end
339
-
340
- it "should append conditions to the query" do
341
- @client.should_receive(:query) do |query, index, comment|
342
- query.should == 'general @focused specific'
343
- end
344
-
345
- ThinkingSphinx::Search.new('general', :conditions => {
346
- :focused => 'specific'
347
- }).first
348
- end
349
-
350
- it "append multiple conditions together" do
351
- @client.should_receive(:query) do |query, index, comment|
352
- query.should match(/general.+@foo word/)
353
- query.should match(/general.+@bar word/)
354
- end
355
-
356
- ThinkingSphinx::Search.new('general', :conditions => {
357
- :foo => 'word', :bar => 'word'
358
- }).first
359
- end
360
-
361
- it "should apply stars if requested, and handle full extended syntax" do
362
- input = %{a b* c (d | e) 123 5&6 (f_f g) !h "i j" "k l"~10 "m n"/3 @o p -(q|r)}
363
- expected = %{*a* b* *c* (*d* | *e*) *123* *5*&*6* (*f_f* *g*) !*h* "i j" "k l"~10 "m n"/3 @o *p* -(*q*|*r*)}
364
-
365
- @client.should_receive(:query) do |query, index, comment|
366
- query.should == expected
367
- end
368
-
369
- ThinkingSphinx::Search.new(input, :star => true).first
370
- end
371
-
372
- it "should default to /\w+/ as token for auto-starring" do
373
- @client.should_receive(:query) do |query, index, comment|
374
- query.should == '*foo*@*bar*.*com*'
375
- end
376
-
377
- ThinkingSphinx::Search.new('foo@bar.com', :star => true).first
378
- end
379
-
380
- it "should honour custom star tokens" do
381
- @client.should_receive(:query) do |query, index, comment|
382
- query.should == '*foo@bar.com* -*foo-bar*'
383
- end
384
-
385
- ThinkingSphinx::Search.new(
386
- 'foo@bar.com -foo-bar', :star => /[\w@.-]+/u
387
- ).first
388
- end
389
-
390
- it "should ignore multi-field limitations" do
391
- @client.should_receive(:query) do |query, index, comment|
392
- query.should == '@(foo,bar) *baz*'
393
- end
394
-
395
- ThinkingSphinx::Search.new('@(foo,bar) baz', :star => true).first
396
- end
397
-
398
- it "should ignore multi-field limitations with spaces" do
399
- @client.should_receive(:query) do |query, index, comment|
400
- query.should == '@(foo bar) *baz*'
401
- end
402
-
403
- ThinkingSphinx::Search.new('@(foo bar) baz', :star => true).first
404
- end
405
-
406
- it "should ignore multi-field limitations in the middle of queries" do
407
- @client.should_receive(:query) do |query, index, comment|
408
- query.should == '*baz* @foo *bar* @(foo,bar) *baz*'
409
- end
410
-
411
- ThinkingSphinx::Search.new(
412
- 'baz @foo bar @(foo,bar) baz', :star => true
413
- ).first
414
- end
415
-
416
- it "should try retry query up to the hard_retry_count option times if it catches an exception" do
417
- @client.should_receive(:query).exactly(4).and_raise("Test Exception")
418
-
419
- expect { ThinkingSphinx::Search.new(:hard_retry_count => 3).first }.
420
- to raise_error("Test Exception")
421
- end
422
-
423
- it "should not retry query if hard_retry_count option is not set" do
424
- @client.should_receive(:query).exactly(1).and_raise("Test Exception")
425
-
426
- expect { ThinkingSphinx::Search.new.first }.
427
- to raise_error("Test Exception")
428
- end
429
-
430
- it "should allow the hard_retry_count to be globally set as a configuration option" do
431
- @config.hard_retry_count = 2
432
-
433
- @client.should_receive(:query).exactly(3).and_raise("Test Exception")
434
-
435
- expect { ThinkingSphinx::Search.new.first }.
436
- to raise_error("Test Exception")
437
- end
438
-
439
- it "should give priority to the hard_retry_count search option over the globally configured option" do
440
- @config.hard_retry_count = 4
441
-
442
- @client.should_receive(:query).exactly(2).and_raise("Test Exception")
443
-
444
- expect { ThinkingSphinx::Search.new(:hard_retry_count => 1).first }.
445
- to raise_error("Test Exception")
446
- end
447
- end
448
-
449
- describe 'comment' do
450
- it "should add comment if explicitly provided" do
451
- @client.should_receive(:query) do |query, index, comment|
452
- comment.should == 'custom log'
453
- end
454
-
455
- ThinkingSphinx::Search.new(:comment => 'custom log').first
456
- end
457
-
458
- it "should default to a blank comment" do
459
- @client.should_receive(:query) do |query, index, comment|
460
- comment.should == ''
461
- end
462
-
463
- ThinkingSphinx::Search.new.first
464
- end
465
- end
466
-
467
- describe 'match mode' do
468
- it "should default to :all" do
469
- ThinkingSphinx::Search.new.first
470
-
471
- @client.match_mode.should == :all
472
- end
473
-
474
- it "should default to :extended if conditions are supplied" do
475
- ThinkingSphinx::Search.new('general', :conditions => {
476
- :foo => 'word', :bar => 'word'
477
- }).first
478
-
479
- @client.match_mode.should == :extended
480
- end
481
-
482
- it "should use explicit match modes" do
483
- ThinkingSphinx::Search.new('general', :conditions => {
484
- :foo => 'word', :bar => 'word'
485
- }, :match_mode => :extended2).first
486
-
487
- @client.match_mode.should == :extended2
488
- end
489
- end
490
-
491
- describe 'sphinx_select' do
492
- it "should default to *" do
493
- ThinkingSphinx::Search.new.first
494
-
495
- @client.select.should == "*"
496
- end
497
-
498
- it "should get set on the client if specified" do
499
- ThinkingSphinx::Search.new('general',
500
- :sphinx_select => "*, foo as bar"
501
- ).first
502
-
503
- @client.select.should == "*, foo as bar"
504
- end
505
-
506
- end
507
-
508
- describe 'pagination' do
509
- it "should set the limit using per_page" do
510
- ThinkingSphinx::Search.new(:per_page => 30).first
511
- @client.limit.should == 30
512
- end
513
-
514
- it "should set the offset if pagination is requested" do
515
- ThinkingSphinx::Search.new(:page => 3).first
516
- @client.offset.should == 40
517
- end
518
-
519
- it "should set the offset by the per_page value" do
520
- ThinkingSphinx::Search.new(:page => 3, :per_page => 30).first
521
- @client.offset.should == 60
522
- end
523
- end
524
-
525
- describe 'filters' do
526
- it "should filter out deleted values by default" do
527
- ThinkingSphinx::Search.new.first
528
-
529
- filter = @client.filters.last
530
- filter.values.should == [0]
531
- filter.attribute.should == 'sphinx_deleted'
532
- filter.exclude?.should be_false
533
- end
534
-
535
- it "should add class filters for explicit classes" do
536
- ThinkingSphinx::Search.new(:classes => [Alpha, Beta]).first
537
-
538
- filter = @client.filters.last
539
- filter.values.should == [Alpha.to_crc32, Beta.to_crc32]
540
- filter.attribute.should == 'class_crc'
541
- filter.exclude?.should be_false
542
- end
543
-
544
- it "should add class filters for subclasses of requested classes" do
545
- ThinkingSphinx::Search.new(:classes => [Person]).first
546
-
547
- filter = @client.filters.last
548
- filter.values.should == [
549
- Parent.to_crc32, Admin::Person.to_crc32,
550
- Child.to_crc32, Teenager.to_crc32, Person.to_crc32
551
- ]
552
- filter.attribute.should == 'class_crc'
553
- filter.exclude?.should be_false
554
- end
555
-
556
- it "should append inclusive filters of integers" do
557
- ThinkingSphinx::Search.new(:with => {:int => 1}).first
558
-
559
- filter = @client.filters.last
560
- filter.values.should == [1]
561
- filter.attribute.should == 'int'
562
- filter.exclude?.should be_false
563
- end
4
+ let(:search) { ThinkingSphinx::Search.new }
5
+ let(:context) { {:results => []} }
6
+ let(:stack) { double('stack', :call => true) }
564
7
 
565
- it "should append inclusive filters of floats" do
566
- ThinkingSphinx::Search.new(:with => {:float => 1.5}).first
567
-
568
- filter = @client.filters.last
569
- filter.values.should == [1.5]
570
- filter.attribute.should == 'float'
571
- filter.exclude?.should be_false
572
- end
573
-
574
- it "should append inclusive filters of booleans" do
575
- ThinkingSphinx::Search.new(:with => {:boolean => true}).first
576
-
577
- filter = @client.filters.last
578
- filter.values.should == [true]
579
- filter.attribute.should == 'boolean'
580
- filter.exclude?.should be_false
581
- end
582
-
583
- it "should append inclusive filters of arrays" do
584
- ThinkingSphinx::Search.new(:with => {:ints => [1, 2, 3]}).first
585
-
586
- filter = @client.filters.last
587
- filter.values.should == [1, 2, 3]
588
- filter.attribute.should == 'ints'
589
- filter.exclude?.should be_false
590
- end
591
-
592
- it "should treat nils in arrays as 0" do
593
- ThinkingSphinx::Search.new(:with => {:ints => [nil, 1, 2, 3]}).first
594
-
595
- filter = @client.filters.last
596
- filter.values.should == [0, 1, 2, 3]
597
- end
598
-
599
- it "should append inclusive filters of time ranges" do
600
- first, last = 1.week.ago, Time.now
601
- ThinkingSphinx::Search.new(:with => {
602
- :time => first..last
603
- }).first
604
-
605
- filter = @client.filters.last
606
- filter.values.should == (first.to_i..last.to_i)
607
- filter.attribute.should == 'time'
608
- filter.exclude?.should be_false
609
- end
610
-
611
- it "should append exclusive filters of integers" do
612
- ThinkingSphinx::Search.new(:without => {:int => 1}).first
613
-
614
- filter = @client.filters.last
615
- filter.values.should == [1]
616
- filter.attribute.should == 'int'
617
- filter.exclude?.should be_true
618
- end
619
-
620
- it "should append exclusive filters of floats" do
621
- ThinkingSphinx::Search.new(:without => {:float => 1.5}).first
622
-
623
- filter = @client.filters.last
624
- filter.values.should == [1.5]
625
- filter.attribute.should == 'float'
626
- filter.exclude?.should be_true
627
- end
628
-
629
- it "should append exclusive filters of booleans" do
630
- ThinkingSphinx::Search.new(:without => {:boolean => true}).first
631
-
632
- filter = @client.filters.last
633
- filter.values.should == [true]
634
- filter.attribute.should == 'boolean'
635
- filter.exclude?.should be_true
636
- end
637
-
638
- it "should append exclusive filters of arrays" do
639
- ThinkingSphinx::Search.new(:without => {:ints => [1, 2, 3]}).first
640
-
641
- filter = @client.filters.last
642
- filter.values.should == [1, 2, 3]
643
- filter.attribute.should == 'ints'
644
- filter.exclude?.should be_true
645
- end
646
-
647
- it "should append exclusive filters of time ranges" do
648
- first, last = 1.week.ago, Time.now
649
- ThinkingSphinx::Search.new(:without => {
650
- :time => first..last
651
- }).first
652
-
653
- filter = @client.filters.last
654
- filter.values.should == (first.to_i..last.to_i)
655
- filter.attribute.should == 'time'
656
- filter.exclude?.should be_true
657
- end
658
-
659
- it "should add separate filters for each item in a with_all value" do
660
- ThinkingSphinx::Search.new(:with_all => {:ints => [1, 2, 3]}).first
661
-
662
- filters = @client.filters[-3, 3]
663
- filters.each do |filter|
664
- filter.attribute.should == 'ints'
665
- filter.exclude?.should be_false
666
- end
667
-
668
- filters[0].values.should == [1]
669
- filters[1].values.should == [2]
670
- filters[2].values.should == [3]
671
- end
672
-
673
- it "should filter out specific ids using :without_ids" do
674
- ThinkingSphinx::Search.new(:without_ids => [4, 5, 6]).first
675
-
676
- filter = @client.filters.last
677
- filter.values.should == [4, 5, 6]
678
- filter.attribute.should == 'sphinx_internal_id'
679
- filter.exclude?.should be_true
680
- end
681
-
682
- it "should not filter out any ids if :without_ids is an empty array" do
683
- ThinkingSphinx::Search.new(:without_ids => []).first
684
-
685
- filter = @client.filters.last
686
- filter.attribute.should_not == 'sphinx_internal_id'
687
- end
688
- end
689
-
690
- describe 'sort mode' do
691
- it "should use :relevance as a default" do
692
- ThinkingSphinx::Search.new.first
693
- @client.sort_mode.should == :relevance
694
- end
695
-
696
- it "should use :attr_asc if a symbol is supplied to :order" do
697
- ThinkingSphinx::Search.new(:order => :created_at).first
698
- @client.sort_mode.should == :attr_asc
699
- end
700
-
701
- it "should use :attr_desc if :desc is the mode" do
702
- ThinkingSphinx::Search.new(
703
- :order => :created_at, :sort_mode => :desc
704
- ).first
705
- @client.sort_mode.should == :attr_desc
706
- end
707
-
708
- it "should use :extended if a string is supplied to :order" do
709
- ThinkingSphinx::Search.new(:order => "created_at ASC").first
710
- @client.sort_mode.should == :extended
711
- end
712
-
713
- it "should use :expr if explicitly requested" do
714
- ThinkingSphinx::Search.new(
715
- :order => "created_at ASC", :sort_mode => :expr
716
- ).first
717
- @client.sort_mode.should == :expr
718
- end
719
-
720
- it "should use :attr_desc if explicitly requested" do
721
- ThinkingSphinx::Search.new(
722
- :order => "created_at", :sort_mode => :desc
723
- ).first
724
- @client.sort_mode.should == :attr_desc
725
- end
726
- end
727
-
728
- describe 'sort by' do
729
- it "should presume order symbols are attributes" do
730
- ThinkingSphinx::Search.new(:order => :created_at).first
731
- @client.sort_by.should == 'created_at'
732
- end
733
-
734
- it "replace field names with their sortable attributes" do
735
- ThinkingSphinx::Search.new(:order => :name, :classes => [Alpha]).first
736
- @client.sort_by.should == 'name_sort'
737
- end
738
-
739
- it "should replace field names in strings" do
740
- ThinkingSphinx::Search.new(
741
- :order => "created_at ASC, name DESC", :classes => [Alpha]
742
- ).first
743
- @client.sort_by.should == 'created_at ASC, name_sort DESC'
744
- end
745
- end
746
-
747
- describe 'max matches' do
748
- it "should use the global setting by default" do
749
- ThinkingSphinx::Search.new.first
750
- @client.max_matches.should == 1000
751
- end
752
-
753
- it "should use explicit setting" do
754
- ThinkingSphinx::Search.new(:max_matches => 2000).first
755
- @client.max_matches.should == 2000
756
- end
757
- end
758
-
759
- describe 'field weights' do
760
- it "should set field weights as provided" do
761
- ThinkingSphinx::Search.new(
762
- :field_weights => {'foo' => 10, 'bar' => 5}
763
- ).first
764
-
765
- @client.field_weights.should == {
766
- 'foo' => 10, 'bar' => 5
767
- }
768
- end
769
-
770
- it "should use field weights set in the index" do
771
- ThinkingSphinx::Search.new(:classes => [Alpha]).first
772
-
773
- @client.field_weights.should == {'name' => 10}
774
- end
775
- end
776
-
777
- describe 'index weights' do
778
- it "should send index weights through to the client" do
779
- ThinkingSphinx::Search.new(:index_weights => {'foo' => 100}).first
780
- @client.index_weights.should == {'foo' => 100}
781
- end
782
-
783
- it "should convert classes to their core and delta index names" do
784
- ThinkingSphinx::Search.new(:index_weights => {Alpha => 100}).first
785
- @client.index_weights.should == {
786
- 'alpha_core' => 100,
787
- 'alpha_delta' => 100
788
- }
789
- end
790
- end
791
-
792
- describe 'grouping' do
793
- it "should convert group into group_by and group_function" do
794
- ThinkingSphinx::Search.new(:group => :edition).first
795
-
796
- @client.group_function.should == :attr
797
- @client.group_by.should == "edition"
798
- end
799
-
800
- it "should pass on explicit grouping arguments" do
801
- ThinkingSphinx::Search.new(
802
- :group_by => 'created_at',
803
- :group_function => :attr,
804
- :group_clause => 'clause',
805
- :group_distinct => 'distinct'
806
- ).first
807
-
808
- @client.group_by.should == 'created_at'
809
- @client.group_function.should == :attr
810
- @client.group_clause.should == 'clause'
811
- @client.group_distinct.should == 'distinct'
812
- end
813
- end
814
-
815
- describe 'anchor' do
816
- it "should detect lat and lng attributes on the given model" do
817
- ThinkingSphinx::Search.new(
818
- :geo => [1.0, -1.0],
819
- :classes => [Alpha]
820
- ).first
821
-
822
- @client.anchor[:latitude_attribute].should == 'lat'
823
- @client.anchor[:longitude_attribute].should == 'lng'
824
- end
825
-
826
- it "should detect lat and lon attributes on the given model" do
827
- ThinkingSphinx::Search.new(
828
- :geo => [1.0, -1.0],
829
- :classes => [Beta]
830
- ).first
831
-
832
- @client.anchor[:latitude_attribute].should == 'lat'
833
- @client.anchor[:longitude_attribute].should == 'lon'
834
- end
835
-
836
- it "should detect latitude and longitude attributes on the given model" do
837
- ThinkingSphinx::Search.new(
838
- :geo => [1.0, -1.0],
839
- :classes => [Person]
840
- ).first
841
-
842
- @client.anchor[:latitude_attribute].should == 'latitude'
843
- @client.anchor[:longitude_attribute].should == 'longitude'
844
- end
845
-
846
- it "should accept manually defined latitude and longitude attributes" do
847
- ThinkingSphinx::Search.new(
848
- :geo => [1.0, -1.0],
849
- :classes => [Alpha],
850
- :latitude_attr => :updown,
851
- :longitude_attr => :leftright
852
- ).first
853
-
854
- @client.anchor[:latitude_attribute].should == 'updown'
855
- @client.anchor[:longitude_attribute].should == 'leftright'
856
- end
857
-
858
- it "should accept manually defined latitude and longitude attributes in the given model" do
859
- ThinkingSphinx::Search.new(
860
- :geo => [1.0, -1.0],
861
- :classes => [Friendship]
862
- ).first
863
-
864
- @client.anchor[:latitude_attribute].should == 'person_id'
865
- @client.anchor[:longitude_attribute].should == 'person_id'
866
- end
867
-
868
- it "should accept geo array for geo-position values" do
869
- ThinkingSphinx::Search.new(
870
- :geo => [1.0, -1.0],
871
- :classes => [Alpha]
872
- ).first
873
-
874
- @client.anchor[:latitude].should == 1.0
875
- @client.anchor[:longitude].should == -1.0
876
- end
877
-
878
- it "should accept lat and lng options for geo-position values" do
879
- ThinkingSphinx::Search.new(
880
- :lat => 1.0,
881
- :lng => -1.0,
882
- :classes => [Alpha]
883
- ).first
884
-
885
- @client.anchor[:latitude].should == 1.0
886
- @client.anchor[:longitude].should == -1.0
887
- end
888
- end
889
-
890
- describe 'sql ordering' do
891
- before :each do
892
- @client.stub! :query => {
893
- :matches => minimal_result_hashes(@alpha_b, @alpha_a)
894
- }
895
- Alpha.stub! :find => [@alpha_a, @alpha_b]
896
- end
897
-
898
- it "shouldn't re-sort SQL results based on Sphinx information" do
899
- search = ThinkingSphinx::Search.new(
900
- :classes => [Alpha],
901
- :sql_order => 'id'
902
- )
903
- search.first.should == @alpha_a
904
- search.last.should == @alpha_b
905
- end
906
-
907
- it "should use the option for the ActiveRecord::Base#find calls" do
908
- Alpha.should_receive(:find) do |mode, options|
909
- options[:order].should == 'id'
910
- end
911
-
912
- ThinkingSphinx::Search.new(
913
- :classes => [Alpha],
914
- :sql_order => 'id'
915
- ).first
916
- end
917
- end
918
-
919
- describe ':only option' do
920
- it "returns the requested attribute as an array" do
921
- ThinkingSphinx::Search.new(:only => :class_crc).first.
922
- should == Alpha.to_crc32
923
- end
924
-
925
- it "returns multiple attributes as hashes with values" do
926
- ThinkingSphinx::Search.new(
927
- :only => [:class_crc, :sphinx_internal_id]
928
- ).first.should == {
929
- :class_crc => Alpha.to_crc32,
930
- :sphinx_internal_id => @alpha_a.id
931
- }
932
- end
933
-
934
- it "handles strings for a single attribute name" do
935
- ThinkingSphinx::Search.new(:only => 'class_crc').first.
936
- should == Alpha.to_crc32
937
- end
938
-
939
- it "handles strings for multiple attribute names" do
940
- ThinkingSphinx::Search.new(
941
- :only => ['class_crc', 'sphinx_internal_id']
942
- ).first.should == {
943
- :class_crc => Alpha.to_crc32,
944
- :sphinx_internal_id => @alpha_a.id
945
- }
946
- end
947
- end
948
-
949
- describe ':attributes_only option' do
950
- it "returns the attributes as hashes with values" do
951
- ThinkingSphinx::Search.new(
952
- :attributes_only => true
953
- ).first.should == {
954
- :sphinx_internal_class => "Alpha",
955
- :class_crc => Alpha.to_crc32,
956
- :sphinx_internal_id => 1
957
- }
958
- end
959
- end
960
-
961
- context 'result objects' do
962
- describe '#excerpts' do
963
- before :each do
964
- @search = ThinkingSphinx::Search.new
965
- end
966
-
967
- it "should add excerpts method if objects don't already have one" do
968
- @search.first.should respond_to(:excerpts)
969
- end
970
-
971
- it "should return an instance of ThinkingSphinx::Excerpter" do
972
- @search.first.excerpts.should be_a(ThinkingSphinx::Excerpter)
973
- end
974
-
975
- it "should not add excerpts method if objects already have one" do
976
- @search.last.excerpts.should_not be_a(ThinkingSphinx::Excerpter)
977
- end
978
-
979
- # Fails in Ruby 1.9 (or maybe it's an RSpec update). Not sure why.
980
- it "should set up the excerpter with the instances and search" do
981
- [@alpha_a, @beta_b, @alpha_b, @beta_a].each do |object|
982
- ThinkingSphinx::Excerpter.should_receive(:new).with(@search, object)
983
- end
984
-
985
- @search.first
986
- end
987
- end
988
-
989
- describe '#sphinx_attributes' do
990
- before :each do
991
- @search = ThinkingSphinx::Search.new
992
- end
993
-
994
- it "should add sphinx_attributes method if objects don't already have one" do
995
- @search.last.should respond_to(:sphinx_attributes)
996
- end
997
-
998
- it "should return a hash" do
999
- @search.last.sphinx_attributes.should be_a(Hash)
1000
- end
1001
-
1002
- it "should not add sphinx_attributes if objects have a method of that name already" do
1003
- @search.first.sphinx_attributes.should_not be_a(Hash)
1004
- end
1005
-
1006
- it "should pair sphinx_attributes with the correct hash" do
1007
- hash = @search.last.sphinx_attributes
1008
- hash['sphinx_internal_id'].should == @search.last.id
1009
- hash['class_crc'].should == @search.last.class.to_crc32
1010
- end
1011
- end
1012
-
1013
- describe '#matching_fields' do
1014
- it "should add matching_fields method if using fieldmask ranking mode" do
1015
- search = ThinkingSphinx::Search.new :rank_mode => :fieldmask
1016
- search.first.should respond_to(:matching_fields)
1017
- end
1018
-
1019
- it "should not add matching_fields method if object already have one" do
1020
- search = ThinkingSphinx::Search.new :rank_mode => :fieldmask
1021
- search.last.matching_fields.should_not be_an(Array)
1022
- end
1023
-
1024
- it "should return an array" do
1025
- search = ThinkingSphinx::Search.new :rank_mode => :fieldmask
1026
- search.first.matching_fields.should be_an(Array)
1027
- end
1028
-
1029
- it "should return the fields that the bitmask match" do
1030
- search = ThinkingSphinx::Search.new :rank_mode => :fieldmask
1031
- search.first.matching_fields.should == ['one', 'three', 'five']
1032
- end
1033
- end
1034
- end
8
+ before :each do
9
+ ThinkingSphinx::Search::Context.stub :new => context
1035
10
 
1036
- context 'Sphinx errors' do
1037
- describe '#error?' do
1038
- before :each do
1039
- @client.stub! :query => {
1040
- :error => @warning = "Not good"
1041
- }
1042
- # @search.should_receive(:error).and_return(nil)
1043
- end
1044
- it "should raise an error" do
1045
- lambda{
1046
- ThinkingSphinx::Search.new.first
1047
- }.should raise_error(ThinkingSphinx::SphinxError)
1048
- end
1049
- it "should not raise an error when ignore_errors is true" do
1050
- lambda{
1051
- ThinkingSphinx::Search.new(:ignore_errors => true).first
1052
- }.should_not raise_error(ThinkingSphinx::SphinxError)
1053
- end
1054
- end
1055
- end
11
+ stub_const 'ThinkingSphinx::Middlewares::DEFAULT', stack
1056
12
  end
1057
13
 
1058
14
  describe '#current_page' do
1059
15
  it "should return 1 by default" do
1060
- ThinkingSphinx::Search.new.current_page.should == 1
16
+ search.current_page.should == 1
1061
17
  end
1062
18
 
1063
19
  it "should handle string page values" do
@@ -1073,93 +29,42 @@ describe ThinkingSphinx::Search do
1073
29
  end
1074
30
  end
1075
31
 
1076
- describe '#per_page' do
1077
- it "should return 20 by default" do
1078
- ThinkingSphinx::Search.new.per_page.should == 20
1079
- end
32
+ describe '#empty?' do
33
+ it "returns false if there is anything in the data set" do
34
+ context[:results] << double
1080
35
 
1081
- it "should allow for custom values" do
1082
- ThinkingSphinx::Search.new(:per_page => 30).per_page.should == 30
36
+ search.should_not be_empty
1083
37
  end
1084
38
 
1085
- it "should prioritise :limit over :per_page if given" do
1086
- ThinkingSphinx::Search.new(
1087
- :per_page => 30, :limit => 40
1088
- ).per_page.should == 40
1089
- end
39
+ it "returns true if the data set is empty" do
40
+ context[:results].clear
1090
41
 
1091
- it "should allow for string arguments" do
1092
- ThinkingSphinx::Search.new(:per_page => '10').per_page.should == 10
42
+ search.should be_empty
1093
43
  end
1094
44
  end
1095
45
 
1096
- describe '#total_pages' do
1097
- it "should calculate the total pages depending on per_page and total_entries" do
1098
- ThinkingSphinx::Search.new.total_pages.should == 3
1099
- end
1100
-
1101
- it "should allow for custom per_page values" do
1102
- ThinkingSphinx::Search.new(:per_page => 30).total_pages.should == 2
1103
- end
1104
-
1105
- it "should not overstep the max_matches implied limit" do
1106
- @client.stub!(:query => {
1107
- :matches => [], :total_found => 41, :total => 40
1108
- })
1109
-
1110
- ThinkingSphinx::Search.new.total_pages.should == 2
1111
- end
46
+ describe '#initialize' do
47
+ it "lazily loads by default" do
48
+ stack.should_not_receive(:call)
1112
49
 
1113
- it "should return 0 if there is no index and therefore no results" do
1114
- @client.stub!(:query => {
1115
- :matches => [], :total_found => nil, :total => nil
1116
- })
1117
-
1118
- ThinkingSphinx::Search.new.total_pages.should == 0
50
+ ThinkingSphinx::Search.new
1119
51
  end
1120
- end
1121
52
 
1122
- describe '#next_page' do
1123
- it "should return one more than the current page" do
1124
- ThinkingSphinx::Search.new.next_page.should == 2
1125
- end
53
+ it "should automatically populate when :populate is set to true" do
54
+ stack.should_receive(:call).and_return(true)
1126
55
 
1127
- it "should return nil if on the last page" do
1128
- ThinkingSphinx::Search.new(:page => 3).next_page.should be_nil
1129
- end
1130
- end
1131
-
1132
- describe '#previous_page' do
1133
- it "should return one less than the current page" do
1134
- ThinkingSphinx::Search.new(:page => 2).previous_page.should == 1
1135
- end
1136
-
1137
- it "should return nil if on the first page" do
1138
- ThinkingSphinx::Search.new.previous_page.should be_nil
1139
- end
1140
- end
1141
-
1142
- describe '#total_entries' do
1143
- it "should return the total number of results, not just the amount on the page" do
1144
- ThinkingSphinx::Search.new.total_entries.should == 41
1145
- end
1146
-
1147
- it "should return 0 if there is no index and therefore no results" do
1148
- @client.stub!(:query => {
1149
- :matches => [], :total_found => nil
1150
- })
1151
-
1152
- ThinkingSphinx::Search.new.total_entries.should == 0
56
+ ThinkingSphinx::Search.new(:populate => true)
1153
57
  end
1154
58
  end
1155
59
 
1156
60
  describe '#offset' do
1157
61
  it "should default to 0" do
1158
- ThinkingSphinx::Search.new.offset.should == 0
62
+ search.offset.should == 0
1159
63
  end
1160
64
 
1161
65
  it "should increase by the per_page value for each page in" do
1162
- ThinkingSphinx::Search.new(:per_page => 25, :page => 2).offset.should == 25
66
+ ThinkingSphinx::Search.new(:per_page => 25, :page => 2).offset.
67
+ should == 25
1163
68
  end
1164
69
 
1165
70
  it "should prioritise explicit :offset over calculated if given" do
@@ -1167,277 +72,80 @@ describe ThinkingSphinx::Search do
1167
72
  end
1168
73
  end
1169
74
 
1170
- describe '#indexes' do
1171
- it "should default to '*'" do
1172
- ThinkingSphinx::Search.new.indexes.should == '*'
1173
- end
1174
-
1175
- it "should use given class to determine index name" do
1176
- ThinkingSphinx::Search.new(:classes => [Alpha]).indexes.
1177
- should == 'alpha_core'
1178
- end
1179
-
1180
- it "should add both core and delta indexes for given classes" do
1181
- ThinkingSphinx::Search.new(:classes => [Alpha, Beta]).indexes.
1182
- should == 'alpha_core,beta_core,beta_delta'
75
+ describe '#page' do
76
+ it "sets the current page" do
77
+ search.page(3)
78
+ search.current_page.should == 3
1183
79
  end
1184
80
 
1185
- it "should respect the :index option" do
1186
- ThinkingSphinx::Search.new(:classes => [Alpha], :index => '*').indexes.
1187
- should == '*'
81
+ it "returns the search object" do
82
+ search.page(2).should == search
1188
83
  end
1189
84
  end
1190
85
 
1191
- describe '.each_with_groupby_and_count' do
1192
- before :each do
1193
- @alpha = Alpha.new
1194
- @alpha.stub!(:id => 1, :read_attribute => 1)
1195
-
1196
- @client.stub! :query => {
1197
- :matches => [{
1198
- :attributes => {
1199
- 'sphinx_internal_id' => @alpha.id,
1200
- 'sphinx_internal_class' => 'Alpha',
1201
- 'class_crc' => Alpha.to_crc32,
1202
- '@groupby' => 101,
1203
- '@count' => 5
1204
- }
1205
- }]
1206
- }
1207
- Alpha.stub :find => [@alpha], :unscoped => Alpha
1208
- end
1209
-
1210
- it "should yield the match, group and count" do
1211
- search = ThinkingSphinx::Search.new
1212
- search.each_with_groupby_and_count do |obj, group, count|
1213
- obj.should == @alpha
1214
- group.should == 101
1215
- count.should == 5
1216
- end
86
+ describe '#per' do
87
+ it "sets the current per_page value" do
88
+ search.per(29)
89
+ search.per_page.should == 29
1217
90
  end
1218
91
 
1219
- it "should be aliased to each_with_group_and_count" do
1220
- search = ThinkingSphinx::Search.new
1221
- search.each_with_group_and_count do |obj, group, count|
1222
- obj.should == @alpha
1223
- group.should == 101
1224
- count.should == 5
1225
- end
92
+ it "returns the search object" do
93
+ search.per(29).should == search
1226
94
  end
1227
95
  end
1228
96
 
1229
- describe '.each_with_weighting' do
1230
- before :each do
1231
- @alpha = Alpha.new
1232
- @alpha.stub!(:id => 1, :read_attribute => 1)
1233
-
1234
- @client.stub! :query => {
1235
- :matches => [{
1236
- :attributes => {
1237
- 'sphinx_internal_id' => @alpha.id,
1238
- 'sphinx_internal_class' => 'Alpha',
1239
- 'class_crc' => Alpha.to_crc32
1240
- }, :weight => 12
1241
- }]
1242
- }
1243
- Alpha.stub :find => [@alpha], :unscoped => Alpha
1244
- end
1245
-
1246
- it "should yield the match and weight" do
1247
- search = ThinkingSphinx::Search.new
1248
- search.each_with_weighting do |obj, weight|
1249
- obj.should == @alpha
1250
- weight.should == 12
1251
- end
1252
- end
1253
- end
1254
-
1255
- describe '.each_with_*' do
1256
- before :each do
1257
- @alpha = Alpha.new
1258
- @alpha.stub!(:id => 1, :read_attribute => 1)
1259
-
1260
- @client.stub! :query => {
1261
- :matches => [{
1262
- :attributes => {
1263
- 'sphinx_internal_id' => @alpha.id,
1264
- 'sphinx_internal_class' => 'Alpha',
1265
- 'class_crc' => Alpha.to_crc32,
1266
- '@geodist' => 101,
1267
- '@groupby' => 102,
1268
- '@count' => 103
1269
- }, :weight => 12
1270
- }]
1271
- }
1272
- Alpha.stub :find => [@alpha], :unscoped => Alpha
1273
-
1274
- @search = ThinkingSphinx::Search.new
1275
- end
1276
-
1277
- it "should yield geodist if requested" do
1278
- @search.each_with_geodist do |obj, distance|
1279
- obj.should == @alpha
1280
- distance.should == 101
1281
- end
1282
- end
1283
-
1284
- it "should yield count if requested" do
1285
- @search.each_with_count do |obj, count|
1286
- obj.should == @alpha
1287
- count.should == 103
1288
- end
1289
- end
1290
-
1291
- it "should yield groupby if requested" do
1292
- @search.each_with_groupby do |obj, group|
1293
- obj.should == @alpha
1294
- group.should == 102
1295
- end
1296
- end
1297
-
1298
- it "should still use the array's each_with_index" do
1299
- @search.each_with_index do |obj, index|
1300
- obj.should == @alpha
1301
- index.should == 0
1302
- end
1303
- end
1304
- end
1305
-
1306
- describe '#excerpt_for' do
1307
- before :each do
1308
- @client.stub!(:excerpts => ['excerpted string'])
1309
- @client.stub!(:query => {
1310
- :matches => [],
1311
- :words => {'one' => {}, 'two' => {}}
1312
- })
1313
- @search = ThinkingSphinx::Search.new('reading comprehension', :classes => [Alpha])
1314
- end
1315
-
1316
- it "should return the Sphinx excerpt value" do
1317
- @search.excerpt_for('string').should == 'excerpted string'
1318
- end
1319
-
1320
- it "should use the given model's core index" do
1321
- @client.should_receive(:excerpts) do |options|
1322
- options[:index].should == 'alpha_core'
1323
- end
1324
-
1325
- @search.excerpt_for('string')
1326
- end
1327
-
1328
- it "should respect the provided index option" do
1329
- @search = ThinkingSphinx::Search.new(:classes => [Alpha], :index => 'foo')
1330
- @client.should_receive(:excerpts) do |options|
1331
- options[:index].should == 'foo'
1332
- end
1333
-
1334
- @search.excerpt_for('string')
97
+ describe '#per_page' do
98
+ it "defaults to 20" do
99
+ search.per_page.should == 20
1335
100
  end
1336
101
 
1337
- it "should optionally take a second argument to allow for multi-model searches" do
1338
- @client.should_receive(:excerpts) do |options|
1339
- options[:index].should == 'beta_core'
1340
- end
1341
-
1342
- @search.excerpt_for('string', Beta)
102
+ it "is set as part of the search options" do
103
+ ThinkingSphinx::Search.new(:per_page => 10).per_page.should == 10
1343
104
  end
1344
105
 
1345
- it "should use the query string" do
1346
- @client.should_receive(:excerpts) do |options|
1347
- options[:words].should == 'reading comprehension'
1348
- end
1349
-
1350
- @search.excerpt_for('string', Beta)
106
+ it "should prioritise :limit over :per_page if given" do
107
+ ThinkingSphinx::Search.new(:per_page => 30, :limit => 40).per_page.
108
+ should == 40
1351
109
  end
1352
110
 
1353
- it "should use the correct index in STI situations" do
1354
- @client.should_receive(:excerpts) do |options|
1355
- options[:index].should == 'person_core'
1356
- end
1357
-
1358
- @search.excerpt_for('string', Parent)
111
+ it "should allow for string arguments" do
112
+ ThinkingSphinx::Search.new(:per_page => '10').per_page.should == 10
1359
113
  end
1360
114
  end
1361
115
 
1362
- describe '#search' do
1363
- before :each do
1364
- @search = ThinkingSphinx::Search.new('word',
1365
- :conditions => {:field => 'field'},
1366
- :with => {:int => 5}
1367
- )
1368
- end
1369
-
1370
- it "should return itself" do
1371
- @search.search.object_id.should == @search.object_id
1372
- end
1373
-
1374
- it "should merge in arguments" do
1375
- @client.should_receive(:query) do |query, index, comments|
1376
- query.should == 'word more @field field'
1377
- end
1378
-
1379
- @search.search('more').first
1380
- end
1381
-
1382
- it "should merge conditions" do
1383
- @client.should_receive(:query) do |query, index, comments|
1384
- query.should match(/@name plato/)
1385
- query.should match(/@field field/)
1386
- end
116
+ describe '#populate' do
117
+ it "runs the middleware" do
118
+ stack.should_receive(:call).with([context]).and_return(true)
1387
119
 
1388
- @search.search(:conditions => {:name => 'plato'}).first
120
+ search.populate
1389
121
  end
1390
122
 
1391
- it "should merge filters" do
1392
- @search.search(:with => {:float => 1.5}).first
123
+ it "does not retrieve results twice" do
124
+ stack.should_receive(:call).with([context]).once.and_return(true)
1393
125
 
1394
- @client.filters.detect { |filter|
1395
- filter.attribute == 'float'
1396
- }.should_not be_nil
1397
- @client.filters.detect { |filter|
1398
- filter.attribute == 'int'
1399
- }.should_not be_nil
126
+ search.populate
127
+ search.populate
1400
128
  end
1401
129
  end
1402
130
 
1403
- describe '#all' do
1404
- before :each do
1405
- @search = ThinkingSphinx::Search.new
1406
- end
1407
-
1408
- it "should populate the result set" do
1409
- @search.all
1410
- @search.should be_populated
131
+ describe '#respond_to?' do
132
+ it "should respond to Array methods" do
133
+ search.respond_to?(:each).should be_true
1411
134
  end
1412
135
 
1413
- it "should return the Search object" do
1414
- @search.all.should be_a(ThinkingSphinx::Search)
136
+ it "should respond to Search methods" do
137
+ search.respond_to?(:per_page).should be_true
1415
138
  end
1416
139
  end
1417
140
 
1418
- describe '#freeze' do
1419
- before :each do
1420
- @search = ThinkingSphinx::Search.new
1421
- end
141
+ describe '#to_a' do
142
+ it "returns each of the standard ActiveRecord objects" do
143
+ unglazed = double('unglazed instance')
144
+ glazed = double('glazed instance', :unglazed => unglazed)
1422
145
 
1423
- it "should populate the result set" do
1424
- @search.freeze
1425
- @search.should be_populated
1426
- end
146
+ context[:results] << glazed
1427
147
 
1428
- it "should freeze the underlying array" do
1429
- @search.freeze
1430
- @search.to_a.should be_frozen
148
+ search.to_a.first.__id__.should == unglazed.__id__
1431
149
  end
1432
-
1433
- it "should return the Search object" do
1434
- @search.freeze.should be_a(ThinkingSphinx::Search)
1435
- end
1436
- end
1437
- end
1438
-
1439
- describe ThinkingSphinx::Search, "playing nice with Search model" do
1440
- it "should not conflict with models called Search" do
1441
- lambda { Search.find(:all) }.should_not raise_error
1442
150
  end
1443
151
  end