mongoid 7.5.4 → 8.1.7

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 (442) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -3
  3. data/README.md +6 -6
  4. data/Rakefile +44 -46
  5. data/lib/config/locales/en.yml +92 -43
  6. data/lib/mongoid/association/accessors.rb +44 -11
  7. data/lib/mongoid/association/bindable.rb +50 -2
  8. data/lib/mongoid/association/builders.rb +5 -3
  9. data/lib/mongoid/association/constrainable.rb +0 -1
  10. data/lib/mongoid/association/eager_loadable.rb +29 -7
  11. data/lib/mongoid/association/embedded/batchable.rb +34 -11
  12. data/lib/mongoid/association/embedded/cyclic.rb +1 -1
  13. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  14. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
  15. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +4 -3
  16. data/lib/mongoid/association/embedded/embedded_in.rb +3 -2
  17. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  18. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +4 -3
  19. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +85 -46
  20. data/lib/mongoid/association/embedded/embeds_many.rb +2 -2
  21. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +19 -5
  22. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +24 -5
  23. data/lib/mongoid/association/embedded/embeds_one.rb +3 -3
  24. data/lib/mongoid/association/macros.rb +8 -1
  25. data/lib/mongoid/association/many.rb +11 -7
  26. data/lib/mongoid/association/nested/many.rb +5 -4
  27. data/lib/mongoid/association/nested/nested_buildable.rb +4 -4
  28. data/lib/mongoid/association/nested/one.rb +45 -7
  29. data/lib/mongoid/association/one.rb +2 -2
  30. data/lib/mongoid/association/options.rb +9 -9
  31. data/lib/mongoid/association/proxy.rb +15 -4
  32. data/lib/mongoid/association/referenced/auto_save.rb +4 -3
  33. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  34. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  35. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +5 -6
  36. data/lib/mongoid/association/referenced/belongs_to.rb +2 -2
  37. data/lib/mongoid/association/referenced/counter_cache.rb +10 -10
  38. data/lib/mongoid/association/referenced/eager.rb +2 -2
  39. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +70 -13
  40. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +6 -3
  41. data/lib/mongoid/association/referenced/has_many/enumerable.rb +22 -30
  42. data/lib/mongoid/association/referenced/has_many/proxy.rb +40 -21
  43. data/lib/mongoid/association/referenced/has_many.rb +3 -3
  44. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  45. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +5 -5
  46. data/lib/mongoid/association/referenced/has_one/proxy.rb +9 -12
  47. data/lib/mongoid/association/referenced/has_one.rb +3 -3
  48. data/lib/mongoid/association/referenced/syncable.rb +4 -4
  49. data/lib/mongoid/association/reflections.rb +4 -4
  50. data/lib/mongoid/association/relatable.rb +44 -10
  51. data/lib/mongoid/association.rb +5 -5
  52. data/lib/mongoid/atomic/modifiers.rb +2 -2
  53. data/lib/mongoid/atomic.rb +16 -7
  54. data/lib/mongoid/attributes/dynamic.rb +4 -4
  55. data/lib/mongoid/attributes/nested.rb +6 -6
  56. data/lib/mongoid/attributes/processing.rb +37 -6
  57. data/lib/mongoid/attributes/projector.rb +2 -2
  58. data/lib/mongoid/attributes/readonly.rb +3 -3
  59. data/lib/mongoid/attributes.rb +51 -42
  60. data/lib/mongoid/changeable.rb +147 -14
  61. data/lib/mongoid/clients/options.rb +5 -1
  62. data/lib/mongoid/clients/sessions.rb +2 -14
  63. data/lib/mongoid/clients/storage_options.rb +2 -5
  64. data/lib/mongoid/clients/validators/storage.rb +3 -15
  65. data/lib/mongoid/collection_configurable.rb +58 -0
  66. data/lib/mongoid/composable.rb +2 -0
  67. data/lib/mongoid/config/defaults.rb +60 -0
  68. data/lib/mongoid/config/options.rb +3 -0
  69. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  70. data/lib/mongoid/config/validators/client.rb +6 -6
  71. data/lib/mongoid/config/validators.rb +1 -0
  72. data/lib/mongoid/config.rb +153 -18
  73. data/lib/mongoid/contextual/aggregable/memory.rb +24 -16
  74. data/lib/mongoid/contextual/aggregable/mongo.rb +5 -5
  75. data/lib/mongoid/contextual/aggregable/none.rb +1 -1
  76. data/lib/mongoid/contextual/atomic.rb +1 -1
  77. data/lib/mongoid/contextual/geo_near.rb +7 -7
  78. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  79. data/lib/mongoid/contextual/memory.rb +285 -58
  80. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  81. data/lib/mongoid/contextual/mongo.rb +540 -346
  82. data/lib/mongoid/contextual/none.rb +193 -20
  83. data/lib/mongoid/contextual/queryable.rb +1 -1
  84. data/lib/mongoid/contextual.rb +14 -2
  85. data/lib/mongoid/copyable.rb +32 -8
  86. data/lib/mongoid/criteria/findable.rb +8 -5
  87. data/lib/mongoid/criteria/includable.rb +27 -22
  88. data/lib/mongoid/criteria/marshalable.rb +10 -2
  89. data/lib/mongoid/criteria/permission.rb +1 -1
  90. data/lib/mongoid/criteria/queryable/aggregable.rb +2 -2
  91. data/lib/mongoid/criteria/queryable/extensions/array.rb +3 -16
  92. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  93. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +2 -2
  94. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  95. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  96. data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -17
  97. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -9
  98. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  99. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  100. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  101. data/lib/mongoid/criteria/queryable/extensions/set.rb +1 -1
  102. data/lib/mongoid/criteria/queryable/extensions/string.rb +4 -14
  103. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +4 -12
  104. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  105. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  106. data/lib/mongoid/criteria/queryable/key.rb +4 -4
  107. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  108. data/lib/mongoid/criteria/queryable/optional.rb +11 -17
  109. data/lib/mongoid/criteria/queryable/options.rb +2 -2
  110. data/lib/mongoid/criteria/queryable/pipeline.rb +1 -1
  111. data/lib/mongoid/criteria/queryable/selectable.rb +47 -38
  112. data/lib/mongoid/criteria/queryable/selector.rb +92 -7
  113. data/lib/mongoid/criteria/queryable/smash.rb +40 -7
  114. data/lib/mongoid/criteria/queryable.rb +12 -7
  115. data/lib/mongoid/criteria/scopable.rb +2 -2
  116. data/lib/mongoid/criteria/translator.rb +45 -0
  117. data/lib/mongoid/criteria.rb +20 -40
  118. data/lib/mongoid/deprecable.rb +37 -0
  119. data/lib/mongoid/deprecation.rb +25 -0
  120. data/lib/mongoid/document.rb +127 -35
  121. data/lib/mongoid/equality.rb +8 -8
  122. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  123. data/lib/mongoid/errors/document_not_found.rb +10 -6
  124. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  125. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  126. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  127. data/lib/mongoid/errors/invalid_config_option.rb +1 -1
  128. data/lib/mongoid/errors/invalid_dependent_strategy.rb +1 -1
  129. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  130. data/lib/mongoid/errors/invalid_field.rb +6 -2
  131. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  132. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  133. data/lib/mongoid/errors/invalid_relation.rb +1 -1
  134. data/lib/mongoid/errors/invalid_relation_option.rb +1 -1
  135. data/lib/mongoid/errors/invalid_session_use.rb +1 -1
  136. data/lib/mongoid/errors/invalid_storage_options.rb +1 -1
  137. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  138. data/lib/mongoid/errors/mongoid_error.rb +3 -3
  139. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +1 -1
  140. data/lib/mongoid/errors/no_client_database.rb +1 -1
  141. data/lib/mongoid/errors/no_client_hosts.rb +1 -1
  142. data/lib/mongoid/errors/readonly_attribute.rb +1 -1
  143. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  144. data/lib/mongoid/errors/unknown_attribute.rb +1 -1
  145. data/lib/mongoid/errors.rb +6 -3
  146. data/lib/mongoid/extensions/array.rb +9 -7
  147. data/lib/mongoid/extensions/big_decimal.rb +33 -10
  148. data/lib/mongoid/extensions/binary.rb +42 -0
  149. data/lib/mongoid/extensions/boolean.rb +8 -2
  150. data/lib/mongoid/extensions/date.rb +26 -20
  151. data/lib/mongoid/extensions/date_time.rb +1 -1
  152. data/lib/mongoid/extensions/false_class.rb +1 -1
  153. data/lib/mongoid/extensions/float.rb +7 -4
  154. data/lib/mongoid/extensions/hash.rb +38 -9
  155. data/lib/mongoid/extensions/integer.rb +7 -4
  156. data/lib/mongoid/extensions/module.rb +1 -1
  157. data/lib/mongoid/extensions/object.rb +10 -8
  158. data/lib/mongoid/extensions/range.rb +41 -10
  159. data/lib/mongoid/extensions/regexp.rb +11 -4
  160. data/lib/mongoid/extensions/set.rb +11 -4
  161. data/lib/mongoid/extensions/string.rb +11 -22
  162. data/lib/mongoid/extensions/symbol.rb +4 -15
  163. data/lib/mongoid/extensions/time.rb +29 -16
  164. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  165. data/lib/mongoid/extensions/true_class.rb +1 -1
  166. data/lib/mongoid/extensions.rb +1 -0
  167. data/lib/mongoid/factory.rb +55 -7
  168. data/lib/mongoid/fields/foreign_key.rb +11 -4
  169. data/lib/mongoid/fields/localized.rb +19 -4
  170. data/lib/mongoid/fields/standard.rb +17 -7
  171. data/lib/mongoid/fields/validators/macro.rb +3 -9
  172. data/lib/mongoid/fields.rb +142 -28
  173. data/lib/mongoid/findable.rb +54 -24
  174. data/lib/mongoid/indexable/specification.rb +2 -2
  175. data/lib/mongoid/indexable/validators/options.rb +6 -2
  176. data/lib/mongoid/interceptable.rb +186 -16
  177. data/lib/mongoid/matchable.rb +1 -1
  178. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  179. data/lib/mongoid/matcher/type.rb +1 -1
  180. data/lib/mongoid/matcher.rb +48 -14
  181. data/lib/mongoid/persistable/creatable.rb +19 -9
  182. data/lib/mongoid/persistable/deletable.rb +2 -2
  183. data/lib/mongoid/persistable/destroyable.rb +1 -1
  184. data/lib/mongoid/persistable/savable.rb +14 -2
  185. data/lib/mongoid/persistable/unsettable.rb +2 -2
  186. data/lib/mongoid/persistable/updatable.rb +69 -12
  187. data/lib/mongoid/persistable/upsertable.rb +21 -2
  188. data/lib/mongoid/persistable.rb +6 -3
  189. data/lib/mongoid/persistence_context.rb +6 -4
  190. data/lib/mongoid/query_cache.rb +13 -261
  191. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  192. data/lib/mongoid/railties/database.rake +7 -2
  193. data/lib/mongoid/reloadable.rb +10 -8
  194. data/lib/mongoid/scopable.rb +15 -13
  195. data/lib/mongoid/selectable.rb +1 -2
  196. data/lib/mongoid/serializable.rb +17 -13
  197. data/lib/mongoid/stateful.rb +57 -10
  198. data/lib/mongoid/tasks/database.rake +12 -0
  199. data/lib/mongoid/tasks/database.rb +20 -2
  200. data/lib/mongoid/threaded/lifecycle.rb +5 -5
  201. data/lib/mongoid/threaded.rb +42 -12
  202. data/lib/mongoid/timestamps/created.rb +1 -1
  203. data/lib/mongoid/timestamps/updated.rb +2 -2
  204. data/lib/mongoid/touchable.rb +3 -4
  205. data/lib/mongoid/traversable.rb +10 -5
  206. data/lib/mongoid/utils.rb +22 -0
  207. data/lib/mongoid/validatable/associated.rb +98 -17
  208. data/lib/mongoid/validatable/localizable.rb +1 -1
  209. data/lib/mongoid/validatable/macros.rb +5 -7
  210. data/lib/mongoid/validatable/presence.rb +2 -2
  211. data/lib/mongoid/validatable/uniqueness.rb +9 -8
  212. data/lib/mongoid/validatable.rb +17 -6
  213. data/lib/mongoid/version.rb +1 -1
  214. data/lib/mongoid/warnings.rb +19 -4
  215. data/lib/mongoid.rb +17 -3
  216. data/spec/config/mongoid.yml +16 -0
  217. data/spec/integration/app_spec.rb +24 -19
  218. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  219. data/spec/integration/associations/embedded_spec.rb +15 -0
  220. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  221. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  222. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  223. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +61 -0
  224. data/spec/integration/associations/has_one_spec.rb +97 -1
  225. data/spec/integration/associations/scope_option_spec.rb +1 -1
  226. data/spec/integration/callbacks_models.rb +132 -1
  227. data/spec/integration/callbacks_spec.rb +381 -4
  228. data/spec/integration/criteria/range_spec.rb +95 -1
  229. data/spec/integration/discriminator_key_spec.rb +118 -80
  230. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  231. data/spec/integration/i18n_fallbacks_spec.rb +3 -32
  232. data/spec/integration/matcher_examples_spec.rb +20 -13
  233. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  234. data/spec/integration/matcher_operator_spec.rb +3 -5
  235. data/spec/integration/persistence/range_field_spec.rb +350 -0
  236. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  237. data/spec/mongoid/association/depending_spec.rb +9 -9
  238. data/spec/mongoid/association/eager_spec.rb +2 -1
  239. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  240. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  241. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +96 -9
  242. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  243. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +290 -65
  244. data/spec/mongoid/association/embedded/embeds_many_models.rb +37 -0
  245. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +16 -0
  246. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  247. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  248. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  249. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  250. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  251. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  252. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  253. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +19 -0
  254. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  255. data/spec/mongoid/association/referenced/belongs_to_spec.rb +4 -20
  256. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +186 -229
  257. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  258. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  259. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  260. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
  261. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +215 -177
  262. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  263. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  264. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  265. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  266. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  267. data/spec/mongoid/association/syncable_spec.rb +15 -1
  268. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  269. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  270. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  271. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  272. data/spec/mongoid/attributes_spec.rb +526 -33
  273. data/spec/mongoid/changeable_spec.rb +429 -37
  274. data/spec/mongoid/clients/factory_spec.rb +23 -30
  275. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  276. data/spec/mongoid/clients_spec.rb +149 -15
  277. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  278. data/spec/mongoid/config/defaults_spec.rb +160 -0
  279. data/spec/mongoid/config_spec.rb +214 -31
  280. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  281. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  282. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  283. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  284. data/spec/mongoid/contextual/memory_spec.rb +850 -88
  285. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  286. data/spec/mongoid/contextual/mongo_spec.rb +2256 -1005
  287. data/spec/mongoid/contextual/none_spec.rb +60 -21
  288. data/spec/mongoid/copyable_spec.rb +453 -11
  289. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  290. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  291. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  292. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  293. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  294. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  295. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  296. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  297. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  298. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  299. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -69
  300. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
  301. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  302. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  303. data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -484
  304. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  305. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +469 -0
  306. data/spec/mongoid/criteria/queryable/selectable_spec.rb +78 -86
  307. data/spec/mongoid/criteria/queryable/selector_spec.rb +15 -3
  308. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  309. data/spec/mongoid/criteria_projection_spec.rb +1 -5
  310. data/spec/mongoid/criteria_spec.rb +469 -1205
  311. data/spec/mongoid/document_fields_spec.rb +173 -24
  312. data/spec/mongoid/document_spec.rb +32 -41
  313. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  314. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  315. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  316. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  317. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  318. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  319. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  320. data/spec/mongoid/extensions/array_spec.rb +16 -2
  321. data/spec/mongoid/extensions/big_decimal_spec.rb +712 -212
  322. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  323. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  324. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  325. data/spec/mongoid/extensions/date_spec.rb +71 -1
  326. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  327. data/spec/mongoid/extensions/float_spec.rb +53 -74
  328. data/spec/mongoid/extensions/hash_spec.rb +33 -3
  329. data/spec/mongoid/extensions/integer_spec.rb +50 -64
  330. data/spec/mongoid/extensions/range_spec.rb +255 -54
  331. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  332. data/spec/mongoid/extensions/set_spec.rb +106 -0
  333. data/spec/mongoid/extensions/string_spec.rb +53 -25
  334. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  335. data/spec/mongoid/extensions/time_spec.rb +639 -106
  336. data/spec/mongoid/extensions/time_with_zone_spec.rb +24 -83
  337. data/spec/mongoid/factory_spec.rb +61 -1
  338. data/spec/mongoid/fields/localized_spec.rb +80 -37
  339. data/spec/mongoid/fields_spec.rb +503 -87
  340. data/spec/mongoid/findable_spec.rb +450 -58
  341. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  342. data/spec/mongoid/indexable_spec.rb +55 -30
  343. data/spec/mongoid/interceptable_spec.rb +824 -22
  344. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  345. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  346. data/spec/mongoid/mongoizable_spec.rb +285 -0
  347. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  348. data/spec/mongoid/persistable/deletable_spec.rb +28 -8
  349. data/spec/mongoid/persistable/destroyable_spec.rb +28 -8
  350. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  351. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  352. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  353. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  354. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  355. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  356. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  357. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  358. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  359. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  360. data/spec/mongoid/persistable/upsertable_spec.rb +89 -1
  361. data/spec/mongoid/persistence_context_spec.rb +31 -57
  362. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  363. data/spec/mongoid/query_cache_spec.rb +56 -215
  364. data/spec/mongoid/reloadable_spec.rb +83 -6
  365. data/spec/mongoid/scopable_spec.rb +91 -1
  366. data/spec/mongoid/serializable_spec.rb +25 -39
  367. data/spec/mongoid/shardable_spec.rb +4 -4
  368. data/spec/mongoid/stateful_spec.rb +150 -8
  369. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  370. data/spec/mongoid/tasks/database_spec.rb +127 -0
  371. data/spec/mongoid/timestamps_spec.rb +392 -4
  372. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  373. data/spec/mongoid/touchable_spec.rb +390 -2
  374. data/spec/mongoid/touchable_spec_models.rb +14 -8
  375. data/spec/mongoid/traversable_spec.rb +13 -35
  376. data/spec/mongoid/validatable/associated_spec.rb +27 -34
  377. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  378. data/spec/mongoid/validatable/uniqueness_spec.rb +58 -31
  379. data/spec/mongoid/warnings_spec.rb +35 -0
  380. data/spec/mongoid_spec.rb +34 -16
  381. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  382. data/spec/rails/mongoid_spec.rb +4 -16
  383. data/spec/spec_helper.rb +5 -0
  384. data/spec/support/constraints.rb +24 -0
  385. data/spec/support/immutable_ids.rb +118 -0
  386. data/spec/support/macros.rb +78 -0
  387. data/spec/support/models/artist.rb +0 -1
  388. data/spec/support/models/augmentation.rb +12 -0
  389. data/spec/support/models/band.rb +5 -0
  390. data/spec/support/models/book.rb +1 -0
  391. data/spec/support/models/building.rb +2 -0
  392. data/spec/support/models/catalog.rb +24 -0
  393. data/spec/support/models/circus.rb +3 -0
  394. data/spec/support/models/cover.rb +10 -0
  395. data/spec/support/models/fanatic.rb +8 -0
  396. data/spec/support/models/implant.rb +9 -0
  397. data/spec/support/models/label.rb +2 -0
  398. data/spec/support/models/lat_lng.rb +6 -0
  399. data/spec/support/models/name.rb +10 -0
  400. data/spec/support/models/passport.rb +9 -0
  401. data/spec/support/models/person.rb +2 -0
  402. data/spec/support/models/player.rb +2 -0
  403. data/spec/support/models/powerup.rb +12 -0
  404. data/spec/support/models/product.rb +1 -0
  405. data/spec/support/models/purse.rb +9 -0
  406. data/spec/support/models/registry.rb +1 -0
  407. data/spec/support/models/school.rb +14 -0
  408. data/spec/support/models/shield.rb +18 -0
  409. data/spec/support/models/student.rb +14 -0
  410. data/spec/support/models/weapon.rb +12 -0
  411. metadata +101 -96
  412. checksums.yaml.gz.sig +0 -0
  413. data/lib/mongoid/errors/eager_load.rb +0 -23
  414. data/lib/mongoid/errors/invalid_value.rb +0 -17
  415. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  416. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
  417. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
  418. data/spec/shared/LICENSE +0 -20
  419. data/spec/shared/bin/get-mongodb-download-url +0 -17
  420. data/spec/shared/bin/s3-copy +0 -45
  421. data/spec/shared/bin/s3-upload +0 -69
  422. data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
  423. data/spec/shared/lib/mrss/cluster_config.rb +0 -231
  424. data/spec/shared/lib/mrss/constraints.rb +0 -378
  425. data/spec/shared/lib/mrss/docker_runner.rb +0 -291
  426. data/spec/shared/lib/mrss/eg_config_utils.rb +0 -51
  427. data/spec/shared/lib/mrss/event_subscriber.rb +0 -210
  428. data/spec/shared/lib/mrss/lite_constraints.rb +0 -238
  429. data/spec/shared/lib/mrss/server_version_registry.rb +0 -120
  430. data/spec/shared/lib/mrss/session_registry.rb +0 -69
  431. data/spec/shared/lib/mrss/session_registry_legacy.rb +0 -60
  432. data/spec/shared/lib/mrss/spec_organizer.rb +0 -179
  433. data/spec/shared/lib/mrss/utils.rb +0 -15
  434. data/spec/shared/share/Dockerfile.erb +0 -325
  435. data/spec/shared/share/haproxy-1.conf +0 -16
  436. data/spec/shared/share/haproxy-2.conf +0 -17
  437. data/spec/shared/shlib/config.sh +0 -27
  438. data/spec/shared/shlib/distro.sh +0 -74
  439. data/spec/shared/shlib/server.sh +0 -392
  440. data/spec/shared/shlib/set_env.sh +0 -169
  441. data.tar.gz.sig +0 -0
  442. metadata.gz.sig +0 -3
@@ -25,7 +25,7 @@ module Mongoid
25
25
  #
26
26
  # @param [ Array ] other The other array.
27
27
  #
28
- # @return [ true, false ] If the objects are equal.
28
+ # @return [ true | false ] If the objects are equal.
29
29
  def ==(other)
30
30
  return false unless other.respond_to?(:entries)
31
31
  entries == other.entries
@@ -74,7 +74,7 @@ module Mongoid
74
74
  # @example Get the distinct values.
75
75
  # context.distinct(:name)
76
76
  #
77
- # @param [ String, Symbol ] field The name of the field.
77
+ # @param [ String | Symbol ] field The name of the field.
78
78
  #
79
79
  # @return [ Array<Object> ] The distinct values for the field.
80
80
  def distinct(field)
@@ -110,9 +110,24 @@ module Mongoid
110
110
  # @example Do any documents exist for the context.
111
111
  # context.exists?
112
112
  #
113
- # @return [ true, false ] If the count is more than zero.
114
- def exists?
115
- count > 0
113
+ # @example Do any documents exist for given _id.
114
+ # context.exists?(BSON::ObjectId(...))
115
+ #
116
+ # @example Do any documents exist for given conditions.
117
+ # context.exists?(name: "...")
118
+ #
119
+ # @param [ Hash | Object | false ] id_or_conditions an _id to
120
+ # search for, a hash of conditions, nil or false.
121
+ #
122
+ # @return [ true | false ] If the count is more than zero.
123
+ # Always false if passed nil or false.
124
+ def exists?(id_or_conditions = :none)
125
+ case id_or_conditions
126
+ when :none then any?
127
+ when nil, false then false
128
+ when Hash then Memory.new(criteria.where(id_or_conditions)).exists?
129
+ else Memory.new(criteria.where(_id: id_or_conditions)).exists?
130
+ end
116
131
  end
117
132
 
118
133
  # Get the first document in the database for the criteria's selector.
@@ -120,20 +135,33 @@ module Mongoid
120
135
  # @example Get the first document.
121
136
  # context.first
122
137
  #
123
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
124
- # return, or a hash of options.
138
+ # @param [ Integer ] limit The number of documents to return.
125
139
  #
126
140
  # @return [ Document ] The first document.
127
- def first(limit_or_opts = nil)
128
- if limit_or_opts.nil? || limit_or_opts.is_a?(Hash)
129
- eager_load([documents.first]).first
141
+ def first(limit = nil)
142
+ if limit
143
+ eager_load(documents.first(limit))
130
144
  else
131
- eager_load(documents.first(limit_or_opts))
145
+ eager_load([documents.first]).first
132
146
  end
133
147
  end
134
148
  alias :one :first
135
149
  alias :find_first :first
136
150
 
151
+ # Get the first document in the database for the criteria's selector or
152
+ # raise an error if none is found.
153
+ #
154
+ # @example Get the first document.
155
+ # context.first!
156
+ #
157
+ # @return [ Document ] The first document.
158
+ #
159
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
160
+ # documents to take.
161
+ def first!
162
+ first || raise_document_not_found_error
163
+ end
164
+
137
165
  # Create the new in memory context.
138
166
  #
139
167
  # @example Create the new context.
@@ -170,52 +198,29 @@ module Mongoid
170
198
  # @example Get the last document.
171
199
  # context.last
172
200
  #
173
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
174
- # return, or a hash of options.
175
- #
176
- # @option limit_or_opts [ :none ] :id_sort This option is deprecated.
177
- # Don't apply a sort on _id if no other sort is defined on the criteria.
201
+ # @param [ Integer ] limit The number of documents to return.
178
202
  #
179
203
  # @return [ Document ] The last document.
180
- def last(limit_or_opts = nil)
181
- if limit_or_opts.nil? || limit_or_opts.is_a?(Hash)
182
- eager_load([documents.last]).first
183
- else
184
- eager_load(documents.last(limit_or_opts))
185
- end
186
- end
187
-
188
- # Take the given number of documents from the database.
189
- #
190
- # @example Take a document.
191
- # context.take
192
- #
193
- # @param [ Integer | nil ] limit The number of documents to take or nil.
194
- #
195
- # @return [ Document ] The document.
196
- def take(limit = nil)
204
+ def last(limit = nil)
197
205
  if limit
198
- eager_load(documents.take(limit))
206
+ eager_load(documents.last(limit))
199
207
  else
200
- eager_load([documents.first]).first
208
+ eager_load([documents.last]).first
201
209
  end
202
210
  end
203
211
 
204
- # Take the given number of documents from the database.
212
+ # Get the last document in the database for the criteria's selector or
213
+ # raise an error if none is found.
205
214
  #
206
- # @example Take a document.
207
- # context.take
215
+ # @example Get the last document.
216
+ # context.last!
208
217
  #
209
- # @return [ Document ] The document.
218
+ # @return [ Document ] The last document.
210
219
  #
211
220
  # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
212
221
  # documents to take.
213
- def take!
214
- if documents.empty?
215
- raise Errors::DocumentNotFound.new(klass, nil, nil)
216
- else
217
- eager_load([documents.first]).first
218
- end
222
+ def last!
223
+ last || raise_document_not_found_error
219
224
  end
220
225
 
221
226
  # Get the length of matching documents in the context.
@@ -236,28 +241,44 @@ module Mongoid
236
241
  #
237
242
  # @param [ Integer ] value The number of documents to return.
238
243
  #
239
- # @return [ Mongo ] The context.
244
+ # @return [ Memory ] The context.
240
245
  def limit(value)
241
246
  self.limiting = value
242
247
  self
243
248
  end
244
249
 
250
+ # Pluck the field values in memory.
251
+ #
252
+ # @example Get the values in memory.
253
+ # context.pluck(:name)
254
+ #
255
+ # @param [ [ String | Symbol ]... ] *fields Field(s) to pluck.
256
+ #
257
+ # @return [ Array<Object> | Array<Array<Object>> ] The plucked values.
245
258
  def pluck(*fields)
246
259
  if Mongoid.legacy_pluck_distinct
247
260
  documents.pluck(*fields)
248
261
  else
249
- documents.map do |d|
250
- if fields.length == 1
251
- retrieve_value_at_path(d, fields.first)
252
- else
253
- fields.map do |field|
254
- retrieve_value_at_path(d, field)
255
- end
256
- end
262
+ documents.map do |doc|
263
+ pluck_from_doc(doc, *fields)
257
264
  end
258
265
  end
259
266
  end
260
267
 
268
+ # Pick the field values in memory.
269
+ #
270
+ # @example Get the values in memory.
271
+ # context.pick(:name)
272
+ #
273
+ # @param [ [ String | Symbol ]... ] *fields Field(s) to pick.
274
+ #
275
+ # @return [ Object | Array<Object> ] The picked values.
276
+ def pick(*fields)
277
+ if doc = documents.first
278
+ pluck_from_doc(doc, *fields)
279
+ end
280
+ end
281
+
261
282
  # Tally the field values in memory.
262
283
  #
263
284
  # @example Get the counts of values in memory.
@@ -274,6 +295,36 @@ module Mongoid
274
295
  end
275
296
  end
276
297
 
298
+ # Take the given number of documents from the database.
299
+ #
300
+ # @example Take a document.
301
+ # context.take
302
+ #
303
+ # @param [ Integer | nil ] limit The number of documents to take or nil.
304
+ #
305
+ # @return [ Document ] The document.
306
+ def take(limit = nil)
307
+ if limit
308
+ eager_load(documents.take(limit))
309
+ else
310
+ eager_load([documents.first]).first
311
+ end
312
+ end
313
+
314
+ # Take the given number of documents from the database or raise an error
315
+ # if none are found.
316
+ #
317
+ # @example Take a document.
318
+ # context.take
319
+ #
320
+ # @return [ Document ] The document.
321
+ #
322
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
323
+ # documents to take.
324
+ def take!
325
+ take || raise_document_not_found_error
326
+ end
327
+
277
328
  # Skips the provided number of documents.
278
329
  #
279
330
  # @example Skip the documents.
@@ -281,7 +332,7 @@ module Mongoid
281
332
  #
282
333
  # @param [ Integer ] value The number of documents to skip.
283
334
  #
284
- # @return [ Mongo ] The context.
335
+ # @return [ Memory ] The context.
285
336
  def skip(value)
286
337
  self.skipping = value
287
338
  self
@@ -295,7 +346,7 @@ module Mongoid
295
346
  # @param [ Hash ] values The sorting values as field/direction(1/-1)
296
347
  # pairs.
297
348
  #
298
- # @return [ Mongo ] The context.
349
+ # @return [ Memory ] The context.
299
350
  def sort(values)
300
351
  in_place_sort(values) and self
301
352
  end
@@ -307,7 +358,7 @@ module Mongoid
307
358
  #
308
359
  # @param [ Hash ] attributes The new attributes for the document.
309
360
  #
310
- # @return [ nil, false ] False if no attributes were provided.
361
+ # @return [ nil | false ] False if no attributes were provided.
311
362
  def update(attributes = nil)
312
363
  update_documents(attributes, [ first ])
313
364
  end
@@ -319,11 +370,167 @@ module Mongoid
319
370
  #
320
371
  # @param [ Hash ] attributes The new attributes for each document.
321
372
  #
322
- # @return [ nil, false ] False if no attributes were provided.
373
+ # @return [ nil | false ] False if no attributes were provided.
323
374
  def update_all(attributes = nil)
324
375
  update_documents(attributes, entries)
325
376
  end
326
377
 
378
+ # Get the second document in the database for the criteria's selector.
379
+ #
380
+ # @example Get the second document.
381
+ # context.second
382
+ #
383
+ # @param [ Integer ] limit The number of documents to return.
384
+ #
385
+ # @return [ Document ] The second document.
386
+ def second
387
+ eager_load([documents.second]).first
388
+ end
389
+
390
+ # Get the second document in the database for the criteria's selector or
391
+ # raise an error if none is found.
392
+ #
393
+ # @example Get the second document.
394
+ # context.second!
395
+ #
396
+ # @return [ Document ] The second document.
397
+ #
398
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
399
+ # documents to take.
400
+ def second!
401
+ second || raise_document_not_found_error
402
+ end
403
+
404
+ # Get the third document in the database for the criteria's selector.
405
+ #
406
+ # @example Get the third document.
407
+ # context.third
408
+ #
409
+ # @param [ Integer ] limit The number of documents to return.
410
+ #
411
+ # @return [ Document ] The third document.
412
+ def third
413
+ eager_load([documents.third]).first
414
+ end
415
+
416
+ # Get the third document in the database for the criteria's selector or
417
+ # raise an error if none is found.
418
+ #
419
+ # @example Get the third document.
420
+ # context.third!
421
+ #
422
+ # @return [ Document ] The third document.
423
+ #
424
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
425
+ # documents to take.
426
+ def third!
427
+ third || raise_document_not_found_error
428
+ end
429
+
430
+ # Get the fourth document in the database for the criteria's selector.
431
+ #
432
+ # @example Get the fourth document.
433
+ # context.fourth
434
+ #
435
+ # @param [ Integer ] limit The number of documents to return.
436
+ #
437
+ # @return [ Document ] The fourth document.
438
+ def fourth
439
+ eager_load([documents.fourth]).first
440
+ end
441
+
442
+ # Get the fourth document in the database for the criteria's selector or
443
+ # raise an error if none is found.
444
+ #
445
+ # @example Get the fourth document.
446
+ # context.fourth!
447
+ #
448
+ # @return [ Document ] The fourth document.
449
+ #
450
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
451
+ # documents to take.
452
+ def fourth!
453
+ fourth || raise_document_not_found_error
454
+ end
455
+
456
+ # Get the fifth document in the database for the criteria's selector.
457
+ #
458
+ # @example Get the fifth document.
459
+ # context.fifth
460
+ #
461
+ # @param [ Integer ] limit The number of documents to return.
462
+ #
463
+ # @return [ Document ] The fifth document.
464
+ def fifth
465
+ eager_load([documents.fifth]).first
466
+ end
467
+
468
+ # Get the fifth document in the database for the criteria's selector or
469
+ # raise an error if none is found.
470
+ #
471
+ # @example Get the fifth document.
472
+ # context.fifth!
473
+ #
474
+ # @return [ Document ] The fifth document.
475
+ #
476
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
477
+ # documents to take.
478
+ def fifth!
479
+ fifth || raise_document_not_found_error
480
+ end
481
+
482
+ # Get the second to last document in the database for the criteria's selector.
483
+ #
484
+ # @example Get the second to last document.
485
+ # context.second_to_last
486
+ #
487
+ # @param [ Integer ] limit The number of documents to return.
488
+ #
489
+ # @return [ Document ] The second to last document.
490
+ def second_to_last
491
+ eager_load([documents.second_to_last]).first
492
+ end
493
+
494
+ # Get the second to last document in the database for the criteria's selector or
495
+ # raise an error if none is found.
496
+ #
497
+ # @example Get the second to last document.
498
+ # context.second_to_last!
499
+ #
500
+ # @return [ Document ] The second to last document.
501
+ #
502
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
503
+ # documents to take.
504
+ def second_to_last!
505
+ second_to_last || raise_document_not_found_error
506
+ end
507
+
508
+ # Get the third to last document in the database for the criteria's selector.
509
+ #
510
+ # @example Get the third to last document.
511
+ # context.third_to_last
512
+ #
513
+ # @param [ Integer ] limit The number of documents to return.
514
+ #
515
+ # @return [ Document ] The third to last document.
516
+ def third_to_last
517
+ eager_load([documents.third_to_last]).first
518
+ end
519
+
520
+ # Get the third to last document in the database for the criteria's selector or
521
+ # raise an error if none is found.
522
+ #
523
+ # @example Get the third to last document.
524
+ # context.third_to_last!
525
+ #
526
+ # @return [ Document ] The third to last document.
527
+ #
528
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
529
+ # documents to take.
530
+ def third_to_last!
531
+ third_to_last || raise_document_not_found_error
532
+ end
533
+
327
534
  private
328
535
 
329
536
  # Get the documents the context should iterate. This follows 3 rules:
@@ -546,6 +753,26 @@ module Mongoid
546
753
  retrieve_value_at_path(curr, remaining)
547
754
  end
548
755
  end
756
+
757
+ # Pluck the field values from the given document.
758
+ #
759
+ # @param [ Document ] doc The document to pluck from.
760
+ # @param [ [ String | Symbol ]... ] *fields Field(s) to pluck.
761
+ #
762
+ # @return [ Object | Array<Object> ] The plucked values.
763
+ def pluck_from_doc(doc, *fields)
764
+ if fields.length == 1
765
+ retrieve_value_at_path(doc, fields.first)
766
+ else
767
+ fields.map do |field|
768
+ retrieve_value_at_path(doc, field)
769
+ end
770
+ end
771
+ end
772
+
773
+ def raise_document_not_found_error
774
+ raise Errors::DocumentNotFound.new(klass, nil, nil)
775
+ end
549
776
  end
550
777
  end
551
778
  end
@@ -0,0 +1,177 @@
1
+ require "mongoid/association/eager_loadable"
2
+
3
+ module Mongoid
4
+ module Contextual
5
+ class Mongo
6
+ # Loads documents for the provided criteria.
7
+ #
8
+ # @api private
9
+ class DocumentsLoader
10
+ extend Forwardable
11
+ include Association::EagerLoadable
12
+
13
+ def_delegators :@future, :value!, :value, :wait!, :wait
14
+
15
+ # Returns synchronous executor to be used when async_query_executor config option
16
+ # is set to :immediate. This executor runs all operations on the current
17
+ # thread, blocking as necessary.
18
+ #
19
+ # @return [ Concurrent::ImmediateExecutor ] The executor
20
+ # to be used to execute document loading tasks.
21
+ def self.immediate_executor
22
+ @@immediate_executor ||= Concurrent::ImmediateExecutor.new
23
+ end
24
+
25
+ # Returns asynchronous executor to be used when async_query_executor config option
26
+ # is set to :global_thread_pool. This executor runs operations on background threads
27
+ # using a thread pool.
28
+ #
29
+ # @return [ Concurrent::ThreadPoolExecutor ] The executor
30
+ # to be used to execute document loading tasks.
31
+ def self.global_thread_pool_async_query_executor
32
+ create_pool = Proc.new do |concurrency|
33
+ Concurrent::ThreadPoolExecutor.new(
34
+ min_threads: 0,
35
+ max_threads: concurrency,
36
+ max_queue: concurrency * 4,
37
+ fallback_policy: :caller_runs
38
+ )
39
+ end
40
+ concurrency = Mongoid.global_executor_concurrency || 4
41
+ @@global_thread_pool_async_query_executor ||= create_pool.call(concurrency)
42
+ if @@global_thread_pool_async_query_executor.max_length != concurrency
43
+ old_pool = @@global_thread_pool_async_query_executor
44
+ @@global_thread_pool_async_query_executor = create_pool.call(concurrency)
45
+ old_pool.shutdown
46
+ end
47
+ @@global_thread_pool_async_query_executor
48
+ end
49
+
50
+ # Returns suitable executor according to Mongoid config options.
51
+ #
52
+ # @param [ String | Symbol] name The query executor name, can be either
53
+ # :immediate or :global_thread_pool. Defaulted to `async_query_executor`
54
+ # config option.
55
+ #
56
+ # @return [ Concurrent::ImmediateExecutor | Concurrent::ThreadPoolExecutor ] The executor
57
+ # to be used to execute document loading tasks.
58
+ #
59
+ # @raise [ Errors::InvalidQueryExecutor ] If an unknown name is provided.
60
+ def self.executor(name = Mongoid.async_query_executor)
61
+ case name.to_sym
62
+ when :immediate
63
+ immediate_executor
64
+ when :global_thread_pool
65
+ global_thread_pool_async_query_executor
66
+ else
67
+ raise Errors::InvalidQueryExecutor.new(name)
68
+ end
69
+ end
70
+
71
+ # @return [ Mongoid::Criteria ] Criteria that specifies which documents should
72
+ # be loaded. Exposed here because `eager_loadable?` method from
73
+ # `Association::EagerLoadable` expects this to be available.
74
+ attr_accessor :criteria
75
+
76
+ # Instantiates the document loader instance and immediately schedules
77
+ # its execution using the provided executor.
78
+ #
79
+ # @param [ Mongo::Collection::View ] view The collection view to get
80
+ # records from the database.
81
+ # @param [ Class ] klass Mongoid model class to instantiate documents.
82
+ # All records obtained from the database will be converted to an
83
+ # instance of this class, if possible.
84
+ # @param [ Mongoid::Criteria ] criteria. Criteria that specifies which
85
+ # documents should be loaded.
86
+ # @param [ Concurrent::AbstractExecutorService ] executor. Executor that
87
+ # is capable of running `Concurrent::Promises::Future` instances.
88
+ def initialize(view, klass, criteria, executor: self.class.executor)
89
+ @view = view
90
+ @klass = klass
91
+ @criteria = criteria
92
+ @mutex = Mutex.new
93
+ @state = :pending
94
+ @future = Concurrent::Promises.future_on(executor) do
95
+ start && execute
96
+ end
97
+ end
98
+
99
+ # Returns false or true whether the loader is in pending state.
100
+ #
101
+ # Pending state means that the loader execution has been scheduled,
102
+ # but has not been started yet.
103
+ #
104
+ # @return [ true | false ] true if the loader is in pending state,
105
+ # otherwise false.
106
+ def pending?
107
+ @mutex.synchronize do
108
+ @state == :pending
109
+ end
110
+ end
111
+
112
+ # Returns false or true whether the loader is in started state.
113
+ #
114
+ # Started state means that the loader execution has been started.
115
+ # Note that the loader stays in this state even after the execution
116
+ # completed (successfully or failed).
117
+ #
118
+ # @return [ true | false ] true if the loader is in started state,
119
+ # otherwise false.
120
+ def started?
121
+ @mutex.synchronize do
122
+ @state == :started
123
+ end
124
+ end
125
+
126
+ # Mark the loader as unscheduled.
127
+ #
128
+ # If the loader is marked unscheduled, it will not be executed. The only
129
+ # option to load the documents is to call `execute` method directly.
130
+ #
131
+ # Please note that if execution of a task has been already started,
132
+ # unscheduling does not have any effect.
133
+ def unschedule
134
+ @mutex.synchronize do
135
+ @state = :cancelled unless @state == :started
136
+ end
137
+ end
138
+
139
+ # Loads records specified by `@criteria` from the database, and convert
140
+ # them to Mongoid documents of `@klass` type.
141
+ #
142
+ # This method is called by the task (possibly asynchronous) scheduled
143
+ # when creating an instance of the loader. However, this method can be
144
+ # called directly, if it is desired to execute loading on the caller
145
+ # thread immediately.
146
+ #
147
+ # Calling this method does not change the state of the loader.
148
+ #
149
+ # @return [ Array<Mongoid::Document> ] Array of document loaded from
150
+ # the database.
151
+ def execute
152
+ documents = @view.map do |doc|
153
+ Factory.from_db(@klass, doc, @criteria)
154
+ end
155
+ eager_load(documents) if eager_loadable?
156
+ documents
157
+ end
158
+
159
+ private
160
+
161
+ # Mark the loader as started if possible.
162
+ #
163
+ # @return [ true | false ] Whether the state was changed to :started.
164
+ def start
165
+ @mutex.synchronize do
166
+ if @state == :pending
167
+ @state = :started
168
+ true
169
+ else
170
+ false
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end