mongoid 9.0.11 → 9.1.1

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 (1033) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -8
  3. data/README.md +5 -11
  4. data/Rakefile +35 -38
  5. data/lib/config/locales/en.yml +60 -0
  6. data/lib/mongoid/association/accessors.rb +27 -26
  7. data/lib/mongoid/association/bindable.rb +43 -45
  8. data/lib/mongoid/association/builders.rb +18 -15
  9. data/lib/mongoid/association/constrainable.rb +3 -5
  10. data/lib/mongoid/association/depending.rb +43 -43
  11. data/lib/mongoid/association/eager.rb +56 -13
  12. data/lib/mongoid/association/eager_load/discriminated_inclusion.rb +88 -0
  13. data/lib/mongoid/association/eager_load/embedded_distributor.rb +151 -0
  14. data/lib/mongoid/association/eager_load/inclusion.rb +173 -0
  15. data/lib/mongoid/association/eager_load/inclusion_tree.rb +96 -0
  16. data/lib/mongoid/association/eager_load/lookup_pipeline.rb +121 -0
  17. data/lib/mongoid/association/eager_load/polymorphic_preloader.rb +61 -0
  18. data/lib/mongoid/association/eager_load/polymorphic_targets.rb +151 -0
  19. data/lib/mongoid/association/eager_loadable.rb +108 -23
  20. data/lib/mongoid/association/embedded/batchable.rb +28 -30
  21. data/lib/mongoid/association/embedded/cyclic.rb +8 -11
  22. data/lib/mongoid/association/embedded/eager.rb +1 -6
  23. data/lib/mongoid/association/embedded/embedded_in/binding.rb +6 -9
  24. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -3
  25. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -0
  26. data/lib/mongoid/association/embedded/embedded_in.rb +25 -22
  27. data/lib/mongoid/association/embedded/embeds_many/binding.rb +0 -2
  28. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +2 -3
  29. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +7 -2
  30. data/lib/mongoid/association/embedded/embeds_many.rb +24 -21
  31. data/lib/mongoid/association/embedded/embeds_one/binding.rb +0 -2
  32. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +2 -6
  33. data/lib/mongoid/association/embedded/embeds_one.rb +21 -18
  34. data/lib/mongoid/association/embedded.rb +0 -1
  35. data/lib/mongoid/association/macros.rb +16 -8
  36. data/lib/mongoid/association/many.rb +75 -3
  37. data/lib/mongoid/association/marshalable.rb +0 -3
  38. data/lib/mongoid/association/nested/many.rb +52 -18
  39. data/lib/mongoid/association/nested/nested_buildable.rb +20 -9
  40. data/lib/mongoid/association/nested/one.rb +10 -8
  41. data/lib/mongoid/association/nested.rb +1 -3
  42. data/lib/mongoid/association/one.rb +0 -3
  43. data/lib/mongoid/association/options.rb +25 -7
  44. data/lib/mongoid/association/referenced/auto_save.rb +0 -2
  45. data/lib/mongoid/association/referenced/belongs_to/binding.rb +11 -15
  46. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +23 -5
  47. data/lib/mongoid/association/referenced/belongs_to/eager.rb +7 -4
  48. data/lib/mongoid/association/referenced/belongs_to.rb +49 -43
  49. data/lib/mongoid/association/referenced/counter_cache.rb +7 -12
  50. data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +0 -2
  51. data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +8 -4
  52. data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +0 -3
  53. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +57 -47
  54. data/lib/mongoid/association/referenced/has_many/binding.rb +0 -2
  55. data/lib/mongoid/association/referenced/has_many/buildable.rb +11 -5
  56. data/lib/mongoid/association/referenced/has_many/eager.rb +0 -3
  57. data/lib/mongoid/association/referenced/has_many/enumerable.rb +109 -38
  58. data/lib/mongoid/association/referenced/has_many/proxy.rb +110 -7
  59. data/lib/mongoid/association/referenced/has_many.rb +30 -24
  60. data/lib/mongoid/association/referenced/has_many_through/eager.rb +99 -0
  61. data/lib/mongoid/association/referenced/has_many_through/proxy.rb +68 -0
  62. data/lib/mongoid/association/referenced/has_many_through.rb +201 -0
  63. data/lib/mongoid/association/referenced/has_one/binding.rb +0 -2
  64. data/lib/mongoid/association/referenced/has_one/buildable.rb +11 -9
  65. data/lib/mongoid/association/referenced/has_one/eager.rb +0 -3
  66. data/lib/mongoid/association/referenced/has_one.rb +27 -21
  67. data/lib/mongoid/association/referenced/has_one_through/eager.rb +65 -0
  68. data/lib/mongoid/association/referenced/has_one_through/proxy.rb +30 -0
  69. data/lib/mongoid/association/referenced/has_one_through.rb +167 -0
  70. data/lib/mongoid/association/referenced/syncable.rb +30 -34
  71. data/lib/mongoid/association/referenced.rb +2 -1
  72. data/lib/mongoid/association/reflections.rb +0 -3
  73. data/lib/mongoid/association/relatable.rb +108 -65
  74. data/lib/mongoid/association.rb +19 -15
  75. data/lib/mongoid/atomic/modifiers.rb +65 -25
  76. data/lib/mongoid/atomic/paths/embedded/many.rb +4 -7
  77. data/lib/mongoid/atomic/paths/embedded/one.rb +2 -4
  78. data/lib/mongoid/atomic/paths/embedded.rb +3 -6
  79. data/lib/mongoid/atomic/paths/root.rb +1 -4
  80. data/lib/mongoid/atomic/paths.rb +2 -3
  81. data/lib/mongoid/atomic.rb +0 -3
  82. data/lib/mongoid/attributes/dynamic.rb +6 -7
  83. data/lib/mongoid/attributes/nested.rb +8 -10
  84. data/lib/mongoid/attributes/projector.rb +7 -20
  85. data/lib/mongoid/attributes/readonly.rb +6 -11
  86. data/lib/mongoid/attributes.rb +18 -34
  87. data/lib/mongoid/cacheable.rb +24 -6
  88. data/lib/mongoid/clients/factory.rb +13 -22
  89. data/lib/mongoid/clients/options.rb +2 -5
  90. data/lib/mongoid/clients/sessions.rb +50 -60
  91. data/lib/mongoid/clients/storage_options.rb +1 -4
  92. data/lib/mongoid/clients/validators/storage.rb +2 -3
  93. data/lib/mongoid/clients/validators.rb +1 -2
  94. data/lib/mongoid/clients.rb +8 -11
  95. data/lib/mongoid/collection_configurable.rb +18 -14
  96. data/lib/mongoid/composable.rb +30 -34
  97. data/lib/mongoid/config/defaults.rb +6 -4
  98. data/lib/mongoid/config/encryption.rb +36 -21
  99. data/lib/mongoid/config/environment.rb +7 -16
  100. data/lib/mongoid/config/introspection.rb +14 -16
  101. data/lib/mongoid/config/options.rb +16 -10
  102. data/lib/mongoid/config/validators/async_query_executor.rb +3 -6
  103. data/lib/mongoid/config/validators/client.rb +12 -15
  104. data/lib/mongoid/config/validators/option.rb +3 -5
  105. data/lib/mongoid/config/validators.rb +3 -4
  106. data/lib/mongoid/config.rb +188 -47
  107. data/lib/mongoid/contextual/aggregable/memory.rb +7 -5
  108. data/lib/mongoid/contextual/aggregable/mongo.rb +20 -22
  109. data/lib/mongoid/contextual/aggregable/none.rb +2 -4
  110. data/lib/mongoid/contextual/aggregable.rb +5 -7
  111. data/lib/mongoid/contextual/atomic.rb +20 -24
  112. data/lib/mongoid/contextual/command.rb +0 -3
  113. data/lib/mongoid/contextual/map_reduce.rb +12 -16
  114. data/lib/mongoid/contextual/memory.rb +87 -69
  115. data/lib/mongoid/contextual/mongo/documents_loader.rb +2 -3
  116. data/lib/mongoid/contextual/mongo.rb +169 -85
  117. data/lib/mongoid/contextual/none.rb +9 -9
  118. data/lib/mongoid/contextual/queryable.rb +1 -4
  119. data/lib/mongoid/contextual.rb +18 -7
  120. data/lib/mongoid/copyable.rb +7 -9
  121. data/lib/mongoid/criteria/findable.rb +5 -7
  122. data/lib/mongoid/criteria/includable.rb +67 -14
  123. data/lib/mongoid/criteria/inspectable.rb +2 -5
  124. data/lib/mongoid/criteria/marshalable.rb +4 -8
  125. data/lib/mongoid/criteria/modifiable.rb +3 -11
  126. data/lib/mongoid/criteria/options.rb +0 -3
  127. data/lib/mongoid/criteria/permission.rb +34 -37
  128. data/lib/mongoid/criteria/queryable/aggregable.rb +9 -10
  129. data/lib/mongoid/criteria/queryable/expandable.rb +4 -9
  130. data/lib/mongoid/criteria/queryable/extensions/array.rb +7 -10
  131. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +3 -5
  132. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -4
  133. data/lib/mongoid/criteria/queryable/extensions/date.rb +2 -6
  134. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +3 -7
  135. data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -4
  136. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +20 -11
  137. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -11
  138. data/lib/mongoid/criteria/queryable/extensions/object.rb +7 -8
  139. data/lib/mongoid/criteria/queryable/extensions/range.rb +6 -9
  140. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +10 -12
  141. data/lib/mongoid/criteria/queryable/extensions/set.rb +4 -6
  142. data/lib/mongoid/criteria/queryable/extensions/string.rb +5 -9
  143. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +3 -7
  144. data/lib/mongoid/criteria/queryable/extensions/time.rb +2 -6
  145. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +2 -12
  146. data/lib/mongoid/criteria/queryable/extensions.rb +18 -21
  147. data/lib/mongoid/criteria/queryable/key.rb +12 -18
  148. data/lib/mongoid/criteria/queryable/macroable.rb +0 -3
  149. data/lib/mongoid/criteria/queryable/mergeable.rb +35 -39
  150. data/lib/mongoid/criteria/queryable/optional.rb +17 -18
  151. data/lib/mongoid/criteria/queryable/options.rb +20 -9
  152. data/lib/mongoid/criteria/queryable/pipeline.rb +6 -9
  153. data/lib/mongoid/criteria/queryable/selectable.rb +253 -199
  154. data/lib/mongoid/criteria/queryable/selector.rb +20 -29
  155. data/lib/mongoid/criteria/queryable/smash.rb +1 -6
  156. data/lib/mongoid/criteria/queryable/storable.rb +20 -39
  157. data/lib/mongoid/criteria/queryable.rb +25 -15
  158. data/lib/mongoid/criteria/scopable.rb +5 -11
  159. data/lib/mongoid/criteria/translator.rb +5 -8
  160. data/lib/mongoid/criteria.rb +109 -54
  161. data/lib/mongoid/deprecable.rb +45 -5
  162. data/lib/mongoid/deprecation.rb +2 -6
  163. data/lib/mongoid/document.rb +1 -1
  164. data/lib/mongoid/encryptable.rb +47 -2
  165. data/lib/mongoid/equality.rb +4 -5
  166. data/lib/mongoid/errors/ambiguous_relationship.rb +2 -5
  167. data/lib/mongoid/errors/attribute_not_loaded.rb +1 -4
  168. data/lib/mongoid/errors/callback.rb +1 -4
  169. data/lib/mongoid/errors/config_redactor.rb +43 -0
  170. data/lib/mongoid/errors/create_collection_failure.rb +8 -11
  171. data/lib/mongoid/errors/criteria_argument_required.rb +2 -5
  172. data/lib/mongoid/errors/delete_restriction.rb +1 -4
  173. data/lib/mongoid/errors/document_not_destroyed.rb +1 -4
  174. data/lib/mongoid/errors/document_not_found.rb +16 -21
  175. data/lib/mongoid/errors/drop_collection_failure.rb +7 -10
  176. data/lib/mongoid/errors/empty_config_file.rb +1 -4
  177. data/lib/mongoid/errors/immutable_attribute.rb +1 -4
  178. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +1 -4
  179. data/lib/mongoid/errors/in_memory_regexp_timeout.rb +26 -0
  180. data/lib/mongoid/errors/invalid_async_query_executor.rb +2 -5
  181. data/lib/mongoid/errors/invalid_auto_encryption_configuration.rb +2 -5
  182. data/lib/mongoid/errors/invalid_collection.rb +1 -3
  183. data/lib/mongoid/errors/invalid_config_file.rb +1 -4
  184. data/lib/mongoid/errors/invalid_config_option.rb +2 -5
  185. data/lib/mongoid/errors/invalid_dependent_strategy.rb +6 -10
  186. data/lib/mongoid/errors/invalid_discriminator_key_target.rb +2 -4
  187. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +1 -4
  188. data/lib/mongoid/errors/invalid_elem_match_operator.rb +5 -9
  189. data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +1 -4
  190. data/lib/mongoid/errors/invalid_estimated_count_scoping.rb +1 -4
  191. data/lib/mongoid/errors/invalid_expression_operator.rb +3 -7
  192. data/lib/mongoid/errors/invalid_field.rb +2 -5
  193. data/lib/mongoid/errors/invalid_field_operator.rb +5 -9
  194. data/lib/mongoid/errors/invalid_field_option.rb +2 -5
  195. data/lib/mongoid/errors/invalid_field_type.rb +1 -4
  196. data/lib/mongoid/errors/invalid_find.rb +1 -4
  197. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +1 -4
  198. data/lib/mongoid/errors/invalid_includes.rb +3 -6
  199. data/lib/mongoid/errors/invalid_index.rb +1 -4
  200. data/lib/mongoid/errors/invalid_options.rb +1 -4
  201. data/lib/mongoid/errors/invalid_path.rb +1 -4
  202. data/lib/mongoid/errors/invalid_persistence_option.rb +4 -7
  203. data/lib/mongoid/errors/invalid_query.rb +6 -11
  204. data/lib/mongoid/errors/invalid_relation.rb +10 -13
  205. data/lib/mongoid/errors/invalid_relation_option.rb +4 -7
  206. data/lib/mongoid/errors/invalid_scope.rb +1 -4
  207. data/lib/mongoid/errors/invalid_session_nesting.rb +0 -3
  208. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +2 -4
  209. data/lib/mongoid/errors/invalid_storage_options.rb +1 -4
  210. data/lib/mongoid/errors/invalid_time.rb +1 -4
  211. data/lib/mongoid/errors/invalid_transaction_nesting.rb +0 -3
  212. data/lib/mongoid/errors/inverse_not_found.rb +1 -4
  213. data/lib/mongoid/errors/mixed_client_configuration.rb +2 -5
  214. data/lib/mongoid/errors/mixed_relations.rb +1 -3
  215. data/lib/mongoid/errors/mongoid_error.rb +7 -11
  216. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +1 -4
  217. data/lib/mongoid/errors/no_client_config.rb +1 -4
  218. data/lib/mongoid/errors/no_client_database.rb +2 -5
  219. data/lib/mongoid/errors/no_client_hosts.rb +2 -5
  220. data/lib/mongoid/errors/no_clients_config.rb +1 -4
  221. data/lib/mongoid/errors/no_default_client.rb +1 -4
  222. data/lib/mongoid/errors/no_encryption_schema.rb +28 -0
  223. data/lib/mongoid/errors/no_environment.rb +1 -4
  224. data/lib/mongoid/errors/no_map_reduce_output.rb +1 -4
  225. data/lib/mongoid/errors/no_metadata.rb +1 -4
  226. data/lib/mongoid/errors/no_parent.rb +1 -4
  227. data/lib/mongoid/errors/readonly_association.rb +29 -0
  228. data/lib/mongoid/errors/readonly_attribute.rb +1 -4
  229. data/lib/mongoid/errors/readonly_document.rb +1 -4
  230. data/lib/mongoid/errors/rollback.rb +0 -2
  231. data/lib/mongoid/errors/scope_overwrite.rb +2 -4
  232. data/lib/mongoid/errors/sessions_not_supported.rb +0 -3
  233. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -3
  234. data/lib/mongoid/errors/transaction_error.rb +0 -3
  235. data/lib/mongoid/errors/transactions_not_supported.rb +0 -3
  236. data/lib/mongoid/errors/unknown_attribute.rb +1 -4
  237. data/lib/mongoid/errors/unknown_model.rb +1 -4
  238. data/lib/mongoid/errors/unregistered_class.rb +1 -1
  239. data/lib/mongoid/errors/unsaved_document.rb +1 -3
  240. data/lib/mongoid/errors/unsupported_isolation_level.rb +22 -0
  241. data/lib/mongoid/errors/unsupported_javascript.rb +1 -4
  242. data/lib/mongoid/errors/validations.rb +3 -5
  243. data/lib/mongoid/errors.rb +76 -72
  244. data/lib/mongoid/evolvable.rb +0 -3
  245. data/lib/mongoid/extensions/array.rb +5 -7
  246. data/lib/mongoid/extensions/big_decimal.rb +6 -7
  247. data/lib/mongoid/extensions/binary.rb +3 -6
  248. data/lib/mongoid/extensions/boolean.rb +4 -7
  249. data/lib/mongoid/extensions/bson_document.rb +28 -0
  250. data/lib/mongoid/extensions/date.rb +10 -14
  251. data/lib/mongoid/extensions/date_time.rb +2 -6
  252. data/lib/mongoid/extensions/decimal128.rb +1 -5
  253. data/lib/mongoid/extensions/false_class.rb +3 -5
  254. data/lib/mongoid/extensions/float.rb +5 -10
  255. data/lib/mongoid/extensions/hash.rb +5 -10
  256. data/lib/mongoid/extensions/integer.rb +5 -10
  257. data/lib/mongoid/extensions/module.rb +1 -4
  258. data/lib/mongoid/extensions/nil_class.rb +0 -1
  259. data/lib/mongoid/extensions/object.rb +9 -14
  260. data/lib/mongoid/extensions/object_id.rb +2 -6
  261. data/lib/mongoid/extensions/range.rb +14 -15
  262. data/lib/mongoid/extensions/raw_value.rb +0 -3
  263. data/lib/mongoid/extensions/regexp.rb +3 -6
  264. data/lib/mongoid/extensions/set.rb +3 -4
  265. data/lib/mongoid/extensions/string.rb +8 -12
  266. data/lib/mongoid/extensions/symbol.rb +3 -7
  267. data/lib/mongoid/extensions/time.rb +24 -26
  268. data/lib/mongoid/extensions/time_with_zone.rb +4 -7
  269. data/lib/mongoid/extensions/true_class.rb +3 -5
  270. data/lib/mongoid/extensions/vector.rb +64 -0
  271. data/lib/mongoid/extensions.rb +27 -26
  272. data/lib/mongoid/factory.rb +5 -9
  273. data/lib/mongoid/field_readable.rb +69 -0
  274. data/lib/mongoid/fields/encrypted.rb +0 -1
  275. data/lib/mongoid/fields/foreign_key.rb +9 -10
  276. data/lib/mongoid/fields/localized.rb +12 -12
  277. data/lib/mongoid/fields/standard.rb +5 -7
  278. data/lib/mongoid/fields/validators/macro.rb +23 -34
  279. data/lib/mongoid/fields/validators.rb +1 -2
  280. data/lib/mongoid/fields.rb +151 -58
  281. data/lib/mongoid/findable.rb +82 -53
  282. data/lib/mongoid/indexable/specification.rb +20 -6
  283. data/lib/mongoid/indexable/validators/options.rb +33 -40
  284. data/lib/mongoid/indexable.rb +53 -40
  285. data/lib/mongoid/inspectable.rb +4 -7
  286. data/lib/mongoid/interceptable.rb +41 -40
  287. data/lib/mongoid/loadable.rb +17 -18
  288. data/lib/mongoid/loggable.rb +4 -8
  289. data/lib/mongoid/matchable.rb +6 -3
  290. data/lib/mongoid/matcher/all.rb +2 -5
  291. data/lib/mongoid/matcher/and.rb +0 -3
  292. data/lib/mongoid/matcher/bits.rb +13 -8
  293. data/lib/mongoid/matcher/bits_all_clear.rb +1 -3
  294. data/lib/mongoid/matcher/bits_all_set.rb +1 -3
  295. data/lib/mongoid/matcher/bits_any_clear.rb +1 -3
  296. data/lib/mongoid/matcher/bits_any_set.rb +1 -3
  297. data/lib/mongoid/matcher/elem_match.rb +13 -15
  298. data/lib/mongoid/matcher/elem_match_expression.rb +0 -3
  299. data/lib/mongoid/matcher/eq.rb +0 -3
  300. data/lib/mongoid/matcher/eq_impl.rb +12 -17
  301. data/lib/mongoid/matcher/eq_impl_with_regexp.rb +4 -9
  302. data/lib/mongoid/matcher/exists.rb +1 -4
  303. data/lib/mongoid/matcher/expression.rb +5 -10
  304. data/lib/mongoid/matcher/expression_operator.rb +1 -3
  305. data/lib/mongoid/matcher/field_expression.rb +10 -13
  306. data/lib/mongoid/matcher/field_operator.rb +4 -6
  307. data/lib/mongoid/matcher/gt.rb +0 -3
  308. data/lib/mongoid/matcher/gte.rb +0 -3
  309. data/lib/mongoid/matcher/in.rb +9 -12
  310. data/lib/mongoid/matcher/lt.rb +0 -3
  311. data/lib/mongoid/matcher/lte.rb +0 -3
  312. data/lib/mongoid/matcher/mod.rb +4 -8
  313. data/lib/mongoid/matcher/ne.rb +0 -3
  314. data/lib/mongoid/matcher/nin.rb +0 -3
  315. data/lib/mongoid/matcher/nor.rb +1 -6
  316. data/lib/mongoid/matcher/not.rb +0 -3
  317. data/lib/mongoid/matcher/or.rb +0 -3
  318. data/lib/mongoid/matcher/regex.rb +9 -13
  319. data/lib/mongoid/matcher/regexp_budget.rb +372 -0
  320. data/lib/mongoid/matcher/size.rb +2 -5
  321. data/lib/mongoid/matcher/type.rb +32 -37
  322. data/lib/mongoid/matcher.rb +8 -15
  323. data/lib/mongoid/model_resolver.rb +1 -0
  324. data/lib/mongoid/persistable/creatable.rb +23 -7
  325. data/lib/mongoid/persistable/deletable.rb +6 -7
  326. data/lib/mongoid/persistable/destroyable.rb +2 -6
  327. data/lib/mongoid/persistable/incrementable.rb +1 -3
  328. data/lib/mongoid/persistable/logical.rb +3 -5
  329. data/lib/mongoid/persistable/maxable.rb +2 -4
  330. data/lib/mongoid/persistable/minable.rb +2 -4
  331. data/lib/mongoid/persistable/multipliable.rb +1 -3
  332. data/lib/mongoid/persistable/poppable.rb +2 -4
  333. data/lib/mongoid/persistable/pullable.rb +3 -5
  334. data/lib/mongoid/persistable/pushable.rb +5 -7
  335. data/lib/mongoid/persistable/renamable.rb +1 -3
  336. data/lib/mongoid/persistable/savable.rb +0 -3
  337. data/lib/mongoid/persistable/settable.rb +4 -13
  338. data/lib/mongoid/persistable/unsettable.rb +1 -3
  339. data/lib/mongoid/persistable/updatable.rb +23 -33
  340. data/lib/mongoid/persistable/upsertable.rb +8 -10
  341. data/lib/mongoid/persistable.rb +28 -27
  342. data/lib/mongoid/persistence_context.rb +69 -41
  343. data/lib/mongoid/pluckable.rb +0 -2
  344. data/lib/mongoid/positional.rb +5 -11
  345. data/lib/mongoid/railtie.rb +16 -22
  346. data/lib/mongoid/railties/console_sandbox.rb +6 -8
  347. data/lib/mongoid/railties/controller_runtime.rb +7 -11
  348. data/lib/mongoid/railties/database.rake +42 -44
  349. data/lib/mongoid/scopable.rb +23 -31
  350. data/lib/mongoid/search_indexable.rb +378 -7
  351. data/lib/mongoid/selectable.rb +1 -3
  352. data/lib/mongoid/serializable.rb +18 -12
  353. data/lib/mongoid/shardable.rb +8 -17
  354. data/lib/mongoid/stateful.rb +5 -10
  355. data/lib/mongoid/stringified_symbol.rb +5 -9
  356. data/lib/mongoid/tasks/database.rake +31 -32
  357. data/lib/mongoid/tasks/database.rb +51 -39
  358. data/lib/mongoid/tasks/encryption.rb +10 -15
  359. data/lib/mongoid/threaded/lifecycle.rb +6 -9
  360. data/lib/mongoid/threaded.rb +168 -32
  361. data/lib/mongoid/timestamps/created/short.rb +2 -3
  362. data/lib/mongoid/timestamps/created.rb +1 -2
  363. data/lib/mongoid/timestamps/short.rb +0 -1
  364. data/lib/mongoid/timestamps/timeless.rb +92 -23
  365. data/lib/mongoid/timestamps/updated/short.rb +2 -3
  366. data/lib/mongoid/timestamps/updated.rb +2 -5
  367. data/lib/mongoid/timestamps.rb +4 -6
  368. data/lib/mongoid/touchable.rb +19 -11
  369. data/lib/mongoid/traversable.rb +5 -4
  370. data/lib/mongoid/validatable/associated.rb +19 -7
  371. data/lib/mongoid/validatable/format.rb +0 -2
  372. data/lib/mongoid/validatable/length.rb +0 -2
  373. data/lib/mongoid/validatable/localizable.rb +0 -3
  374. data/lib/mongoid/validatable/macros.rb +0 -2
  375. data/lib/mongoid/validatable/numericality.rb +24 -3
  376. data/lib/mongoid/validatable/presence.rb +8 -10
  377. data/lib/mongoid/validatable/queryable.rb +0 -3
  378. data/lib/mongoid/validatable/uniqueness.rb +12 -14
  379. data/lib/mongoid/validatable.rb +15 -20
  380. data/lib/mongoid/version.rb +1 -1
  381. data/lib/mongoid/warnings.rb +10 -11
  382. data/lib/mongoid.rb +30 -34
  383. data/lib/rails/generators/mongoid/config/config_generator.rb +2 -4
  384. data/lib/rails/generators/mongoid/config/templates/mongoid.rb +4 -5
  385. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +2 -2
  386. data/lib/rails/generators/mongoid/model/model_generator.rb +5 -8
  387. data/lib/rails/generators/mongoid_generator.rb +6 -10
  388. data/lib/rails/mongoid.rb +1 -3
  389. data/spec/integration/active_job_spec.rb +1 -2
  390. data/spec/integration/app_spec.rb +149 -179
  391. data/spec/integration/associations/belongs_to_spec.rb +43 -28
  392. data/spec/integration/associations/embedded_dirty_spec.rb +0 -1
  393. data/spec/integration/associations/embedded_spec.rb +41 -43
  394. data/spec/integration/associations/embeds_many_spec.rb +46 -29
  395. data/spec/integration/associations/embeds_one_spec.rb +2 -1
  396. data/spec/integration/associations/foreign_key_spec.rb +10 -11
  397. data/spec/integration/associations/foreign_key_spec_models.rb +8 -9
  398. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +33 -15
  399. data/spec/integration/associations/has_many_spec.rb +17 -18
  400. data/spec/integration/associations/has_one_spec.rb +42 -45
  401. data/spec/integration/associations/nested_attributes_assignment_spec.rb +36 -39
  402. data/spec/integration/associations/reverse_population_spec.rb +4 -5
  403. data/spec/integration/associations/reverse_population_spec_models.rb +0 -1
  404. data/spec/integration/associations/scope_option_spec.rb +18 -20
  405. data/spec/integration/atomic/modifiers_spec.rb +72 -52
  406. data/spec/integration/bson_regexp_raw_spec.rb +2 -3
  407. data/spec/integration/caching_spec.rb +68 -0
  408. data/spec/integration/callbacks_models.rb +11 -9
  409. data/spec/integration/callbacks_spec.rb +78 -80
  410. data/spec/integration/contextual/empty_spec.rb +19 -20
  411. data/spec/integration/criteria/alias_query_spec.rb +12 -19
  412. data/spec/integration/criteria/date_field_spec.rb +1 -2
  413. data/spec/integration/criteria/default_scope_spec.rb +23 -18
  414. data/spec/integration/criteria/logical_spec.rb +18 -19
  415. data/spec/integration/criteria/range_spec.rb +77 -86
  416. data/spec/integration/criteria/raw_value_spec.rb +122 -109
  417. data/spec/integration/criteria/time_with_zone_spec.rb +33 -24
  418. data/spec/integration/discriminator_key_spec.rb +85 -85
  419. data/spec/integration/discriminator_value_spec.rb +70 -73
  420. data/spec/integration/document_spec.rb +9 -10
  421. data/spec/integration/dots_and_dollars_spec.rb +115 -120
  422. data/spec/integration/encryption_spec.rb +157 -9
  423. data/spec/integration/i18n_fallbacks_spec.rb +7 -8
  424. data/spec/integration/isolation_state_spec.rb +241 -0
  425. data/spec/integration/matcher_examples_spec.rb +145 -168
  426. data/spec/integration/matcher_operator_data/in.yml +6 -6
  427. data/spec/integration/matcher_operator_data/regex.yml +21 -0
  428. data/spec/integration/matcher_operator_spec.rb +16 -26
  429. data/spec/integration/matcher_regexp_timeout_spec.rb +215 -0
  430. data/spec/integration/matcher_spec.rb +31 -32
  431. data/spec/integration/persistence/collection_options_spec.rb +0 -2
  432. data/spec/integration/persistence/range_field_spec.rb +24 -2
  433. data/spec/integration/query_operator_guard_spec.rb +89 -0
  434. data/spec/integration/server_query_spec.rb +43 -37
  435. data/spec/integration/shardable_spec.rb +10 -11
  436. data/spec/integration/stringified_symbol_field_spec.rb +28 -43
  437. data/spec/lite_spec_helper.rb +11 -12
  438. data/spec/mongoid/association/accessors_spec.rb +197 -285
  439. data/spec/mongoid/association/auto_save_spec.rb +62 -93
  440. data/spec/mongoid/association/builders_spec.rb +121 -74
  441. data/spec/mongoid/association/constrainable_spec.rb +9 -22
  442. data/spec/mongoid/association/counter_cache_spec.rb +71 -104
  443. data/spec/mongoid/association/depending_spec.rb +166 -208
  444. data/spec/mongoid/association/eager_loadable_spec.rb +47 -0
  445. data/spec/mongoid/association/eager_spec.rb +416 -80
  446. data/spec/mongoid/association/embedded/cyclic_spec.rb +36 -48
  447. data/spec/mongoid/association/embedded/dirty_spec.rb +15 -20
  448. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +36 -54
  449. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +8 -15
  450. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +135 -175
  451. data/spec/mongoid/association/embedded/embedded_in_spec.rb +25 -127
  452. data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +9 -14
  453. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +38 -51
  454. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +1184 -1340
  455. data/spec/mongoid/association/embedded/embeds_many_models.rb +17 -17
  456. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +11 -11
  457. data/spec/mongoid/association/embedded/embeds_many_spec.rb +25 -138
  458. data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +15 -23
  459. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +18 -26
  460. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +204 -273
  461. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +0 -1
  462. data/spec/mongoid/association/embedded/embeds_one_models.rb +0 -1
  463. data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +5 -6
  464. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -143
  465. data/spec/mongoid/association/fallback_spec.rb +425 -0
  466. data/spec/mongoid/association/macros_spec.rb +239 -300
  467. data/spec/mongoid/association/nested/many_spec.rb +51 -73
  468. data/spec/mongoid/association/nested/one_spec.rb +56 -80
  469. data/spec/mongoid/association/options_spec.rb +187 -310
  470. data/spec/mongoid/association/polymorphic_spec.rb +35 -53
  471. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +55 -76
  472. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +36 -41
  473. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +98 -101
  474. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +258 -345
  475. data/spec/mongoid/association/referenced/belongs_to_models.rb +4 -3
  476. data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +3 -4
  477. data/spec/mongoid/association/referenced/belongs_to_spec.rb +91 -294
  478. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +42 -56
  479. data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +41 -32
  480. data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +36 -42
  481. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +8 -9
  482. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +819 -975
  483. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +9 -9
  484. data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +5 -6
  485. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +109 -177
  486. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +29 -43
  487. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +53 -53
  488. data/spec/mongoid/association/referenced/has_many/eager_spec.rb +137 -67
  489. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +431 -675
  490. data/spec/mongoid/association/referenced/has_many/proxy_query_spec.rb +1 -2
  491. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +318 -11
  492. data/spec/mongoid/association/referenced/has_many_models.rb +1 -2
  493. data/spec/mongoid/association/referenced/has_many_query_spec.rb +3 -4
  494. data/spec/mongoid/association/referenced/has_many_spec.rb +44 -188
  495. data/spec/mongoid/association/referenced/has_many_through/eager_spec.rb +58 -0
  496. data/spec/mongoid/association/referenced/has_many_through/proxy_spec.rb +62 -0
  497. data/spec/mongoid/association/referenced/has_many_through_spec.rb +399 -0
  498. data/spec/mongoid/association/referenced/has_one/binding_spec.rb +26 -38
  499. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +28 -29
  500. data/spec/mongoid/association/referenced/has_one/eager_spec.rb +29 -42
  501. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +270 -332
  502. data/spec/mongoid/association/referenced/has_one_models.rb +1 -2
  503. data/spec/mongoid/association/referenced/has_one_query_spec.rb +3 -4
  504. data/spec/mongoid/association/referenced/has_one_spec.rb +40 -188
  505. data/spec/mongoid/association/referenced/has_one_through/eager_spec.rb +58 -0
  506. data/spec/mongoid/association/referenced/has_one_through/proxy_spec.rb +49 -0
  507. data/spec/mongoid/association/referenced/has_one_through_spec.rb +211 -0
  508. data/spec/mongoid/association/reflections_spec.rb +14 -24
  509. data/spec/mongoid/association/syncable_spec.rb +102 -125
  510. data/spec/mongoid/association_spec.rb +47 -70
  511. data/spec/mongoid/atomic/modifiers_spec.rb +184 -197
  512. data/spec/mongoid/atomic/paths/embedded/many_spec.rb +39 -52
  513. data/spec/mongoid/atomic/paths/embedded/one_spec.rb +35 -49
  514. data/spec/mongoid/atomic/paths/root_spec.rb +9 -15
  515. data/spec/mongoid/atomic/paths_spec.rb +81 -117
  516. data/spec/mongoid/atomic_spec.rb +156 -171
  517. data/spec/mongoid/attributes/dynamic_spec.rb +5 -6
  518. data/spec/mongoid/attributes/nested_spec.rb +1461 -1693
  519. data/spec/mongoid/attributes/nested_spec_models.rb +8 -9
  520. data/spec/mongoid/attributes/projector_spec.rb +2 -6
  521. data/spec/mongoid/attributes/readonly_spec.rb +73 -97
  522. data/spec/mongoid/attributes_spec.rb +669 -826
  523. data/spec/mongoid/cacheable_spec.rb +74 -44
  524. data/spec/mongoid/changeable_spec.rb +591 -733
  525. data/spec/mongoid/clients/factory_spec.rb +122 -154
  526. data/spec/mongoid/clients/options_spec.rb +40 -59
  527. data/spec/mongoid/clients/sessions_spec.rb +25 -44
  528. data/spec/mongoid/clients/transactions_spec.rb +33 -50
  529. data/spec/mongoid/clients/transactions_spec_models.rb +3 -4
  530. data/spec/mongoid/clients_spec.rb +265 -355
  531. data/spec/mongoid/collection_configurable_spec.rb +9 -12
  532. data/spec/mongoid/composable_spec.rb +2 -9
  533. data/spec/mongoid/config/defaults_spec.rb +56 -30
  534. data/spec/mongoid/config/encryption_spec.rb +282 -57
  535. data/spec/mongoid/config/environment_spec.rb +30 -40
  536. data/spec/mongoid/config/introspection_spec.rb +42 -37
  537. data/spec/mongoid/config/options_spec.rb +14 -21
  538. data/spec/mongoid/config_spec.rb +145 -195
  539. data/spec/mongoid/contextual/aggregable/memory_spec.rb +189 -135
  540. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +4 -7
  541. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +149 -187
  542. data/spec/mongoid/contextual/aggregable/none_spec.rb +14 -16
  543. data/spec/mongoid/contextual/atomic_spec.rb +223 -271
  544. data/spec/mongoid/contextual/map_reduce_spec.rb +110 -138
  545. data/spec/mongoid/contextual/memory_spec.rb +883 -854
  546. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +12 -13
  547. data/spec/mongoid/contextual/mongo_spec.rb +1008 -1213
  548. data/spec/mongoid/contextual/none_spec.rb +54 -59
  549. data/spec/mongoid/contextual/short_circuit_spec.rb +139 -0
  550. data/spec/mongoid/copyable_spec.rb +254 -300
  551. data/spec/mongoid/copyable_spec_models.rb +0 -1
  552. data/spec/mongoid/criteria/findable_spec.rb +322 -387
  553. data/spec/mongoid/criteria/includable_spec.rb +1356 -432
  554. data/spec/mongoid/criteria/includable_spec_models.rb +16 -7
  555. data/spec/mongoid/criteria/inspectable_spec.rb +11 -14
  556. data/spec/mongoid/criteria/marshalable_spec.rb +11 -14
  557. data/spec/mongoid/criteria/modifiable_spec.rb +366 -512
  558. data/spec/mongoid/criteria/options_spec.rb +2 -7
  559. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +112 -141
  560. data/spec/mongoid/criteria/queryable/expandable_spec.rb +8 -11
  561. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +127 -184
  562. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +123 -60
  563. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +84 -117
  564. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +44 -65
  565. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +86 -108
  566. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +94 -33
  567. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +103 -138
  568. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +95 -34
  569. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +25 -38
  570. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +26 -28
  571. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +32 -54
  572. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +136 -130
  573. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +16 -24
  574. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +15 -24
  575. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +12 -19
  576. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +46 -63
  577. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +28 -42
  578. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +73 -96
  579. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +71 -92
  580. data/spec/mongoid/criteria/queryable/key_spec.rb +32 -36
  581. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +44 -49
  582. data/spec/mongoid/criteria/queryable/optional_spec.rb +373 -486
  583. data/spec/mongoid/criteria/queryable/options_spec.rb +172 -123
  584. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +65 -87
  585. data/spec/mongoid/criteria/queryable/queryable_spec.rb +41 -53
  586. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +589 -679
  587. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +7 -11
  588. data/spec/mongoid/criteria/queryable/selectable_spec.rb +807 -998
  589. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +354 -190
  590. data/spec/mongoid/criteria/queryable/selector_spec.rb +294 -390
  591. data/spec/mongoid/criteria/queryable/smash_spec.rb +6 -11
  592. data/spec/mongoid/criteria/queryable/storable_spec.rb +54 -81
  593. data/spec/mongoid/criteria/queryable_mql_spec.rb +92 -0
  594. data/spec/mongoid/criteria/scopable_spec.rb +102 -138
  595. data/spec/mongoid/criteria/translator_spec.rb +59 -60
  596. data/spec/mongoid/criteria_projection_spec.rb +81 -99
  597. data/spec/mongoid/criteria_spec.rb +937 -949
  598. data/spec/mongoid/document_fields_spec.rb +28 -30
  599. data/spec/mongoid/document_persistence_context_spec.rb +13 -15
  600. data/spec/mongoid/document_query_spec.rb +9 -12
  601. data/spec/mongoid/document_spec.rb +317 -409
  602. data/spec/mongoid/encryptable_spec.rb +61 -0
  603. data/spec/mongoid/equality_spec.rb +69 -102
  604. data/spec/mongoid/errors/ambiguous_relationship_spec.rb +8 -11
  605. data/spec/mongoid/errors/attribute_not_loaded_spec.rb +7 -10
  606. data/spec/mongoid/errors/callback_spec.rb +8 -11
  607. data/spec/mongoid/errors/config_redactor_spec.rb +112 -0
  608. data/spec/mongoid/errors/delete_restriction_spec.rb +5 -8
  609. data/spec/mongoid/errors/document_not_destroyed_spec.rb +7 -10
  610. data/spec/mongoid/errors/document_not_found_spec.rb +51 -61
  611. data/spec/mongoid/errors/invalid_collection_spec.rb +9 -13
  612. data/spec/mongoid/errors/invalid_config_file_spec.rb +8 -11
  613. data/spec/mongoid/errors/invalid_config_option_spec.rb +8 -11
  614. data/spec/mongoid/errors/invalid_field_option_spec.rb +7 -10
  615. data/spec/mongoid/errors/invalid_field_spec.rb +10 -11
  616. data/spec/mongoid/errors/invalid_field_type_spec.rb +9 -12
  617. data/spec/mongoid/errors/invalid_find_spec.rb +8 -11
  618. data/spec/mongoid/errors/invalid_includes_spec.rb +9 -13
  619. data/spec/mongoid/errors/invalid_index_spec.rb +8 -11
  620. data/spec/mongoid/errors/invalid_options_spec.rb +8 -11
  621. data/spec/mongoid/errors/invalid_path_spec.rb +7 -10
  622. data/spec/mongoid/errors/invalid_relation_spec.rb +15 -16
  623. data/spec/mongoid/errors/invalid_scope_spec.rb +8 -11
  624. data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +3 -6
  625. data/spec/mongoid/errors/invalid_storage_options_spec.rb +8 -11
  626. data/spec/mongoid/errors/invalid_time_spec.rb +8 -11
  627. data/spec/mongoid/errors/inverse_not_found_spec.rb +9 -12
  628. data/spec/mongoid/errors/mixed_client_configuration_spec.rb +40 -12
  629. data/spec/mongoid/errors/mixed_relations_spec.rb +8 -11
  630. data/spec/mongoid/errors/mongoid_error_spec.rb +21 -24
  631. data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +6 -9
  632. data/spec/mongoid/errors/no_client_config_spec.rb +7 -10
  633. data/spec/mongoid/errors/no_client_database_spec.rb +38 -12
  634. data/spec/mongoid/errors/no_client_hosts_spec.rb +35 -12
  635. data/spec/mongoid/errors/no_clients_config_spec.rb +7 -10
  636. data/spec/mongoid/errors/no_environment_spec.rb +8 -11
  637. data/spec/mongoid/errors/no_map_reduce_output_spec.rb +8 -11
  638. data/spec/mongoid/errors/no_metadata_spec.rb +7 -10
  639. data/spec/mongoid/errors/no_parent_spec.rb +7 -10
  640. data/spec/mongoid/errors/readonly_association_spec.rb +34 -0
  641. data/spec/mongoid/errors/readonly_attribute_spec.rb +7 -10
  642. data/spec/mongoid/errors/readonly_document_spec.rb +6 -9
  643. data/spec/mongoid/errors/scope_overwrite_spec.rb +9 -12
  644. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +9 -12
  645. data/spec/mongoid/errors/unknown_attribute_spec.rb +5 -8
  646. data/spec/mongoid/errors/unsaved_document_spec.rb +8 -11
  647. data/spec/mongoid/errors/unsupported_javascript_spec.rb +9 -12
  648. data/spec/mongoid/errors/validations_spec.rb +11 -14
  649. data/spec/mongoid/extensions/array_spec.rb +70 -92
  650. data/spec/mongoid/extensions/big_decimal_spec.rb +233 -313
  651. data/spec/mongoid/extensions/binary_spec.rb +21 -32
  652. data/spec/mongoid/extensions/boolean_spec.rb +52 -75
  653. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +43 -54
  654. data/spec/mongoid/extensions/date_spec.rb +26 -38
  655. data/spec/mongoid/extensions/date_time_spec.rb +22 -32
  656. data/spec/mongoid/extensions/decimal128_spec.rb +12 -18
  657. data/spec/mongoid/extensions/false_class_spec.rb +10 -17
  658. data/spec/mongoid/extensions/float_spec.rb +40 -61
  659. data/spec/mongoid/extensions/hash_spec.rb +46 -64
  660. data/spec/mongoid/extensions/integer_spec.rb +40 -61
  661. data/spec/mongoid/extensions/module_spec.rb +13 -18
  662. data/spec/mongoid/extensions/nil_class_spec.rb +2 -5
  663. data/spec/mongoid/extensions/object_id_spec.rb +159 -247
  664. data/spec/mongoid/extensions/object_spec.rb +31 -47
  665. data/spec/mongoid/extensions/range_spec.rb +112 -115
  666. data/spec/mongoid/extensions/raw_value_spec.rb +10 -12
  667. data/spec/mongoid/extensions/regexp_spec.rb +23 -36
  668. data/spec/mongoid/extensions/set_spec.rb +38 -49
  669. data/spec/mongoid/extensions/string_spec.rb +118 -167
  670. data/spec/mongoid/extensions/stringified_symbol_spec.rb +29 -43
  671. data/spec/mongoid/extensions/symbol_spec.rb +12 -20
  672. data/spec/mongoid/extensions/time_spec.rb +160 -202
  673. data/spec/mongoid/extensions/time_with_zone_spec.rb +79 -105
  674. data/spec/mongoid/extensions/true_class_spec.rb +10 -17
  675. data/spec/mongoid/extensions/vector_spec.rb +175 -0
  676. data/spec/mongoid/factory_spec.rb +125 -148
  677. data/spec/mongoid/fields/foreign_key_spec.rb +124 -169
  678. data/spec/mongoid/fields/localized_spec.rb +140 -185
  679. data/spec/mongoid/fields/standard_spec.rb +43 -59
  680. data/spec/mongoid/fields_spec.rb +751 -620
  681. data/spec/mongoid/findable_spec.rb +260 -228
  682. data/spec/mongoid/indexable/specification_spec.rb +42 -58
  683. data/spec/mongoid/indexable_spec.rb +260 -264
  684. data/spec/mongoid/inspectable_spec.rb +45 -55
  685. data/spec/mongoid/interceptable_spec.rb +784 -922
  686. data/spec/mongoid/interceptable_spec_models.rb +35 -35
  687. data/spec/mongoid/loading_spec.rb +47 -43
  688. data/spec/mongoid/loggable_spec.rb +3 -6
  689. data/spec/mongoid/matcher/extract_attribute_spec.rb +2 -6
  690. data/spec/mongoid/matcher/regexp_budget_spec.rb +570 -0
  691. data/spec/mongoid/mongoizable_spec.rb +81 -90
  692. data/spec/mongoid/monkey_patches_spec.rb +4 -0
  693. data/spec/mongoid/persistable/creatable_spec.rb +181 -220
  694. data/spec/mongoid/persistable/deletable_spec.rb +139 -179
  695. data/spec/mongoid/persistable/destroyable_spec.rb +135 -164
  696. data/spec/mongoid/persistable/incrementable_spec.rb +65 -84
  697. data/spec/mongoid/persistable/logical_spec.rb +48 -61
  698. data/spec/mongoid/persistable/maxable_spec.rb +45 -44
  699. data/spec/mongoid/persistable/minable_spec.rb +45 -44
  700. data/spec/mongoid/persistable/multipliable_spec.rb +54 -69
  701. data/spec/mongoid/persistable/poppable_spec.rb +47 -60
  702. data/spec/mongoid/persistable/pullable_spec.rb +79 -103
  703. data/spec/mongoid/persistable/pushable_spec.rb +106 -131
  704. data/spec/mongoid/persistable/renamable_spec.rb +52 -65
  705. data/spec/mongoid/persistable/savable_spec.rb +152 -189
  706. data/spec/mongoid/persistable/settable_spec.rb +121 -145
  707. data/spec/mongoid/persistable/unsettable_spec.rb +56 -73
  708. data/spec/mongoid/persistable/updatable_spec.rb +185 -232
  709. data/spec/mongoid/persistable/upsertable_spec.rb +66 -77
  710. data/spec/mongoid/persistable_spec.rb +132 -139
  711. data/spec/mongoid/persistence_context_spec.rb +31 -89
  712. data/spec/mongoid/positional_spec.rb +67 -79
  713. data/spec/mongoid/railties/bson_object_id_serializer_spec.rb +0 -3
  714. data/spec/mongoid/railties/console_sandbox_spec.rb +0 -1
  715. data/spec/mongoid/relations/proxy_spec.rb +0 -1
  716. data/spec/mongoid/reloadable_spec.rb +250 -145
  717. data/spec/mongoid/scopable_spec.rb +319 -398
  718. data/spec/mongoid/search_indexable_spec.rb +735 -44
  719. data/spec/mongoid/selectable_spec.rb +36 -51
  720. data/spec/mongoid/serializable_spec.rb +269 -312
  721. data/spec/mongoid/shardable_models.rb +5 -5
  722. data/spec/mongoid/shardable_spec.rb +44 -46
  723. data/spec/mongoid/stateful_spec.rb +55 -75
  724. data/spec/mongoid/tasks/database_rake_spec.rb +138 -141
  725. data/spec/mongoid/tasks/database_spec.rb +98 -80
  726. data/spec/mongoid/tasks/encryption_spec.rb +22 -20
  727. data/spec/mongoid/threaded_spec.rb +57 -83
  728. data/spec/mongoid/timestamps/created/short_spec.rb +12 -16
  729. data/spec/mongoid/timestamps/created_spec.rb +16 -20
  730. data/spec/mongoid/timestamps/timeless_spec.rb +228 -48
  731. data/spec/mongoid/timestamps/updated/short_spec.rb +21 -28
  732. data/spec/mongoid/timestamps/updated_spec.rb +18 -25
  733. data/spec/mongoid/timestamps_spec.rb +171 -188
  734. data/spec/mongoid/timestamps_spec_models.rb +12 -13
  735. data/spec/mongoid/touchable_spec.rb +355 -294
  736. data/spec/mongoid/touchable_spec_models.rb +45 -37
  737. data/spec/mongoid/traversable_spec.rb +435 -471
  738. data/spec/mongoid/validatable/associated_spec.rb +60 -59
  739. data/spec/mongoid/validatable/format_spec.rb +24 -34
  740. data/spec/mongoid/validatable/length_spec.rb +62 -86
  741. data/spec/mongoid/validatable/numericality_spec.rb +114 -23
  742. data/spec/mongoid/validatable/presence_spec.rb +149 -203
  743. data/spec/mongoid/validatable/uniqueness_spec.rb +632 -830
  744. data/spec/mongoid/validatable_spec.rb +71 -103
  745. data/spec/mongoid/warnings_spec.rb +5 -9
  746. data/spec/mongoid_spec.rb +25 -41
  747. data/spec/rails/controller_extension/controller_runtime_spec.rb +45 -49
  748. data/spec/rails/mongoid_spec.rb +15 -15
  749. data/spec/shared/lib/mrss/cluster_config.rb +5 -40
  750. data/spec/shared/lib/mrss/constraints.rb +7 -46
  751. data/spec/shared/lib/mrss/docker_runner.rb +10 -21
  752. data/spec/shared/lib/mrss/eg_config_utils.rb +0 -31
  753. data/spec/shared/lib/mrss/release/candidate.rb +18 -12
  754. data/spec/shared/lib/mrss/server_version_registry.rb +1 -5
  755. data/spec/shared/share/Dockerfile.erb +6 -8
  756. data/spec/shared/shlib/server.sh +0 -50
  757. data/spec/shared/shlib/set_env.sh +4 -10
  758. data/spec/spec_helper.rb +59 -32
  759. data/spec/support/authorization.rb +0 -1
  760. data/spec/support/client_registry.rb +1 -2
  761. data/spec/support/constraints.rb +8 -25
  762. data/spec/support/crypt/models.rb +164 -8
  763. data/spec/support/crypt.rb +6 -9
  764. data/spec/support/expectations.rb +21 -7
  765. data/spec/support/feature_sandbox.rb +1 -4
  766. data/spec/support/helpers.rb +0 -1
  767. data/spec/support/immutable_ids.rb +20 -21
  768. data/spec/support/macros.rb +1 -3
  769. data/spec/support/models/account.rb +4 -5
  770. data/spec/support/models/acolyte.rb +5 -5
  771. data/spec/support/models/actor.rb +3 -3
  772. data/spec/support/models/actress.rb +0 -1
  773. data/spec/support/models/address.rb +11 -11
  774. data/spec/support/models/address_component.rb +1 -1
  775. data/spec/support/models/address_number.rb +1 -1
  776. data/spec/support/models/agency.rb +1 -1
  777. data/spec/support/models/agent.rb +1 -1
  778. data/spec/support/models/album.rb +1 -2
  779. data/spec/support/models/alert.rb +1 -1
  780. data/spec/support/models/animal.rb +4 -5
  781. data/spec/support/models/answer.rb +1 -1
  782. data/spec/support/models/appointment.rb +2 -2
  783. data/spec/support/models/armrest.rb +0 -1
  784. data/spec/support/models/array_field.rb +0 -1
  785. data/spec/support/models/article.rb +0 -1
  786. data/spec/support/models/artist.rb +16 -12
  787. data/spec/support/models/artwork.rb +1 -1
  788. data/spec/support/models/audible_sound.rb +0 -1
  789. data/spec/support/models/audio.rb +2 -2
  790. data/spec/support/models/augmentation.rb +1 -2
  791. data/spec/support/models/author.rb +1 -1
  792. data/spec/support/models/baby.rb +1 -1
  793. data/spec/support/models/band.rb +0 -1
  794. data/spec/support/models/bar.rb +2 -2
  795. data/spec/support/models/basic.rb +0 -1
  796. data/spec/support/models/bed.rb +0 -1
  797. data/spec/support/models/big_palette.rb +0 -1
  798. data/spec/support/models/birthday.rb +3 -5
  799. data/spec/support/models/bolt.rb +0 -1
  800. data/spec/support/models/bomb.rb +1 -1
  801. data/spec/support/models/book.rb +1 -1
  802. data/spec/support/models/breed.rb +1 -1
  803. data/spec/support/models/browser.rb +1 -2
  804. data/spec/support/models/building.rb +0 -1
  805. data/spec/support/models/building_address.rb +1 -1
  806. data/spec/support/models/bus.rb +1 -1
  807. data/spec/support/models/business.rb +2 -2
  808. data/spec/support/models/callback_test.rb +1 -1
  809. data/spec/support/models/canvas.rb +5 -6
  810. data/spec/support/models/car.rb +0 -1
  811. data/spec/support/models/cat.rb +0 -2
  812. data/spec/support/models/catalog.rb +0 -1
  813. data/spec/support/models/category.rb +1 -1
  814. data/spec/support/models/child.rb +1 -1
  815. data/spec/support/models/child_doc.rb +5 -6
  816. data/spec/support/models/church.rb +1 -1
  817. data/spec/support/models/circle.rb +0 -1
  818. data/spec/support/models/circuit.rb +2 -2
  819. data/spec/support/models/circus.rb +0 -1
  820. data/spec/support/models/code.rb +2 -1
  821. data/spec/support/models/coding/pull_request.rb +0 -1
  822. data/spec/support/models/coding.rb +0 -1
  823. data/spec/support/models/comment.rb +0 -1
  824. data/spec/support/models/company.rb +0 -1
  825. data/spec/support/models/consumption_period.rb +0 -1
  826. data/spec/support/models/contextable_item.rb +1 -1
  827. data/spec/support/models/contractor.rb +1 -1
  828. data/spec/support/models/cookie.rb +0 -1
  829. data/spec/support/models/country_code.rb +2 -3
  830. data/spec/support/models/courier_job.rb +2 -2
  831. data/spec/support/models/cover.rb +0 -1
  832. data/spec/support/models/crate.rb +0 -1
  833. data/spec/support/models/customer.rb +0 -1
  834. data/spec/support/models/customer_address.rb +0 -1
  835. data/spec/support/models/deed.rb +1 -1
  836. data/spec/support/models/definition.rb +1 -1
  837. data/spec/support/models/delegating_patient.rb +0 -1
  838. data/spec/support/models/description.rb +0 -1
  839. data/spec/support/models/dictionary.rb +1 -1
  840. data/spec/support/models/division.rb +2 -2
  841. data/spec/support/models/doctor.rb +0 -1
  842. data/spec/support/models/dog.rb +2 -2
  843. data/spec/support/models/dokument.rb +1 -1
  844. data/spec/support/models/draft.rb +0 -1
  845. data/spec/support/models/dragon.rb +1 -1
  846. data/spec/support/models/driver.rb +2 -2
  847. data/spec/support/models/drug.rb +1 -1
  848. data/spec/support/models/dungeon.rb +1 -1
  849. data/spec/support/models/edit.rb +1 -1
  850. data/spec/support/models/email.rb +1 -1
  851. data/spec/support/models/employer.rb +1 -2
  852. data/spec/support/models/entry.rb +1 -1
  853. data/spec/support/models/eraser.rb +0 -1
  854. data/spec/support/models/even.rb +1 -1
  855. data/spec/support/models/event.rb +3 -4
  856. data/spec/support/models/exhibition.rb +1 -1
  857. data/spec/support/models/exhibitor.rb +1 -1
  858. data/spec/support/models/explosion.rb +1 -1
  859. data/spec/support/models/eye.rb +0 -1
  860. data/spec/support/models/eye_bowl.rb +2 -3
  861. data/spec/support/models/face.rb +2 -3
  862. data/spec/support/models/fanatic.rb +1 -1
  863. data/spec/support/models/favorite.rb +1 -1
  864. data/spec/support/models/filesystem.rb +1 -1
  865. data/spec/support/models/fire_hydrant.rb +1 -1
  866. data/spec/support/models/firefox.rb +0 -1
  867. data/spec/support/models/fish.rb +0 -1
  868. data/spec/support/models/folder.rb +0 -2
  869. data/spec/support/models/folder_item.rb +1 -3
  870. data/spec/support/models/fruits.rb +9 -5
  871. data/spec/support/models/game.rb +3 -4
  872. data/spec/support/models/ghost.rb +0 -1
  873. data/spec/support/models/guitar.rb +0 -1
  874. data/spec/support/models/hole.rb +0 -1
  875. data/spec/support/models/home.rb +1 -1
  876. data/spec/support/models/house.rb +2 -2
  877. data/spec/support/models/html_writer.rb +0 -1
  878. data/spec/support/models/id_key.rb +3 -3
  879. data/spec/support/models/idnodef.rb +0 -1
  880. data/spec/support/models/image.rb +0 -1
  881. data/spec/support/models/implant.rb +1 -2
  882. data/spec/support/models/instrument.rb +2 -3
  883. data/spec/support/models/item.rb +2 -2
  884. data/spec/support/models/jar.rb +1 -2
  885. data/spec/support/models/kaleidoscope.rb +1 -1
  886. data/spec/support/models/kangaroo.rb +1 -1
  887. data/spec/support/models/label.rb +2 -2
  888. data/spec/support/models/language.rb +1 -1
  889. data/spec/support/models/lat_lng.rb +0 -1
  890. data/spec/support/models/league.rb +1 -1
  891. data/spec/support/models/learner.rb +0 -1
  892. data/spec/support/models/line_item.rb +1 -1
  893. data/spec/support/models/location.rb +1 -1
  894. data/spec/support/models/login.rb +1 -2
  895. data/spec/support/models/manufacturer.rb +0 -1
  896. data/spec/support/models/meat.rb +1 -1
  897. data/spec/support/models/membership.rb +1 -1
  898. data/spec/support/models/message.rb +1 -2
  899. data/spec/support/models/minim.rb +0 -1
  900. data/spec/support/models/mixed_drink.rb +1 -1
  901. data/spec/support/models/modifier_models.rb +25 -0
  902. data/spec/support/models/mop.rb +0 -1
  903. data/spec/support/models/movie.rb +1 -1
  904. data/spec/support/models/my_hash.rb +1 -2
  905. data/spec/support/models/name.rb +4 -5
  906. data/spec/support/models/name_only.rb +0 -1
  907. data/spec/support/models/node.rb +1 -1
  908. data/spec/support/models/note.rb +3 -3
  909. data/spec/support/models/nut.rb +0 -1
  910. data/spec/support/models/odd.rb +1 -1
  911. data/spec/support/models/order.rb +1 -1
  912. data/spec/support/models/ordered_post.rb +1 -1
  913. data/spec/support/models/ordered_preference.rb +1 -1
  914. data/spec/support/models/oscar.rb +1 -1
  915. data/spec/support/models/other_owner_object.rb +0 -1
  916. data/spec/support/models/override.rb +3 -11
  917. data/spec/support/models/ownable.rb +1 -1
  918. data/spec/support/models/owner.rb +1 -1
  919. data/spec/support/models/pack.rb +0 -1
  920. data/spec/support/models/page.rb +3 -3
  921. data/spec/support/models/page_question.rb +1 -1
  922. data/spec/support/models/palette.rb +2 -2
  923. data/spec/support/models/parent.rb +2 -2
  924. data/spec/support/models/parent_doc.rb +1 -1
  925. data/spec/support/models/passport.rb +0 -1
  926. data/spec/support/models/patient.rb +2 -2
  927. data/spec/support/models/pdf_writer.rb +0 -1
  928. data/spec/support/models/pencil.rb +0 -1
  929. data/spec/support/models/person.rb +32 -28
  930. data/spec/support/models/pet.rb +1 -1
  931. data/spec/support/models/pet_owner.rb +1 -1
  932. data/spec/support/models/phone.rb +1 -2
  933. data/spec/support/models/piano.rb +0 -1
  934. data/spec/support/models/pizza.rb +1 -1
  935. data/spec/support/models/player.rb +5 -5
  936. data/spec/support/models/post.rb +12 -12
  937. data/spec/support/models/post_genre.rb +1 -1
  938. data/spec/support/models/powerup.rb +1 -2
  939. data/spec/support/models/preference.rb +2 -2
  940. data/spec/support/models/princess.rb +1 -1
  941. data/spec/support/models/product.rb +3 -3
  942. data/spec/support/models/profile.rb +2 -1
  943. data/spec/support/models/pronunciation.rb +1 -1
  944. data/spec/support/models/pub.rb +2 -2
  945. data/spec/support/models/publication/encyclopedia.rb +0 -1
  946. data/spec/support/models/publication/review.rb +0 -1
  947. data/spec/support/models/publication.rb +0 -1
  948. data/spec/support/models/purchase.rb +1 -1
  949. data/spec/support/models/purchased_item.rb +1 -1
  950. data/spec/support/models/question.rb +2 -2
  951. data/spec/support/models/quiz.rb +1 -1
  952. data/spec/support/models/rating.rb +1 -1
  953. data/spec/support/models/record.rb +2 -3
  954. data/spec/support/models/registry.rb +1 -1
  955. data/spec/support/models/role.rb +1 -1
  956. data/spec/support/models/root_category.rb +1 -1
  957. data/spec/support/models/sandbox/app/models/app_models_message.rb +0 -1
  958. data/spec/support/models/sandbox/lib/models/lib_models_message.rb +0 -1
  959. data/spec/support/models/sandbox/sandbox_message.rb +0 -1
  960. data/spec/support/models/sandbox/sandbox_user.rb +0 -1
  961. data/spec/support/models/sandbox/subdir/sandbox_comment.rb +0 -1
  962. data/spec/support/models/sandwich.rb +1 -1
  963. data/spec/support/models/scheduler.rb +0 -1
  964. data/spec/support/models/school.rb +0 -1
  965. data/spec/support/models/scribe.rb +1 -1
  966. data/spec/support/models/sealer.rb +0 -1
  967. data/spec/support/models/seat.rb +0 -1
  968. data/spec/support/models/seo.rb +1 -1
  969. data/spec/support/models/series.rb +1 -1
  970. data/spec/support/models/server.rb +1 -1
  971. data/spec/support/models/service.rb +2 -2
  972. data/spec/support/models/shape.rb +3 -3
  973. data/spec/support/models/shelf.rb +1 -1
  974. data/spec/support/models/shield.rb +2 -2
  975. data/spec/support/models/shipment_address.rb +0 -1
  976. data/spec/support/models/shipping_container.rb +1 -1
  977. data/spec/support/models/shipping_pack.rb +0 -1
  978. data/spec/support/models/shirt.rb +0 -1
  979. data/spec/support/models/shop.rb +2 -2
  980. data/spec/support/models/short_agent.rb +0 -1
  981. data/spec/support/models/short_quiz.rb +1 -1
  982. data/spec/support/models/simple.rb +1 -1
  983. data/spec/support/models/slave.rb +1 -1
  984. data/spec/support/models/song.rb +1 -2
  985. data/spec/support/models/sound.rb +2 -2
  986. data/spec/support/models/spacer.rb +0 -1
  987. data/spec/support/models/square.rb +0 -1
  988. data/spec/support/models/staff.rb +0 -1
  989. data/spec/support/models/store_as_dup_test1.rb +2 -2
  990. data/spec/support/models/store_as_dup_test2.rb +1 -1
  991. data/spec/support/models/store_as_dup_test3.rb +2 -2
  992. data/spec/support/models/store_as_dup_test4.rb +1 -1
  993. data/spec/support/models/strategy.rb +0 -1
  994. data/spec/support/models/student.rb +1 -2
  995. data/spec/support/models/sub_item.rb +0 -1
  996. data/spec/support/models/subscription.rb +2 -2
  997. data/spec/support/models/survey.rb +2 -2
  998. data/spec/support/models/symptom.rb +2 -2
  999. data/spec/support/models/system_role.rb +2 -3
  1000. data/spec/support/models/tag.rb +2 -2
  1001. data/spec/support/models/target.rb +1 -1
  1002. data/spec/support/models/template.rb +1 -1
  1003. data/spec/support/models/thing.rb +1 -1
  1004. data/spec/support/models/threadlocker.rb +0 -1
  1005. data/spec/support/models/title.rb +0 -1
  1006. data/spec/support/models/tool.rb +3 -3
  1007. data/spec/support/models/topping.rb +1 -1
  1008. data/spec/support/models/toy.rb +0 -1
  1009. data/spec/support/models/track.rb +1 -1
  1010. data/spec/support/models/translation.rb +1 -1
  1011. data/spec/support/models/tree.rb +2 -3
  1012. data/spec/support/models/truck.rb +0 -1
  1013. data/spec/support/models/updatable.rb +0 -1
  1014. data/spec/support/models/user.rb +3 -4
  1015. data/spec/support/models/user_account.rb +3 -3
  1016. data/spec/support/models/validation_callback.rb +4 -4
  1017. data/spec/support/models/vehicle.rb +2 -3
  1018. data/spec/support/models/version.rb +1 -1
  1019. data/spec/support/models/vertex.rb +0 -1
  1020. data/spec/support/models/vet_visit.rb +1 -1
  1021. data/spec/support/models/video.rb +2 -2
  1022. data/spec/support/models/video_game.rb +0 -1
  1023. data/spec/support/models/washer.rb +0 -1
  1024. data/spec/support/models/weapon.rb +1 -2
  1025. data/spec/support/models/wiki_page.rb +2 -3
  1026. data/spec/support/models/word.rb +2 -2
  1027. data/spec/support/models/word_origin.rb +1 -2
  1028. data/spec/support/models/writer.rb +3 -3
  1029. data/spec/support/rails_mock.rb +7 -12
  1030. data/spec/support/shared/time.rb +0 -1
  1031. data/spec/support/sinatra_mock.rb +4 -2
  1032. data/spec/support/spec_config.rb +19 -18
  1033. metadata +64 -2
@@ -1,28 +1,27 @@
1
1
  # frozen_string_literal: true
2
- # rubocop:todo all
3
2
 
4
- require "spec_helper"
5
- require_relative "./includable_spec_models.rb"
3
+ require 'spec_helper'
4
+ require_relative 'includable_spec_models'
6
5
 
7
6
  describe Mongoid::Criteria::Includable do
8
-
9
- describe "#includes" do
10
-
7
+ shared_examples_for 'eager loading' do |method_name|
11
8
  let!(:person) do
12
9
  Person.create!(age: 1)
13
10
  end
14
11
 
15
- context "when providing a name that is not a relation" do
12
+ context 'when providing a name that is not a relation' do
13
+ let(:expected_error) do
14
+ (method_name == :eager_load) ? ArgumentError : Mongoid::Errors::InvalidIncludes
15
+ end
16
16
 
17
- it "raises an error" do
18
- expect {
19
- Person.includes(:members)
20
- }.to raise_error(Mongoid::Errors::InvalidIncludes)
17
+ it 'raises an error' do
18
+ expect do
19
+ Person.send(method_name, :members)
20
+ end.to raise_error(expected_error)
21
21
  end
22
22
  end
23
23
 
24
- context "when providing one association" do
25
-
24
+ context 'when providing one association' do
26
25
  let!(:user) do
27
26
  User.create!(posts: [ post1 ])
28
27
  end
@@ -32,20 +31,19 @@ describe Mongoid::Criteria::Includable do
32
31
  end
33
32
 
34
33
  let(:result) do
35
- User.includes(:posts).first
34
+ User.send(method_name, :posts).first
36
35
  end
37
36
 
38
- it "executes the query" do
37
+ it 'executes the query' do
39
38
  expect(result).to eq(user)
40
39
  end
41
40
 
42
- it "includes the related objects" do
41
+ it 'includes the related objects' do
43
42
  expect(result.posts).to eq([ post1 ])
44
43
  end
45
44
  end
46
45
 
47
- context "when providing a list of associations" do
48
-
46
+ context 'when providing a list of associations' do
49
47
  let!(:user) do
50
48
  User.create!(posts: [ post1 ], descriptions: [ description1 ])
51
49
  end
@@ -59,24 +57,26 @@ describe Mongoid::Criteria::Includable do
59
57
  end
60
58
 
61
59
  let(:result) do
62
- User.includes(:posts, :descriptions).first
60
+ User.send(method_name, :posts, :descriptions).first
63
61
  end
64
62
 
65
- it "executes the query" do
63
+ it 'executes the query' do
66
64
  expect(result).to eq(user)
67
65
  end
68
66
 
69
- it "includes the related objects" do
67
+ it 'includes the related objects' do
70
68
  expect(result.posts).to eq([ post1 ])
71
69
  expect(result.descriptions).to eq([ description1 ])
72
70
  end
73
71
  end
74
72
 
75
- context "when providing a nested association" do
76
-
73
+ context 'when providing a nested association' do
77
74
  let!(:user) do
78
75
  User.create!
79
76
  end
77
+ let(:result) do
78
+ User.send(method_name, posts: [ :alerts ]).first
79
+ end
80
80
 
81
81
  before do
82
82
  p = Post.create!(alerts: [ Alert.create! ])
@@ -84,37 +84,31 @@ describe Mongoid::Criteria::Includable do
84
84
  user.save!
85
85
  end
86
86
 
87
- let(:result) do
88
- User.includes(:posts => [:alerts]).first
89
- end
90
-
91
- it "executes the query" do
87
+ it 'executes the query' do
92
88
  expect(result).to eq(user)
93
89
  end
94
90
 
95
- it "includes the related objects" do
91
+ it 'includes the related objects' do
96
92
  expect(result.posts.size).to eq(1)
97
93
  expect(result.posts.first.alerts.size).to eq(1)
98
94
  end
99
95
  end
100
96
 
101
- context "when providing a deeply nested association" do
102
-
97
+ context 'when providing a deeply nested association' do
103
98
  let!(:user) do
104
99
  User.create!
105
100
  end
106
101
 
107
102
  let(:results) do
108
- User.includes(:posts => [{ :alerts => :items }]).to_a
103
+ User.send(method_name, posts: [ { alerts: :items } ]).to_a
109
104
  end
110
105
 
111
- it "executes the query" do
106
+ it 'executes the query' do
112
107
  expect(results.first).to eq(user)
113
108
  end
114
109
  end
115
110
 
116
- context "when the models are inherited" do
117
-
111
+ context 'when the models are inherited' do
118
112
  before(:all) do
119
113
  class A
120
114
  include Mongoid::Document
@@ -126,6 +120,7 @@ describe Mongoid::Criteria::Includable do
126
120
 
127
121
  class C
128
122
  include Mongoid::Document
123
+
129
124
  has_one :b
130
125
  end
131
126
  end
@@ -136,8 +131,7 @@ describe Mongoid::Criteria::Includable do
136
131
  Object.send(:remove_const, :C)
137
132
  end
138
133
 
139
- context "when the includes is on the subclass" do
140
-
134
+ context 'when the includes is on the subclass' do
141
135
  let!(:c_one) do
142
136
  C.create!
143
137
  end
@@ -151,16 +145,16 @@ describe Mongoid::Criteria::Includable do
151
145
  end
152
146
 
153
147
  let!(:results) do
154
- C.includes(:b).to_a.detect do |c|
148
+ C.send(method_name, :b).to_a.detect do |c|
155
149
  c.id == c_two.id
156
150
  end
157
151
  end
158
152
 
159
- it "returns the correct documents" do
153
+ it 'returns the correct documents' do
160
154
  expect(results).to eq(c_two)
161
155
  end
162
156
 
163
- it "does not query the db" do
157
+ it 'does not query the db' do
164
158
  expect_query(0) do
165
159
  results.b
166
160
  end
@@ -168,10 +162,8 @@ describe Mongoid::Criteria::Includable do
168
162
  end
169
163
  end
170
164
 
171
- context "when the models are inherited from another one model" do
172
-
173
- context "when the relation is a has_one" do
174
-
165
+ context 'when the models are inherited from another one model' do
166
+ context 'when the relation is a has_one' do
175
167
  before(:all) do
176
168
  class A
177
169
  include Mongoid::Document
@@ -187,6 +179,7 @@ describe Mongoid::Criteria::Includable do
187
179
 
188
180
  class D
189
181
  include Mongoid::Document
182
+
190
183
  has_one :b
191
184
  has_one :c
192
185
  end
@@ -199,8 +192,7 @@ describe Mongoid::Criteria::Includable do
199
192
  Object.send(:remove_const, :D)
200
193
  end
201
194
 
202
- context "when the includes is on the several relations" do
203
-
195
+ context 'when the includes is on the several relations' do
204
196
  let!(:d_one) do
205
197
  D.create!
206
198
  end
@@ -218,31 +210,29 @@ describe Mongoid::Criteria::Includable do
218
210
  end
219
211
 
220
212
  let!(:results) do
221
- D.includes(:b, :c).entries.detect do |d|
222
- d.id == d_two.id
223
- end
213
+ query = -> { D.send(method_name, :b, :c).entries.detect { |d| d.id == d_two.id } }
214
+ (method_name == :eager_load) ? expect_query(1, &query) : query.call
224
215
  end
225
216
 
226
- it "returns the correct documents" do
217
+ it 'returns the correct documents' do
227
218
  expect(results).to eq(d_two)
228
219
  end
229
220
 
230
- it "does not query the db on b" do
221
+ it 'does not query the db on b' do
231
222
  expect_query(0) do
232
223
  results.b
233
224
  end
234
225
  end
235
226
 
236
- it "does not query the db on c" do
227
+ it 'does not query the db on c' do
237
228
  expect_query(0) do
238
- results.b
229
+ results.c
239
230
  end
240
231
  end
241
232
  end
242
233
  end
243
234
 
244
- context "when the relation is a has_many" do
245
-
235
+ context 'when the relation is a has_many' do
246
236
  before(:all) do
247
237
  class A
248
238
  include Mongoid::Document
@@ -258,6 +248,7 @@ describe Mongoid::Criteria::Includable do
258
248
 
259
249
  class D
260
250
  include Mongoid::Document
251
+
261
252
  has_many :b
262
253
  has_many :c
263
254
  end
@@ -270,8 +261,7 @@ describe Mongoid::Criteria::Includable do
270
261
  Object.send(:remove_const, :D)
271
262
  end
272
263
 
273
- context "when the includes is on the several relations" do
274
-
264
+ context 'when the includes is on the several relations' do
275
265
  let!(:d_one) do
276
266
  D.create!
277
267
  end
@@ -289,53 +279,50 @@ describe Mongoid::Criteria::Includable do
289
279
  end
290
280
 
291
281
  let!(:results) do
292
- D.includes(:b, :c).entries.detect do |d|
293
- d.id == d_two.id
294
- end
282
+ query = -> { D.send(method_name, :b, :c).entries.detect { |d| d.id == d_two.id } }
283
+ (method_name == :eager_load) ? expect_query(1, &query) : query.call
295
284
  end
296
285
 
297
- it "returns the correct documents" do
286
+ it 'returns the correct documents' do
298
287
  expect(results).to eq(d_two)
299
288
  end
300
289
 
301
- it "does not query the db on b" do
290
+ it 'does not query the db on b' do
302
291
  expect_query(0) do
303
292
  results.b
304
293
  end
305
294
  end
306
295
 
307
- it "does not query the db on c" do
296
+ it 'does not query the db on c' do
308
297
  expect_query(0) do
309
- results.b
298
+ results.c
310
299
  end
311
300
  end
312
301
  end
313
302
  end
314
303
  end
315
304
 
316
- context "when including the same association multiple times" do
317
-
305
+ context 'when including the same association multiple times' do
318
306
  let(:criteria) do
319
- Person.all.includes(:posts, :posts).includes(:posts)
307
+ Person.all.send(method_name, :posts, :posts).send(method_name, :posts)
320
308
  end
321
309
 
322
310
  let(:association) do
323
311
  Person.reflect_on_association(:posts)
324
312
  end
325
313
 
326
- it "does not duplicate the association in the inclusions" do
314
+ it 'does not duplicate the association in the inclusions' do
327
315
  expect(criteria.inclusions).to eq([ association ])
328
316
  end
329
317
  end
330
318
 
331
- context "when mapping the results more than once" do
332
-
319
+ context 'when mapping the results more than once' do
333
320
  let!(:post) do
334
- person.posts.create!(title: "one")
321
+ person.posts.create!(title: 'one')
335
322
  end
336
323
 
337
324
  let(:criteria) do
338
- Post.includes(:person)
325
+ Post.send(method_name, :person)
339
326
  end
340
327
 
341
328
  let!(:results) do
@@ -343,90 +330,86 @@ describe Mongoid::Criteria::Includable do
343
330
  criteria.map { |doc| doc }
344
331
  end
345
332
 
346
- it "returns the proper results" do
347
- expect(results.first.title).to eq("one")
333
+ it 'returns the proper results' do
334
+ expect(results.first.title).to eq('one')
348
335
  end
349
336
  end
350
337
 
351
- context "when including a belongs to relation" do
352
-
353
- context "when the criteria is from the root" do
354
-
338
+ context 'when including a belongs to relation' do
339
+ context 'when the criteria is from the root' do
355
340
  let!(:person_two) do
356
341
  Person.create!(age: 2)
357
342
  end
358
343
 
359
344
  let!(:post_one) do
360
- person.posts.create!(title: "one")
345
+ person.posts.create!(title: 'one')
361
346
  end
362
347
 
363
348
  let!(:post_two) do
364
- person_two.posts.create!(title: "two")
349
+ person_two.posts.create!(title: 'two')
365
350
  end
366
351
 
367
- context "when calling first" do
368
-
352
+ context 'when calling first' do
369
353
  let(:criteria) do
370
- Post.includes(:person)
354
+ Post.send(method_name, :person)
371
355
  end
372
356
 
373
357
  let!(:document) do
374
- criteria.first
358
+ query = -> { criteria.first }
359
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
375
360
  end
376
361
 
377
- it "eager loads the first document" do
362
+ it 'eager loads the first document' do
378
363
  expect_query(0) do
379
364
  expect(document.person).to eq(person)
380
365
  end
381
366
  end
382
367
 
383
- it "returns the first document" do
368
+ it 'returns the first document' do
384
369
  expect(document).to eq(post_one)
385
370
  end
386
371
  end
387
372
 
388
- context "when calling last" do
389
-
373
+ context 'when calling last' do
390
374
  let!(:criteria) do
391
- Post.asc(:_id).includes(:person)
375
+ Post.asc(:_id).send(method_name, :person)
392
376
  end
393
377
 
394
378
  let!(:document) do
395
379
  criteria.last
396
380
  end
397
381
 
398
- it "eager loads the last document" do
382
+ it 'eager loads the last document' do
399
383
  expect_query(0) do
400
384
  expect(document.person).to eq(person_two)
401
385
  end
402
386
  end
403
387
 
404
- it "returns the last document" do
388
+ it 'returns the last document' do
405
389
  expect(document).to eq(post_two)
406
390
  end
407
391
  end
408
392
  end
409
393
 
410
- context "when the criteria is from an embedded relation" do
411
-
394
+ context 'when the criteria is from an embedded relation' do
412
395
  let(:peep) do
413
396
  Person.create!
414
397
  end
415
398
 
416
399
  let!(:address_one) do
417
- peep.addresses.create!(street: "rosenthaler")
400
+ peep.addresses.create!(street: 'rosenthaler')
418
401
  end
419
402
 
420
403
  let!(:address_two) do
421
- peep.addresses.create!(street: "weinmeister")
404
+ peep.addresses.create!(street: 'weinmeister')
422
405
  end
423
406
 
424
407
  let!(:depeche) do
425
- Band.create!(name: "Depeche Mode")
408
+ Band.create!(name: 'Depeche Mode')
426
409
  end
427
410
 
428
411
  let!(:tool) do
429
- Band.create!(name: "Tool")
412
+ Band.create!(name: 'Tool')
430
413
  end
431
414
 
432
415
  before do
@@ -436,10 +419,9 @@ describe Mongoid::Criteria::Includable do
436
419
  address_two.save!
437
420
  end
438
421
 
439
- context "when calling first" do
440
-
422
+ context 'when calling first' do
441
423
  let(:criteria) do
442
- peep.reload.addresses.includes(:band)
424
+ peep.reload.addresses.send(method_name, :band)
443
425
  end
444
426
 
445
427
  let(:context) do
@@ -447,24 +429,25 @@ describe Mongoid::Criteria::Includable do
447
429
  end
448
430
 
449
431
  let!(:document) do
432
+ # Since this is called on an embedded criteria, we will be using the includes path
433
+ # rather than the $lookup path, so we do not need to check queries.
450
434
  criteria.first
451
435
  end
452
436
 
453
- it "eager loads the first document" do
437
+ it 'eager loads the first document' do
454
438
  expect_query(0) do
455
439
  expect(document.band).to eq(depeche)
456
440
  end
457
441
  end
458
442
 
459
- it "returns the document" do
443
+ it 'returns the document' do
460
444
  expect(document).to eq(address_one)
461
445
  end
462
446
  end
463
447
 
464
- context "when calling last" do
465
-
448
+ context 'when calling last' do
466
449
  let(:criteria) do
467
- peep.reload.addresses.includes(:band)
450
+ peep.reload.addresses.send(method_name, :band)
468
451
  end
469
452
 
470
453
  let(:context) do
@@ -472,24 +455,24 @@ describe Mongoid::Criteria::Includable do
472
455
  end
473
456
 
474
457
  let!(:document) do
475
- criteria.last
458
+ query = -> { criteria.last }
459
+ (method_name == :eager_load) ? expect_query(2, &query) : query.call
476
460
  end
477
461
 
478
- it "eager loads the last document" do
462
+ it 'eager loads the last document' do
479
463
  expect_query(0) do
480
464
  expect(document.band).to eq(tool)
481
465
  end
482
466
  end
483
467
 
484
- it "returns the document" do
468
+ it 'returns the document' do
485
469
  expect(document).to eq(address_two)
486
470
  end
487
471
  end
488
472
 
489
- context "when iterating all documents" do
490
-
473
+ context 'when iterating all documents' do
491
474
  let(:criteria) do
492
- peep.reload.addresses.includes(:band)
475
+ peep.reload.addresses.send(method_name, :band)
493
476
  end
494
477
 
495
478
  let(:context) do
@@ -497,32 +480,32 @@ describe Mongoid::Criteria::Includable do
497
480
  end
498
481
 
499
482
  let!(:documents) do
500
- criteria.to_a
483
+ query = -> { criteria.to_a }
484
+ (method_name == :eager_load) ? expect_query(2, &query) : query.call
501
485
  end
502
486
 
503
- it "eager loads the first document" do
487
+ it 'eager loads the first document' do
504
488
  expect_query(0) do
505
489
  expect(documents.first.band).to eq(depeche)
506
490
  end
507
491
  end
508
492
 
509
- it "eager loads the last document" do
493
+ it 'eager loads the last document' do
510
494
  expect_query(0) do
511
495
  expect(documents.last.band).to eq(tool)
512
496
  end
513
497
  end
514
498
 
515
- it "returns the documents" do
499
+ it 'returns the documents' do
516
500
  expect(documents).to eq([ address_one, address_two ])
517
501
  end
518
502
  end
519
503
  end
520
504
  end
521
505
 
522
- context "when providing inclusions to the default scope" do
523
-
506
+ context 'when providing inclusions to the default scope' do
524
507
  before do
525
- Person.default_scope(->{ Person.includes(:posts) })
508
+ Person.default_scope(-> { Person.send(method_name, :posts) })
526
509
  end
527
510
 
528
511
  after do
@@ -530,65 +513,61 @@ describe Mongoid::Criteria::Includable do
530
513
  end
531
514
 
532
515
  let!(:post_one) do
533
- person.posts.create!(title: "one")
516
+ person.posts.create!(title: 'one')
534
517
  end
535
518
 
536
519
  let!(:post_two) do
537
- person.posts.create!(title: "two")
520
+ person.posts.create!(title: 'two')
538
521
  end
539
522
 
540
- context "when the criteria has no options" do
541
-
523
+ context 'when the criteria has no options' do
542
524
  let!(:criteria) do
543
525
  Person.asc(:age).all
544
526
  end
545
527
 
546
528
  let!(:documents) do
547
- criteria.entries
529
+ query = -> { criteria.entries }
530
+ (method_name == :eager_load) ? expect_less_than_queries(2, &query) : query.call
548
531
  end
549
532
 
550
- it "returns the correct documents" do
533
+ it 'returns the correct documents' do
551
534
  expect(documents).to eq([ person ])
552
535
  end
553
536
 
554
- it "eager loads the first document" do
537
+ it 'eager loads the first document' do
555
538
  expect_query(0) do
556
539
  expect(documents.first.posts.first).to eq(post_one)
557
540
  end
558
541
  end
559
542
 
560
- it "eager loads the last document" do
543
+ it 'eager loads the last document' do
561
544
  expect_query(0) do
562
545
  expect(documents.first.posts.last).to eq(post_two)
563
546
  end
564
547
  end
565
548
 
566
- context "when executing the query twice" do
567
-
568
- let!(:new_criteria) do
569
- Person.where(id: person.id)
570
- end
571
-
572
- let!(:new_context) do
573
- new_criteria.context
574
- end
549
+ context 'when executing the query twice' do
550
+ let(:new_criteria) { Person.where(id: person.id) }
551
+ let(:from_db) { new_criteria.first }
552
+ let(:new_context) { new_criteria.context }
575
553
 
576
554
  before do
577
- expect(new_context).to receive(:eager_load).with([person]).once.and_call_original
578
- end
555
+ if method_name == :eager_load
556
+ expect(new_context).to receive(:eager_load_with_lookup).once.and_call_original
557
+ else
558
+ expect(new_context).to receive(:eager_load).with([ person ]).once.and_call_original
559
+ end
579
560
 
580
- let!(:from_db) do
581
- new_criteria.first
561
+ from_db
582
562
  end
583
563
 
584
- it "does not duplicate documents in the relation" do
564
+ it 'does not duplicate documents in the relation' do
585
565
  expect(person.posts.size).to eq(2)
586
566
  end
587
567
  end
588
568
  end
589
569
 
590
- context "when calling first on the criteria" do
591
-
570
+ context 'when calling first on the criteria' do
592
571
  let(:criteria) do
593
572
  Person.asc(:age).all
594
573
  end
@@ -597,66 +576,62 @@ describe Mongoid::Criteria::Includable do
597
576
  criteria.first
598
577
  end
599
578
 
600
- it "returns the correct documents" do
579
+ it 'returns the correct documents' do
601
580
  expect(from_db).to eq(person)
602
581
  end
603
582
 
604
- it "eager loads the first document" do
583
+ it 'eager loads the first document' do
605
584
  expect_query(0) do
606
585
  expect(from_db.posts.first).to eq(post_one)
607
586
  end
608
587
  end
609
588
 
610
- it "eager loads the last document" do
589
+ it 'eager loads the last document' do
611
590
  expect_query(0) do
612
591
  expect(from_db.posts.last).to eq(post_two)
613
592
  end
614
593
  end
615
594
  end
616
595
 
617
- context "when calling last on the criteria" do
618
-
619
- let(:criteria) do
620
- Person.asc(:age).all
621
- end
622
-
623
- let!(:context) do
624
- criteria.context
625
- end
596
+ context 'when calling last on the criteria' do
597
+ let(:criteria) { Person.asc(:age).all }
598
+ let(:from_db) { criteria.last }
599
+ let(:context) { criteria.context }
626
600
 
627
601
  before do
628
- expect(context).to receive(:eager_load).with([person]).once.and_call_original
629
- end
602
+ if method_name == :eager_load
603
+ expect(context).to receive(:eager_load_with_lookup).once.and_call_original
604
+ else
605
+ expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
606
+ end
630
607
 
631
- let!(:from_db) do
632
- criteria.last
608
+ from_db
633
609
  end
634
610
 
635
- it "returns the correct documents" do
611
+ it 'returns the correct documents' do
636
612
  expect(from_db).to eq(person)
637
613
  end
638
614
 
639
- it "eager loads the first document" do
615
+ it 'eager loads the first document' do
640
616
  expect_query(0) do
641
617
  expect(from_db.posts.first).to eq(post_one)
642
618
  end
643
619
  end
644
620
 
645
- it "eager loads the last document" do
621
+ it 'eager loads the last document' do
646
622
  expect_query(0) do
647
623
  expect(from_db.posts.last).to eq(post_two)
648
624
  end
649
625
  end
650
626
  end
651
627
 
652
- context "when the criteria has limiting options" do
653
-
628
+ context 'when the criteria has limiting options' do
654
629
  let!(:person_two) do
655
630
  Person.create!
656
631
  end
657
632
 
658
633
  let!(:post_three) do
659
- person_two.posts.create!(title: "three")
634
+ person_two.posts.create!(title: 'three')
660
635
  end
661
636
 
662
637
  let!(:criteria) do
@@ -664,20 +639,21 @@ describe Mongoid::Criteria::Includable do
664
639
  end
665
640
 
666
641
  let!(:documents) do
667
- criteria.entries
642
+ query = -> { criteria.entries }
643
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
668
644
  end
669
645
 
670
- it "returns the correct documents" do
646
+ it 'returns the correct documents' do
671
647
  expect(criteria).to eq([ person ])
672
648
  end
673
649
 
674
- it "eager loads the first document" do
650
+ it 'eager loads the first document' do
675
651
  expect_query(0) do
676
652
  expect(documents.first.posts.first).to eq(post_one)
677
653
  end
678
654
  end
679
655
 
680
- it "eager loads the second document" do
656
+ it 'eager loads the second document' do
681
657
  expect_query(0) do
682
658
  expect(documents.first.posts.last).to eq(post_two)
683
659
  end
@@ -685,107 +661,106 @@ describe Mongoid::Criteria::Includable do
685
661
  end
686
662
  end
687
663
 
688
- context "when including a has and belongs to many" do
689
-
664
+ context 'when including a has and belongs to many' do
690
665
  let!(:preference_one) do
691
- person.preferences.create!(name: "one")
666
+ person.preferences.create!(name: 'one')
692
667
  end
693
668
 
694
669
  let!(:preference_two) do
695
- person.preferences.create!(name: "two")
670
+ person.preferences.create!(name: 'two')
696
671
  end
697
672
 
698
- context "when one of the related items is deleted" do
699
-
673
+ context 'when one of the related items is deleted' do
700
674
  before do
701
675
  person.preferences = [ preference_one, preference_two ]
702
676
  preference_two.delete
703
677
  end
704
678
 
705
679
  let(:criteria) do
706
- Person.where(id: person.id).includes(:preferences)
680
+ Person.where(id: person.id).send(method_name, :preferences)
707
681
  end
708
682
 
709
- it "only loads the existing related items" do
683
+ it 'only loads the existing related items' do
710
684
  expect(criteria.entries.first.preferences).to eq([ preference_one ])
711
685
  end
712
686
  end
713
687
 
714
- context "when the criteria has no options" do
715
-
688
+ context 'when the criteria has no options' do
716
689
  let!(:criteria) do
717
- Person.asc(:age).includes(:preferences)
690
+ Person.asc(:age).send(method_name, :preferences)
718
691
  end
719
692
 
720
693
  let!(:documents) do
721
- criteria.entries
694
+ query = -> { criteria.entries }
695
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
722
696
  end
723
697
 
724
- it "returns the correct documents" do
698
+ it 'returns the correct documents' do
725
699
  expect(documents).to eq([ person ])
726
700
  end
727
701
 
728
- it "eager loads the first document" do
702
+ it 'eager loads the first document' do
729
703
  expect_query(0) do
730
704
  expect(documents.first.preferences.first).to eq(preference_one)
731
705
  end
732
706
  end
733
707
 
734
- it "eager loads the last document" do
708
+ it 'eager loads the last document' do
735
709
  expect_query(0) do
736
710
  expect(documents.first.preferences.last).to eq(preference_two)
737
711
  end
738
712
  end
739
713
  end
740
714
 
741
- context "when calling first on the criteria" do
742
-
715
+ context 'when calling first on the criteria' do
743
716
  let!(:criteria) do
744
- Person.asc(:age).includes(:preferences)
717
+ Person.asc(:age).send(method_name, :preferences)
745
718
  end
746
719
 
720
+ # here
747
721
  let!(:from_db) do
748
- criteria.first
722
+ query = -> { criteria.first }
723
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
749
724
  end
750
725
 
751
- it "returns the correct documents" do
726
+ it 'returns the correct documents' do
752
727
  expect(from_db).to eq(person)
753
728
  end
754
729
 
755
- it "eager loads the first document" do
730
+ it 'eager loads the first document' do
756
731
  expect_query(0) do
757
732
  expect(from_db.preferences.first).to eq(preference_one)
758
733
  end
759
734
  end
760
735
 
761
- it "eager loads the last document" do
736
+ it 'eager loads the last document' do
762
737
  expect_query(0) do
763
738
  expect(from_db.preferences.last).to eq(preference_two)
764
739
  end
765
740
  end
766
741
  end
767
742
 
768
- context "when calling last on the criteria" do
769
-
743
+ context 'when calling last on the criteria' do
770
744
  let!(:criteria) do
771
- Person.asc(:age).includes(:preferences)
745
+ Person.asc(:age).send(method_name, :preferences)
772
746
  end
773
747
 
774
748
  let!(:from_db) do
775
- criteria.last
749
+ query = -> { criteria.last }
750
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
776
751
  end
777
752
 
778
- it "returns the correct documents" do
753
+ it 'returns the correct documents' do
779
754
  expect(from_db).to eq(person)
780
755
  end
781
756
 
782
- it "eager loads the first document" do
757
+ it 'eager loads the first document' do
783
758
  expect_query(0) do
784
759
  expect(from_db.preferences.first).to eq(preference_one)
785
760
  end
786
761
  end
787
762
 
788
- it "eager loads the last document" do
763
+ it 'eager loads the last document' do
789
764
  expect_query(0) do
790
765
  expect(from_db.preferences.last).to eq(preference_two)
791
766
  end
@@ -793,107 +768,105 @@ describe Mongoid::Criteria::Includable do
793
768
  end
794
769
  end
795
770
 
796
- context "when including a has many" do
797
-
771
+ context 'when including a has many' do
798
772
  let!(:post_one) do
799
- person.posts.create!(title: "one")
773
+ person.posts.create!(title: 'one')
800
774
  end
801
775
 
802
776
  let!(:post_two) do
803
- person.posts.create!(title: "two")
777
+ person.posts.create!(title: 'two')
804
778
  end
805
779
 
806
- context "when the criteria has no options" do
807
-
780
+ context 'when the criteria has no options' do
808
781
  let!(:criteria) do
809
- Person.asc(:age).includes(:posts)
782
+ Person.asc(:age).send(method_name, :posts)
810
783
  end
811
784
 
812
785
  let!(:documents) do
813
- criteria.entries
786
+ query = -> { criteria.entries }
787
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
814
788
  end
815
789
 
816
- it "returns the correct documents" do
790
+ it 'returns the correct documents' do
817
791
  expect(documents).to eq([ person ])
818
792
  end
819
793
 
820
- it "eager loads the first document" do
794
+ it 'eager loads the first document' do
821
795
  expect_query(0) do
822
796
  expect(documents.first.posts.first).to eq(post_one)
823
797
  end
824
798
  end
825
799
 
826
- it "eager loads the last document" do
800
+ it 'eager loads the last document' do
827
801
  expect_query(0) do
828
802
  expect(documents.first.posts.last).to eq(post_two)
829
803
  end
830
804
  end
831
805
  end
832
806
 
833
- context "when calling first on the criteria" do
834
-
807
+ context 'when calling first on the criteria' do
835
808
  let!(:criteria) do
836
- Person.asc(:age).includes(:posts)
809
+ Person.asc(:age).send(method_name, :posts)
837
810
  end
838
811
 
839
812
  let!(:from_db) do
840
813
  criteria.first
841
814
  end
842
815
 
843
- it "returns the correct documents" do
816
+ it 'returns the correct documents' do
844
817
  expect(from_db).to eq(person)
845
818
  end
846
819
 
847
- context "when subsequently getting all documents" do
848
-
820
+ context 'when subsequently getting all documents' do
849
821
  let!(:documents) do
850
822
  criteria.entries
851
823
  end
852
824
 
853
- it "returns the correct documents" do
825
+ it 'returns the correct documents' do
854
826
  expect(documents).to eq([ person ])
855
827
  end
856
828
  end
857
829
  end
858
830
 
859
- context "when calling last on the criteria" do
860
-
831
+ context 'when calling last on the criteria' do
861
832
  let!(:criteria) do
862
- Person.asc(:age).includes(:posts)
833
+ Person.asc(:age).send(method_name, :posts)
863
834
  end
864
835
 
865
836
  let!(:from_db) do
866
837
  criteria.last
867
838
  end
868
839
 
869
- it "returns the correct documents" do
840
+ it 'returns the correct documents' do
870
841
  expect(from_db).to eq(person)
871
842
  end
872
843
 
873
- context "when subsequently getting all documents" do
874
-
844
+ context 'when subsequently getting all documents' do
875
845
  let!(:documents) do
876
846
  criteria.entries
877
847
  end
878
848
 
879
- it "returns the correct documents" do
849
+ it 'returns the correct documents' do
880
850
  expect(documents).to eq([ person ])
881
851
  end
882
852
  end
883
853
  end
884
854
 
885
- context "when the criteria has limiting options" do
886
-
887
- let!(:person_two) do
855
+ context 'when the criteria has limiting options' do
856
+ let(:person_two) do
888
857
  Person.create!
889
858
  end
890
859
 
891
- let!(:post_three) do
892
- person_two.posts.create!(title: "three")
860
+ let(:documents) do
861
+ criteria.entries
893
862
  end
894
863
 
895
- let!(:criteria) do
896
- Person.includes(:posts).asc(:age).limit(1)
864
+ let(:post_three) do
865
+ person_two.posts.create!(title: 'three')
866
+ end
867
+
868
+ let(:criteria) do
869
+ Person.send(method_name, :posts).asc(:age).limit(1)
897
870
  end
898
871
 
899
872
  let(:context) do
@@ -901,33 +874,37 @@ describe Mongoid::Criteria::Includable do
901
874
  end
902
875
 
903
876
  before do
904
- expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
905
- end
877
+ post_three
906
878
 
907
- let!(:documents) do
908
- criteria.entries
879
+ if method_name == :includes
880
+ expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
881
+ else
882
+ expect(context).to receive(:eager_load_with_lookup).once.and_call_original
883
+ end
909
884
  end
910
885
 
911
- it "returns the correct documents" do
886
+ it 'returns the correct documents' do
912
887
  expect(documents).to eq([ person ])
913
888
  end
914
889
  end
915
890
  end
916
891
 
917
- context "when including a has one" do
918
-
892
+ context 'when including a has one' do
919
893
  let!(:game_one) do
920
- person.create_game(name: "one")
894
+ person.create_game(name: 'one')
921
895
  end
922
896
 
923
897
  let!(:game_two) do
924
- person.create_game(name: "two")
898
+ person.create_game(name: 'two')
925
899
  end
926
900
 
927
- context "when the criteria has no options" do
901
+ context 'when the criteria has no options' do
902
+ let(:criteria) do
903
+ Person.asc(:age).send(method_name, :game)
904
+ end
928
905
 
929
- let!(:criteria) do
930
- Person.asc(:age).includes(:game)
906
+ let(:documents) do
907
+ criteria.entries
931
908
  end
932
909
 
933
910
  let(:context) do
@@ -935,30 +912,33 @@ describe Mongoid::Criteria::Includable do
935
912
  end
936
913
 
937
914
  before do
938
- expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
939
- end
940
-
941
- let!(:documents) do
942
- criteria.entries
915
+ if method_name == :includes
916
+ expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
917
+ else
918
+ expect(context).to receive(:eager_load_with_lookup).once.and_call_original
919
+ end
943
920
  end
944
921
 
945
- it "returns the correct documents" do
922
+ it 'returns the correct documents' do
946
923
  expect(documents).to eq([ person ])
947
924
  end
948
925
  end
949
926
 
950
- context "when the criteria has limiting options" do
951
-
952
- let!(:person_two) do
927
+ context 'when the criteria has limiting options' do
928
+ let(:person_two) do
953
929
  Person.create!(age: 2)
954
930
  end
955
931
 
956
- let!(:game_three) do
957
- person_two.create_game(name: "Skyrim")
932
+ let(:documents) do
933
+ criteria.entries
958
934
  end
959
935
 
960
- let!(:criteria) do
961
- Person.where(id: person.id).includes(:game).asc(:age).limit(1)
936
+ let(:game_three) do
937
+ person_two.create_game(name: 'Skyrim')
938
+ end
939
+
940
+ let(:criteria) do
941
+ Person.where(id: person.id).send(method_name, :game).asc(:age).limit(1)
962
942
  end
963
943
 
964
944
  let(:context) do
@@ -966,37 +946,42 @@ describe Mongoid::Criteria::Includable do
966
946
  end
967
947
 
968
948
  before do
969
- expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
970
- end
949
+ person_two
950
+ game_three
971
951
 
972
- let!(:documents) do
973
- criteria.entries
952
+ if method_name == :includes
953
+ expect(context).to receive(:eager_load).with([ person ]).once.and_call_original
954
+ else
955
+ expect(context).to receive(:eager_load_with_lookup).once.and_call_original
956
+ end
974
957
  end
975
958
 
976
- it "returns the correct documents" do
959
+ it 'returns the correct documents' do
977
960
  expect(documents).to eq([ person ])
978
961
  end
979
962
  end
980
963
  end
981
964
 
982
- context "when including a belongs to" do
983
-
965
+ context 'when including a belongs to' do
984
966
  let(:person_two) do
985
967
  Person.create!(age: 2)
986
968
  end
987
969
 
988
970
  let!(:game_one) do
989
- person.create_game(name: "one")
971
+ person.create_game(name: 'one')
990
972
  end
991
973
 
992
974
  let!(:game_two) do
993
- person_two.create_game(name: "two")
975
+ person_two.create_game(name: 'two')
994
976
  end
995
977
 
996
- context "when providing no options" do
978
+ context 'when providing no options' do
979
+ let(:criteria) do
980
+ Game.send(method_name, :person)
981
+ end
997
982
 
998
- let!(:criteria) do
999
- Game.includes(:person)
983
+ let(:documents) do
984
+ criteria.entries
1000
985
  end
1001
986
 
1002
987
  let(:context) do
@@ -1004,22 +989,27 @@ describe Mongoid::Criteria::Includable do
1004
989
  end
1005
990
 
1006
991
  before do
1007
- expect(context).to receive(:preload).twice.and_call_original
1008
- end
992
+ if method_name == :includes
993
+ expect(context).to receive(:preload).twice.and_call_original
994
+ else
995
+ expect(context).to receive(:preload_for_lookup).twice.and_call_original
996
+ end
1009
997
 
1010
- let!(:documents) do
1011
- criteria.entries
998
+ documents
1012
999
  end
1013
1000
 
1014
- it "returns the correct documents" do
1001
+ it 'returns the correct documents' do
1015
1002
  expect(criteria).to eq([ game_one, game_two ])
1016
1003
  end
1017
1004
  end
1018
1005
 
1019
- context "when the criteria has limiting options" do
1006
+ context 'when the criteria has limiting options' do
1007
+ let(:criteria) do
1008
+ Game.where(id: game_one.id).send(method_name, :person).asc(:_id).limit(1)
1009
+ end
1020
1010
 
1021
- let!(:criteria) do
1022
- Game.where(id: game_one.id).includes(:person).asc(:_id).limit(1)
1011
+ let(:documents) do
1012
+ criteria.entries
1023
1013
  end
1024
1014
 
1025
1015
  let(:context) do
@@ -1027,81 +1017,105 @@ describe Mongoid::Criteria::Includable do
1027
1017
  end
1028
1018
 
1029
1019
  before do
1030
- expect(context).to receive(:eager_load).with([ game_one ]).once.and_call_original
1031
- end
1020
+ if method_name == :includes
1021
+ expect(context).to receive(:eager_load).with([ game_one ]).once.and_call_original
1022
+ else
1023
+ expect(context).to receive(:eager_load_with_lookup).once.and_call_original
1024
+ end
1032
1025
 
1033
- let!(:documents) do
1034
- criteria.entries
1026
+ documents
1035
1027
  end
1036
1028
 
1037
- it "returns the correct documents" do
1029
+ it 'returns the correct documents' do
1038
1030
  expect(documents).to eq([ game_one ])
1039
1031
  end
1040
1032
  end
1041
1033
  end
1042
1034
 
1043
- context "when including multiples in the same criteria" do
1035
+ context 'when including multiples in the same criteria' do
1036
+ let(:documents) { criteria.entries }
1037
+ let(:post_one) { person.posts.create!(title: 'one') }
1038
+ let(:post_two) { person.posts.create!(title: 'two') }
1039
+ let(:game_one) { person.create_game(name: 'one') }
1040
+ let(:game_two) { person.create_game(name: 'two') }
1041
+ let(:criteria) { Person.send(method_name, :posts, :game).asc(:age) }
1042
+ let(:context) { criteria.context }
1044
1043
 
1045
- let!(:post_one) do
1046
- person.posts.create!(title: "one")
1047
- end
1044
+ before do
1045
+ post_one
1046
+ post_two
1047
+ game_one
1048
+ game_two
1048
1049
 
1049
- let!(:post_two) do
1050
- person.posts.create!(title: "two")
1051
- end
1050
+ if method_name == :includes
1051
+ expect(context).to receive(:preload).twice.and_call_original
1052
+ else
1053
+ expect(context).to receive(:preload_for_lookup).twice.and_call_original
1054
+ end
1052
1055
 
1053
- let!(:game_one) do
1054
- person.create_game(name: "one")
1056
+ documents
1055
1057
  end
1056
1058
 
1057
- let!(:game_two) do
1058
- person.create_game(name: "two")
1059
+ it 'returns the correct documents' do
1060
+ expect(criteria).to eq([ person ])
1059
1061
  end
1062
+ end
1060
1063
 
1061
- let!(:criteria) do
1062
- Person.includes(:posts, :game).asc(:age)
1064
+ context 'when classes inherit from each other' do
1065
+ let!(:admin) do
1066
+ IncAdmin.create!(admin_level: 2)
1063
1067
  end
1064
1068
 
1065
- let(:context) do
1066
- criteria.context
1069
+ let!(:post) do
1070
+ admin.posts.create!
1067
1071
  end
1068
1072
 
1069
- before do
1070
- expect(context).to receive(:preload).twice.and_call_original
1073
+ let(:criteria) do
1074
+ IncUser.send(method_name, :posts)
1071
1075
  end
1072
1076
 
1073
1077
  let!(:documents) do
1074
- criteria.entries
1078
+ query = -> { criteria.entries }
1079
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
1075
1080
  end
1076
1081
 
1077
- it "returns the correct documents" do
1078
- expect(criteria).to eq([ person ])
1082
+ it 'returns the correct documents' do
1083
+ expect(documents).to eq([ admin ])
1079
1084
  end
1080
- end
1081
1085
 
1082
- context "when including nested referenced associations" do
1086
+ it 'eager loads the posts' do
1087
+ expect_query(0) do
1088
+ expect(documents.first.posts).to eq([ post ])
1089
+ end
1090
+ end
1091
+ end
1083
1092
 
1084
- context "when using a has_one association" do
1093
+ context 'when including nested referenced associations' do
1094
+ context 'when using a has_one association' do
1085
1095
  before(:all) do
1086
1096
  class A
1087
1097
  include Mongoid::Document
1098
+
1088
1099
  has_one :b
1089
1100
  end
1090
1101
 
1091
1102
  class B
1092
1103
  include Mongoid::Document
1104
+
1093
1105
  belongs_to :a
1094
1106
  has_one :c
1095
1107
  end
1096
1108
 
1097
1109
  class C
1098
1110
  include Mongoid::Document
1111
+
1099
1112
  belongs_to :b
1100
1113
  has_one :d
1101
1114
  end
1102
1115
 
1103
1116
  class D
1104
1117
  include Mongoid::Document
1118
+
1105
1119
  belongs_to :c
1106
1120
  end
1107
1121
  end
@@ -1135,97 +1149,101 @@ describe Mongoid::Criteria::Includable do
1135
1149
  a.b = b
1136
1150
  end
1137
1151
 
1138
- context "when including the belongs_to assocation" do
1152
+ context 'when including the belongs_to association' do
1139
1153
  let!(:result) do
1140
- C.includes(b: :a).first
1154
+ C.send(method_name, b: :a).first
1141
1155
  end
1142
1156
 
1143
- it "finds the right document" do
1157
+ it 'finds the right document' do
1144
1158
  expect(result).to eq(c)
1145
1159
  expect(result.b).to eq(c.b)
1146
1160
  expect(result.b.a).to eq(c.b.a)
1147
1161
  end
1148
1162
 
1149
- it "does not execute a query" do
1150
- expect_no_queries do
1163
+ it 'does not execute a query' do
1164
+ expect_query(0) do
1151
1165
  result.b.a
1152
1166
  end
1153
1167
  end
1154
1168
  end
1155
1169
 
1156
- context "when including a doubly-nested belongs_to assocation" do
1170
+ context 'when including a doubly-nested belongs_to association' do
1157
1171
  let!(:result) do
1158
- D.includes(c: { b: :a }).first
1172
+ query = -> { D.send(method_name, c: { b: :a }).first }
1173
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
1159
1174
  end
1160
1175
 
1161
- it "finds the right document" do
1176
+ it 'finds the right document' do
1162
1177
  expect(result).to eq(d)
1163
1178
  expect(result.c).to eq(d.c)
1164
1179
  expect(result.c.b).to eq(d.c.b)
1165
1180
  expect(result.c.b.a).to eq(d.c.b.a)
1166
1181
  end
1167
1182
 
1168
- it "does not execute a query" do
1169
- expect_no_queries do
1183
+ it 'does not execute a query' do
1184
+ expect_query(0) do
1170
1185
  result.c.b.a
1171
1186
  end
1172
1187
  end
1173
1188
  end
1174
1189
 
1175
- context "when including the has_many assocation" do
1190
+ context 'when including the has_many association' do
1176
1191
  let!(:result) do
1177
- A.includes(b: :c).first
1192
+ query = -> { A.send(method_name, b: :c).first }
1193
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
1178
1194
  end
1179
1195
 
1180
- it "finds the right document" do
1196
+ it 'finds the right document' do
1181
1197
  expect(result).to eq(a)
1182
1198
  expect(result.b).to eq(a.b)
1183
1199
  expect(result.b.c).to eq(a.b.c)
1184
1200
  end
1185
1201
 
1186
- it "does not executes a query" do
1187
- expect_no_queries do
1202
+ it 'does not executes a query' do
1203
+ expect_query(0) do
1188
1204
  result.b.c
1189
1205
  end
1190
1206
  end
1191
1207
  end
1192
1208
 
1193
- context "when including a doubly-nested has_many assocation" do
1209
+ context 'when including a doubly-nested has_many association' do
1194
1210
  let!(:result) do
1195
- A.includes(b: { c: :d }).first
1211
+ query = -> { A.send(method_name, b: { c: :d }).first }
1212
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
1196
1213
  end
1197
1214
 
1198
- it "finds the right document" do
1215
+ it 'finds the right document' do
1199
1216
  expect(result).to eq(a)
1200
1217
  expect(result.b).to eq(a.b)
1201
1218
  expect(result.b.c).to eq(a.b.c)
1202
1219
  expect(result.b.c.d).to eq(a.b.c.d)
1203
1220
  end
1204
1221
 
1205
- it "does not execute a query" do
1206
- expect_no_queries do
1222
+ it 'does not execute a query' do
1223
+ expect_query(0) do
1207
1224
  result.b.c.d
1208
1225
  end
1209
1226
  end
1210
1227
  end
1211
1228
 
1212
- context "when there are multiple documents" do
1229
+ context 'when there are multiple documents' do
1213
1230
  let!(:as) do
1214
- res = 9.times.map do |i|
1231
+ res = 9.times.map do |_i|
1215
1232
  A.create!.tap do |a|
1216
1233
  a.b = B.create!.tap do |b|
1217
1234
  b.c = C.create!
1218
1235
  end
1219
1236
  end
1220
1237
  end
1221
- [a, *res]
1238
+ [ a, *res ]
1222
1239
  end
1223
1240
 
1224
1241
  let!(:results) do
1225
- A.includes(b: :c).entries.sort
1242
+ query = -> { A.send(method_name, b: :c).entries.sort }
1243
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
1226
1244
  end
1227
1245
 
1228
- it "finds the right document" do
1246
+ it 'finds the right document' do
1229
1247
  as.length.times do |i|
1230
1248
  expect(as[i]).to eq(results[i])
1231
1249
  expect(as[i].b).to eq(results[i].b)
@@ -1233,8 +1251,8 @@ describe Mongoid::Criteria::Includable do
1233
1251
  end
1234
1252
  end
1235
1253
 
1236
- it "does not execute a query" do
1237
- expect_no_queries do
1254
+ it 'does not execute a query' do
1255
+ expect_query(0) do
1238
1256
  results.each do |a|
1239
1257
  a.b.c
1240
1258
  end
@@ -1242,7 +1260,7 @@ describe Mongoid::Criteria::Includable do
1242
1260
  end
1243
1261
  end
1244
1262
 
1245
- context "when there are multiple associations" do
1263
+ context 'when there are multiple associations' do
1246
1264
  before(:all) do
1247
1265
  class A
1248
1266
  has_one :c
@@ -1256,16 +1274,18 @@ describe Mongoid::Criteria::Includable do
1256
1274
  let(:c2) { C.create! }
1257
1275
  let(:d2) { D.create! }
1258
1276
 
1277
+ let(:results) do
1278
+ query = -> { A.send(method_name, b: { c: :d }, c: :d).first }
1279
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
1280
+ end
1281
+
1259
1282
  before do
1260
1283
  a.c = c2
1261
1284
  a.c.d = d2
1285
+ results
1262
1286
  end
1263
1287
 
1264
- let!(:results) do
1265
- A.includes(b: { c: :d }, c: :d).first
1266
- end
1267
-
1268
- it "finds the right document" do
1288
+ it 'finds the right document' do
1269
1289
  expect(results).to eq(a)
1270
1290
  expect(results.b).to eq(a.b)
1271
1291
  expect(results.b.c).to eq(a.b.c)
@@ -1274,8 +1294,8 @@ describe Mongoid::Criteria::Includable do
1274
1294
  expect(results.c.d).to eq(a.c.d)
1275
1295
  end
1276
1296
 
1277
- it "does not execute a query" do
1278
- expect_no_queries do
1297
+ it 'does not execute a query' do
1298
+ expect_query(0) do
1279
1299
  results.c.d
1280
1300
  results.b.c.d
1281
1301
  end
@@ -1284,8 +1304,28 @@ describe Mongoid::Criteria::Includable do
1284
1304
  end
1285
1305
  end
1286
1306
 
1287
- context "when using a has_many association" do
1307
+ context 'when using a has_many association with an empty association' do
1308
+ let!(:user) do
1309
+ IncUser.create!
1310
+ end
1311
+
1312
+ let!(:result) do
1313
+ IncUser.send(method_name, :posts, :comments).where(id: user.id).first
1314
+ end
1315
+
1316
+ it 'executes the query' do
1317
+ expect(result).to eq(user)
1318
+ end
1319
+
1320
+ it 'does not issue extra queries' do
1321
+ expect_query(0) do
1322
+ result.posts.to_a
1323
+ result.comments.to_a
1324
+ end
1325
+ end
1326
+ end
1288
1327
 
1328
+ context 'when using a has_many association' do
1289
1329
  let!(:user) do
1290
1330
  IncUser.create!(posts: posts, comments: user_comments)
1291
1331
  end
@@ -1295,19 +1335,20 @@ describe Mongoid::Criteria::Includable do
1295
1335
  end
1296
1336
 
1297
1337
  let!(:user_comments) do
1298
- 2.times.map{ IncComment.create! }
1338
+ 2.times.map { IncComment.create! }
1299
1339
  end
1300
1340
 
1301
1341
  let!(:post_comments) do
1302
- 2.times.map{ IncComment.create! }
1342
+ 2.times.map { IncComment.create! }
1303
1343
  end
1304
1344
 
1305
- context "when including the same class twice" do
1345
+ context 'when including the same class twice' do
1306
1346
  let!(:results) do
1307
- IncPost.includes({ user: :comments }, :comments).entries.sort
1347
+ query = -> { IncPost.send(method_name, { user: :comments }, :comments).entries.sort }
1348
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
1308
1349
  end
1309
1350
 
1310
- it "finds the right documents" do
1351
+ it 'finds the right documents' do
1311
1352
  posts.length.times do |i|
1312
1353
  expect(posts[i]).to eq(results[i])
1313
1354
  expect(posts[i].user).to eq(results[i].user)
@@ -1316,8 +1357,8 @@ describe Mongoid::Criteria::Includable do
1316
1357
  end
1317
1358
  end
1318
1359
 
1319
- it "does not execute a query" do
1320
- expect_no_queries do
1360
+ it 'does not execute a query' do
1361
+ expect_query(0) do
1321
1362
  results.each do |res|
1322
1363
  res.user
1323
1364
  res.user.comments.to_a
@@ -1327,14 +1368,15 @@ describe Mongoid::Criteria::Includable do
1327
1368
  end
1328
1369
  end
1329
1370
 
1330
- context "when the association chain has a class name twice" do
1371
+ context 'when the association chain has a class name twice' do
1331
1372
  let!(:thread) { IncThread.create!(comments: user_comments) }
1332
1373
 
1333
1374
  let!(:result) do
1334
- IncThread.includes(comments: { user: { posts: :comments } }).first
1375
+ query = -> { IncThread.send(method_name, comments: { user: { posts: :comments } }).first }
1376
+ (method_name == :eager_load) ? expect_less_than_queries(3, &query) : query.call
1335
1377
  end
1336
1378
 
1337
- it "finds the right document" do
1379
+ it 'finds the right document' do
1338
1380
  expect(result).to eq(thread)
1339
1381
  result.comments.length.times do |i|
1340
1382
  c1 = result.comments[i]
@@ -1351,8 +1393,8 @@ describe Mongoid::Criteria::Includable do
1351
1393
  end
1352
1394
  end
1353
1395
 
1354
- it "does not execute a query" do
1355
- expect_no_queries do
1396
+ it 'does not execute a query' do
1397
+ expect_query(0) do
1356
1398
  result.comments.each do |comment|
1357
1399
  comment.user.posts.each do |post|
1358
1400
  post.comments.to_a
@@ -1364,112 +1406,994 @@ describe Mongoid::Criteria::Includable do
1364
1406
  end
1365
1407
  end
1366
1408
 
1367
- describe "#inclusions" do
1368
-
1369
- let(:criteria) do
1370
- Band.includes(:records)
1371
- end
1372
-
1373
- let(:association) do
1374
- Band.relations["records"]
1375
- end
1376
-
1377
- it "returns the inclusions" do
1378
- expect(criteria.inclusions).to eq([ association ])
1379
- end
1409
+ describe '#includes' do
1410
+ it_behaves_like 'eager loading', :includes
1380
1411
  end
1381
1412
 
1382
- describe "#inclusions=" do
1413
+ describe '#eager_load' do
1414
+ # 4.4 lookup does not support the lookup pipeline as it is currently written
1415
+ min_server_version '5.0'
1416
+ it_behaves_like 'eager loading', :eager_load
1383
1417
 
1384
- let(:criteria) do
1385
- Band.all
1386
- end
1418
+ context 'when the inclusion list is empty' do
1419
+ let!(:band) { Band.create! }
1387
1420
 
1388
- let(:association) do
1389
- Band.relations["records"]
1421
+ it 'returns the documents without eager loading' do
1422
+ expect(Band.eager_load([]).first).to eq(band)
1423
+ end
1390
1424
  end
1391
1425
 
1392
- before do
1393
- criteria.inclusions = [ association ]
1394
- end
1426
+ context 'when the association is defined on a subclass of the queried class' do
1427
+ before(:all) do
1428
+ class Machine
1429
+ include Mongoid::Document
1430
+ end
1395
1431
 
1396
- it "sets the inclusions" do
1397
- expect(criteria.inclusions).to eq([ association ])
1398
- end
1399
- end
1432
+ class Peripheral
1433
+ include Mongoid::Document
1434
+ end
1400
1435
 
1401
- context "When multiple associations reference the same class" do
1402
- before do
1403
- IncBlog.create(
1404
- posts: [
1405
- IncBlogPost.create(author: IncAuthor.create),
1406
- IncBlogPost.create(author: IncAuthor.create),
1407
- IncBlogPost.create(author: IncAuthor.create),
1408
- ],
1409
- highlighted_post: IncBlogPost.create(author: IncAuthor.create)
1410
- )
1411
- end
1436
+ class Webcam < Peripheral
1437
+ end
1412
1438
 
1413
- let!(:result) do
1414
- IncBlog.includes(:posts, highlighted_post: :author).first
1415
- end
1439
+ class Mouse < Peripheral
1440
+ belongs_to :machine
1441
+ end
1442
+ end
1416
1443
 
1417
- it "does not execute a query" do
1418
- expect_no_queries do
1419
- result.posts.to_a
1420
- result.highlighted_post
1444
+ after(:all) do
1445
+ Object.send(:remove_const, :Mouse)
1446
+ Object.send(:remove_const, :Webcam)
1447
+ Object.send(:remove_const, :Peripheral)
1448
+ Object.send(:remove_const, :Machine)
1421
1449
  end
1422
- end
1423
1450
 
1424
- it "executes a query for the non-retrieved elements" do
1425
- expect_query(3) do
1426
- result.posts.each do |post|
1427
- post.author
1451
+ let!(:machine) { Machine.create! }
1452
+ let!(:webcam) { Webcam.create! }
1453
+ let!(:mouse) { Mouse.create!(machine: machine) }
1454
+
1455
+ it 'eager-loads it through the queried superclass' do
1456
+ expect_query(1) do
1457
+ loaded = Peripheral.eager_load(:machine).detect { |doc| doc.is_a?(Mouse) }
1458
+ expect(loaded.machine).to eq(machine)
1428
1459
  end
1429
1460
  end
1430
1461
  end
1431
- end
1432
1462
 
1433
- context "When multiple parent_inclusions for the same association" do
1434
- before do
1435
- IncBlog.create(
1436
- posts: [
1437
- IncBlogPost.create(author: IncAuthor.create),
1438
- IncBlogPost.create(author: IncAuthor.create),
1439
- IncBlogPost.create(author: IncAuthor.create),
1440
- ],
1441
- highlighted_post: IncBlogPost.create(author: IncAuthor.create),
1442
- pinned_post: IncBlogPost.create(author: IncAuthor.create)
1443
- )
1444
- end
1463
+ context 'when the association is defined on a subclass of an associated class' do
1464
+ before(:all) do
1465
+ class Brand
1466
+ include Mongoid::Document
1467
+ end
1445
1468
 
1446
- let!(:result) do
1447
- IncBlog.includes(:posts, highlighted_post: :author, pinned_post: :author).first
1448
- end
1469
+ class Machine
1470
+ include Mongoid::Document
1471
+ end
1449
1472
 
1450
- it "does not execute a query" do
1451
- expect_no_queries do
1452
- result.posts.to_a
1453
- result.highlighted_post
1454
- result.pinned_post
1455
- end
1456
- end
1473
+ class Laptop < Machine
1474
+ belongs_to :brand
1475
+ end
1457
1476
 
1458
- it "executes a query for the non-retrieved elements" do
1459
- expect_query(3) do
1460
- result.posts.each do |post|
1461
- post.author
1477
+ class Peripheral
1478
+ include Mongoid::Document
1462
1479
  end
1463
- end
1464
- end
1465
1480
 
1466
- context "when including an association and using each twice on a criteria" do
1481
+ class Mouse < Peripheral
1482
+ belongs_to :machine
1483
+ end
1484
+ end
1485
+
1486
+ after(:all) do
1487
+ Object.send(:remove_const, :Mouse)
1488
+ Object.send(:remove_const, :Peripheral)
1489
+ Object.send(:remove_const, :Laptop)
1490
+ Object.send(:remove_const, :Machine)
1491
+ Object.send(:remove_const, :Brand)
1492
+ end
1493
+
1494
+ let!(:brand) { Brand.create! }
1495
+ let!(:laptop) { Laptop.create!(brand: brand) }
1496
+ let!(:mouse) { Mouse.create!(machine: laptop) }
1497
+
1498
+ it 'eager-loads it through the parent association' do
1499
+ expect_query(1) do
1500
+ loaded = Peripheral.eager_load(machine: :brand).first
1501
+ expect(loaded.machine).to eq(laptop)
1502
+ expect(loaded.machine.brand).to eq(brand)
1503
+ end
1504
+ end
1505
+ end
1506
+
1507
+ context 'when a has_many is defined only on a subclass' do
1508
+ before(:all) do
1509
+ class Gadget
1510
+ include Mongoid::Document
1511
+ end
1512
+
1513
+ class Speaker < Gadget
1514
+ has_many :cables
1515
+ end
1516
+
1517
+ class Cable
1518
+ include Mongoid::Document
1519
+
1520
+ belongs_to :speaker
1521
+ end
1522
+ end
1523
+
1524
+ after(:all) do
1525
+ Object.send(:remove_const, :Cable)
1526
+ Object.send(:remove_const, :Speaker)
1527
+ Object.send(:remove_const, :Gadget)
1528
+ end
1529
+
1530
+ let!(:speaker) { Speaker.create! }
1531
+ let!(:cable) { Cable.create!(speaker: speaker) }
1532
+
1533
+ it 'eager-loads it through the queried superclass' do
1534
+ expect_query(1) do
1535
+ loaded = Gadget.eager_load(:cables).first
1536
+ expect(loaded.cables).to eq([ cable ])
1537
+ end
1538
+ end
1539
+ end
1540
+
1541
+ context 'when a has_one is defined only on a subclass' do
1542
+ before(:all) do
1543
+ class Gadget
1544
+ include Mongoid::Document
1545
+ end
1546
+
1547
+ class Speaker < Gadget
1548
+ has_one :cable
1549
+ end
1550
+
1551
+ class Cable
1552
+ include Mongoid::Document
1553
+
1554
+ belongs_to :speaker
1555
+ end
1556
+ end
1557
+
1558
+ after(:all) do
1559
+ Object.send(:remove_const, :Cable)
1560
+ Object.send(:remove_const, :Speaker)
1561
+ Object.send(:remove_const, :Gadget)
1562
+ end
1563
+
1564
+ let!(:speaker) { Speaker.create! }
1565
+ let!(:cable) { Cable.create!(speaker: speaker) }
1566
+
1567
+ it 'eager-loads it through the queried superclass' do
1568
+ expect_query(1) do
1569
+ loaded = Gadget.eager_load(:cable).first
1570
+ expect(loaded.cable).to eq(cable)
1571
+ end
1572
+ end
1573
+ end
1574
+
1575
+ context 'when a has_and_belongs_to_many is defined only on a subclass' do
1576
+ before(:all) do
1577
+ class Cable
1578
+ include Mongoid::Document
1579
+
1580
+ has_and_belongs_to_many :speakers
1581
+ end
1582
+
1583
+ class Gadget
1584
+ include Mongoid::Document
1585
+ end
1586
+
1587
+ class Speaker < Gadget
1588
+ has_and_belongs_to_many :cables
1589
+ end
1590
+ end
1591
+
1592
+ after(:all) do
1593
+ Object.send(:remove_const, :Speaker)
1594
+ Object.send(:remove_const, :Gadget)
1595
+ Object.send(:remove_const, :Cable)
1596
+ end
1597
+
1598
+ let!(:cable) { Cable.create! }
1599
+ let!(:speaker) { Speaker.create!(cables: [ cable ]) }
1600
+
1601
+ it 'eager-loads it through the queried superclass' do
1602
+ expect_query(1) do
1603
+ loaded = Gadget.eager_load(:cables).first
1604
+ expect(loaded.cables).to eq([ cable ])
1605
+ end
1606
+ end
1607
+ end
1608
+
1609
+ context 'when a belongs_to lives inside an embedded document' do
1610
+ before(:all) do
1611
+ class Device
1612
+ include Mongoid::Document
1613
+ end
1614
+
1615
+ class Port
1616
+ include Mongoid::Document
1617
+
1618
+ embedded_in :computer
1619
+ belongs_to :device
1620
+ end
1621
+
1622
+ class Computer
1623
+ include Mongoid::Document
1624
+
1625
+ embeds_one :port
1626
+ end
1627
+ end
1628
+
1629
+ after(:all) do
1630
+ Object.send(:remove_const, :Computer)
1631
+ Object.send(:remove_const, :Port)
1632
+ Object.send(:remove_const, :Device)
1633
+ end
1634
+
1635
+ let!(:device) { Device.create! }
1636
+ let!(:computer) { Computer.create!(port: Port.new(device: device)) }
1637
+
1638
+ it 'eager-loads it through the embedded document' do
1639
+ expect_query(1) do
1640
+ loaded = Computer.eager_load(port: :device).first
1641
+ expect(loaded.port.device).to eq(device)
1642
+ end
1643
+ end
1644
+
1645
+ it 'leaves the embedded document absent instead of synthesizing it' do
1646
+ without_port = Computer.create!
1647
+ loaded = expect_query(1) do
1648
+ Computer.eager_load(port: :device).to_a.index_by(&:id)
1649
+ end
1650
+ expect_no_queries do
1651
+ expect(loaded[without_port.id].port).to be_nil
1652
+ end
1653
+ end
1654
+ end
1655
+
1656
+ context 'when two embeds_one associations of the same class are eager-loaded' do
1657
+ before(:all) do
1658
+ class Device
1659
+ include Mongoid::Document
1660
+ end
1661
+
1662
+ class Port
1663
+ include Mongoid::Document
1664
+
1665
+ embedded_in :computer
1666
+ belongs_to :device
1667
+ end
1668
+
1669
+ class Computer
1670
+ include Mongoid::Document
1671
+
1672
+ embeds_one :left_port, class_name: 'Port'
1673
+ embeds_one :right_port, class_name: 'Port'
1674
+ end
1675
+ end
1676
+
1677
+ after(:all) do
1678
+ Object.send(:remove_const, :Computer)
1679
+ Object.send(:remove_const, :Port)
1680
+ Object.send(:remove_const, :Device)
1681
+ end
1682
+
1683
+ let!(:device1) { Device.create! }
1684
+ let!(:device2) { Device.create! }
1685
+ let!(:computer) do
1686
+ Computer.create!(
1687
+ left_port: Port.new(device: device1),
1688
+ right_port: Port.new(device: device2)
1689
+ )
1690
+ end
1691
+
1692
+ it 'eager-loads the belongs_to in both embedded documents' do
1693
+ expect_query(1) do
1694
+ loaded = Computer.eager_load(left_port: :device, right_port: :device).first
1695
+ expect(loaded.left_port.device).to eq(device1)
1696
+ expect(loaded.right_port.device).to eq(device2)
1697
+ end
1698
+ end
1699
+ end
1700
+
1701
+ context 'when a belongs_to lives inside a doubly embedded document' do
1702
+ before(:all) do
1703
+ class Device
1704
+ include Mongoid::Document
1705
+ end
1706
+
1707
+ class Port
1708
+ include Mongoid::Document
1709
+
1710
+ embedded_in :panel
1711
+ belongs_to :device
1712
+ end
1713
+
1714
+ class Panel
1715
+ include Mongoid::Document
1716
+
1717
+ embedded_in :computer
1718
+ embeds_one :port
1719
+ end
1720
+
1721
+ class Computer
1722
+ include Mongoid::Document
1723
+
1724
+ embeds_one :panel
1725
+ end
1726
+ end
1727
+
1728
+ after(:all) do
1729
+ Object.send(:remove_const, :Computer)
1730
+ Object.send(:remove_const, :Panel)
1731
+ Object.send(:remove_const, :Port)
1732
+ Object.send(:remove_const, :Device)
1733
+ end
1734
+
1735
+ let!(:device) { Device.create! }
1736
+ let!(:computer) { Computer.create!(panel: Panel.new(port: Port.new(device: device))) }
1737
+
1738
+ it 'eager-loads it through both embedded documents' do
1739
+ expect_query(1) do
1740
+ loaded = Computer.eager_load(panel: { port: :device }).first
1741
+ expect(loaded.panel.port.device).to eq(device)
1742
+ end
1743
+ end
1744
+ end
1745
+
1746
+ context 'when a belongs_to is defined only on a subclass of an embedded document' do
1747
+ before(:all) do
1748
+ class Device
1749
+ include Mongoid::Document
1750
+ end
1751
+
1752
+ class Port
1753
+ include Mongoid::Document
1754
+
1755
+ embedded_in :computer
1756
+ end
1757
+
1758
+ class UsbPort < Port
1759
+ belongs_to :device
1760
+ end
1761
+
1762
+ class Computer
1763
+ include Mongoid::Document
1764
+
1765
+ embeds_one :port
1766
+ end
1767
+ end
1768
+
1769
+ after(:all) do
1770
+ Object.send(:remove_const, :Computer)
1771
+ Object.send(:remove_const, :UsbPort)
1772
+ Object.send(:remove_const, :Port)
1773
+ Object.send(:remove_const, :Device)
1774
+ end
1775
+
1776
+ let!(:device) { Device.create! }
1777
+ let!(:computer) { Computer.create!(port: UsbPort.new(device: device)) }
1778
+
1779
+ it 'eager-loads it through the embedded subclass' do
1780
+ expect_query(1) do
1781
+ loaded = Computer.eager_load(port: :device).first
1782
+ expect(loaded.port.device).to eq(device)
1783
+ end
1784
+ end
1785
+ end
1786
+
1787
+ context 'when a belongs_to lives inside an embeds_many' do
1788
+ before(:all) do
1789
+ class Device
1790
+ include Mongoid::Document
1791
+ end
1792
+
1793
+ class Port
1794
+ include Mongoid::Document
1795
+
1796
+ embedded_in :computer
1797
+ belongs_to :device
1798
+ end
1799
+
1800
+ class Computer
1801
+ include Mongoid::Document
1802
+
1803
+ embeds_many :ports
1804
+ end
1805
+ end
1806
+
1807
+ after(:all) do
1808
+ Object.send(:remove_const, :Computer)
1809
+ Object.send(:remove_const, :Port)
1810
+ Object.send(:remove_const, :Device)
1811
+ end
1812
+
1813
+ let!(:device1) { Device.create! }
1814
+ let!(:device2) { Device.create! }
1815
+ let!(:computer) { Computer.create!(ports: [ Port.new(device: device1), Port.new(device: device2) ]) }
1816
+
1817
+ it 'eager-loads each embedded belongs_to without extra queries' do
1818
+ expect_query(1) do
1819
+ loaded = Computer.eager_load(ports: :device).first
1820
+ expect(loaded.ports.map(&:device)).to eq([ device1, device2 ])
1821
+ end
1822
+ end
1823
+ end
1824
+
1825
+ context 'when a has_and_belongs_to_many lives inside an embedded document' do
1826
+ before(:all) do
1827
+ class Device
1828
+ include Mongoid::Document
1829
+ end
1830
+
1831
+ class Port
1832
+ include Mongoid::Document
1833
+
1834
+ embedded_in :computer
1835
+ has_and_belongs_to_many :devices
1836
+ end
1837
+
1838
+ class Computer
1839
+ include Mongoid::Document
1840
+
1841
+ embeds_one :port
1842
+ end
1843
+ end
1844
+
1845
+ after(:all) do
1846
+ Object.send(:remove_const, :Computer)
1847
+ Object.send(:remove_const, :Port)
1848
+ Object.send(:remove_const, :Device)
1849
+ end
1850
+
1851
+ let!(:device1) { Device.create! }
1852
+ let!(:device2) { Device.create! }
1853
+ let!(:computer) { Computer.create!(port: Port.new(devices: [ device1, device2 ])) }
1854
+
1855
+ it 'eager-loads the devices referenced by the embedded port' do
1856
+ expect_query(1) do
1857
+ loaded = Computer.eager_load(port: :devices).first
1858
+ expect(loaded.port.devices).to eq([ device1, device2 ])
1859
+ end
1860
+ end
1861
+ end
1862
+
1863
+ context 'when an embedded belongs_to targets a superclass of the queried subclass' do
1864
+ before(:all) do
1865
+ class Device
1866
+ include Mongoid::Document
1867
+ end
1868
+
1869
+ class Computer < Device
1870
+ embeds_one :port
1871
+ end
1872
+
1873
+ class Port
1874
+ include Mongoid::Document
1875
+
1876
+ embedded_in :computer
1877
+ belongs_to :device
1878
+ end
1879
+ end
1880
+
1881
+ after(:all) do
1882
+ Object.send(:remove_const, :Port)
1883
+ Object.send(:remove_const, :Computer)
1884
+ Object.send(:remove_const, :Device)
1885
+ end
1886
+
1887
+ let!(:device) { Device.create! }
1888
+ let!(:computer) { Computer.create!(port: Port.new(device: device)) }
1889
+
1890
+ it 'eager-loads the embedded belongs_to through the queried subclass' do
1891
+ expect_query(1) do
1892
+ loaded = Computer.eager_load(port: :device).first
1893
+ expect(loaded.port.device).to eq(device)
1894
+ end
1895
+ end
1896
+ end
1897
+
1898
+ context 'when an embedded association is nested under a referenced one' do
1899
+ before(:all) do
1900
+ class Device
1901
+ include Mongoid::Document
1902
+ end
1903
+
1904
+ class Port
1905
+ include Mongoid::Document
1906
+
1907
+ embedded_in :computer
1908
+ belongs_to :device
1909
+ end
1910
+
1911
+ class Computer
1912
+ include Mongoid::Document
1913
+
1914
+ embeds_one :port
1915
+ end
1916
+
1917
+ class Desk
1918
+ include Mongoid::Document
1919
+
1920
+ belongs_to :computer
1921
+ end
1922
+ end
1923
+
1924
+ after(:all) do
1925
+ Object.send(:remove_const, :Desk)
1926
+ Object.send(:remove_const, :Computer)
1927
+ Object.send(:remove_const, :Port)
1928
+ Object.send(:remove_const, :Device)
1929
+ end
1930
+
1931
+ let!(:device) { Device.create! }
1932
+ let!(:computer) { Computer.create!(port: Port.new(device: device)) }
1933
+ let!(:desk) { Desk.create!(computer: computer) }
1934
+
1935
+ it 'eager-loads the embedded association together with its referenced child' do
1936
+ expect_query(1) do
1937
+ loaded = Desk.eager_load(computer: { port: :device }).first
1938
+ expect(loaded.computer.port.device).to eq(device)
1939
+ end
1940
+ end
1941
+ end
1942
+
1943
+ context 'when an embedded association is nested two levels under a referenced one' do
1944
+ before(:all) do
1945
+ class Device
1946
+ include Mongoid::Document
1947
+ end
1948
+
1949
+ class Pin
1950
+ include Mongoid::Document
1951
+
1952
+ embedded_in :port
1953
+ belongs_to :device
1954
+ end
1955
+
1956
+ class Port
1957
+ include Mongoid::Document
1958
+
1959
+ embedded_in :computer
1960
+ embeds_one :pin
1961
+ end
1962
+
1963
+ class Computer
1964
+ include Mongoid::Document
1965
+
1966
+ embeds_one :port
1967
+ end
1968
+
1969
+ class Desk
1970
+ include Mongoid::Document
1971
+
1972
+ belongs_to :computer
1973
+ end
1974
+ end
1975
+
1976
+ after(:all) do
1977
+ Object.send(:remove_const, :Desk)
1978
+ Object.send(:remove_const, :Computer)
1979
+ Object.send(:remove_const, :Port)
1980
+ Object.send(:remove_const, :Pin)
1981
+ Object.send(:remove_const, :Device)
1982
+ end
1983
+
1984
+ let!(:device) { Device.create! }
1985
+ let!(:computer) { Computer.create!(port: Port.new(pin: Pin.new(device: device))) }
1986
+ let!(:desk) { Desk.create!(computer: computer) }
1987
+
1988
+ it 'eager-loads the doubly embedded association together with its referenced child' do
1989
+ expect_query(1) do
1990
+ loaded = Desk.eager_load(computer: { port: { pin: :device } }).first
1991
+ expect(loaded.computer.port.pin.device).to eq(device)
1992
+ end
1993
+ end
1994
+ end
1995
+
1996
+ context 'when an embeds_many is nested inside another embeds_many under a referenced one' do
1997
+ before(:all) do
1998
+ class Device
1999
+ include Mongoid::Document
2000
+ end
2001
+
2002
+ class Port
2003
+ include Mongoid::Document
2004
+
2005
+ embedded_in :card
2006
+ belongs_to :device
2007
+ end
2008
+
2009
+ class Card
2010
+ include Mongoid::Document
2011
+
2012
+ embedded_in :computer
2013
+ embeds_many :ports
2014
+ end
2015
+
2016
+ class Computer
2017
+ include Mongoid::Document
2018
+
2019
+ embeds_many :cards
2020
+ end
2021
+
2022
+ class Desk
2023
+ include Mongoid::Document
2024
+
2025
+ belongs_to :computer
2026
+ end
2027
+ end
2028
+
2029
+ after(:all) do
2030
+ Object.send(:remove_const, :Desk)
2031
+ Object.send(:remove_const, :Computer)
2032
+ Object.send(:remove_const, :Card)
2033
+ Object.send(:remove_const, :Port)
2034
+ Object.send(:remove_const, :Device)
2035
+ end
2036
+
2037
+ let!(:devices) { Array.new(4) { Device.create! } }
2038
+ let!(:computer) do
2039
+ Computer.create!(
2040
+ cards: [
2041
+ Card.new(ports: [ Port.new(device: devices[0]), Port.new(device: devices[1]) ]),
2042
+ Card.new(ports: [ Port.new(device: devices[2]), Port.new(device: devices[3]) ])
2043
+ ]
2044
+ )
2045
+ end
2046
+ let!(:desk) { Desk.create!(computer: computer) }
2047
+
2048
+ it 'eager-loads each deeply embedded belongs_to correlated to its own element' do
2049
+ expect_query(1) do
2050
+ loaded = Desk.eager_load(computer: { cards: { ports: :device } }).first
2051
+ got = loaded.computer.cards.flat_map { |card| card.ports.map(&:device) }
2052
+ expect(got).to eq(devices)
2053
+ end
2054
+ end
2055
+ end
2056
+
2057
+ context 'when a polymorphic belongs_to is eager-loaded' do
2058
+ before(:all) do
2059
+ class Printer
2060
+ include Mongoid::Document
2061
+ end
2062
+
2063
+ class Scanner
2064
+ include Mongoid::Document
2065
+ end
2066
+
2067
+ class Cartridge
2068
+ include Mongoid::Document
2069
+
2070
+ belongs_to :device, polymorphic: true
2071
+ end
2072
+ end
2073
+
2074
+ after(:all) do
2075
+ Object.send(:remove_const, :Cartridge)
2076
+ Object.send(:remove_const, :Scanner)
2077
+ Object.send(:remove_const, :Printer)
2078
+ end
2079
+
2080
+ let!(:printer) { Printer.create! }
2081
+ let!(:scanner) { Scanner.create! }
2082
+ let!(:printer_cartridge) { Cartridge.create!(device: printer) }
2083
+ let!(:scanner_cartridge) { Cartridge.create!(device: scanner) }
2084
+
2085
+ it 'eager-loads polymorphic targets of different types in a single extra query' do
2086
+ expect_query(2) do
2087
+ loaded = Cartridge.eager_load(:device).to_a.index_by(&:id)
2088
+ expect(loaded[printer_cartridge.id].device).to eq(printer)
2089
+ expect(loaded[scanner_cartridge.id].device).to eq(scanner)
2090
+ end
2091
+ end
2092
+ end
2093
+
2094
+ context 'when a polymorphic target is stored in another database' do
2095
+ before(:all) do
2096
+ class LocalDevice
2097
+ include Mongoid::Document
2098
+ end
2099
+
2100
+ class RemoteDevice
2101
+ include Mongoid::Document
2102
+
2103
+ store_in database: 'secondary'
2104
+ end
2105
+
2106
+ class Accessory
2107
+ include Mongoid::Document
2108
+
2109
+ belongs_to :device, polymorphic: true
2110
+ end
2111
+ end
2112
+
2113
+ after(:all) do
2114
+ Object.send(:remove_const, :Accessory)
2115
+ Object.send(:remove_const, :RemoteDevice)
2116
+ Object.send(:remove_const, :LocalDevice)
2117
+ end
2118
+
2119
+ # RemoteDevice lives in its own database, which the global cleanup hook
2120
+ # (default database only) does not touch, so drop it here.
2121
+ after { RemoteDevice.collection.drop }
2122
+
2123
+ let!(:local_device) { LocalDevice.create! }
2124
+ let!(:remote_device) { RemoteDevice.create! }
2125
+ let!(:local_accessory) { Accessory.create!(device: local_device) }
2126
+ let!(:remote_accessory) { Accessory.create!(device: remote_device) }
2127
+
2128
+ it 'eager-loads the target stored in the other database' do
2129
+ # One query materializes the roots, one $facet fetches the same-database
2130
+ # target, and one direct query fetches the target in the other database.
2131
+ loaded = expect_query(3) do
2132
+ Accessory.eager_load(:device).to_a.index_by(&:id)
2133
+ end
2134
+
2135
+ expect_no_queries do
2136
+ expect(loaded[local_accessory.id].device).to eq(local_device)
2137
+ expect(loaded[remote_accessory.id].device).to eq(remote_device)
2138
+ end
2139
+ end
2140
+ end
2141
+
2142
+ context 'when a non-polymorphic target is stored in another database' do
2143
+ before(:all) do
2144
+ class RemoteServer
2145
+ include Mongoid::Document
2146
+
2147
+ store_in database: 'secondary'
2148
+ end
2149
+
2150
+ class Workstation
2151
+ include Mongoid::Document
2152
+
2153
+ belongs_to :server, class_name: 'RemoteServer', optional: true
2154
+ end
2155
+ end
2156
+
2157
+ after(:all) do
2158
+ Object.send(:remove_const, :Workstation)
2159
+ Object.send(:remove_const, :RemoteServer)
2160
+ end
2161
+
2162
+ # RemoteServer lives in its own database, which the global cleanup hook
2163
+ # (default database only) does not touch, so drop it here.
2164
+ after { RemoteServer.collection.drop }
2165
+
2166
+ let!(:server) { RemoteServer.create! }
2167
+ let!(:workstation) { Workstation.create!(server: server) }
2168
+
2169
+ it 'eager-loads the target stored in the other database' do
2170
+ # A $lookup cannot reach another database, so this falls back to
2171
+ # separate-query loading: one query materializes the roots and one fetches
2172
+ # the targets, instead of silently returning nothing.
2173
+ loaded = expect_query(2) do
2174
+ Workstation.eager_load(:server).to_a
2175
+ end
2176
+
2177
+ expect_no_queries do
2178
+ expect(loaded.first.server).to eq(server)
2179
+ end
2180
+ end
2181
+ end
2182
+
2183
+ context 'when a has_many of the same name is defined on more than one subclass' do
2184
+ before(:all) do
2185
+ class Supplier
2186
+ include Mongoid::Document
2187
+ end
2188
+
2189
+ class Cog
2190
+ include Mongoid::Document
2191
+
2192
+ belongs_to :machine, optional: true
2193
+ belongs_to :supplier, optional: true
2194
+ end
2195
+
2196
+ class Belt
2197
+ include Mongoid::Document
2198
+
2199
+ belongs_to :machine, optional: true
2200
+ belongs_to :supplier, optional: true
2201
+ end
2202
+
2203
+ class Machine
2204
+ include Mongoid::Document
2205
+ end
2206
+
2207
+ class Lathe < Machine
2208
+ has_many :widgets, class_name: 'Cog', inverse_of: :machine
2209
+ end
2210
+
2211
+ class Press < Machine
2212
+ has_many :widgets, class_name: 'Belt', inverse_of: :machine
2213
+ end
2214
+ end
2215
+
2216
+ after(:all) do
2217
+ Object.send(:remove_const, :Press)
2218
+ Object.send(:remove_const, :Lathe)
2219
+ Object.send(:remove_const, :Machine)
2220
+ Object.send(:remove_const, :Belt)
2221
+ Object.send(:remove_const, :Cog)
2222
+ Object.send(:remove_const, :Supplier)
2223
+ end
2224
+
2225
+ let!(:cog_supplier) { Supplier.create! }
2226
+ let!(:belt_supplier) { Supplier.create! }
2227
+ let!(:lathe) { Lathe.create! }
2228
+ let!(:press) { Press.create! }
2229
+ let!(:cog) { Cog.create!(machine: lathe, supplier: cog_supplier) }
2230
+ let!(:belt) { Belt.create!(machine: press, supplier: belt_supplier) }
2231
+
2232
+ it 'loads each subclass association without one overwriting the other' do
2233
+ loaded = expect_query(1) do
2234
+ Machine.eager_load(:widgets).to_a.index_by(&:id)
2235
+ end
2236
+ expect_no_queries do
2237
+ expect(loaded[lathe.id].widgets).to eq([ cog ])
2238
+ expect(loaded[press.id].widgets).to eq([ belt ])
2239
+ end
2240
+ end
2241
+
2242
+ it 'eager-loads inclusions nested under each subclass association' do
2243
+ loaded = expect_query(1) do
2244
+ Machine.eager_load(widgets: :supplier).to_a.index_by(&:id)
2245
+ end
2246
+ expect_no_queries do
2247
+ expect(loaded[lathe.id].widgets.first.supplier).to eq(cog_supplier)
2248
+ expect(loaded[press.id].widgets.first.supplier).to eq(belt_supplier)
2249
+ end
2250
+ end
2251
+ end
2252
+
2253
+ context 'when a has_many targets a class sharing its collection with sibling subclasses' do
2254
+ before(:all) do
2255
+ class Part
2256
+ include Mongoid::Document
2257
+ end
2258
+
2259
+ class Chip < Part
2260
+ belongs_to :board, class_name: 'Board', optional: true
2261
+ end
2262
+
2263
+ class Cable < Part
2264
+ belongs_to :board, class_name: 'Board', optional: true
2265
+ end
2266
+
2267
+ class Board
2268
+ include Mongoid::Document
2269
+
2270
+ has_many :chips, class_name: 'Chip', inverse_of: :board
2271
+ end
2272
+ end
2273
+
2274
+ after(:all) do
2275
+ Object.send(:remove_const, :Board)
2276
+ Object.send(:remove_const, :Cable)
2277
+ Object.send(:remove_const, :Chip)
2278
+ Object.send(:remove_const, :Part)
2279
+ end
2280
+
2281
+ let!(:board) { Board.create! }
2282
+ let!(:chip) { Chip.create!(board: board) }
2283
+ let!(:cable) { Cable.create!(board: board) }
2284
+
2285
+ it 'eager-loads only the chips, not the sibling subclass' do
2286
+ expect_query(1) do
2287
+ loaded = Board.eager_load(:chips).first
2288
+ expect(loaded.chips.to_a).to eq([ chip ])
2289
+ end
2290
+ end
2291
+ end
2292
+ end
2293
+
2294
+ describe '#inclusions' do
2295
+ let(:criteria) do
2296
+ Band.includes(:records)
2297
+ end
2298
+
2299
+ let(:association) do
2300
+ Band.relations['records']
2301
+ end
2302
+
2303
+ it 'returns the inclusions' do
2304
+ expect(criteria.inclusions).to eq([ association ])
2305
+ end
2306
+ end
2307
+
2308
+ describe '#inclusions=' do
2309
+ let(:criteria) do
2310
+ Band.all
2311
+ end
2312
+
2313
+ let(:association) do
2314
+ Band.relations['records']
2315
+ end
2316
+
2317
+ before do
2318
+ criteria.inclusions = [ association ]
2319
+ end
2320
+
2321
+ it 'sets the inclusions' do
2322
+ expect(criteria.inclusions).to eq([ association ])
2323
+ end
2324
+ end
2325
+
2326
+ context 'When multiple associations reference the same class' do
2327
+ before do
2328
+ IncBlog.create(
2329
+ posts: [
2330
+ IncBlogPost.create(author: IncAuthor.create),
2331
+ IncBlogPost.create(author: IncAuthor.create),
2332
+ IncBlogPost.create(author: IncAuthor.create)
2333
+ ],
2334
+ highlighted_post: IncBlogPost.create(author: IncAuthor.create)
2335
+ )
2336
+ end
2337
+
2338
+ let!(:result) do
2339
+ IncBlog.includes(:posts, highlighted_post: :author).first
2340
+ end
2341
+
2342
+ it 'does not execute a query' do
2343
+ expect_query(0) do
2344
+ result.posts.to_a
2345
+ result.highlighted_post
2346
+ end
2347
+ end
2348
+
2349
+ it 'executes a query for the non-retrieved elements' do
2350
+ expect_query(3) do
2351
+ result.posts.each do |post|
2352
+ post.author
2353
+ end
2354
+ end
2355
+ end
2356
+ end
2357
+
2358
+ context 'When multiple parent_inclusions for the same association' do
2359
+ before do
2360
+ IncBlog.create(
2361
+ posts: [
2362
+ IncBlogPost.create(author: IncAuthor.create),
2363
+ IncBlogPost.create(author: IncAuthor.create),
2364
+ IncBlogPost.create(author: IncAuthor.create)
2365
+ ],
2366
+ highlighted_post: IncBlogPost.create(author: IncAuthor.create),
2367
+ pinned_post: IncBlogPost.create(author: IncAuthor.create)
2368
+ )
2369
+ end
2370
+
2371
+ let!(:result) do
2372
+ IncBlog.includes(:posts, highlighted_post: :author, pinned_post: :author).first
2373
+ end
2374
+
2375
+ it 'does not execute a query' do
2376
+ expect_query(0) do
2377
+ result.posts.to_a
2378
+ result.highlighted_post
2379
+ result.pinned_post
2380
+ end
2381
+ end
2382
+
2383
+ it 'executes a query for the non-retrieved elements' do
2384
+ expect_query(3) do
2385
+ result.posts.each do |post|
2386
+ post.author
2387
+ end
2388
+ end
2389
+ end
1467
2390
 
2391
+ context 'when including an association and using each twice on a criteria' do
1468
2392
  let(:criteria) { IncPost.all.includes(:person) }
1469
2393
 
1470
2394
  before do
1471
- p = IncPerson.create!(name: "name")
1472
- 4.times { IncPost.create!(person: p)}
2395
+ p = IncPerson.create!(name: 'name')
2396
+ 4.times { IncPost.create!(person: p) }
1473
2397
  criteria
1474
2398
  expect_query(2) do
1475
2399
  criteria.each(&:person)
@@ -1483,7 +2407,7 @@ describe Mongoid::Criteria::Includable do
1483
2407
  # trying to retrieve their person.
1484
2408
  # MONGOID-3942 reported that after iterating the criteria a second time,
1485
2409
  # the posts would not get the eager loaded person.
1486
- it "eager loads the criteria" do
2410
+ it 'eager loads the criteria' do
1487
2411
  expect_query(2) do
1488
2412
  criteria.each(&:person)
1489
2413
  end