thinking-sphinx 2.1.0 → 3.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (352) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +13 -0
  3. data/Appraisals +7 -0
  4. data/Gemfile +10 -0
  5. data/HISTORY +2 -267
  6. data/LICENCE +1 -1
  7. data/README.textile +194 -226
  8. data/Rakefile +24 -0
  9. data/gemfiles/.gitignore +1 -0
  10. data/gemfiles/rails_3_1.gemfile +11 -0
  11. data/gemfiles/rails_3_2.gemfile +11 -0
  12. data/lib/thinking-sphinx.rb +1 -1
  13. data/lib/thinking_sphinx.rb +34 -292
  14. data/lib/thinking_sphinx/active_record.rb +22 -383
  15. data/lib/thinking_sphinx/active_record/association.rb +9 -0
  16. data/lib/thinking_sphinx/active_record/association_proxy.rb +68 -0
  17. data/lib/thinking_sphinx/active_record/associations.rb +68 -0
  18. data/lib/thinking_sphinx/active_record/attribute.rb +20 -0
  19. data/lib/thinking_sphinx/active_record/attribute/sphinx_presenter.rb +32 -0
  20. data/lib/thinking_sphinx/active_record/attribute/type.rb +79 -0
  21. data/lib/thinking_sphinx/active_record/attribute/values.rb +18 -0
  22. data/lib/thinking_sphinx/active_record/base.rb +36 -0
  23. data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +31 -0
  24. data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +55 -0
  25. data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +59 -0
  26. data/lib/thinking_sphinx/active_record/column.rb +30 -0
  27. data/lib/thinking_sphinx/active_record/database_adapters.rb +51 -0
  28. data/lib/thinking_sphinx/active_record/database_adapters/abstract_adapter.rb +13 -0
  29. data/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb +23 -0
  30. data/lib/thinking_sphinx/active_record/database_adapters/postgresql_adapter.rb +25 -0
  31. data/lib/thinking_sphinx/active_record/field.rb +11 -0
  32. data/lib/thinking_sphinx/active_record/index.rb +55 -0
  33. data/lib/thinking_sphinx/active_record/interpreter.rb +47 -0
  34. data/lib/thinking_sphinx/active_record/log_subscriber.rb +10 -58
  35. data/lib/thinking_sphinx/active_record/property.rb +28 -0
  36. data/lib/thinking_sphinx/active_record/property_sql_presenter.rb +60 -0
  37. data/lib/thinking_sphinx/active_record/sql_builder.rb +159 -0
  38. data/lib/thinking_sphinx/active_record/sql_source.rb +138 -0
  39. data/lib/thinking_sphinx/active_record/sql_source/template.rb +46 -0
  40. data/lib/thinking_sphinx/batched_search.rb +26 -0
  41. data/lib/thinking_sphinx/callbacks.rb +15 -0
  42. data/lib/thinking_sphinx/configuration.rb +80 -331
  43. data/lib/thinking_sphinx/configuration/consistent_ids.rb +31 -0
  44. data/lib/thinking_sphinx/configuration/defaults.rb +5 -0
  45. data/lib/thinking_sphinx/core.rb +6 -0
  46. data/lib/thinking_sphinx/core/index.rb +68 -0
  47. data/lib/thinking_sphinx/core/interpreter.rb +19 -0
  48. data/lib/thinking_sphinx/deltas.rb +35 -26
  49. data/lib/thinking_sphinx/deltas/default_delta.rb +56 -56
  50. data/lib/thinking_sphinx/excerpter.rb +23 -21
  51. data/lib/thinking_sphinx/facet.rb +22 -127
  52. data/lib/thinking_sphinx/facet_search.rb +95 -162
  53. data/lib/thinking_sphinx/index.rb +39 -143
  54. data/lib/thinking_sphinx/index_set.rb +51 -0
  55. data/lib/thinking_sphinx/masks.rb +8 -0
  56. data/lib/thinking_sphinx/masks/group_enumerators_mask.rb +23 -0
  57. data/lib/thinking_sphinx/masks/pagination_mask.rb +60 -0
  58. data/lib/thinking_sphinx/masks/scopes_mask.rb +35 -0
  59. data/lib/thinking_sphinx/masks/weight_enumerator_mask.rb +11 -0
  60. data/lib/thinking_sphinx/middlewares.rb +36 -0
  61. data/lib/thinking_sphinx/middlewares/active_record_translator.rb +73 -0
  62. data/lib/thinking_sphinx/middlewares/geographer.rb +53 -0
  63. data/lib/thinking_sphinx/middlewares/glazier.rb +39 -0
  64. data/lib/thinking_sphinx/middlewares/ids_only.rb +13 -0
  65. data/lib/thinking_sphinx/middlewares/inquirer.rb +62 -0
  66. data/lib/thinking_sphinx/middlewares/middleware.rb +9 -0
  67. data/lib/thinking_sphinx/middlewares/sphinxql.rb +149 -0
  68. data/lib/thinking_sphinx/middlewares/stale_id_checker.rb +45 -0
  69. data/lib/thinking_sphinx/middlewares/stale_id_filter.rb +46 -0
  70. data/lib/thinking_sphinx/panes.rb +8 -0
  71. data/lib/thinking_sphinx/panes/attributes_pane.rb +9 -0
  72. data/lib/thinking_sphinx/panes/distance_pane.rb +13 -0
  73. data/lib/thinking_sphinx/panes/excerpts_pane.rb +37 -0
  74. data/lib/thinking_sphinx/panes/weight_pane.rb +9 -0
  75. data/lib/thinking_sphinx/railtie.rb +6 -40
  76. data/lib/thinking_sphinx/rake_interface.rb +47 -0
  77. data/lib/thinking_sphinx/real_time.rb +11 -0
  78. data/lib/thinking_sphinx/real_time/attribute.rb +5 -0
  79. data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +48 -0
  80. data/lib/thinking_sphinx/real_time/field.rb +3 -0
  81. data/lib/thinking_sphinx/real_time/index.rb +47 -0
  82. data/lib/thinking_sphinx/real_time/index/template.rb +33 -0
  83. data/lib/thinking_sphinx/real_time/interpreter.rb +23 -0
  84. data/lib/thinking_sphinx/real_time/property.rb +16 -0
  85. data/lib/thinking_sphinx/scopes.rb +22 -0
  86. data/lib/thinking_sphinx/search.rb +90 -1028
  87. data/lib/thinking_sphinx/search/batch_inquirer.rb +27 -0
  88. data/lib/thinking_sphinx/search/context.rb +26 -0
  89. data/lib/thinking_sphinx/search/glaze.rb +32 -0
  90. data/lib/thinking_sphinx/search/merger.rb +24 -0
  91. data/lib/thinking_sphinx/search/query.rb +43 -0
  92. data/lib/thinking_sphinx/search/stale_ids_exception.rb +11 -0
  93. data/lib/thinking_sphinx/search/translator.rb +50 -0
  94. data/lib/thinking_sphinx/tasks.rb +22 -125
  95. data/lib/thinking_sphinx/test.rb +9 -19
  96. data/sketchpad.rb +58 -0
  97. data/spec/acceptance/association_scoping_spec.rb +23 -0
  98. data/spec/acceptance/attribute_access_spec.rb +39 -0
  99. data/spec/acceptance/attribute_updates_spec.rb +16 -0
  100. data/spec/acceptance/batch_searching_spec.rb +21 -0
  101. data/spec/acceptance/big_integers_spec.rb +27 -0
  102. data/spec/acceptance/excerpts_spec.rb +14 -0
  103. data/spec/acceptance/facets_spec.rb +122 -0
  104. data/spec/acceptance/geosearching_spec.rb +39 -0
  105. data/spec/acceptance/grouping_by_attributes_spec.rb +77 -0
  106. data/spec/acceptance/paginating_search_results_spec.rb +24 -0
  107. data/spec/acceptance/remove_deleted_records_spec.rb +23 -0
  108. data/spec/acceptance/search_counts_spec.rb +18 -0
  109. data/spec/acceptance/search_for_just_ids_spec.rb +19 -0
  110. data/spec/acceptance/searching_across_models_spec.rb +28 -0
  111. data/spec/acceptance/searching_on_fields_spec.rb +56 -0
  112. data/spec/acceptance/searching_with_filters_spec.rb +109 -0
  113. data/spec/acceptance/searching_with_sti_spec.rb +55 -0
  114. data/spec/acceptance/searching_within_a_model_spec.rb +52 -0
  115. data/spec/acceptance/sorting_search_results_spec.rb +41 -0
  116. data/spec/acceptance/spec_helper.rb +4 -0
  117. data/spec/acceptance/specifying_sql_spec.rb +62 -0
  118. data/spec/acceptance/sphinx_scopes_spec.rb +49 -0
  119. data/spec/acceptance/sql_deltas_spec.rb +43 -0
  120. data/spec/acceptance/support/database_cleaner.rb +11 -0
  121. data/spec/acceptance/support/sphinx_controller.rb +39 -0
  122. data/spec/acceptance/support/sphinx_helpers.rb +24 -0
  123. data/spec/acceptance/suspended_deltas_spec.rb +20 -0
  124. data/spec/internal/.gitignore +1 -0
  125. data/spec/internal/app/indices/animal_index.rb +3 -0
  126. data/spec/internal/app/indices/article_index.rb +24 -0
  127. data/spec/internal/app/indices/book_index.rb +8 -0
  128. data/spec/internal/app/indices/city_index.rb +6 -0
  129. data/spec/internal/app/indices/product_index.rb +3 -0
  130. data/spec/internal/app/indices/tee_index.rb +4 -0
  131. data/spec/internal/app/indices/user_index.rb +5 -0
  132. data/spec/internal/app/models/animal.rb +2 -0
  133. data/spec/internal/app/models/article.rb +5 -0
  134. data/spec/internal/app/models/bird.rb +2 -0
  135. data/spec/internal/app/models/book.rb +11 -0
  136. data/spec/internal/app/models/city.rb +2 -0
  137. data/spec/internal/app/models/colour.rb +3 -0
  138. data/spec/internal/app/models/flightless_bird.rb +2 -0
  139. data/spec/internal/app/models/mammal.rb +2 -0
  140. data/spec/internal/app/models/product.rb +3 -0
  141. data/spec/internal/app/models/tag.rb +4 -0
  142. data/{features/thinking_sphinx → spec/internal/app}/models/tagging.rb +1 -1
  143. data/spec/internal/app/models/tee.rb +3 -0
  144. data/spec/internal/app/models/tweet.rb +3 -0
  145. data/spec/internal/app/models/user.rb +3 -0
  146. data/spec/internal/config/database.yml +5 -0
  147. data/spec/internal/db/schema.rb +65 -0
  148. data/spec/internal/log/.gitignore +1 -0
  149. data/spec/spec_helper.rb +8 -49
  150. data/spec/support/sphinx_yaml_helpers.rb +9 -0
  151. data/spec/thinking_sphinx/active_record/association_spec.rb +12 -0
  152. data/spec/thinking_sphinx/active_record/associations_spec.rb +184 -0
  153. data/spec/thinking_sphinx/active_record/attribute/type_spec.rb +147 -0
  154. data/spec/thinking_sphinx/active_record/base_spec.rb +61 -0
  155. data/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +80 -0
  156. data/spec/thinking_sphinx/active_record/callbacks/delta_callbacks_spec.rb +147 -0
  157. data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +69 -0
  158. data/spec/thinking_sphinx/active_record/column_spec.rb +47 -0
  159. data/spec/thinking_sphinx/active_record/database_adapters/abstract_adapter_spec.rb +31 -0
  160. data/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +43 -0
  161. data/spec/thinking_sphinx/active_record/database_adapters/postgresql_adapter_spec.rb +45 -0
  162. data/spec/thinking_sphinx/active_record/database_adapters_spec.rb +108 -0
  163. data/spec/thinking_sphinx/active_record/field_spec.rb +36 -0
  164. data/spec/thinking_sphinx/active_record/index_spec.rb +208 -0
  165. data/spec/thinking_sphinx/active_record/interpreter_spec.rb +293 -0
  166. data/spec/thinking_sphinx/active_record/property_sql_presenter_spec.rb +162 -0
  167. data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +666 -0
  168. data/spec/thinking_sphinx/active_record/sql_source_spec.rb +401 -0
  169. data/spec/thinking_sphinx/configuration_spec.rb +264 -171
  170. data/spec/thinking_sphinx/deltas/default_delta_spec.rb +116 -0
  171. data/spec/thinking_sphinx/deltas_spec.rb +58 -0
  172. data/spec/thinking_sphinx/excerpter_spec.rb +40 -38
  173. data/spec/thinking_sphinx/facet_search_spec.rb +49 -151
  174. data/spec/thinking_sphinx/index_set_spec.rb +68 -0
  175. data/spec/thinking_sphinx/index_spec.rb +91 -155
  176. data/spec/thinking_sphinx/masks/pagination_mask_spec.rb +121 -0
  177. data/spec/thinking_sphinx/masks/scopes_mask_spec.rb +68 -0
  178. data/spec/thinking_sphinx/middlewares/active_record_translator_spec.rb +132 -0
  179. data/spec/thinking_sphinx/middlewares/geographer_spec.rb +89 -0
  180. data/spec/thinking_sphinx/middlewares/glazier_spec.rb +62 -0
  181. data/spec/thinking_sphinx/middlewares/inquirer_spec.rb +55 -0
  182. data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +271 -0
  183. data/spec/thinking_sphinx/middlewares/stale_id_checker_spec.rb +47 -0
  184. data/spec/thinking_sphinx/middlewares/stale_id_filter_spec.rb +91 -0
  185. data/spec/thinking_sphinx/panes/attributes_pane_spec.rb +21 -0
  186. data/spec/thinking_sphinx/panes/distance_pane_spec.rb +41 -0
  187. data/spec/thinking_sphinx/panes/excerpts_pane_spec.rb +53 -0
  188. data/spec/thinking_sphinx/panes/weight_pane_spec.rb +20 -0
  189. data/spec/thinking_sphinx/rake_interface_spec.rb +147 -0
  190. data/spec/thinking_sphinx/real_time/attribute_spec.rb +62 -0
  191. data/spec/thinking_sphinx/real_time/callbacks/real_time_callbacks_spec.rb +76 -0
  192. data/spec/thinking_sphinx/real_time/field_spec.rb +54 -0
  193. data/spec/thinking_sphinx/real_time/index_spec.rb +154 -0
  194. data/spec/thinking_sphinx/real_time/interpreter_spec.rb +147 -0
  195. data/spec/thinking_sphinx/scopes_spec.rb +38 -0
  196. data/spec/thinking_sphinx/search/glaze_spec.rb +55 -0
  197. data/spec/thinking_sphinx/search/query_spec.rb +46 -0
  198. data/spec/thinking_sphinx/search_spec.rb +65 -1357
  199. data/spec/thinking_sphinx_spec.rb +19 -182
  200. data/thinking-sphinx.gemspec +33 -0
  201. metadata +318 -431
  202. data/features/abstract_inheritance.feature +0 -10
  203. data/features/alternate_primary_key.feature +0 -27
  204. data/features/attribute_transformation.feature +0 -22
  205. data/features/attribute_updates.feature +0 -79
  206. data/features/deleting_instances.feature +0 -70
  207. data/features/direct_attributes.feature +0 -11
  208. data/features/excerpts.feature +0 -21
  209. data/features/extensible_delta_indexing.feature +0 -9
  210. data/features/facets.feature +0 -88
  211. data/features/facets_across_model.feature +0 -29
  212. data/features/field_sorting.feature +0 -18
  213. data/features/handling_edits.feature +0 -97
  214. data/features/retry_stale_indexes.feature +0 -24
  215. data/features/searching_across_models.feature +0 -20
  216. data/features/searching_by_index.feature +0 -41
  217. data/features/searching_by_model.feature +0 -175
  218. data/features/searching_with_find_arguments.feature +0 -56
  219. data/features/sphinx_detection.feature +0 -25
  220. data/features/sphinx_scopes.feature +0 -68
  221. data/features/step_definitions/alpha_steps.rb +0 -16
  222. data/features/step_definitions/beta_steps.rb +0 -7
  223. data/features/step_definitions/common_steps.rb +0 -205
  224. data/features/step_definitions/extensible_delta_indexing_steps.rb +0 -7
  225. data/features/step_definitions/facet_steps.rb +0 -96
  226. data/features/step_definitions/find_arguments_steps.rb +0 -36
  227. data/features/step_definitions/gamma_steps.rb +0 -15
  228. data/features/step_definitions/scope_steps.rb +0 -19
  229. data/features/step_definitions/search_steps.rb +0 -94
  230. data/features/step_definitions/sphinx_steps.rb +0 -35
  231. data/features/sti_searching.feature +0 -19
  232. data/features/support/env.rb +0 -24
  233. data/features/support/lib/generic_delta_handler.rb +0 -8
  234. data/features/thinking_sphinx/database.example.yml +0 -3
  235. data/features/thinking_sphinx/db/.gitignore +0 -1
  236. data/features/thinking_sphinx/db/fixtures/alphas.rb +0 -8
  237. data/features/thinking_sphinx/db/fixtures/authors.rb +0 -1
  238. data/features/thinking_sphinx/db/fixtures/betas.rb +0 -11
  239. data/features/thinking_sphinx/db/fixtures/boxes.rb +0 -9
  240. data/features/thinking_sphinx/db/fixtures/categories.rb +0 -1
  241. data/features/thinking_sphinx/db/fixtures/cats.rb +0 -3
  242. data/features/thinking_sphinx/db/fixtures/comments.rb +0 -24
  243. data/features/thinking_sphinx/db/fixtures/developers.rb +0 -31
  244. data/features/thinking_sphinx/db/fixtures/dogs.rb +0 -3
  245. data/features/thinking_sphinx/db/fixtures/extensible_betas.rb +0 -10
  246. data/features/thinking_sphinx/db/fixtures/foxes.rb +0 -3
  247. data/features/thinking_sphinx/db/fixtures/gammas.rb +0 -10
  248. data/features/thinking_sphinx/db/fixtures/music.rb +0 -4
  249. data/features/thinking_sphinx/db/fixtures/people.rb +0 -1001
  250. data/features/thinking_sphinx/db/fixtures/post_keywords.txt +0 -1
  251. data/features/thinking_sphinx/db/fixtures/posts.rb +0 -10
  252. data/features/thinking_sphinx/db/fixtures/robots.rb +0 -8
  253. data/features/thinking_sphinx/db/fixtures/tags.rb +0 -27
  254. data/features/thinking_sphinx/db/migrations/create_alphas.rb +0 -8
  255. data/features/thinking_sphinx/db/migrations/create_animals.rb +0 -5
  256. data/features/thinking_sphinx/db/migrations/create_authors.rb +0 -3
  257. data/features/thinking_sphinx/db/migrations/create_authors_posts.rb +0 -6
  258. data/features/thinking_sphinx/db/migrations/create_betas.rb +0 -5
  259. data/features/thinking_sphinx/db/migrations/create_boxes.rb +0 -5
  260. data/features/thinking_sphinx/db/migrations/create_categories.rb +0 -3
  261. data/features/thinking_sphinx/db/migrations/create_comments.rb +0 -10
  262. data/features/thinking_sphinx/db/migrations/create_developers.rb +0 -7
  263. data/features/thinking_sphinx/db/migrations/create_extensible_betas.rb +0 -5
  264. data/features/thinking_sphinx/db/migrations/create_gammas.rb +0 -3
  265. data/features/thinking_sphinx/db/migrations/create_genres.rb +0 -3
  266. data/features/thinking_sphinx/db/migrations/create_music.rb +0 -6
  267. data/features/thinking_sphinx/db/migrations/create_people.rb +0 -13
  268. data/features/thinking_sphinx/db/migrations/create_posts.rb +0 -6
  269. data/features/thinking_sphinx/db/migrations/create_robots.rb +0 -4
  270. data/features/thinking_sphinx/db/migrations/create_taggings.rb +0 -5
  271. data/features/thinking_sphinx/db/migrations/create_tags.rb +0 -4
  272. data/features/thinking_sphinx/models/alpha.rb +0 -23
  273. data/features/thinking_sphinx/models/andrew.rb +0 -17
  274. data/features/thinking_sphinx/models/animal.rb +0 -5
  275. data/features/thinking_sphinx/models/author.rb +0 -3
  276. data/features/thinking_sphinx/models/beta.rb +0 -13
  277. data/features/thinking_sphinx/models/box.rb +0 -8
  278. data/features/thinking_sphinx/models/cat.rb +0 -3
  279. data/features/thinking_sphinx/models/category.rb +0 -4
  280. data/features/thinking_sphinx/models/comment.rb +0 -10
  281. data/features/thinking_sphinx/models/developer.rb +0 -21
  282. data/features/thinking_sphinx/models/dog.rb +0 -3
  283. data/features/thinking_sphinx/models/extensible_beta.rb +0 -9
  284. data/features/thinking_sphinx/models/fox.rb +0 -5
  285. data/features/thinking_sphinx/models/gamma.rb +0 -5
  286. data/features/thinking_sphinx/models/genre.rb +0 -3
  287. data/features/thinking_sphinx/models/medium.rb +0 -5
  288. data/features/thinking_sphinx/models/music.rb +0 -10
  289. data/features/thinking_sphinx/models/person.rb +0 -24
  290. data/features/thinking_sphinx/models/post.rb +0 -22
  291. data/features/thinking_sphinx/models/robot.rb +0 -12
  292. data/features/thinking_sphinx/models/tag.rb +0 -3
  293. data/lib/cucumber/thinking_sphinx/external_world.rb +0 -12
  294. data/lib/cucumber/thinking_sphinx/internal_world.rb +0 -137
  295. data/lib/cucumber/thinking_sphinx/sql_logger.rb +0 -28
  296. data/lib/thinking_sphinx/action_controller.rb +0 -31
  297. data/lib/thinking_sphinx/active_record/attribute_updates.rb +0 -54
  298. data/lib/thinking_sphinx/active_record/collection_proxy.rb +0 -47
  299. data/lib/thinking_sphinx/active_record/collection_proxy_with_scopes.rb +0 -27
  300. data/lib/thinking_sphinx/active_record/delta.rb +0 -67
  301. data/lib/thinking_sphinx/active_record/has_many_association.rb +0 -44
  302. data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +0 -21
  303. data/lib/thinking_sphinx/active_record/scopes.rb +0 -110
  304. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +0 -94
  305. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +0 -62
  306. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +0 -188
  307. data/lib/thinking_sphinx/association.rb +0 -230
  308. data/lib/thinking_sphinx/attribute.rb +0 -405
  309. data/lib/thinking_sphinx/auto_version.rb +0 -40
  310. data/lib/thinking_sphinx/bundled_search.rb +0 -40
  311. data/lib/thinking_sphinx/class_facet.rb +0 -20
  312. data/lib/thinking_sphinx/connection.rb +0 -71
  313. data/lib/thinking_sphinx/context.rb +0 -81
  314. data/lib/thinking_sphinx/core/string.rb +0 -15
  315. data/lib/thinking_sphinx/deltas/delete_job.rb +0 -16
  316. data/lib/thinking_sphinx/deltas/index_job.rb +0 -17
  317. data/lib/thinking_sphinx/deploy/capistrano.rb +0 -99
  318. data/lib/thinking_sphinx/field.rb +0 -98
  319. data/lib/thinking_sphinx/index/builder.rb +0 -315
  320. data/lib/thinking_sphinx/index/faux_column.rb +0 -118
  321. data/lib/thinking_sphinx/join.rb +0 -37
  322. data/lib/thinking_sphinx/property.rb +0 -187
  323. data/lib/thinking_sphinx/search_methods.rb +0 -439
  324. data/lib/thinking_sphinx/sinatra.rb +0 -7
  325. data/lib/thinking_sphinx/source.rb +0 -194
  326. data/lib/thinking_sphinx/source/internal_properties.rb +0 -51
  327. data/lib/thinking_sphinx/source/sql.rb +0 -174
  328. data/spec/fixtures/data.sql +0 -32
  329. data/spec/fixtures/database.yml.default +0 -3
  330. data/spec/fixtures/models.rb +0 -164
  331. data/spec/fixtures/structure.sql +0 -146
  332. data/spec/sphinx_helper.rb +0 -60
  333. data/spec/support/rails.rb +0 -25
  334. data/spec/thinking_sphinx/active_record/delta_spec.rb +0 -123
  335. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +0 -173
  336. data/spec/thinking_sphinx/active_record/scopes_spec.rb +0 -177
  337. data/spec/thinking_sphinx/active_record_spec.rb +0 -573
  338. data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +0 -163
  339. data/spec/thinking_sphinx/association_spec.rb +0 -250
  340. data/spec/thinking_sphinx/attribute_spec.rb +0 -552
  341. data/spec/thinking_sphinx/auto_version_spec.rb +0 -103
  342. data/spec/thinking_sphinx/connection_spec.rb +0 -77
  343. data/spec/thinking_sphinx/context_spec.rb +0 -127
  344. data/spec/thinking_sphinx/core/array_spec.rb +0 -9
  345. data/spec/thinking_sphinx/core/string_spec.rb +0 -9
  346. data/spec/thinking_sphinx/facet_spec.rb +0 -359
  347. data/spec/thinking_sphinx/field_spec.rb +0 -127
  348. data/spec/thinking_sphinx/index/builder_spec.rb +0 -532
  349. data/spec/thinking_sphinx/index/faux_column_spec.rb +0 -36
  350. data/spec/thinking_sphinx/search_methods_spec.rb +0 -156
  351. data/spec/thinking_sphinx/source_spec.rb +0 -267
  352. data/spec/thinking_sphinx/test_spec.rb +0 -20
@@ -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