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
@@ -0,0 +1,1492 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require_relative "./includable_spec_models.rb"
5
+
6
+ describe Mongoid::Criteria::Includable do
7
+
8
+ describe "#includes" do
9
+
10
+ let!(:person) do
11
+ Person.create!(age: 1)
12
+ end
13
+
14
+ context "when providing a name that is not a relation" do
15
+
16
+ it "raises an error" do
17
+ expect {
18
+ Person.includes(:members)
19
+ }.to raise_error(Mongoid::Errors::InvalidIncludes)
20
+ end
21
+ end
22
+
23
+ context "when providing one association" do
24
+
25
+ let!(:user) do
26
+ User.create!(posts: [ post1 ])
27
+ end
28
+
29
+ let!(:post1) do
30
+ Post.create!
31
+ end
32
+
33
+ let(:result) do
34
+ User.includes(:posts).first
35
+ end
36
+
37
+ it "executes the query" do
38
+ expect(result).to eq(user)
39
+ end
40
+
41
+ it "includes the related objects" do
42
+ expect(result.posts).to eq([ post1 ])
43
+ end
44
+ end
45
+
46
+ context "when providing a list of associations" do
47
+
48
+ let!(:user) do
49
+ User.create!(posts: [ post1 ], descriptions: [ description1 ])
50
+ end
51
+
52
+ let!(:post1) do
53
+ Post.create!
54
+ end
55
+
56
+ let!(:description1) do
57
+ Description.create!(details: 1)
58
+ end
59
+
60
+ let(:result) do
61
+ User.includes(:posts, :descriptions).first
62
+ end
63
+
64
+ it "executes the query" do
65
+ expect(result).to eq(user)
66
+ end
67
+
68
+ it "includes the related objects" do
69
+ expect(result.posts).to eq([ post1 ])
70
+ expect(result.descriptions).to eq([ description1 ])
71
+ end
72
+ end
73
+
74
+ context "when providing a nested association" do
75
+
76
+ let!(:user) do
77
+ User.create!
78
+ end
79
+
80
+ before do
81
+ p = Post.create!(alerts: [ Alert.create! ])
82
+ user.posts = [ p ]
83
+ user.save!
84
+ end
85
+
86
+ let(:result) do
87
+ User.includes(:posts => [:alerts]).first
88
+ end
89
+
90
+ it "executes the query" do
91
+ expect(result).to eq(user)
92
+ end
93
+
94
+ it "includes the related objects" do
95
+ expect(result.posts.size).to eq(1)
96
+ expect(result.posts.first.alerts.size).to eq(1)
97
+ end
98
+ end
99
+
100
+ context "when providing a deeply nested association" do
101
+
102
+ let!(:user) do
103
+ User.create!
104
+ end
105
+
106
+ let(:results) do
107
+ User.includes(:posts => [{ :alerts => :items }]).to_a
108
+ end
109
+
110
+ it "executes the query" do
111
+ expect(results.first).to eq(user)
112
+ end
113
+ end
114
+
115
+ context "when the models are inherited" do
116
+
117
+ before(:all) do
118
+ class A
119
+ include Mongoid::Document
120
+ end
121
+
122
+ class B < A
123
+ belongs_to :c
124
+ end
125
+
126
+ class C
127
+ include Mongoid::Document
128
+ has_one :b
129
+ end
130
+ end
131
+
132
+ after(:all) do
133
+ Object.send(:remove_const, :A)
134
+ Object.send(:remove_const, :B)
135
+ Object.send(:remove_const, :C)
136
+ end
137
+
138
+ context "when the includes is on the subclass" do
139
+
140
+ let!(:c_one) do
141
+ C.create!
142
+ end
143
+
144
+ let!(:c_two) do
145
+ C.create!
146
+ end
147
+
148
+ let!(:b) do
149
+ B.create!(c: c_two)
150
+ end
151
+
152
+ let!(:results) do
153
+ C.includes(:b).to_a.detect do |c|
154
+ c.id == c_two.id
155
+ end
156
+ end
157
+
158
+ it "returns the correct documents" do
159
+ expect(results).to eq(c_two)
160
+ end
161
+
162
+ it "does not query the db" do
163
+ expect_query(0) do
164
+ results.b
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ context "when the models are inherited from another one model" do
171
+
172
+ context "when the relation is a has_one" do
173
+
174
+ before(:all) do
175
+ class A
176
+ include Mongoid::Document
177
+ end
178
+
179
+ class B < A
180
+ belongs_to :d
181
+ end
182
+
183
+ class C < A
184
+ belongs_to :d
185
+ end
186
+
187
+ class D
188
+ include Mongoid::Document
189
+ has_one :b
190
+ has_one :c
191
+ end
192
+ end
193
+
194
+ after(:all) do
195
+ Object.send(:remove_const, :A)
196
+ Object.send(:remove_const, :B)
197
+ Object.send(:remove_const, :C)
198
+ Object.send(:remove_const, :D)
199
+ end
200
+
201
+ context "when the includes is on the several relations" do
202
+
203
+ let!(:d_one) do
204
+ D.create!
205
+ end
206
+
207
+ let!(:d_two) do
208
+ D.create!
209
+ end
210
+
211
+ let!(:b) do
212
+ B.create!(d: d_two)
213
+ end
214
+
215
+ let!(:c) do
216
+ C.create!(d: d_two)
217
+ end
218
+
219
+ let!(:results) do
220
+ D.includes(:b, :c).entries.detect do |d|
221
+ d.id == d_two.id
222
+ end
223
+ end
224
+
225
+ it "returns the correct documents" do
226
+ expect(results).to eq(d_two)
227
+ end
228
+
229
+ it "does not query the db on b" do
230
+ expect_query(0) do
231
+ results.b
232
+ end
233
+ end
234
+
235
+ it "does not query the db on c" do
236
+ expect_query(0) do
237
+ results.b
238
+ end
239
+ end
240
+ end
241
+ end
242
+
243
+ context "when the relation is a has_many" do
244
+
245
+ before(:all) do
246
+ class A
247
+ include Mongoid::Document
248
+ end
249
+
250
+ class B < A
251
+ belongs_to :d
252
+ end
253
+
254
+ class C < A
255
+ belongs_to :d
256
+ end
257
+
258
+ class D
259
+ include Mongoid::Document
260
+ has_many :b
261
+ has_many :c
262
+ end
263
+ end
264
+
265
+ after(:all) do
266
+ Object.send(:remove_const, :A)
267
+ Object.send(:remove_const, :B)
268
+ Object.send(:remove_const, :C)
269
+ Object.send(:remove_const, :D)
270
+ end
271
+
272
+ context "when the includes is on the several relations" do
273
+
274
+ let!(:d_one) do
275
+ D.create!
276
+ end
277
+
278
+ let!(:d_two) do
279
+ D.create!
280
+ end
281
+
282
+ let!(:bs) do
283
+ 2.times.map { B.create!(d: d_two) }
284
+ end
285
+
286
+ let!(:cs) do
287
+ 2.times.map { C.create!(d: d_two) }
288
+ end
289
+
290
+ let!(:results) do
291
+ D.includes(:b, :c).entries.detect do |d|
292
+ d.id == d_two.id
293
+ end
294
+ end
295
+
296
+ it "returns the correct documents" do
297
+ expect(results).to eq(d_two)
298
+ end
299
+
300
+ it "does not query the db on b" do
301
+ expect_query(0) do
302
+ results.b
303
+ end
304
+ end
305
+
306
+ it "does not query the db on c" do
307
+ expect_query(0) do
308
+ results.b
309
+ end
310
+ end
311
+ end
312
+ end
313
+ end
314
+
315
+ context "when including the same association multiple times" do
316
+
317
+ let(:criteria) do
318
+ Person.all.includes(:posts, :posts).includes(:posts)
319
+ end
320
+
321
+ let(:association) do
322
+ Person.reflect_on_association(:posts)
323
+ end
324
+
325
+ it "does not duplicate the association in the inclusions" do
326
+ expect(criteria.inclusions).to eq([ association ])
327
+ end
328
+ end
329
+
330
+ context "when mapping the results more than once" do
331
+
332
+ let!(:post) do
333
+ person.posts.create!(title: "one")
334
+ end
335
+
336
+ let(:criteria) do
337
+ Post.includes(:person)
338
+ end
339
+
340
+ let!(:results) do
341
+ criteria.map { |doc| doc }
342
+ criteria.map { |doc| doc }
343
+ end
344
+
345
+ it "returns the proper results" do
346
+ expect(results.first.title).to eq("one")
347
+ end
348
+ end
349
+
350
+ context "when including a belongs to relation" do
351
+
352
+ context "when the criteria is from the root" do
353
+
354
+ let!(:person_two) do
355
+ Person.create!(age: 2)
356
+ end
357
+
358
+ let!(:post_one) do
359
+ person.posts.create!(title: "one")
360
+ end
361
+
362
+ let!(:post_two) do
363
+ person_two.posts.create!(title: "two")
364
+ end
365
+
366
+ context "when calling first" do
367
+
368
+ let(:criteria) do
369
+ Post.includes(:person)
370
+ end
371
+
372
+ let!(:document) do
373
+ criteria.first
374
+ end
375
+
376
+ it "eager loads the first document" do
377
+ expect_query(0) do
378
+ expect(document.person).to eq(person)
379
+ end
380
+ end
381
+
382
+ it "returns the first document" do
383
+ expect(document).to eq(post_one)
384
+ end
385
+ end
386
+
387
+ context "when calling last" do
388
+
389
+ let!(:criteria) do
390
+ Post.asc(:_id).includes(:person)
391
+ end
392
+
393
+ let!(:document) do
394
+ criteria.last
395
+ end
396
+
397
+ it "eager loads the last document" do
398
+ expect_query(0) do
399
+ expect(document.person).to eq(person_two)
400
+ end
401
+ end
402
+
403
+ it "returns the last document" do
404
+ expect(document).to eq(post_two)
405
+ end
406
+ end
407
+ end
408
+
409
+ context "when the criteria is from an embedded relation" do
410
+
411
+ let(:peep) do
412
+ Person.create!
413
+ end
414
+
415
+ let!(:address_one) do
416
+ peep.addresses.create!(street: "rosenthaler")
417
+ end
418
+
419
+ let!(:address_two) do
420
+ peep.addresses.create!(street: "weinmeister")
421
+ end
422
+
423
+ let!(:depeche) do
424
+ Band.create!(name: "Depeche Mode")
425
+ end
426
+
427
+ let!(:tool) do
428
+ Band.create!(name: "Tool")
429
+ end
430
+
431
+ before do
432
+ address_one.band = depeche
433
+ address_two.band = tool
434
+ address_one.save!
435
+ address_two.save!
436
+ end
437
+
438
+ context "when calling first" do
439
+
440
+ let(:criteria) do
441
+ peep.reload.addresses.includes(:band)
442
+ end
443
+
444
+ let(:context) do
445
+ criteria.context
446
+ end
447
+
448
+ let!(:document) do
449
+ criteria.first
450
+ end
451
+
452
+ it "eager loads the first document" do
453
+ expect_query(0) do
454
+ expect(document.band).to eq(depeche)
455
+ end
456
+ end
457
+
458
+ it "returns the document" do
459
+ expect(document).to eq(address_one)
460
+ end
461
+ end
462
+
463
+ context "when calling last" do
464
+
465
+ let(:criteria) do
466
+ peep.reload.addresses.includes(:band)
467
+ end
468
+
469
+ let(:context) do
470
+ criteria.context
471
+ end
472
+
473
+ let!(:document) do
474
+ criteria.last
475
+ end
476
+
477
+ it "eager loads the last document" do
478
+ expect_query(0) do
479
+ expect(document.band).to eq(tool)
480
+ end
481
+ end
482
+
483
+ it "returns the document" do
484
+ expect(document).to eq(address_two)
485
+ end
486
+ end
487
+
488
+ context "when iterating all documents" do
489
+
490
+ let(:criteria) do
491
+ peep.reload.addresses.includes(:band)
492
+ end
493
+
494
+ let(:context) do
495
+ criteria.context
496
+ end
497
+
498
+ let!(:documents) do
499
+ criteria.to_a
500
+ end
501
+
502
+ it "eager loads the first document" do
503
+ expect_query(0) do
504
+ expect(documents.first.band).to eq(depeche)
505
+ end
506
+ end
507
+
508
+ it "eager loads the last document" do
509
+ expect_query(0) do
510
+ expect(documents.last.band).to eq(tool)
511
+ end
512
+ end
513
+
514
+ it "returns the documents" do
515
+ expect(documents).to eq([ address_one, address_two ])
516
+ end
517
+ end
518
+ end
519
+ end
520
+
521
+ context "when providing inclusions to the default scope" do
522
+
523
+ before do
524
+ Person.default_scope(->{ Person.includes(:posts) })
525
+ end
526
+
527
+ after do
528
+ Person.default_scoping = nil
529
+ end
530
+
531
+ let!(:post_one) do
532
+ person.posts.create!(title: "one")
533
+ end
534
+
535
+ let!(:post_two) do
536
+ person.posts.create!(title: "two")
537
+ end
538
+
539
+ context "when the criteria has no options" do
540
+
541
+ let!(:criteria) do
542
+ Person.asc(:age).all
543
+ end
544
+
545
+ let!(:documents) do
546
+ criteria.entries
547
+ end
548
+
549
+ it "returns the correct documents" do
550
+ expect(documents).to eq([ person ])
551
+ end
552
+
553
+ it "eager loads the first document" do
554
+ expect_query(0) do
555
+ expect(documents.first.posts.first).to eq(post_one)
556
+ end
557
+ end
558
+
559
+ it "eager loads the last document" do
560
+ expect_query(0) do
561
+ expect(documents.first.posts.last).to eq(post_two)
562
+ end
563
+ end
564
+
565
+ context "when executing the query twice" do
566
+
567
+ let!(:new_criteria) do
568
+ Person.where(id: person.id)
569
+ end
570
+
571
+ let!(:new_context) do
572
+ new_criteria.context
573
+ end
574
+
575
+ before do
576
+ expect(new_context).to receive(:eager_load).with([person]).once.and_call_original
577
+ end
578
+
579
+ let!(:from_db) do
580
+ new_criteria.first
581
+ end
582
+
583
+ it "does not duplicate documents in the relation" do
584
+ expect(person.posts.size).to eq(2)
585
+ end
586
+ end
587
+ end
588
+
589
+ context "when calling first on the criteria" do
590
+
591
+ let(:criteria) do
592
+ Person.asc(:age).all
593
+ end
594
+
595
+ let!(:from_db) do
596
+ criteria.first
597
+ end
598
+
599
+ it "returns the correct documents" do
600
+ expect(from_db).to eq(person)
601
+ end
602
+
603
+ it "eager loads the first document" do
604
+ expect_query(0) do
605
+ expect(from_db.posts.first).to eq(post_one)
606
+ end
607
+ end
608
+
609
+ it "eager loads the last document" do
610
+ expect_query(0) do
611
+ expect(from_db.posts.last).to eq(post_two)
612
+ end
613
+ end
614
+ end
615
+
616
+ context "when calling last on the criteria" do
617
+
618
+ let(:criteria) do
619
+ Person.asc(:age).all
620
+ end
621
+
622
+ let!(:context) do
623
+ criteria.context
624
+ end
625
+
626
+ before do
627
+ expect(context).to receive(:eager_load).with([person]).once.and_call_original
628
+ end
629
+
630
+ let!(:from_db) do
631
+ criteria.last
632
+ end
633
+
634
+ it "returns the correct documents" do
635
+ expect(from_db).to eq(person)
636
+ end
637
+
638
+ it "eager loads the first document" do
639
+ expect_query(0) do
640
+ expect(from_db.posts.first).to eq(post_one)
641
+ end
642
+ end
643
+
644
+ it "eager loads the last document" do
645
+ expect_query(0) do
646
+ expect(from_db.posts.last).to eq(post_two)
647
+ end
648
+ end
649
+ end
650
+
651
+ context "when the criteria has limiting options" do
652
+
653
+ let!(:person_two) do
654
+ Person.create!
655
+ end
656
+
657
+ let!(:post_three) do
658
+ person_two.posts.create!(title: "three")
659
+ end
660
+
661
+ let!(:criteria) do
662
+ Person.asc(:age).limit(1)
663
+ end
664
+
665
+ let!(:documents) do
666
+ criteria.entries
667
+ end
668
+
669
+ it "returns the correct documents" do
670
+ expect(criteria).to eq([ person ])
671
+ end
672
+
673
+ it "eager loads the first document" do
674
+ expect_query(0) do
675
+ expect(documents.first.posts.first).to eq(post_one)
676
+ end
677
+ end
678
+
679
+ it "eager loads the second document" do
680
+ expect_query(0) do
681
+ expect(documents.first.posts.last).to eq(post_two)
682
+ end
683
+ end
684
+ end
685
+ end
686
+
687
+ context "when including a has and belongs to many" do
688
+
689
+ let!(:preference_one) do
690
+ person.preferences.create!(name: "one")
691
+ end
692
+
693
+ let!(:preference_two) do
694
+ person.preferences.create!(name: "two")
695
+ end
696
+
697
+ context "when one of the related items is deleted" do
698
+
699
+ before do
700
+ person.preferences = [ preference_one, preference_two ]
701
+ preference_two.delete
702
+ end
703
+
704
+ let(:criteria) do
705
+ Person.where(id: person.id).includes(:preferences)
706
+ end
707
+
708
+ it "only loads the existing related items" do
709
+ expect(criteria.entries.first.preferences).to eq([ preference_one ])
710
+ end
711
+ end
712
+
713
+ context "when the criteria has no options" do
714
+
715
+ let!(:criteria) do
716
+ Person.asc(:age).includes(:preferences)
717
+ end
718
+
719
+ let!(:documents) do
720
+ criteria.entries
721
+ end
722
+
723
+ it "returns the correct documents" do
724
+ expect(documents).to eq([ person ])
725
+ end
726
+
727
+ it "eager loads the first document" do
728
+ expect_query(0) do
729
+ expect(documents.first.preferences.first).to eq(preference_one)
730
+ end
731
+ end
732
+
733
+ it "eager loads the last document" do
734
+ expect_query(0) do
735
+ expect(documents.first.preferences.last).to eq(preference_two)
736
+ end
737
+ end
738
+ end
739
+
740
+ context "when calling first on the criteria" do
741
+
742
+ let!(:criteria) do
743
+ Person.asc(:age).includes(:preferences)
744
+ end
745
+
746
+ let!(:from_db) do
747
+ criteria.first
748
+ end
749
+
750
+ it "returns the correct documents" do
751
+ expect(from_db).to eq(person)
752
+ end
753
+
754
+ it "eager loads the first document" do
755
+ expect_query(0) do
756
+ expect(from_db.preferences.first).to eq(preference_one)
757
+ end
758
+ end
759
+
760
+ it "eager loads the last document" do
761
+ expect_query(0) do
762
+ expect(from_db.preferences.last).to eq(preference_two)
763
+ end
764
+ end
765
+ end
766
+
767
+ context "when calling last on the criteria" do
768
+
769
+ let!(:criteria) do
770
+ Person.asc(:age).includes(:preferences)
771
+ end
772
+
773
+ let!(:from_db) do
774
+ criteria.last
775
+ end
776
+
777
+ it "returns the correct documents" do
778
+ expect(from_db).to eq(person)
779
+ end
780
+
781
+ it "eager loads the first document" do
782
+ expect_query(0) do
783
+ expect(from_db.preferences.first).to eq(preference_one)
784
+ end
785
+ end
786
+
787
+ it "eager loads the last document" do
788
+ expect_query(0) do
789
+ expect(from_db.preferences.last).to eq(preference_two)
790
+ end
791
+ end
792
+ end
793
+ end
794
+
795
+ context "when including a has many" do
796
+
797
+ let!(:post_one) do
798
+ person.posts.create!(title: "one")
799
+ end
800
+
801
+ let!(:post_two) do
802
+ person.posts.create!(title: "two")
803
+ end
804
+
805
+ context "when the criteria has no options" do
806
+
807
+ let!(:criteria) do
808
+ Person.asc(:age).includes(:posts)
809
+ end
810
+
811
+ let!(:documents) do
812
+ criteria.entries
813
+ end
814
+
815
+ it "returns the correct documents" do
816
+ expect(documents).to eq([ person ])
817
+ end
818
+
819
+ it "eager loads the first document" do
820
+ expect_query(0) do
821
+ expect(documents.first.posts.first).to eq(post_one)
822
+ end
823
+ end
824
+
825
+ it "eager loads the last document" do
826
+ expect_query(0) do
827
+ expect(documents.first.posts.last).to eq(post_two)
828
+ end
829
+ end
830
+ end
831
+
832
+ context "when calling first on the criteria" do
833
+
834
+ let!(:criteria) do
835
+ Person.asc(:age).includes(:posts)
836
+ end
837
+
838
+ let!(:from_db) do
839
+ criteria.first
840
+ end
841
+
842
+ it "returns the correct documents" do
843
+ expect(from_db).to eq(person)
844
+ end
845
+
846
+ context "when subsequently getting all documents" do
847
+
848
+ let!(:documents) do
849
+ criteria.entries
850
+ end
851
+
852
+ it "returns the correct documents" do
853
+ expect(documents).to eq([ person ])
854
+ end
855
+ end
856
+ end
857
+
858
+ context "when calling last on the criteria" do
859
+
860
+ let!(:criteria) do
861
+ Person.asc(:age).includes(:posts)
862
+ end
863
+
864
+ let!(:from_db) do
865
+ criteria.last
866
+ end
867
+
868
+ it "returns the correct documents" do
869
+ expect(from_db).to eq(person)
870
+ end
871
+
872
+ context "when subsequently getting all documents" do
873
+
874
+ let!(:documents) do
875
+ criteria.entries
876
+ end
877
+
878
+ it "returns the correct documents" do
879
+ expect(documents).to eq([ person ])
880
+ end
881
+ end
882
+ end
883
+
884
+ context "when the criteria has limiting options" do
885
+
886
+ let!(:person_two) do
887
+ Person.create!
888
+ end
889
+
890
+ let!(:post_three) do
891
+ person_two.posts.create!(title: "three")
892
+ end
893
+
894
+ let!(:criteria) do
895
+ Person.includes(:posts).asc(:age).limit(1)
896
+ end
897
+
898
+ let(:context) do
899
+ criteria.context
900
+ end
901
+
902
+ before do
903
+ expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
904
+ end
905
+
906
+ let!(:documents) do
907
+ criteria.entries
908
+ end
909
+
910
+ it "returns the correct documents" do
911
+ expect(documents).to eq([ person ])
912
+ end
913
+ end
914
+ end
915
+
916
+ context "when including a has one" do
917
+
918
+ let!(:game_one) do
919
+ person.create_game(name: "one")
920
+ end
921
+
922
+ let!(:game_two) do
923
+ person.create_game(name: "two")
924
+ end
925
+
926
+ context "when the criteria has no options" do
927
+
928
+ let!(:criteria) do
929
+ Person.asc(:age).includes(:game)
930
+ end
931
+
932
+ let(:context) do
933
+ criteria.context
934
+ end
935
+
936
+ before do
937
+ expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
938
+ end
939
+
940
+ let!(:documents) do
941
+ criteria.entries
942
+ end
943
+
944
+ it "returns the correct documents" do
945
+ expect(documents).to eq([ person ])
946
+ end
947
+ end
948
+
949
+ context "when the criteria has limiting options" do
950
+
951
+ let!(:person_two) do
952
+ Person.create!(age: 2)
953
+ end
954
+
955
+ let!(:game_three) do
956
+ person_two.create_game(name: "Skyrim")
957
+ end
958
+
959
+ let!(:criteria) do
960
+ Person.where(id: person.id).includes(:game).asc(:age).limit(1)
961
+ end
962
+
963
+ let(:context) do
964
+ criteria.context
965
+ end
966
+
967
+ before do
968
+ expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
969
+ end
970
+
971
+ let!(:documents) do
972
+ criteria.entries
973
+ end
974
+
975
+ it "returns the correct documents" do
976
+ expect(documents).to eq([ person ])
977
+ end
978
+ end
979
+ end
980
+
981
+ context "when including a belongs to" do
982
+
983
+ let(:person_two) do
984
+ Person.create!(age: 2)
985
+ end
986
+
987
+ let!(:game_one) do
988
+ person.create_game(name: "one")
989
+ end
990
+
991
+ let!(:game_two) do
992
+ person_two.create_game(name: "two")
993
+ end
994
+
995
+ context "when providing no options" do
996
+
997
+ let!(:criteria) do
998
+ Game.includes(:person)
999
+ end
1000
+
1001
+ let(:context) do
1002
+ criteria.context
1003
+ end
1004
+
1005
+ before do
1006
+ expect(context).to receive(:preload).twice.and_call_original
1007
+ end
1008
+
1009
+ let!(:documents) do
1010
+ criteria.entries
1011
+ end
1012
+
1013
+ it "returns the correct documents" do
1014
+ expect(criteria).to eq([ game_one, game_two ])
1015
+ end
1016
+ end
1017
+
1018
+ context "when the criteria has limiting options" do
1019
+
1020
+ let!(:criteria) do
1021
+ Game.where(id: game_one.id).includes(:person).asc(:_id).limit(1)
1022
+ end
1023
+
1024
+ let(:context) do
1025
+ criteria.context
1026
+ end
1027
+
1028
+ before do
1029
+ expect(context).to receive(:eager_load).with([ game_one ]).once.and_call_original
1030
+ end
1031
+
1032
+ let!(:documents) do
1033
+ criteria.entries
1034
+ end
1035
+
1036
+ it "returns the correct documents" do
1037
+ expect(documents).to eq([ game_one ])
1038
+ end
1039
+ end
1040
+ end
1041
+
1042
+ context "when including multiples in the same criteria" do
1043
+
1044
+ let!(:post_one) do
1045
+ person.posts.create!(title: "one")
1046
+ end
1047
+
1048
+ let!(:post_two) do
1049
+ person.posts.create!(title: "two")
1050
+ end
1051
+
1052
+ let!(:game_one) do
1053
+ person.create_game(name: "one")
1054
+ end
1055
+
1056
+ let!(:game_two) do
1057
+ person.create_game(name: "two")
1058
+ end
1059
+
1060
+ let!(:criteria) do
1061
+ Person.includes(:posts, :game).asc(:age)
1062
+ end
1063
+
1064
+ let(:context) do
1065
+ criteria.context
1066
+ end
1067
+
1068
+ before do
1069
+ expect(context).to receive(:preload).twice.and_call_original
1070
+ end
1071
+
1072
+ let!(:documents) do
1073
+ criteria.entries
1074
+ end
1075
+
1076
+ it "returns the correct documents" do
1077
+ expect(criteria).to eq([ person ])
1078
+ end
1079
+ end
1080
+
1081
+ context "when including nested referenced associations" do
1082
+
1083
+ context "when using a has_one association" do
1084
+ before(:all) do
1085
+ class A
1086
+ include Mongoid::Document
1087
+ has_one :b
1088
+ end
1089
+
1090
+ class B
1091
+ include Mongoid::Document
1092
+ belongs_to :a
1093
+ has_one :c
1094
+ end
1095
+
1096
+ class C
1097
+ include Mongoid::Document
1098
+ belongs_to :b
1099
+ has_one :d
1100
+ end
1101
+
1102
+ class D
1103
+ include Mongoid::Document
1104
+ belongs_to :c
1105
+ end
1106
+ end
1107
+
1108
+ after(:all) do
1109
+ Object.send(:remove_const, :A)
1110
+ Object.send(:remove_const, :B)
1111
+ Object.send(:remove_const, :C)
1112
+ Object.send(:remove_const, :D)
1113
+ end
1114
+
1115
+ let!(:a) do
1116
+ A.create!
1117
+ end
1118
+
1119
+ let!(:b) do
1120
+ B.create!
1121
+ end
1122
+
1123
+ let!(:c) do
1124
+ C.create!
1125
+ end
1126
+
1127
+ let!(:d) do
1128
+ D.create!
1129
+ end
1130
+
1131
+ before do
1132
+ c.d = d
1133
+ b.c = c
1134
+ a.b = b
1135
+ end
1136
+
1137
+ context "when including the belongs_to assocation" do
1138
+ let!(:result) do
1139
+ C.includes(b: :a).first
1140
+ end
1141
+
1142
+ it "finds the right document" do
1143
+ expect(result).to eq(c)
1144
+ expect(result.b).to eq(c.b)
1145
+ expect(result.b.a).to eq(c.b.a)
1146
+ end
1147
+
1148
+ it "does not execute a query" do
1149
+ expect_no_queries do
1150
+ result.b.a
1151
+ end
1152
+ end
1153
+ end
1154
+
1155
+ context "when including a doubly-nested belongs_to assocation" do
1156
+ let!(:result) do
1157
+ D.includes(c: { b: :a }).first
1158
+ end
1159
+
1160
+ it "finds the right document" do
1161
+ expect(result).to eq(d)
1162
+ expect(result.c).to eq(d.c)
1163
+ expect(result.c.b).to eq(d.c.b)
1164
+ expect(result.c.b.a).to eq(d.c.b.a)
1165
+ end
1166
+
1167
+ it "does not execute a query" do
1168
+ expect_no_queries do
1169
+ result.c.b.a
1170
+ end
1171
+ end
1172
+ end
1173
+
1174
+ context "when including the has_many assocation" do
1175
+ let!(:result) do
1176
+ A.includes(b: :c).first
1177
+ end
1178
+
1179
+ it "finds the right document" do
1180
+ expect(result).to eq(a)
1181
+ expect(result.b).to eq(a.b)
1182
+ expect(result.b.c).to eq(a.b.c)
1183
+ end
1184
+
1185
+ it "does not executes a query" do
1186
+ expect_no_queries do
1187
+ result.b.c
1188
+ end
1189
+ end
1190
+ end
1191
+
1192
+ context "when including a doubly-nested has_many assocation" do
1193
+ let!(:result) do
1194
+ A.includes(b: { c: :d }).first
1195
+ end
1196
+
1197
+ it "finds the right document" do
1198
+ expect(result).to eq(a)
1199
+ expect(result.b).to eq(a.b)
1200
+ expect(result.b.c).to eq(a.b.c)
1201
+ expect(result.b.c.d).to eq(a.b.c.d)
1202
+ end
1203
+
1204
+ it "does not execute a query" do
1205
+ expect_no_queries do
1206
+ result.b.c.d
1207
+ end
1208
+ end
1209
+ end
1210
+
1211
+ context "when there are multiple documents" do
1212
+ let!(:as) do
1213
+ res = 9.times.map do |i|
1214
+ A.create!.tap do |a|
1215
+ a.b = B.create!.tap do |b|
1216
+ b.c = C.create!
1217
+ end
1218
+ end
1219
+ end
1220
+ [a, *res]
1221
+ end
1222
+
1223
+ let!(:results) do
1224
+ A.includes(b: :c).entries.sort
1225
+ end
1226
+
1227
+ it "finds the right document" do
1228
+ as.length.times do |i|
1229
+ expect(as[i]).to eq(results[i])
1230
+ expect(as[i].b).to eq(results[i].b)
1231
+ expect(as[i].b.c).to eq(results[i].b.c)
1232
+ end
1233
+ end
1234
+
1235
+ it "does not execute a query" do
1236
+ expect_no_queries do
1237
+ results.each do |a|
1238
+ a.b.c
1239
+ end
1240
+ end
1241
+ end
1242
+ end
1243
+
1244
+ context "when there are multiple associations" do
1245
+ before(:all) do
1246
+ class A
1247
+ has_one :c
1248
+ end
1249
+
1250
+ class C
1251
+ belongs_to :a
1252
+ end
1253
+ end
1254
+
1255
+ let(:c2) { C.create! }
1256
+ let(:d2) { D.create! }
1257
+
1258
+ before do
1259
+ a.c = c2
1260
+ a.c.d = d2
1261
+ end
1262
+
1263
+ let!(:results) do
1264
+ A.includes(b: { c: :d }, c: :d).first
1265
+ end
1266
+
1267
+ it "finds the right document" do
1268
+ expect(results).to eq(a)
1269
+ expect(results.b).to eq(a.b)
1270
+ expect(results.b.c).to eq(a.b.c)
1271
+ expect(results.b.c.d).to eq(a.b.c.d)
1272
+ expect(results.c).to eq(a.c)
1273
+ expect(results.c.d).to eq(a.c.d)
1274
+ end
1275
+
1276
+ it "does not execute a query" do
1277
+ expect_no_queries do
1278
+ results.c.d
1279
+ results.b.c.d
1280
+ end
1281
+ end
1282
+ end
1283
+ end
1284
+ end
1285
+
1286
+ context "when using a has_many association" do
1287
+
1288
+ let!(:user) do
1289
+ IncUser.create!(posts: posts, comments: user_comments)
1290
+ end
1291
+
1292
+ let!(:posts) do
1293
+ [ IncPost.create!(comments: post_comments) ]
1294
+ end
1295
+
1296
+ let!(:user_comments) do
1297
+ 2.times.map{ IncComment.create! }
1298
+ end
1299
+
1300
+ let!(:post_comments) do
1301
+ 2.times.map{ IncComment.create! }
1302
+ end
1303
+
1304
+ context "when including the same class twice" do
1305
+ let!(:results) do
1306
+ IncPost.includes({ user: :comments }, :comments).entries.sort
1307
+ end
1308
+
1309
+ it "finds the right documents" do
1310
+ posts.length.times do |i|
1311
+ expect(posts[i]).to eq(results[i])
1312
+ expect(posts[i].user).to eq(results[i].user)
1313
+ expect(posts[i].user.comments).to eq(results[i].user.comments)
1314
+ expect(posts[i].comments).to eq(results[i].comments)
1315
+ end
1316
+ end
1317
+
1318
+ it "does not execute a query" do
1319
+ expect_no_queries do
1320
+ results.each do |res|
1321
+ res.user
1322
+ res.user.comments.to_a
1323
+ res.comments.to_a
1324
+ end
1325
+ end
1326
+ end
1327
+ end
1328
+
1329
+ context "when the association chain has a class name twice" do
1330
+ let!(:thread) { IncThread.create!(comments: user_comments) }
1331
+
1332
+ let!(:result) do
1333
+ IncThread.includes(comments: { user: { posts: :comments } }).first
1334
+ end
1335
+
1336
+ it "finds the right document" do
1337
+ expect(result).to eq(thread)
1338
+ result.comments.length.times do |i|
1339
+ c1 = result.comments[i]
1340
+ c2 = thread.comments[i]
1341
+ expect(c1).to eq(c2)
1342
+ expect(c1.user).to eq(c2.user)
1343
+ c1.user.posts.length.times do |i|
1344
+ p1 = c1.user.posts[i]
1345
+ p2 = c2.user.posts[i]
1346
+
1347
+ expect(p1).to eq(p2)
1348
+ expect(p1.comments).to eq(p2.comments)
1349
+ end
1350
+ end
1351
+ end
1352
+
1353
+ it "does not execute a query" do
1354
+ expect_no_queries do
1355
+ result.comments.each do |comment|
1356
+ comment.user.posts.each do |post|
1357
+ post.comments.to_a
1358
+ end
1359
+ end
1360
+ end
1361
+ end
1362
+ end
1363
+ end
1364
+ end
1365
+
1366
+ describe "#inclusions" do
1367
+
1368
+ let(:criteria) do
1369
+ Band.includes(:records)
1370
+ end
1371
+
1372
+ let(:association) do
1373
+ Band.relations["records"]
1374
+ end
1375
+
1376
+ it "returns the inclusions" do
1377
+ expect(criteria.inclusions).to eq([ association ])
1378
+ end
1379
+ end
1380
+
1381
+ describe "#inclusions=" do
1382
+
1383
+ let(:criteria) do
1384
+ Band.all
1385
+ end
1386
+
1387
+ let(:association) do
1388
+ Band.relations["records"]
1389
+ end
1390
+
1391
+ before do
1392
+ criteria.inclusions = [ association ]
1393
+ end
1394
+
1395
+ it "sets the inclusions" do
1396
+ expect(criteria.inclusions).to eq([ association ])
1397
+ end
1398
+ end
1399
+
1400
+ context "When multiple associations reference the same class" do
1401
+ before do
1402
+ IncBlog.create(
1403
+ posts: [
1404
+ IncBlogPost.create(author: IncAuthor.create),
1405
+ IncBlogPost.create(author: IncAuthor.create),
1406
+ IncBlogPost.create(author: IncAuthor.create),
1407
+ ],
1408
+ highlighted_post: IncBlogPost.create(author: IncAuthor.create)
1409
+ )
1410
+ end
1411
+
1412
+ let!(:result) do
1413
+ IncBlog.includes(:posts, highlighted_post: :author).first
1414
+ end
1415
+
1416
+ it "does not execute a query" do
1417
+ expect_no_queries do
1418
+ result.posts.to_a
1419
+ result.highlighted_post
1420
+ end
1421
+ end
1422
+
1423
+ it "executes a query for the non-retrieved elements" do
1424
+ expect_query(3) do
1425
+ result.posts.each do |post|
1426
+ post.author
1427
+ end
1428
+ end
1429
+ end
1430
+ end
1431
+
1432
+ context "When multiple parent_inclusions for the same association" do
1433
+ before do
1434
+ IncBlog.create(
1435
+ posts: [
1436
+ IncBlogPost.create(author: IncAuthor.create),
1437
+ IncBlogPost.create(author: IncAuthor.create),
1438
+ IncBlogPost.create(author: IncAuthor.create),
1439
+ ],
1440
+ highlighted_post: IncBlogPost.create(author: IncAuthor.create),
1441
+ pinned_post: IncBlogPost.create(author: IncAuthor.create)
1442
+ )
1443
+ end
1444
+
1445
+ let!(:result) do
1446
+ IncBlog.includes(:posts, highlighted_post: :author, pinned_post: :author).first
1447
+ end
1448
+
1449
+ it "does not execute a query" do
1450
+ expect_no_queries do
1451
+ result.posts.to_a
1452
+ result.highlighted_post
1453
+ result.pinned_post
1454
+ end
1455
+ end
1456
+
1457
+ it "executes a query for the non-retrieved elements" do
1458
+ expect_query(3) do
1459
+ result.posts.each do |post|
1460
+ post.author
1461
+ end
1462
+ end
1463
+ end
1464
+
1465
+ context "when including an association and using each twice on a criteria" do
1466
+
1467
+ let(:criteria) { IncPost.all.includes(:person) }
1468
+
1469
+ before do
1470
+ p = IncPerson.create!(name: "name")
1471
+ 4.times { IncPost.create!(person: p)}
1472
+ criteria
1473
+ expect_query(2) do
1474
+ criteria.each(&:person)
1475
+ end
1476
+ end
1477
+
1478
+ # The reason we are checking for two operations here is:
1479
+ # - The first operation gets all of the posts
1480
+ # - The second operation gets the person from the first post
1481
+ # Now, all subsequent posts should use the eager loaded person when
1482
+ # trying to retrieve their person.
1483
+ # MONGOID-3942 reported that after iterating the criteria a second time,
1484
+ # the posts would not get the eager loaded person.
1485
+ it "eager loads the criteria" do
1486
+ expect_query(2) do
1487
+ criteria.each(&:person)
1488
+ end
1489
+ end
1490
+ end
1491
+ end
1492
+ end