mongoid 7.0.2 → 8.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 (1104) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +33 -33
  4. data/LICENSE +1 -0
  5. data/README.md +34 -20
  6. data/Rakefile +100 -5
  7. data/lib/config/locales/en.yml +220 -105
  8. data/lib/mongoid/association/accessors.rb +176 -84
  9. data/lib/mongoid/association/bindable.rb +57 -28
  10. data/lib/mongoid/association/builders.rb +9 -15
  11. data/lib/mongoid/association/constrainable.rb +5 -7
  12. data/lib/mongoid/association/depending.rb +9 -18
  13. data/lib/mongoid/association/eager_loadable.rb +31 -10
  14. data/lib/mongoid/association/embedded/batchable.rb +68 -54
  15. data/lib/mongoid/association/embedded/cyclic.rb +10 -17
  16. data/lib/mongoid/association/embedded/embedded_in/binding.rb +27 -9
  17. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +9 -6
  18. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +16 -25
  19. data/lib/mongoid/association/embedded/embedded_in.rb +9 -28
  20. data/lib/mongoid/association/embedded/embeds_many/binding.rb +5 -8
  21. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +10 -6
  22. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +156 -135
  23. data/lib/mongoid/association/embedded/embeds_many.rb +10 -37
  24. data/lib/mongoid/association/embedded/embeds_one/binding.rb +4 -8
  25. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +27 -10
  26. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +64 -30
  27. data/lib/mongoid/association/embedded/embeds_one.rb +11 -34
  28. data/lib/mongoid/association/embedded.rb +2 -0
  29. data/lib/mongoid/association/macros.rb +65 -41
  30. data/lib/mongoid/association/many.rb +25 -35
  31. data/lib/mongoid/association/marshalable.rb +3 -6
  32. data/lib/mongoid/association/nested/many.rb +22 -30
  33. data/lib/mongoid/association/nested/nested_buildable.rb +9 -15
  34. data/lib/mongoid/association/nested/one.rb +57 -30
  35. data/lib/mongoid/association/nested.rb +3 -3
  36. data/lib/mongoid/association/one.rb +5 -12
  37. data/lib/mongoid/association/options.rb +16 -46
  38. data/lib/mongoid/association/proxy.rb +52 -40
  39. data/lib/mongoid/association/referenced/auto_save.rb +9 -14
  40. data/lib/mongoid/association/referenced/belongs_to/binding.rb +5 -9
  41. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +11 -9
  42. data/lib/mongoid/association/referenced/belongs_to/eager.rb +40 -3
  43. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +19 -31
  44. data/lib/mongoid/association/referenced/belongs_to.rb +16 -38
  45. data/lib/mongoid/association/referenced/counter_cache.rb +14 -25
  46. data/lib/mongoid/association/referenced/eager.rb +42 -38
  47. data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +12 -11
  48. data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +5 -5
  49. data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +2 -1
  50. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +106 -67
  51. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +29 -46
  52. data/lib/mongoid/association/referenced/has_many/binding.rb +3 -6
  53. data/lib/mongoid/association/referenced/has_many/buildable.rb +5 -5
  54. data/lib/mongoid/association/referenced/has_many/eager.rb +2 -1
  55. data/lib/mongoid/association/referenced/has_many/enumerable.rb +440 -456
  56. data/lib/mongoid/association/referenced/has_many/proxy.rb +104 -127
  57. data/lib/mongoid/association/referenced/has_many.rb +21 -45
  58. data/lib/mongoid/association/referenced/has_one/binding.rb +4 -9
  59. data/lib/mongoid/association/referenced/has_one/buildable.rb +20 -6
  60. data/lib/mongoid/association/referenced/has_one/eager.rb +2 -1
  61. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +16 -29
  62. data/lib/mongoid/association/referenced/has_one/proxy.rb +25 -30
  63. data/lib/mongoid/association/referenced/has_one.rb +16 -36
  64. data/lib/mongoid/association/referenced/syncable.rb +11 -26
  65. data/lib/mongoid/association/referenced.rb +2 -0
  66. data/lib/mongoid/association/reflections.rb +7 -6
  67. data/lib/mongoid/association/relatable.rb +149 -89
  68. data/lib/mongoid/association.rb +13 -27
  69. data/lib/mongoid/atomic/modifiers.rb +29 -53
  70. data/lib/mongoid/atomic/paths/embedded/many.rb +23 -7
  71. data/lib/mongoid/atomic/paths/embedded/one.rb +4 -7
  72. data/lib/mongoid/atomic/paths/embedded.rb +3 -4
  73. data/lib/mongoid/atomic/paths/root.rb +4 -7
  74. data/lib/mongoid/atomic/paths.rb +2 -1
  75. data/lib/mongoid/atomic.rb +49 -47
  76. data/lib/mongoid/attributes/dynamic.rb +22 -36
  77. data/lib/mongoid/attributes/nested.rb +12 -15
  78. data/lib/mongoid/attributes/processing.rb +19 -27
  79. data/lib/mongoid/attributes/projector.rb +119 -0
  80. data/lib/mongoid/attributes/readonly.rb +6 -9
  81. data/lib/mongoid/attributes.rb +103 -100
  82. data/lib/mongoid/cacheable.rb +7 -10
  83. data/lib/mongoid/changeable.rb +152 -73
  84. data/lib/mongoid/clients/factory.rb +42 -17
  85. data/lib/mongoid/clients/options.rb +21 -18
  86. data/lib/mongoid/clients/sessions.rb +10 -10
  87. data/lib/mongoid/clients/storage_options.rb +9 -17
  88. data/lib/mongoid/clients/validators/storage.rb +5 -24
  89. data/lib/mongoid/clients/validators.rb +2 -1
  90. data/lib/mongoid/clients.rb +3 -10
  91. data/lib/mongoid/collection_configurable.rb +58 -0
  92. data/lib/mongoid/composable.rb +7 -9
  93. data/lib/mongoid/config/defaults.rb +60 -0
  94. data/lib/mongoid/config/environment.rb +51 -13
  95. data/lib/mongoid/config/options.rb +20 -23
  96. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  97. data/lib/mongoid/config/validators/client.rb +8 -23
  98. data/lib/mongoid/config/validators/option.rb +2 -3
  99. data/lib/mongoid/config/validators.rb +3 -1
  100. data/lib/mongoid/config.rb +235 -48
  101. data/lib/mongoid/contextual/aggregable/memory.rb +40 -27
  102. data/lib/mongoid/contextual/aggregable/mongo.rb +32 -33
  103. data/lib/mongoid/contextual/aggregable/none.rb +65 -0
  104. data/lib/mongoid/contextual/aggregable.rb +17 -0
  105. data/lib/mongoid/contextual/atomic.rb +29 -31
  106. data/lib/mongoid/contextual/command.rb +2 -5
  107. data/lib/mongoid/contextual/geo_near.rb +13 -44
  108. data/lib/mongoid/contextual/map_reduce.rb +7 -35
  109. data/lib/mongoid/contextual/memory.rb +387 -81
  110. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  111. data/lib/mongoid/contextual/mongo.rb +641 -283
  112. data/lib/mongoid/contextual/none.rb +264 -31
  113. data/lib/mongoid/contextual/queryable.rb +3 -4
  114. data/lib/mongoid/contextual.rb +21 -11
  115. data/lib/mongoid/copyable.rb +46 -17
  116. data/lib/mongoid/criteria/findable.rb +20 -20
  117. data/lib/mongoid/criteria/includable.rb +32 -34
  118. data/lib/mongoid/criteria/inspectable.rb +2 -3
  119. data/lib/mongoid/criteria/marshalable.rb +12 -7
  120. data/lib/mongoid/criteria/modifiable.rb +15 -21
  121. data/lib/mongoid/criteria/options.rb +4 -5
  122. data/lib/mongoid/criteria/permission.rb +3 -2
  123. data/lib/mongoid/criteria/queryable/aggregable.rb +4 -15
  124. data/lib/mongoid/criteria/queryable/expandable.rb +68 -0
  125. data/lib/mongoid/criteria/queryable/extensions/array.rb +7 -41
  126. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +28 -8
  127. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +5 -6
  128. data/lib/mongoid/criteria/queryable/extensions/date.rb +9 -9
  129. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +11 -12
  130. data/lib/mongoid/criteria/queryable/extensions/hash.rb +4 -41
  131. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +3 -14
  132. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +4 -21
  133. data/lib/mongoid/criteria/queryable/extensions/object.rb +6 -30
  134. data/lib/mongoid/criteria/queryable/extensions/range.rb +49 -17
  135. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +12 -19
  136. data/lib/mongoid/criteria/queryable/extensions/set.rb +4 -5
  137. data/lib/mongoid/criteria/queryable/extensions/string.rb +7 -32
  138. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +7 -22
  139. data/lib/mongoid/criteria/queryable/extensions/time.rb +10 -10
  140. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +19 -7
  141. data/lib/mongoid/criteria/queryable/extensions.rb +1 -4
  142. data/lib/mongoid/criteria/queryable/key.rb +105 -31
  143. data/lib/mongoid/criteria/queryable/macroable.rb +3 -4
  144. data/lib/mongoid/criteria/queryable/mergeable.rb +205 -44
  145. data/lib/mongoid/criteria/queryable/optional.rb +16 -65
  146. data/lib/mongoid/criteria/queryable/options.rb +4 -21
  147. data/lib/mongoid/criteria/queryable/pipeline.rb +5 -15
  148. data/lib/mongoid/criteria/queryable/selectable.rb +471 -168
  149. data/lib/mongoid/criteria/queryable/selector.rb +133 -58
  150. data/lib/mongoid/criteria/queryable/smash.rb +42 -18
  151. data/lib/mongoid/criteria/queryable/storable.rb +237 -0
  152. data/lib/mongoid/criteria/queryable.rb +18 -15
  153. data/lib/mongoid/criteria/scopable.rb +29 -21
  154. data/lib/mongoid/criteria/translator.rb +45 -0
  155. data/lib/mongoid/criteria.rb +106 -111
  156. data/lib/mongoid/deprecable.rb +36 -0
  157. data/lib/mongoid/deprecation.rb +25 -0
  158. data/lib/mongoid/document.rb +162 -103
  159. data/lib/mongoid/equality.rb +35 -18
  160. data/lib/mongoid/errors/ambiguous_relationship.rb +4 -5
  161. data/lib/mongoid/errors/callback.rb +2 -3
  162. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  163. data/lib/mongoid/errors/criteria_argument_required.rb +18 -0
  164. data/lib/mongoid/errors/delete_restriction.rb +10 -13
  165. data/lib/mongoid/errors/document_not_destroyed.rb +4 -7
  166. data/lib/mongoid/errors/document_not_found.rb +35 -21
  167. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  168. data/lib/mongoid/errors/empty_config_file.rb +25 -0
  169. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  170. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +2 -3
  171. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  172. data/lib/mongoid/errors/invalid_collection.rb +2 -1
  173. data/lib/mongoid/errors/invalid_config_file.rb +25 -0
  174. data/lib/mongoid/errors/invalid_config_option.rb +3 -4
  175. data/lib/mongoid/errors/invalid_dependent_strategy.rb +3 -4
  176. data/lib/mongoid/errors/invalid_discriminator_key_target.rb +24 -0
  177. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  178. data/lib/mongoid/errors/invalid_elem_match_operator.rb +32 -0
  179. data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +25 -0
  180. data/lib/mongoid/errors/invalid_expression_operator.rb +27 -0
  181. data/lib/mongoid/errors/invalid_field.rb +8 -7
  182. data/lib/mongoid/errors/invalid_field_operator.rb +32 -0
  183. data/lib/mongoid/errors/invalid_field_option.rb +2 -3
  184. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  185. data/lib/mongoid/errors/invalid_find.rb +2 -3
  186. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  187. data/lib/mongoid/errors/invalid_includes.rb +2 -3
  188. data/lib/mongoid/errors/invalid_index.rb +2 -3
  189. data/lib/mongoid/errors/invalid_options.rb +4 -5
  190. data/lib/mongoid/errors/invalid_path.rb +2 -3
  191. data/lib/mongoid/errors/invalid_persistence_option.rb +2 -5
  192. data/lib/mongoid/errors/invalid_query.rb +40 -0
  193. data/lib/mongoid/errors/invalid_relation.rb +5 -10
  194. data/lib/mongoid/errors/invalid_relation_option.rb +4 -5
  195. data/lib/mongoid/errors/invalid_scope.rb +2 -3
  196. data/lib/mongoid/errors/invalid_session_use.rb +3 -6
  197. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +6 -5
  198. data/lib/mongoid/errors/invalid_storage_options.rb +3 -4
  199. data/lib/mongoid/errors/invalid_storage_parent.rb +4 -3
  200. data/lib/mongoid/errors/invalid_time.rb +2 -3
  201. data/lib/mongoid/errors/inverse_not_found.rb +3 -4
  202. data/lib/mongoid/errors/mixed_client_configuration.rb +2 -3
  203. data/lib/mongoid/errors/mixed_relations.rb +2 -3
  204. data/lib/mongoid/errors/mongoid_error.rb +6 -13
  205. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +3 -4
  206. data/lib/mongoid/errors/no_client_config.rb +4 -5
  207. data/lib/mongoid/errors/no_client_database.rb +3 -4
  208. data/lib/mongoid/errors/no_client_hosts.rb +3 -4
  209. data/lib/mongoid/errors/no_clients_config.rb +2 -3
  210. data/lib/mongoid/errors/no_default_client.rb +3 -4
  211. data/lib/mongoid/errors/no_environment.rb +2 -3
  212. data/lib/mongoid/errors/no_map_reduce_output.rb +2 -3
  213. data/lib/mongoid/errors/no_metadata.rb +2 -3
  214. data/lib/mongoid/errors/no_parent.rb +2 -3
  215. data/lib/mongoid/errors/readonly_attribute.rb +3 -4
  216. data/lib/mongoid/errors/readonly_document.rb +3 -6
  217. data/lib/mongoid/errors/scope_overwrite.rb +2 -1
  218. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +3 -1
  219. data/lib/mongoid/errors/unknown_attribute.rb +3 -4
  220. data/lib/mongoid/errors/unknown_model.rb +2 -3
  221. data/lib/mongoid/errors/unsaved_document.rb +3 -2
  222. data/lib/mongoid/errors/unsupported_javascript.rb +2 -3
  223. data/lib/mongoid/errors/validations.rb +2 -1
  224. data/lib/mongoid/errors.rb +18 -4
  225. data/lib/mongoid/evolvable.rb +4 -5
  226. data/lib/mongoid/extensions/array.rb +37 -44
  227. data/lib/mongoid/extensions/big_decimal.rb +35 -21
  228. data/lib/mongoid/extensions/binary.rb +42 -0
  229. data/lib/mongoid/extensions/boolean.rb +10 -6
  230. data/lib/mongoid/extensions/date.rb +32 -25
  231. data/lib/mongoid/extensions/date_time.rb +5 -13
  232. data/lib/mongoid/extensions/decimal128.rb +2 -5
  233. data/lib/mongoid/extensions/false_class.rb +5 -8
  234. data/lib/mongoid/extensions/float.rb +12 -14
  235. data/lib/mongoid/extensions/hash.rb +64 -42
  236. data/lib/mongoid/extensions/integer.rb +12 -16
  237. data/lib/mongoid/extensions/module.rb +3 -4
  238. data/lib/mongoid/extensions/nil_class.rb +2 -5
  239. data/lib/mongoid/extensions/object.rb +27 -52
  240. data/lib/mongoid/extensions/object_id.rb +2 -7
  241. data/lib/mongoid/extensions/range.rb +42 -20
  242. data/lib/mongoid/extensions/regexp.rb +14 -7
  243. data/lib/mongoid/extensions/set.rb +13 -11
  244. data/lib/mongoid/extensions/string.rb +35 -64
  245. data/lib/mongoid/extensions/symbol.rb +6 -22
  246. data/lib/mongoid/extensions/time.rb +38 -22
  247. data/lib/mongoid/extensions/time_with_zone.rb +26 -9
  248. data/lib/mongoid/extensions/true_class.rb +5 -8
  249. data/lib/mongoid/extensions.rb +19 -3
  250. data/lib/mongoid/factory.rb +104 -17
  251. data/lib/mongoid/fields/foreign_key.rb +14 -26
  252. data/lib/mongoid/fields/localized.rb +21 -15
  253. data/lib/mongoid/fields/standard.rb +23 -43
  254. data/lib/mongoid/fields/validators/macro.rb +32 -20
  255. data/lib/mongoid/fields/validators.rb +2 -1
  256. data/lib/mongoid/fields.rb +349 -76
  257. data/lib/mongoid/findable.rb +115 -34
  258. data/lib/mongoid/indexable/specification.rb +5 -18
  259. data/lib/mongoid/indexable/validators/options.rb +8 -9
  260. data/lib/mongoid/indexable.rb +6 -21
  261. data/lib/mongoid/inspectable.rb +4 -11
  262. data/lib/mongoid/interceptable.rb +85 -41
  263. data/lib/mongoid/loggable.rb +13 -16
  264. data/lib/mongoid/matchable.rb +4 -154
  265. data/lib/mongoid/matcher/all.rb +22 -0
  266. data/lib/mongoid/matcher/and.rb +21 -0
  267. data/lib/mongoid/matcher/bits.rb +41 -0
  268. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  269. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  270. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  271. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  272. data/lib/mongoid/matcher/elem_match.rb +36 -0
  273. data/lib/mongoid/matcher/elem_match_expression.rb +20 -0
  274. data/lib/mongoid/matcher/eq.rb +11 -0
  275. data/lib/mongoid/matcher/eq_impl.rb +67 -0
  276. data/lib/mongoid/matcher/eq_impl_with_regexp.rb +26 -0
  277. data/lib/mongoid/matcher/exists.rb +15 -0
  278. data/lib/mongoid/matcher/expression.rb +35 -0
  279. data/lib/mongoid/matcher/expression_operator.rb +19 -0
  280. data/lib/mongoid/matcher/field_expression.rb +62 -0
  281. data/lib/mongoid/matcher/field_operator.rb +54 -0
  282. data/lib/mongoid/matcher/gt.rb +17 -0
  283. data/lib/mongoid/matcher/gte.rb +17 -0
  284. data/lib/mongoid/matcher/in.rb +25 -0
  285. data/lib/mongoid/matcher/lt.rb +17 -0
  286. data/lib/mongoid/matcher/lte.rb +17 -0
  287. data/lib/mongoid/matcher/mod.rb +17 -0
  288. data/lib/mongoid/matcher/ne.rb +16 -0
  289. data/lib/mongoid/matcher/nin.rb +11 -0
  290. data/lib/mongoid/matcher/nor.rb +25 -0
  291. data/lib/mongoid/matcher/not.rb +29 -0
  292. data/lib/mongoid/matcher/or.rb +21 -0
  293. data/lib/mongoid/matcher/regex.rb +41 -0
  294. data/lib/mongoid/matcher/size.rb +26 -0
  295. data/lib/mongoid/matcher/type.rb +99 -0
  296. data/lib/mongoid/matcher.rb +130 -0
  297. data/lib/mongoid/persistable/creatable.rb +23 -30
  298. data/lib/mongoid/persistable/deletable.rb +7 -23
  299. data/lib/mongoid/persistable/destroyable.rb +12 -11
  300. data/lib/mongoid/persistable/incrementable.rb +6 -7
  301. data/lib/mongoid/persistable/logical.rb +4 -6
  302. data/lib/mongoid/persistable/poppable.rb +3 -6
  303. data/lib/mongoid/persistable/pullable.rb +3 -8
  304. data/lib/mongoid/persistable/pushable.rb +14 -10
  305. data/lib/mongoid/persistable/renamable.rb +10 -8
  306. data/lib/mongoid/persistable/savable.rb +16 -9
  307. data/lib/mongoid/persistable/settable.rb +3 -6
  308. data/lib/mongoid/persistable/unsettable.rb +10 -10
  309. data/lib/mongoid/persistable/updatable.rb +99 -30
  310. data/lib/mongoid/persistable/upsertable.rb +23 -9
  311. data/lib/mongoid/persistable.rb +138 -40
  312. data/lib/mongoid/persistence_context.rb +107 -52
  313. data/lib/mongoid/positional.rb +3 -6
  314. data/lib/mongoid/query_cache.rb +18 -234
  315. data/lib/mongoid/railtie.rb +20 -16
  316. data/lib/mongoid/railties/controller_runtime.rb +88 -0
  317. data/lib/mongoid/railties/database.rake +16 -2
  318. data/lib/mongoid/reloadable.rb +19 -22
  319. data/lib/mongoid/scopable.rb +37 -60
  320. data/lib/mongoid/selectable.rb +8 -18
  321. data/lib/mongoid/serializable.rb +33 -34
  322. data/lib/mongoid/shardable.rb +108 -21
  323. data/lib/mongoid/stateful.rb +60 -20
  324. data/lib/mongoid/stringified_symbol.rb +52 -0
  325. data/lib/mongoid/tasks/database.rake +24 -5
  326. data/lib/mongoid/tasks/database.rb +105 -7
  327. data/lib/mongoid/threaded/lifecycle.rb +7 -26
  328. data/lib/mongoid/threaded.rb +80 -67
  329. data/lib/mongoid/timestamps/created/short.rb +2 -1
  330. data/lib/mongoid/timestamps/created.rb +4 -3
  331. data/lib/mongoid/timestamps/short.rb +2 -1
  332. data/lib/mongoid/timestamps/timeless.rb +6 -9
  333. data/lib/mongoid/timestamps/updated/short.rb +2 -1
  334. data/lib/mongoid/timestamps/updated.rb +5 -6
  335. data/lib/mongoid/timestamps.rb +3 -2
  336. data/lib/mongoid/touchable.rb +54 -25
  337. data/lib/mongoid/traversable.rb +185 -61
  338. data/lib/mongoid/utils.rb +22 -0
  339. data/lib/mongoid/validatable/associated.rb +5 -6
  340. data/lib/mongoid/validatable/format.rb +2 -1
  341. data/lib/mongoid/validatable/length.rb +2 -1
  342. data/lib/mongoid/validatable/localizable.rb +3 -4
  343. data/lib/mongoid/validatable/macros.rb +8 -15
  344. data/lib/mongoid/validatable/presence.rb +10 -15
  345. data/lib/mongoid/validatable/queryable.rb +2 -3
  346. data/lib/mongoid/validatable/uniqueness.rb +30 -42
  347. data/lib/mongoid/validatable.rb +16 -32
  348. data/lib/mongoid/version.rb +3 -2
  349. data/lib/mongoid/warnings.rb +44 -0
  350. data/lib/mongoid.rb +50 -17
  351. data/lib/rails/generators/mongoid/config/config_generator.rb +10 -2
  352. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +53 -32
  353. data/lib/rails/generators/mongoid/model/model_generator.rb +3 -2
  354. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  355. data/lib/rails/generators/mongoid_generator.rb +2 -1
  356. data/lib/rails/mongoid.rb +4 -5
  357. data/spec/README.md +33 -0
  358. data/spec/config/mongoid.yml +29 -3
  359. data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
  360. data/spec/integration/app_spec.rb +345 -0
  361. data/spec/integration/associations/belongs_to_spec.rb +33 -0
  362. data/spec/integration/associations/embedded_dirty_spec.rb +57 -0
  363. data/spec/integration/associations/embedded_spec.rb +283 -0
  364. data/spec/integration/associations/embeds_many_spec.rb +219 -0
  365. data/spec/integration/associations/embeds_one_spec.rb +41 -0
  366. data/spec/integration/associations/foreign_key_spec.rb +107 -0
  367. data/spec/integration/associations/foreign_key_spec_models.rb +64 -0
  368. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  369. data/spec/integration/associations/has_many_spec.rb +128 -0
  370. data/spec/integration/associations/has_one_spec.rb +272 -0
  371. data/spec/integration/associations/nested_attributes_assignment_spec.rb +115 -0
  372. data/spec/integration/associations/reverse_population_spec.rb +34 -0
  373. data/spec/integration/associations/reverse_population_spec_models.rb +36 -0
  374. data/spec/integration/associations/scope_option_spec.rb +101 -0
  375. data/spec/integration/atomic/modifiers_spec.rb +116 -0
  376. data/spec/integration/bson_regexp_raw_spec.rb +19 -0
  377. data/spec/integration/callbacks_models.rb +192 -0
  378. data/spec/integration/callbacks_spec.rb +584 -0
  379. data/spec/integration/contextual/empty_spec.rb +141 -0
  380. data/spec/integration/criteria/alias_query_spec.rb +161 -0
  381. data/spec/integration/criteria/date_field_spec.rb +40 -0
  382. data/spec/integration/criteria/default_scope_spec.rb +72 -0
  383. data/spec/integration/criteria/logical_spec.rb +124 -0
  384. data/spec/integration/criteria/range_spec.rb +359 -0
  385. data/spec/integration/criteria/time_with_zone_spec.rb +142 -0
  386. data/spec/integration/discriminator_key_spec.rb +391 -0
  387. data/spec/integration/discriminator_value_spec.rb +206 -0
  388. data/spec/integration/document_spec.rb +51 -0
  389. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  390. data/spec/integration/i18n_fallbacks_spec.rb +74 -0
  391. data/spec/integration/matcher_examples_spec.rb +765 -0
  392. data/spec/integration/matcher_operator_data/all.yml +140 -0
  393. data/spec/integration/matcher_operator_data/and.yml +93 -0
  394. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  395. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  396. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  397. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  398. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  399. data/spec/integration/matcher_operator_data/elem_match.yml +409 -0
  400. data/spec/integration/matcher_operator_data/elem_match_expr.yml +213 -0
  401. data/spec/integration/matcher_operator_data/eq.yml +191 -0
  402. data/spec/integration/matcher_operator_data/exists.yml +213 -0
  403. data/spec/integration/matcher_operator_data/generic_op.yml +17 -0
  404. data/spec/integration/matcher_operator_data/gt.yml +132 -0
  405. data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
  406. data/spec/integration/matcher_operator_data/gte.yml +132 -0
  407. data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
  408. data/spec/integration/matcher_operator_data/implicit.yml +331 -0
  409. data/spec/integration/matcher_operator_data/implicit_traversal.yml +112 -0
  410. data/spec/integration/matcher_operator_data/in.yml +210 -0
  411. data/spec/integration/matcher_operator_data/invalid_op.yml +59 -0
  412. data/spec/integration/matcher_operator_data/invalid_syntax.yml +39 -0
  413. data/spec/integration/matcher_operator_data/lt.yml +132 -0
  414. data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
  415. data/spec/integration/matcher_operator_data/lte.yml +132 -0
  416. data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
  417. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  418. data/spec/integration/matcher_operator_data/multiple.yml +29 -0
  419. data/spec/integration/matcher_operator_data/ne.yml +150 -0
  420. data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
  421. data/spec/integration/matcher_operator_data/nin.yml +114 -0
  422. data/spec/integration/matcher_operator_data/nor.yml +126 -0
  423. data/spec/integration/matcher_operator_data/not.yml +196 -0
  424. data/spec/integration/matcher_operator_data/or.yml +137 -0
  425. data/spec/integration/matcher_operator_data/regex.yml +174 -0
  426. data/spec/integration/matcher_operator_data/regex_options.yml +72 -0
  427. data/spec/integration/matcher_operator_data/size.yml +174 -0
  428. data/spec/integration/matcher_operator_data/type.yml +70 -0
  429. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  430. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  431. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  432. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  433. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  434. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  435. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  436. data/spec/integration/matcher_operator_data/type_decimal.yml +41 -0
  437. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  438. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  439. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  440. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  441. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  442. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  443. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  444. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  445. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  446. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  447. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  448. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  449. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  450. data/spec/integration/matcher_operator_spec.rb +122 -0
  451. data/spec/integration/matcher_spec.rb +283 -0
  452. data/spec/integration/persistence/range_field_spec.rb +350 -0
  453. data/spec/integration/server_query_spec.rb +141 -0
  454. data/spec/integration/shardable_spec.rb +148 -0
  455. data/spec/integration/stringified_symbol_field_spec.rb +203 -0
  456. data/spec/lite_spec_helper.rb +83 -0
  457. data/spec/mongoid/association/accessors_spec.rb +284 -77
  458. data/spec/mongoid/association/auto_save_spec.rb +74 -33
  459. data/spec/mongoid/association/builders_spec.rb +3 -1
  460. data/spec/mongoid/association/constrainable_spec.rb +2 -0
  461. data/spec/mongoid/association/counter_cache_spec.rb +35 -33
  462. data/spec/mongoid/association/depending_spec.rb +431 -338
  463. data/spec/mongoid/association/eager_spec.rb +8 -5
  464. data/spec/mongoid/association/embedded/cyclic_spec.rb +4 -2
  465. data/spec/mongoid/association/embedded/dirty_spec.rb +4 -2
  466. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +4 -1
  467. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +56 -0
  468. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +152 -13
  469. data/spec/mongoid/association/embedded/embedded_in_spec.rb +61 -1
  470. data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +2 -0
  471. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +114 -0
  472. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +706 -197
  473. data/spec/mongoid/association/embedded/embeds_many_models.rb +227 -0
  474. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +63 -0
  475. data/spec/mongoid/association/embedded/embeds_many_spec.rb +81 -1
  476. data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +2 -0
  477. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +27 -0
  478. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +38 -23
  479. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +8 -0
  480. data/spec/mongoid/association/embedded/embeds_one_models.rb +73 -0
  481. data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +28 -0
  482. data/spec/mongoid/association/embedded/embeds_one_spec.rb +77 -1
  483. data/spec/mongoid/association/macros_spec.rb +11 -9
  484. data/spec/mongoid/association/nested/many_spec.rb +2 -0
  485. data/spec/mongoid/association/nested/one_spec.rb +18 -12
  486. data/spec/mongoid/association/options_spec.rb +2 -0
  487. data/spec/mongoid/association/polymorphic_spec.rb +2 -0
  488. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +4 -1
  489. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +111 -16
  490. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +266 -17
  491. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +114 -58
  492. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  493. data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +57 -0
  494. data/spec/mongoid/association/referenced/belongs_to_spec.rb +96 -29
  495. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +3 -1
  496. data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +28 -1
  497. data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +67 -4
  498. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +76 -0
  499. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +559 -385
  500. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +92 -0
  501. data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +39 -0
  502. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +84 -7
  503. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +3 -1
  504. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +132 -0
  505. data/spec/mongoid/association/referenced/has_many/eager_spec.rb +40 -9
  506. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +415 -129
  507. data/spec/mongoid/association/referenced/has_many/proxy_query_spec.rb +23 -0
  508. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +859 -502
  509. data/spec/mongoid/association/referenced/has_many_models.rb +97 -0
  510. data/spec/mongoid/association/referenced/has_many_query_spec.rb +37 -0
  511. data/spec/mongoid/association/referenced/has_many_spec.rb +51 -3
  512. data/spec/mongoid/association/referenced/has_one/binding_spec.rb +2 -0
  513. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +55 -9
  514. data/spec/mongoid/association/referenced/has_one/eager_spec.rb +34 -4
  515. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +135 -27
  516. data/spec/mongoid/association/referenced/has_one_models.rb +113 -0
  517. data/spec/mongoid/association/referenced/has_one_query_spec.rb +37 -0
  518. data/spec/mongoid/association/referenced/has_one_spec.rb +87 -7
  519. data/spec/mongoid/association/reflections_spec.rb +2 -0
  520. data/spec/mongoid/association/syncable_spec.rb +48 -32
  521. data/spec/mongoid/association_spec.rb +2 -0
  522. data/spec/mongoid/atomic/modifiers_spec.rb +49 -0
  523. data/spec/mongoid/atomic/paths/embedded/many_spec.rb +2 -0
  524. data/spec/mongoid/atomic/paths/embedded/one_spec.rb +2 -0
  525. data/spec/mongoid/atomic/paths/root_spec.rb +2 -0
  526. data/spec/mongoid/atomic/paths_spec.rb +93 -12
  527. data/spec/mongoid/atomic_spec.rb +53 -6
  528. data/spec/mongoid/attributes/dynamic_spec.rb +152 -0
  529. data/spec/mongoid/attributes/nested_spec.rb +149 -78
  530. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  531. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  532. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  533. data/spec/mongoid/attributes/projector_spec.rb +40 -0
  534. data/spec/mongoid/attributes/readonly_spec.rb +24 -22
  535. data/spec/mongoid/attributes_spec.rb +895 -54
  536. data/spec/mongoid/cacheable_spec.rb +6 -4
  537. data/spec/mongoid/changeable_spec.rb +484 -67
  538. data/spec/mongoid/clients/factory_spec.rb +139 -33
  539. data/spec/mongoid/clients/options_spec.rb +76 -54
  540. data/spec/mongoid/clients/sessions_spec.rb +35 -63
  541. data/spec/mongoid/clients/transactions_spec.rb +87 -41
  542. data/spec/mongoid/clients_spec.rb +257 -31
  543. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  544. data/spec/mongoid/composable_spec.rb +2 -0
  545. data/spec/mongoid/config/defaults_spec.rb +160 -0
  546. data/spec/mongoid/config/environment_spec.rb +126 -8
  547. data/spec/mongoid/config/options_spec.rb +22 -3
  548. data/spec/mongoid/config_spec.rb +507 -2
  549. data/spec/mongoid/contextual/aggregable/memory_spec.rb +433 -153
  550. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  551. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  552. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +122 -20
  553. data/spec/mongoid/contextual/aggregable/none_spec.rb +60 -0
  554. data/spec/mongoid/contextual/atomic_spec.rb +242 -81
  555. data/spec/mongoid/contextual/geo_near_spec.rb +31 -19
  556. data/spec/mongoid/contextual/map_reduce_spec.rb +22 -19
  557. data/spec/mongoid/contextual/memory_spec.rb +1828 -303
  558. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  559. data/spec/mongoid/contextual/mongo_spec.rb +3505 -1268
  560. data/spec/mongoid/contextual/none_spec.rb +80 -67
  561. data/spec/mongoid/copyable_spec.rb +697 -40
  562. data/spec/mongoid/copyable_spec_models.rb +47 -0
  563. data/spec/mongoid/criteria/findable_spec.rb +161 -228
  564. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  565. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  566. data/spec/mongoid/criteria/inspectable_spec.rb +2 -0
  567. data/spec/mongoid/criteria/marshalable_spec.rb +20 -1
  568. data/spec/mongoid/criteria/modifiable_spec.rb +100 -48
  569. data/spec/mongoid/criteria/options_spec.rb +2 -0
  570. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +3 -1
  571. data/spec/mongoid/criteria/queryable/expandable_spec.rb +61 -0
  572. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +9 -19
  573. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +136 -26
  574. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +3 -1
  575. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +13 -0
  576. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +46 -17
  577. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +2 -0
  578. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +2 -15
  579. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +2 -0
  580. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +2 -0
  581. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +119 -0
  582. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +2 -0
  583. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +239 -178
  584. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +3 -1
  585. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +9 -7
  586. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +2 -0
  587. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +7 -70
  588. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +2 -59
  589. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +53 -23
  590. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +41 -1
  591. data/spec/mongoid/criteria/queryable/key_spec.rb +50 -6
  592. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +145 -12
  593. data/spec/mongoid/criteria/queryable/optional_spec.rb +18 -485
  594. data/spec/mongoid/criteria/queryable/options_spec.rb +3 -1
  595. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +2 -0
  596. data/spec/mongoid/criteria/queryable/queryable_spec.rb +3 -1
  597. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +2538 -0
  598. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +38 -0
  599. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1193 -2934
  600. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +589 -0
  601. data/spec/mongoid/criteria/queryable/selector_spec.rb +56 -5
  602. data/spec/mongoid/criteria/queryable/smash_spec.rb +2 -0
  603. data/spec/mongoid/criteria/queryable/storable_spec.rb +226 -0
  604. data/spec/mongoid/criteria/scopable_spec.rb +210 -0
  605. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  606. data/spec/mongoid/criteria_projection_spec.rb +406 -0
  607. data/spec/mongoid/criteria_spec.rb +1334 -1719
  608. data/spec/mongoid/document_fields_spec.rb +262 -0
  609. data/spec/mongoid/document_persistence_context_spec.rb +32 -0
  610. data/spec/mongoid/document_query_spec.rb +89 -0
  611. data/spec/mongoid/document_spec.rb +212 -67
  612. data/spec/mongoid/equality_spec.rb +144 -41
  613. data/spec/mongoid/errors/ambiguous_relationship_spec.rb +5 -3
  614. data/spec/mongoid/errors/callback_spec.rb +2 -0
  615. data/spec/mongoid/errors/delete_restriction_spec.rb +4 -2
  616. data/spec/mongoid/errors/document_not_destroyed_spec.rb +2 -0
  617. data/spec/mongoid/errors/document_not_found_spec.rb +78 -0
  618. data/spec/mongoid/errors/invalid_collection_spec.rb +2 -0
  619. data/spec/mongoid/errors/{eager_load_spec.rb → invalid_config_file_spec.rb} +7 -5
  620. data/spec/mongoid/errors/invalid_config_option_spec.rb +2 -0
  621. data/spec/mongoid/errors/invalid_field_option_spec.rb +2 -0
  622. data/spec/mongoid/errors/invalid_field_spec.rb +3 -1
  623. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  624. data/spec/mongoid/errors/invalid_find_spec.rb +2 -0
  625. data/spec/mongoid/errors/invalid_includes_spec.rb +2 -0
  626. data/spec/mongoid/errors/invalid_index_spec.rb +2 -0
  627. data/spec/mongoid/errors/invalid_options_spec.rb +4 -2
  628. data/spec/mongoid/errors/invalid_path_spec.rb +2 -0
  629. data/spec/mongoid/errors/invalid_relation_spec.rb +4 -2
  630. data/spec/mongoid/errors/invalid_scope_spec.rb +3 -1
  631. data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +2 -0
  632. data/spec/mongoid/errors/invalid_storage_options_spec.rb +2 -0
  633. data/spec/mongoid/errors/invalid_time_spec.rb +2 -0
  634. data/spec/mongoid/errors/inverse_not_found_spec.rb +3 -1
  635. data/spec/mongoid/errors/mixed_client_configuration_spec.rb +2 -0
  636. data/spec/mongoid/errors/mixed_relations_spec.rb +2 -0
  637. data/spec/mongoid/errors/mongoid_error_spec.rb +24 -8
  638. data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +5 -3
  639. data/spec/mongoid/errors/no_client_config_spec.rb +4 -2
  640. data/spec/mongoid/errors/no_client_database_spec.rb +5 -3
  641. data/spec/mongoid/errors/no_client_hosts_spec.rb +5 -3
  642. data/spec/mongoid/errors/no_clients_config_spec.rb +2 -0
  643. data/spec/mongoid/errors/no_environment_spec.rb +5 -3
  644. data/spec/mongoid/errors/no_map_reduce_output_spec.rb +2 -0
  645. data/spec/mongoid/errors/no_metadata_spec.rb +4 -2
  646. data/spec/mongoid/errors/no_parent_spec.rb +3 -1
  647. data/spec/mongoid/errors/readonly_attribute_spec.rb +2 -0
  648. data/spec/mongoid/errors/readonly_document_spec.rb +4 -2
  649. data/spec/mongoid/errors/scope_overwrite_spec.rb +2 -0
  650. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +3 -1
  651. data/spec/mongoid/errors/unknown_attribute_spec.rb +4 -2
  652. data/spec/mongoid/errors/unsaved_document_spec.rb +3 -1
  653. data/spec/mongoid/errors/unsupported_javascript_spec.rb +2 -0
  654. data/spec/mongoid/errors/validations_spec.rb +2 -0
  655. data/spec/mongoid/extensions/array_spec.rb +41 -45
  656. data/spec/mongoid/extensions/big_decimal_spec.rb +715 -213
  657. data/spec/mongoid/extensions/binary_spec.rb +46 -9
  658. data/spec/mongoid/extensions/boolean_spec.rb +70 -82
  659. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +339 -0
  660. data/spec/mongoid/extensions/date_spec.rb +58 -140
  661. data/spec/mongoid/extensions/date_time_spec.rb +32 -69
  662. data/spec/mongoid/extensions/decimal128_spec.rb +2 -0
  663. data/spec/mongoid/extensions/false_class_spec.rb +3 -1
  664. data/spec/mongoid/extensions/float_spec.rb +66 -73
  665. data/spec/mongoid/extensions/hash_spec.rb +135 -0
  666. data/spec/mongoid/extensions/integer_spec.rb +61 -63
  667. data/spec/mongoid/extensions/module_spec.rb +2 -0
  668. data/spec/mongoid/extensions/nil_class_spec.rb +2 -0
  669. data/spec/mongoid/extensions/object_id_spec.rb +2 -0
  670. data/spec/mongoid/extensions/object_spec.rb +13 -24
  671. data/spec/mongoid/extensions/range_spec.rb +257 -54
  672. data/spec/mongoid/extensions/regexp_spec.rb +70 -20
  673. data/spec/mongoid/extensions/set_spec.rb +108 -0
  674. data/spec/mongoid/extensions/string_spec.rb +146 -57
  675. data/spec/mongoid/extensions/stringified_symbol_spec.rb +84 -0
  676. data/spec/mongoid/extensions/symbol_spec.rb +20 -25
  677. data/spec/mongoid/extensions/time_spec.rb +668 -106
  678. data/spec/mongoid/extensions/time_with_zone_spec.rb +57 -83
  679. data/spec/mongoid/extensions/true_class_spec.rb +3 -1
  680. data/spec/mongoid/extensions_spec.rb +16 -2
  681. data/spec/mongoid/factory_spec.rb +347 -27
  682. data/spec/mongoid/fields/foreign_key_spec.rb +2 -0
  683. data/spec/mongoid/fields/localized_spec.rb +86 -41
  684. data/spec/mongoid/fields/standard_spec.rb +2 -0
  685. data/spec/mongoid/fields_spec.rb +869 -114
  686. data/spec/mongoid/findable_spec.rb +521 -65
  687. data/spec/mongoid/indexable/specification_spec.rb +4 -2
  688. data/spec/mongoid/indexable_spec.rb +87 -32
  689. data/spec/mongoid/inspectable_spec.rb +39 -2
  690. data/spec/mongoid/interceptable_spec.rb +761 -98
  691. data/spec/mongoid/interceptable_spec_models.rb +307 -0
  692. data/spec/mongoid/loggable_spec.rb +2 -0
  693. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  694. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +239 -0
  695. data/spec/mongoid/matcher/extract_attribute_spec.rb +36 -0
  696. data/spec/mongoid/mongoizable_spec.rb +285 -0
  697. data/spec/mongoid/persistable/creatable_spec.rb +114 -29
  698. data/spec/mongoid/persistable/deletable_spec.rb +300 -18
  699. data/spec/mongoid/persistable/destroyable_spec.rb +228 -18
  700. data/spec/mongoid/persistable/incrementable_spec.rb +66 -13
  701. data/spec/mongoid/persistable/logical_spec.rb +56 -3
  702. data/spec/mongoid/persistable/poppable_spec.rb +55 -3
  703. data/spec/mongoid/persistable/pullable_spec.rb +108 -6
  704. data/spec/mongoid/persistable/pushable_spec.rb +163 -7
  705. data/spec/mongoid/persistable/renamable_spec.rb +54 -2
  706. data/spec/mongoid/persistable/savable_spec.rb +284 -25
  707. data/spec/mongoid/persistable/settable_spec.rb +91 -8
  708. data/spec/mongoid/persistable/unsettable_spec.rb +55 -3
  709. data/spec/mongoid/persistable/updatable_spec.rb +63 -49
  710. data/spec/mongoid/persistable/upsertable_spec.rb +93 -3
  711. data/spec/mongoid/persistable_spec.rb +85 -9
  712. data/spec/mongoid/persistence_context_spec.rb +60 -59
  713. data/spec/mongoid/positional_spec.rb +2 -0
  714. data/spec/mongoid/query_cache_middleware_spec.rb +50 -0
  715. data/spec/mongoid/query_cache_spec.rb +446 -78
  716. data/spec/mongoid/relations/proxy_spec.rb +9 -7
  717. data/spec/mongoid/reloadable_spec.rb +381 -26
  718. data/spec/mongoid/scopable_spec.rb +206 -38
  719. data/spec/mongoid/selectable_spec.rb +8 -6
  720. data/spec/mongoid/serializable_spec.rb +148 -38
  721. data/spec/mongoid/shardable_models.rb +75 -0
  722. data/spec/mongoid/shardable_spec.rb +239 -34
  723. data/spec/mongoid/stateful_spec.rb +153 -9
  724. data/spec/mongoid/tasks/database_rake_spec.rb +89 -13
  725. data/spec/mongoid/tasks/database_spec.rb +130 -1
  726. data/spec/mongoid/threaded_spec.rb +72 -2
  727. data/spec/mongoid/timestamps/created/short_spec.rb +3 -1
  728. data/spec/mongoid/timestamps/created_spec.rb +3 -1
  729. data/spec/mongoid/timestamps/timeless_spec.rb +4 -2
  730. data/spec/mongoid/timestamps/updated/short_spec.rb +5 -3
  731. data/spec/mongoid/timestamps/updated_spec.rb +5 -3
  732. data/spec/mongoid/timestamps_spec.rb +400 -10
  733. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  734. data/spec/mongoid/touchable_spec.rb +568 -33
  735. data/spec/mongoid/touchable_spec_models.rb +59 -0
  736. data/spec/mongoid/traversable_spec.rb +1145 -1
  737. data/spec/mongoid/validatable/associated_spec.rb +2 -0
  738. data/spec/mongoid/validatable/format_spec.rb +2 -0
  739. data/spec/mongoid/validatable/length_spec.rb +2 -0
  740. data/spec/mongoid/validatable/numericality_spec.rb +2 -0
  741. data/spec/mongoid/validatable/presence_spec.rb +28 -22
  742. data/spec/mongoid/validatable/uniqueness_spec.rb +159 -103
  743. data/spec/mongoid/validatable_spec.rb +5 -3
  744. data/spec/mongoid/warnings_spec.rb +35 -0
  745. data/spec/mongoid_spec.rb +36 -10
  746. data/spec/rails/controller_extension/controller_runtime_spec.rb +112 -0
  747. data/spec/rails/mongoid_spec.rb +8 -18
  748. data/spec/shared/LICENSE +20 -0
  749. data/spec/shared/bin/get-mongodb-download-url +17 -0
  750. data/spec/shared/bin/s3-copy +45 -0
  751. data/spec/shared/bin/s3-upload +69 -0
  752. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  753. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  754. data/spec/shared/lib/mrss/constraints.rb +378 -0
  755. data/spec/shared/lib/mrss/docker_runner.rb +298 -0
  756. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  757. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  758. data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
  759. data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
  760. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  761. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  762. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  763. data/spec/shared/lib/mrss/utils.rb +37 -0
  764. data/spec/shared/share/Dockerfile.erb +321 -0
  765. data/spec/shared/share/haproxy-1.conf +16 -0
  766. data/spec/shared/share/haproxy-2.conf +17 -0
  767. data/spec/shared/shlib/config.sh +27 -0
  768. data/spec/shared/shlib/distro.sh +74 -0
  769. data/spec/shared/shlib/server.sh +416 -0
  770. data/spec/shared/shlib/set_env.sh +169 -0
  771. data/spec/spec_helper.rb +74 -88
  772. data/spec/support/authorization.rb +2 -0
  773. data/spec/support/client_registry.rb +9 -0
  774. data/spec/support/constraints.rb +77 -0
  775. data/spec/support/expectations.rb +21 -3
  776. data/spec/support/helpers.rb +11 -0
  777. data/spec/support/immutable_ids.rb +118 -0
  778. data/spec/support/macros.rb +129 -0
  779. data/spec/{app → support}/models/account.rb +3 -1
  780. data/spec/{app → support}/models/acolyte.rb +2 -0
  781. data/spec/{app → support}/models/actor.rb +3 -1
  782. data/spec/support/models/actress.rb +4 -0
  783. data/spec/{app → support}/models/address.rb +6 -0
  784. data/spec/{app → support}/models/address_component.rb +2 -0
  785. data/spec/{app → support}/models/address_number.rb +2 -0
  786. data/spec/{app → support}/models/agency.rb +2 -0
  787. data/spec/{app → support}/models/agent.rb +2 -0
  788. data/spec/{app → support}/models/album.rb +2 -0
  789. data/spec/{app → support}/models/alert.rb +2 -0
  790. data/spec/{app → support}/models/animal.rb +2 -0
  791. data/spec/{app → support}/models/answer.rb +2 -0
  792. data/spec/{app → support}/models/appointment.rb +2 -0
  793. data/spec/support/models/armrest.rb +9 -0
  794. data/spec/{app → support}/models/article.rb +2 -0
  795. data/spec/{app → support}/models/artist.rb +4 -1
  796. data/spec/{app → support}/models/artwork.rb +2 -0
  797. data/spec/support/models/audible_sound.rb +3 -0
  798. data/spec/{app → support}/models/audio.rb +2 -0
  799. data/spec/support/models/augmentation.rb +25 -0
  800. data/spec/{app → support}/models/author.rb +2 -0
  801. data/spec/{app → support}/models/baby.rb +2 -0
  802. data/spec/{app → support}/models/band.rb +10 -0
  803. data/spec/{app → support}/models/bar.rb +2 -0
  804. data/spec/{app → support}/models/basic.rb +2 -0
  805. data/spec/support/models/bed.rb +3 -0
  806. data/spec/{app → support}/models/big_palette.rb +2 -0
  807. data/spec/{app → support}/models/birthday.rb +2 -0
  808. data/spec/support/models/bolt.rb +7 -0
  809. data/spec/{app → support}/models/bomb.rb +2 -0
  810. data/spec/{app → support}/models/book.rb +3 -0
  811. data/spec/{app → support}/models/breed.rb +2 -0
  812. data/spec/{app → support}/models/browser.rb +3 -1
  813. data/spec/{app → support}/models/building.rb +4 -0
  814. data/spec/{app → support}/models/building_address.rb +2 -0
  815. data/spec/{app → support}/models/bus.rb +2 -0
  816. data/spec/{app → support}/models/business.rb +2 -0
  817. data/spec/{app → support}/models/callback_test.rb +2 -0
  818. data/spec/{app → support}/models/canvas.rb +3 -1
  819. data/spec/support/models/car.rb +3 -0
  820. data/spec/{app → support}/models/cat.rb +2 -0
  821. data/spec/support/models/catalog.rb +24 -0
  822. data/spec/{app → support}/models/category.rb +2 -0
  823. data/spec/{app → support}/models/child.rb +2 -0
  824. data/spec/{app → support}/models/child_doc.rb +5 -3
  825. data/spec/{app → support}/models/church.rb +2 -0
  826. data/spec/{app → support}/models/circle.rb +2 -0
  827. data/spec/{app → support}/models/circuit.rb +2 -0
  828. data/spec/support/models/circus.rb +12 -0
  829. data/spec/{app → support}/models/code.rb +4 -0
  830. data/spec/support/models/coding/pull_request.rb +11 -0
  831. data/spec/support/models/coding.rb +3 -0
  832. data/spec/{app → support}/models/comment.rb +2 -0
  833. data/spec/{app → support}/models/company.rb +2 -0
  834. data/spec/{app → support}/models/consumption_period.rb +2 -0
  835. data/spec/{app → support}/models/contextable_item.rb +2 -0
  836. data/spec/{app → support}/models/contractor.rb +2 -0
  837. data/spec/{app → support}/models/cookie.rb +2 -0
  838. data/spec/{app → support}/models/country_code.rb +4 -0
  839. data/spec/{app → support}/models/courier_job.rb +2 -0
  840. data/spec/support/models/cover.rb +10 -0
  841. data/spec/support/models/crate.rb +12 -0
  842. data/spec/support/models/customer.rb +10 -0
  843. data/spec/support/models/customer_address.rb +11 -0
  844. data/spec/support/models/deed.rb +7 -0
  845. data/spec/{app → support}/models/definition.rb +2 -0
  846. data/spec/support/models/delegating_patient.rb +15 -0
  847. data/spec/{app → support}/models/description.rb +2 -0
  848. data/spec/{app → support}/models/dictionary.rb +8 -0
  849. data/spec/{app → support}/models/division.rb +2 -0
  850. data/spec/{app → support}/models/doctor.rb +2 -0
  851. data/spec/{app → support}/models/dog.rb +2 -0
  852. data/spec/{app → support}/models/dokument.rb +2 -0
  853. data/spec/{app → support}/models/draft.rb +2 -0
  854. data/spec/{app → support}/models/dragon.rb +2 -0
  855. data/spec/{app → support}/models/driver.rb +3 -1
  856. data/spec/{app → support}/models/drug.rb +2 -0
  857. data/spec/{app → support}/models/dungeon.rb +2 -0
  858. data/spec/{app → support}/models/edit.rb +2 -0
  859. data/spec/{app → support}/models/email.rb +2 -0
  860. data/spec/{app → support}/models/employer.rb +2 -0
  861. data/spec/{app → support}/models/entry.rb +2 -0
  862. data/spec/support/models/eraser.rb +3 -0
  863. data/spec/{app → support}/models/even.rb +2 -0
  864. data/spec/{app → support}/models/event.rb +2 -0
  865. data/spec/{app → support}/models/exhibition.rb +2 -0
  866. data/spec/{app → support}/models/exhibitor.rb +2 -0
  867. data/spec/{app → support}/models/explosion.rb +2 -0
  868. data/spec/{app → support}/models/eye.rb +2 -0
  869. data/spec/{app → support}/models/eye_bowl.rb +2 -0
  870. data/spec/{app → support}/models/face.rb +2 -0
  871. data/spec/support/models/fanatic.rb +8 -0
  872. data/spec/{app → support}/models/favorite.rb +2 -0
  873. data/spec/{app → support}/models/filesystem.rb +2 -0
  874. data/spec/{app → support}/models/fire_hydrant.rb +2 -0
  875. data/spec/{app → support}/models/firefox.rb +2 -0
  876. data/spec/{app → support}/models/fish.rb +2 -0
  877. data/spec/{app → support}/models/folder.rb +2 -0
  878. data/spec/{app → support}/models/folder_item.rb +2 -0
  879. data/spec/{app → support}/models/fruits.rb +2 -0
  880. data/spec/{app → support}/models/game.rb +2 -0
  881. data/spec/{app → support}/models/ghost.rb +2 -0
  882. data/spec/support/models/guitar.rb +4 -0
  883. data/spec/support/models/hole.rb +12 -0
  884. data/spec/{app → support}/models/home.rb +2 -0
  885. data/spec/{app → support}/models/house.rb +2 -0
  886. data/spec/{app → support}/models/html_writer.rb +2 -0
  887. data/spec/{app → support}/models/id_key.rb +2 -0
  888. data/spec/support/models/idnodef.rb +7 -0
  889. data/spec/{app → support}/models/image.rb +2 -0
  890. data/spec/{app → support}/models/implant.rb +11 -0
  891. data/spec/support/models/instrument.rb +8 -0
  892. data/spec/{app → support}/models/item.rb +3 -1
  893. data/spec/{app → support}/models/jar.rb +2 -0
  894. data/spec/{app → support}/models/kaleidoscope.rb +2 -0
  895. data/spec/{app → support}/models/kangaroo.rb +3 -1
  896. data/spec/{app → support}/models/label.rb +6 -1
  897. data/spec/{app → support}/models/language.rb +2 -0
  898. data/spec/{app → support}/models/lat_lng.rb +2 -0
  899. data/spec/{app → support}/models/league.rb +2 -0
  900. data/spec/support/models/learner.rb +4 -0
  901. data/spec/{app → support}/models/line_item.rb +2 -0
  902. data/spec/{app → support}/models/location.rb +2 -0
  903. data/spec/{app → support}/models/login.rb +2 -0
  904. data/spec/{app → support}/models/manufacturer.rb +2 -0
  905. data/spec/{app → support}/models/meat.rb +2 -0
  906. data/spec/{app → support}/models/membership.rb +3 -0
  907. data/spec/{app → support}/models/message.rb +2 -0
  908. data/spec/support/models/minim.rb +6 -0
  909. data/spec/{app → support}/models/mixed_drink.rb +2 -0
  910. data/spec/support/models/mop.rb +24 -0
  911. data/spec/{app → support}/models/movie.rb +2 -0
  912. data/spec/support/models/my_hash.rb +4 -0
  913. data/spec/{app → support}/models/name.rb +2 -0
  914. data/spec/support/models/name_only.rb +8 -0
  915. data/spec/{app → support}/models/node.rb +2 -0
  916. data/spec/{app → support}/models/note.rb +2 -0
  917. data/spec/support/models/nut.rb +7 -0
  918. data/spec/{app → support}/models/odd.rb +2 -0
  919. data/spec/support/models/order.rb +12 -0
  920. data/spec/{app → support}/models/ordered_post.rb +3 -1
  921. data/spec/{app → support}/models/ordered_preference.rb +2 -0
  922. data/spec/{app → support}/models/oscar.rb +2 -0
  923. data/spec/support/models/other_owner_object.rb +4 -0
  924. data/spec/{app → support}/models/override.rb +2 -0
  925. data/spec/{app → support}/models/ownable.rb +2 -0
  926. data/spec/{app → support}/models/owner.rb +4 -0
  927. data/spec/{app → support}/models/pack.rb +2 -0
  928. data/spec/{app → support}/models/page.rb +2 -0
  929. data/spec/{app → support}/models/page_question.rb +2 -0
  930. data/spec/{app → support}/models/palette.rb +3 -1
  931. data/spec/{app → support}/models/parent.rb +2 -0
  932. data/spec/{app → support}/models/parent_doc.rb +2 -0
  933. data/spec/support/models/passport.rb +22 -0
  934. data/spec/{app → support}/models/patient.rb +2 -0
  935. data/spec/{app → support}/models/pdf_writer.rb +2 -0
  936. data/spec/support/models/pencil.rb +3 -0
  937. data/spec/{app → support}/models/person.rb +22 -1
  938. data/spec/{app → support}/models/pet.rb +2 -0
  939. data/spec/{app → support}/models/pet_owner.rb +2 -0
  940. data/spec/{app → support}/models/phone.rb +5 -1
  941. data/spec/support/models/piano.rb +4 -0
  942. data/spec/{app → support}/models/pizza.rb +2 -0
  943. data/spec/{app → support}/models/player.rb +4 -0
  944. data/spec/{app → support}/models/post.rb +2 -0
  945. data/spec/{app → support}/models/post_genre.rb +2 -0
  946. data/spec/support/models/powerup.rb +25 -0
  947. data/spec/{app → support}/models/preference.rb +2 -0
  948. data/spec/{app → support}/models/princess.rb +2 -0
  949. data/spec/{app → support}/models/product.rb +3 -0
  950. data/spec/support/models/profile.rb +17 -0
  951. data/spec/{app → support}/models/pronunciation.rb +2 -0
  952. data/spec/{app → support}/models/pub.rb +2 -0
  953. data/spec/support/models/publication/encyclopedia.rb +11 -0
  954. data/spec/support/models/publication/review.rb +13 -0
  955. data/spec/support/models/publication.rb +4 -0
  956. data/spec/{app → support}/models/purchase.rb +2 -0
  957. data/spec/support/models/purchased_item.rb +10 -0
  958. data/spec/{app → support}/models/question.rb +2 -0
  959. data/spec/{app → support}/models/quiz.rb +2 -0
  960. data/spec/{app → support}/models/rating.rb +2 -0
  961. data/spec/{app → support}/models/record.rb +2 -0
  962. data/spec/{app → support}/models/registry.rb +3 -0
  963. data/spec/{app → support}/models/role.rb +2 -0
  964. data/spec/{app → support}/models/root_category.rb +2 -0
  965. data/spec/{app → support}/models/sandwich.rb +2 -0
  966. data/spec/{app → support}/models/scheduler.rb +2 -0
  967. data/spec/support/models/school.rb +14 -0
  968. data/spec/support/models/scribe.rb +7 -0
  969. data/spec/support/models/sealer.rb +7 -0
  970. data/spec/support/models/seat.rb +24 -0
  971. data/spec/{app → support}/models/seo.rb +2 -0
  972. data/spec/support/models/series.rb +7 -0
  973. data/spec/{app → support}/models/server.rb +2 -0
  974. data/spec/{app → support}/models/service.rb +2 -0
  975. data/spec/{app → support}/models/shape.rb +4 -2
  976. data/spec/{app → support}/models/shelf.rb +2 -0
  977. data/spec/support/models/shield.rb +18 -0
  978. data/spec/{app → support}/models/shipment_address.rb +2 -0
  979. data/spec/{app → support}/models/shipping_container.rb +2 -0
  980. data/spec/{app → support}/models/shipping_pack.rb +2 -0
  981. data/spec/support/models/shirt.rb +11 -0
  982. data/spec/{app → support}/models/shop.rb +2 -0
  983. data/spec/{app → support}/models/short_agent.rb +2 -0
  984. data/spec/{app → support}/models/short_quiz.rb +2 -0
  985. data/spec/{app → support}/models/simple.rb +2 -0
  986. data/spec/{app → support}/models/slave.rb +2 -0
  987. data/spec/{app → support}/models/song.rb +2 -0
  988. data/spec/{app → support}/models/sound.rb +2 -0
  989. data/spec/support/models/spacer.rb +7 -0
  990. data/spec/{app → support}/models/square.rb +2 -0
  991. data/spec/{app → support}/models/staff.rb +2 -0
  992. data/spec/{app → support}/models/store_as_dup_test1.rb +2 -0
  993. data/spec/{app → support}/models/store_as_dup_test2.rb +2 -0
  994. data/spec/support/models/store_as_dup_test3.rb +7 -0
  995. data/spec/support/models/store_as_dup_test4.rb +7 -0
  996. data/spec/{app → support}/models/strategy.rb +2 -0
  997. data/spec/support/models/student.rb +14 -0
  998. data/spec/{app → support}/models/sub_item.rb +2 -0
  999. data/spec/{app → support}/models/subscription.rb +2 -0
  1000. data/spec/{app → support}/models/survey.rb +2 -0
  1001. data/spec/{app → support}/models/symptom.rb +2 -0
  1002. data/spec/support/models/system_role.rb +7 -0
  1003. data/spec/{app → support}/models/tag.rb +2 -0
  1004. data/spec/{app → support}/models/target.rb +2 -0
  1005. data/spec/{app → support}/models/template.rb +2 -0
  1006. data/spec/{app → support}/models/thing.rb +2 -0
  1007. data/spec/support/models/threadlocker.rb +7 -0
  1008. data/spec/{app → support}/models/title.rb +2 -0
  1009. data/spec/{app → support}/models/tool.rb +4 -2
  1010. data/spec/{app → support}/models/topping.rb +2 -0
  1011. data/spec/support/models/toy.rb +9 -0
  1012. data/spec/{app → support}/models/track.rb +2 -0
  1013. data/spec/{app → support}/models/translation.rb +2 -0
  1014. data/spec/{app → support}/models/tree.rb +2 -0
  1015. data/spec/support/models/truck.rb +7 -0
  1016. data/spec/{app → support}/models/user.rb +2 -0
  1017. data/spec/{app → support}/models/user_account.rb +2 -0
  1018. data/spec/{app → support}/models/validation_callback.rb +2 -0
  1019. data/spec/support/models/vehicle.rb +18 -0
  1020. data/spec/{app → support}/models/version.rb +2 -0
  1021. data/spec/{app → support}/models/vertex.rb +3 -1
  1022. data/spec/{app → support}/models/vet_visit.rb +2 -0
  1023. data/spec/{app → support}/models/video.rb +2 -0
  1024. data/spec/support/models/video_game.rb +3 -0
  1025. data/spec/support/models/washer.rb +7 -0
  1026. data/spec/support/models/weapon.rb +25 -0
  1027. data/spec/{app → support}/models/wiki_page.rb +3 -0
  1028. data/spec/{app → support}/models/word.rb +2 -0
  1029. data/spec/{app → support}/models/word_origin.rb +2 -0
  1030. data/spec/{app → support}/models/writer.rb +4 -2
  1031. data/spec/support/schema_maps/schema_map_aws.json +17 -0
  1032. data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  1033. data/spec/support/schema_maps/schema_map_azure.json +17 -0
  1034. data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  1035. data/spec/support/schema_maps/schema_map_gcp.json +17 -0
  1036. data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  1037. data/spec/support/schema_maps/schema_map_kmip.json +17 -0
  1038. data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  1039. data/spec/support/schema_maps/schema_map_local.json +18 -0
  1040. data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
  1041. data/spec/support/shared/time.rb +53 -0
  1042. data/spec/support/spec_config.rb +64 -0
  1043. data.tar.gz.sig +1 -2
  1044. metadata +1158 -615
  1045. metadata.gz.sig +0 -0
  1046. data/lib/mongoid/criteria/queryable/forwardable.rb +0 -65
  1047. data/lib/mongoid/errors/eager_load.rb +0 -22
  1048. data/lib/mongoid/errors/invalid_value.rb +0 -16
  1049. data/lib/mongoid/matchable/all.rb +0 -27
  1050. data/lib/mongoid/matchable/and.rb +0 -30
  1051. data/lib/mongoid/matchable/default.rb +0 -72
  1052. data/lib/mongoid/matchable/elem_match.rb +0 -34
  1053. data/lib/mongoid/matchable/exists.rb +0 -23
  1054. data/lib/mongoid/matchable/gt.rb +0 -23
  1055. data/lib/mongoid/matchable/gte.rb +0 -23
  1056. data/lib/mongoid/matchable/in.rb +0 -24
  1057. data/lib/mongoid/matchable/lt.rb +0 -23
  1058. data/lib/mongoid/matchable/lte.rb +0 -23
  1059. data/lib/mongoid/matchable/ne.rb +0 -21
  1060. data/lib/mongoid/matchable/nin.rb +0 -22
  1061. data/lib/mongoid/matchable/nor.rb +0 -37
  1062. data/lib/mongoid/matchable/or.rb +0 -33
  1063. data/lib/mongoid/matchable/regexp.rb +0 -27
  1064. data/lib/mongoid/matchable/size.rb +0 -21
  1065. data/lib/support/ruby_version.rb +0 -26
  1066. data/spec/app/models/actress.rb +0 -2
  1067. data/spec/app/models/augmentation.rb +0 -11
  1068. data/spec/app/models/bed.rb +0 -1
  1069. data/spec/app/models/car.rb +0 -1
  1070. data/spec/app/models/circus.rb +0 -7
  1071. data/spec/app/models/eraser.rb +0 -1
  1072. data/spec/app/models/learner.rb +0 -2
  1073. data/spec/app/models/my_hash.rb +0 -2
  1074. data/spec/app/models/passport.rb +0 -5
  1075. data/spec/app/models/pencil.rb +0 -1
  1076. data/spec/app/models/powerup.rb +0 -11
  1077. data/spec/app/models/profile.rb +0 -5
  1078. data/spec/app/models/series.rb +0 -4
  1079. data/spec/app/models/truck.rb +0 -3
  1080. data/spec/app/models/vehicle.rb +0 -11
  1081. data/spec/app/models/video_game.rb +0 -1
  1082. data/spec/app/models/weapon.rb +0 -11
  1083. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -58
  1084. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -58
  1085. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +0 -87
  1086. data/spec/mongoid/matchable/all_spec.rb +0 -31
  1087. data/spec/mongoid/matchable/and_spec.rb +0 -187
  1088. data/spec/mongoid/matchable/default_spec.rb +0 -130
  1089. data/spec/mongoid/matchable/elem_match_spec.rb +0 -106
  1090. data/spec/mongoid/matchable/exists_spec.rb +0 -57
  1091. data/spec/mongoid/matchable/gt_spec.rb +0 -86
  1092. data/spec/mongoid/matchable/gte_spec.rb +0 -84
  1093. data/spec/mongoid/matchable/in_spec.rb +0 -49
  1094. data/spec/mongoid/matchable/lt_spec.rb +0 -85
  1095. data/spec/mongoid/matchable/lte_spec.rb +0 -85
  1096. data/spec/mongoid/matchable/ne_spec.rb +0 -46
  1097. data/spec/mongoid/matchable/nin_spec.rb +0 -48
  1098. data/spec/mongoid/matchable/nor_spec.rb +0 -209
  1099. data/spec/mongoid/matchable/or_spec.rb +0 -131
  1100. data/spec/mongoid/matchable/regexp_spec.rb +0 -59
  1101. data/spec/mongoid/matchable/size_spec.rb +0 -25
  1102. data/spec/mongoid/matchable_spec.rb +0 -853
  1103. /data/spec/{app → support}/models/array_field.rb +0 -0
  1104. /data/spec/{app → support}/models/updatable.rb +0 -0
@@ -1,4 +1,6 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
3
+ require "mongoid/contextual/mongo/documents_loader"
2
4
  require "mongoid/contextual/atomic"
3
5
  require "mongoid/contextual/aggregable/mongo"
4
6
  require "mongoid/contextual/command"
@@ -9,15 +11,16 @@ require "mongoid/association/eager_loadable"
9
11
  module Mongoid
10
12
  module Contextual
11
13
  class Mongo
14
+ extend Forwardable
12
15
  include Enumerable
13
16
  include Aggregable::Mongo
14
17
  include Atomic
15
18
  include Association::EagerLoadable
16
19
  include Queryable
17
20
 
21
+ Mongoid.deprecate(self, :geo_near)
22
+
18
23
  # Options constant.
19
- #
20
- # @since 5.0.0
21
24
  OPTIONS = [ :hint,
22
25
  :limit,
23
26
  :skip,
@@ -35,17 +38,17 @@ module Mongoid
35
38
  # @attribute [r] view The Mongo collection view.
36
39
  attr_reader :view
37
40
 
38
- # Is the context cached?
41
+ # Run an explain on the criteria.
39
42
  #
40
- # @example Is the context cached?
41
- # context.cached?
43
+ # @example Explain the criteria.
44
+ # Band.where(name: "Depeche Mode").explain
42
45
  #
43
- # @return [ true, false ] If the context is cached.
46
+ # @param [ Hash ] options customizable options (See Mongo::Collection::View::Explainable)
44
47
  #
45
- # @since 3.0.0
46
- def cached?
47
- !!@cache
48
- end
48
+ # @return [ Hash ] The explain result.
49
+ def_delegator :view, :explain
50
+
51
+ attr_reader :documents_loader
49
52
 
50
53
  # Get the number of documents matching the query.
51
54
  #
@@ -64,11 +67,28 @@ module Mongoid
64
67
  # into the count.
65
68
  #
66
69
  # @return [ Integer ] The number of matches.
67
- #
68
- # @since 3.0.0
69
70
  def count(options = {}, &block)
70
71
  return super(&block) if block_given?
71
- try_cache(:count) { view.count(options) }
72
+ view.count_documents(options)
73
+ end
74
+
75
+ # Get the estimated number of documents matching the query.
76
+ #
77
+ # Unlike count, estimated_count does not take a block because it is not
78
+ # traditionally defined (with a block) on Enumarable like count is.
79
+ #
80
+ # @example Get the estimated number of matching documents.
81
+ # context.estimated_count
82
+ #
83
+ # @param [ Hash ] options The options, such as maxTimeMS to be factored
84
+ # into the count.
85
+ #
86
+ # @return [ Integer ] The number of matches.
87
+ def estimated_count(options = {})
88
+ unless self.criteria.selector.empty?
89
+ raise Mongoid::Errors::InvalidEstimatedCountCriteria.new(self.klass)
90
+ end
91
+ view.estimated_document_count(options)
72
92
  end
73
93
 
74
94
  # Delete all documents in the database that match the selector.
@@ -77,8 +97,6 @@ module Mongoid
77
97
  # context.delete
78
98
  #
79
99
  # @return [ nil ] Nil.
80
- #
81
- # @since 3.0.0
82
100
  def delete
83
101
  view.delete_many.deleted_count
84
102
  end
@@ -90,8 +108,6 @@ module Mongoid
90
108
  # context.destroy
91
109
  #
92
110
  # @return [ nil ] Nil.
93
- #
94
- # @since 3.0.0
95
111
  def destroy
96
112
  each.inject(0) do |count, doc|
97
113
  doc.destroy
@@ -106,14 +122,23 @@ module Mongoid
106
122
  # @example Get the distinct values.
107
123
  # context.distinct(:name)
108
124
  #
109
- # @param [ String, Symbol ] field The name of the field.
125
+ # @param [ String | Symbol ] field The name of the field.
110
126
  #
111
127
  # @return [ Array<Object> ] The distinct values for the field.
112
- #
113
- # @since 3.0.0
114
128
  def distinct(field)
115
- view.distinct(klass.database_field_name(field)).map do |value|
116
- value.class.demongoize(value)
129
+ name = if Mongoid.legacy_pluck_distinct
130
+ klass.database_field_name(field)
131
+ else
132
+ klass.cleanse_localized_field_names(field)
133
+ end
134
+
135
+ view.distinct(name).map do |value|
136
+ if Mongoid.legacy_pluck_distinct
137
+ value.class.demongoize(value)
138
+ else
139
+ is_translation = "#{name}_translations" == field.to_s
140
+ recursive_demongoize(name, value, is_translation)
141
+ end
117
142
  end
118
143
  end
119
144
 
@@ -126,14 +151,11 @@ module Mongoid
126
151
  # end
127
152
  #
128
153
  # @return [ Enumerator ] The enumerator.
129
- #
130
- # @since 3.0.0
131
154
  def each(&block)
132
155
  if block_given?
133
156
  documents_for_iteration.each do |doc|
134
157
  yield_document(doc, &block)
135
158
  end
136
- @cache_loaded = true
137
159
  self
138
160
  else
139
161
  to_enum
@@ -145,34 +167,30 @@ module Mongoid
145
167
  # @example Do any documents exist for the context.
146
168
  # context.exists?
147
169
  #
148
- # @note We don't use count here since Mongo does not use counted
149
- # b-tree indexes, unless a count is already cached then that is
150
- # used to determine the value.
170
+ # @example Do any documents exist for given _id.
171
+ # context.exists?(BSON::ObjectId(...))
151
172
  #
152
- # @return [ true, false ] If the count is more than zero.
173
+ # @example Do any documents exist for given conditions.
174
+ # context.exists?(name: "...")
153
175
  #
154
- # @since 3.0.0
155
- def exists?
156
- return !documents.empty? if cached? && cache_loaded?
157
- return @count > 0 if instance_variable_defined?(:@count)
158
-
159
- try_cache(:exists) do
160
- !!(view.projection(_id: 1).limit(1).first)
176
+ # @note We don't use count here since Mongo does not use counted
177
+ # b-tree indexes.
178
+ #
179
+ # @param [ Hash | Object | false ] id_or_conditions an _id to
180
+ # search for, a hash of conditions, nil or false.
181
+ #
182
+ # @return [ true | false ] If the count is more than zero.
183
+ # Always false if passed nil or false.
184
+ def exists?(id_or_conditions = :none)
185
+ return false if self.view.limit == 0
186
+ case id_or_conditions
187
+ when :none then !!(view.projection(_id: 1).limit(1).first)
188
+ when nil, false then false
189
+ when Hash then Mongo.new(criteria.where(id_or_conditions)).exists?
190
+ else Mongo.new(criteria.where(_id: id_or_conditions)).exists?
161
191
  end
162
192
  end
163
193
 
164
- # Run an explain on the criteria.
165
- #
166
- # @example Explain the criteria.
167
- # Band.where(name: "Depeche Mode").explain
168
- #
169
- # @return [ Hash ] The explain result.
170
- #
171
- # @since 3.0.0
172
- def explain
173
- view.explain
174
- end
175
-
176
194
  # Execute the find and modify command, used for MongoDB's
177
195
  # $findAndModify.
178
196
  #
@@ -182,13 +200,11 @@ module Mongoid
182
200
  # @param [ Hash ] update The updates.
183
201
  # @param [ Hash ] options The command options.
184
202
  #
185
- # @option options [ :before, :after ] :return_document Return the updated document
203
+ # @option options [ :before | :after ] :return_document Return the updated document
186
204
  # from before or after update.
187
- # @option options [ true, false ] :upsert Create the document if it doesn't exist.
205
+ # @option options [ true | false ] :upsert Create the document if it doesn't exist.
188
206
  #
189
207
  # @return [ Document ] The result of the command.
190
- #
191
- # @since 5.0.0
192
208
  def find_one_and_update(update, options = {})
193
209
  if doc = view.find_one_and_update(update, options)
194
210
  Factory.from_db(klass, doc)
@@ -204,13 +220,11 @@ module Mongoid
204
220
  # @param [ Hash ] replacement The replacement.
205
221
  # @param [ Hash ] options The command options.
206
222
  #
207
- # @option options [ :before, :after ] :return_document Return the updated document
223
+ # @option options [ :before | :after ] :return_document Return the updated document
208
224
  # from before or after update.
209
- # @option options [ true, false ] :upsert Create the document if it doesn't exist.
225
+ # @option options [ true | false ] :upsert Create the document if it doesn't exist.
210
226
  #
211
227
  # @return [ Document ] The result of the command.
212
- #
213
- # @since 5.0.0
214
228
  def find_one_and_replace(replacement, options = {})
215
229
  if doc = view.find_one_and_replace(replacement, options)
216
230
  Factory.from_db(klass, doc)
@@ -224,58 +238,16 @@ module Mongoid
224
238
  # context.find_one_and_delete
225
239
  #
226
240
  # @return [ Document ] The result of the command.
227
- #
228
- # @since 5.0.0
229
241
  def find_one_and_delete
230
242
  if doc = view.find_one_and_delete
231
243
  Factory.from_db(klass, doc)
232
244
  end
233
245
  end
234
246
 
235
- # Get the first document in the database for the criteria's selector.
236
- #
237
- # @example Get the first document.
238
- # context.first
239
- #
240
- # @note Automatically adding a sort on _id when no other sort is
241
- # defined on the criteria has the potential to cause bad performance issues.
242
- # If you experience unexpected poor performance when using #first or #last
243
- # and have no sort defined on the criteria, use the option { id_sort: :none }.
244
- # Be aware that #first/#last won't guarantee order in this case.
245
- #
246
- # @param [ Hash ] opts The options for the query returning the first document.
247
- #
248
- # @option opts [ :none ] :id_sort Don't apply a sort on _id if no other sort
249
- # is defined on the criteria.
250
- #
251
- # @return [ Document ] The first document.
252
- #
253
- # @since 3.0.0
254
- def first(opts = {})
255
- return documents.first if cached? && cache_loaded?
256
- try_cache(:first) do
257
- if sort = view.sort || ({ _id: 1 } unless opts[:id_sort] == :none)
258
- if raw_doc = view.sort(sort).limit(-1).first
259
- doc = Factory.from_db(klass, raw_doc, criteria)
260
- eager_load([doc]).first
261
- end
262
- else
263
- if raw_doc = view.limit(-1).first
264
- doc = Factory.from_db(klass, raw_doc, criteria)
265
- eager_load([doc]).first
266
- end
267
- end
268
- end
269
- end
270
- alias :one :first
271
-
272
247
  # Return the first result without applying sort
273
248
  #
274
249
  # @api private
275
- #
276
- # @since 4.0.2
277
250
  def find_first
278
- return documents.first if cached? && cache_loaded?
279
251
  if raw_doc = view.first
280
252
  doc = Factory.from_db(klass, raw_doc, criteria)
281
253
  eager_load([doc]).first
@@ -300,34 +272,11 @@ module Mongoid
300
272
  #
301
273
  # @return [ GeoNear ] The GeoNear command.
302
274
  #
303
- # @since 3.1.0
275
+ # @deprecated
304
276
  def geo_near(coordinates)
305
277
  GeoNear.new(collection, criteria, coordinates)
306
278
  end
307
279
 
308
- # Invoke the block for each element of Contextual. Create a new array
309
- # containing the values returned by the block.
310
- #
311
- # If the symbol field name is passed instead of the block, additional
312
- # optimizations would be used.
313
- #
314
- # @example Map by some field.
315
- # context.map(:field1)
316
- #
317
- # @example Map with block.
318
- # context.map(&:field1)
319
- #
320
- # @param [ Symbol ] field The field name.
321
- #
322
- # @return [ Array ] The result of mapping.
323
- def map(field = nil, &block)
324
- if block_given?
325
- super(&block)
326
- else
327
- criteria.pluck(field)
328
- end
329
- end
330
-
331
280
  # Create the new Mongo context. This delegates operations to the
332
281
  # underlying driver.
333
282
  #
@@ -335,56 +284,25 @@ module Mongoid
335
284
  # Mongo.new(criteria)
336
285
  #
337
286
  # @param [ Criteria ] criteria The criteria.
338
- #
339
- # @since 3.0.0
340
287
  def initialize(criteria)
341
- @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
288
+ @criteria, @klass = criteria, criteria.klass
342
289
  @collection = @klass.collection
343
290
  criteria.send(:merge_type_selection)
344
291
  @view = collection.find(criteria.selector, session: _session)
345
292
  apply_options
346
293
  end
347
294
 
348
- delegate(:database_field_name, to: :@klass)
349
-
350
- # Get the last document in the database for the criteria's selector.
351
- #
352
- # @example Get the last document.
353
- # context.last
354
- #
355
- # @note Automatically adding a sort on _id when no other sort is
356
- # defined on the criteria has the potential to cause bad performance issues.
357
- # If you experience unexpected poor performance when using #first or #last
358
- # and have no sort defined on the criteria, use the option { id_sort: :none }.
359
- # Be aware that #first/#last won't guarantee order in this case.
360
- #
361
- # @param [ Hash ] opts The options for the query returning the first document.
362
- #
363
- # @option opts [ :none ] :id_sort Don't apply a sort on _id if no other sort
364
- # is defined on the criteria.
365
- #
366
- # @since 3.0.0
367
- def last(opts = {})
368
- try_cache(:last) do
369
- with_inverse_sorting(opts) do
370
- if raw_doc = view.limit(-1).first
371
- doc = Factory.from_db(klass, raw_doc, criteria)
372
- eager_load([doc]).first
373
- end
374
- end
375
- end
376
- end
295
+ def_delegator :@klass, :database_field_name
377
296
 
378
- # Get's the number of documents matching the query selector.
297
+ # Returns the number of documents in the database matching
298
+ # the query selector.
379
299
  #
380
300
  # @example Get the length.
381
301
  # context.length
382
302
  #
383
303
  # @return [ Integer ] The number of documents.
384
- #
385
- # @since 3.0.0
386
304
  def length
387
- @length ||= self.count
305
+ self.count
388
306
  end
389
307
  alias :size :length
390
308
 
@@ -396,8 +314,6 @@ module Mongoid
396
314
  # @param [ Integer ] value The number of documents to return.
397
315
  #
398
316
  # @return [ Mongo ] The context.
399
- #
400
- # @since 3.0.0
401
317
  def limit(value)
402
318
  @view = view.limit(value) and self
403
319
  end
@@ -411,40 +327,174 @@ module Mongoid
411
327
  # @param [ String ] reduce The reduce js function.
412
328
  #
413
329
  # @return [ MapReduce ] The map/reduce lazy wrapper.
414
- #
415
- # @since 3.0.0
416
330
  def map_reduce(map, reduce)
417
331
  MapReduce.new(collection, criteria, map, reduce)
418
332
  end
419
333
 
420
- # Pluck the single field values from the database. Will return duplicates
421
- # if they exist and only works for top level fields.
334
+ # Pluck the field value(s) from the database. Returns one
335
+ # result for each document found in the database for
336
+ # the context. The results are normalized according to their
337
+ # Mongoid field types. Note that the results may include
338
+ # duplicates and nil values.
422
339
  #
423
340
  # @example Pluck a field.
424
341
  # context.pluck(:_id)
425
342
  #
426
- # @note This method will return the raw db values - it performs no custom
427
- # serialization.
428
- #
429
- # @param [ String, Symbol, Array ] fields Fields to pluck.
430
- #
431
- # @return [ Array<Object, Array> ] The plucked values.
343
+ # @param [ [ String | Symbol ]... ] *fields Field(s) to pluck,
344
+ # which may include nested fields using dot-notation.
432
345
  #
433
- # @since 3.1.0
346
+ # @return [ Array<Object> | Array<Array<Object>> ] The plucked values.
347
+ # If the *fields arg contains a single value, each result
348
+ # in the array will be a single value. Otherwise, each
349
+ # result in the array will be an array of values.
434
350
  def pluck(*fields)
351
+ # Multiple fields can map to the same field name. For example, plucking
352
+ # a field and its _translations field map to the same field in the database.
353
+ # because of this, we need to keep track of the fields requested.
354
+ normalized_field_names = []
435
355
  normalized_select = fields.inject({}) do |hash, f|
436
- hash[klass.database_field_name(f)] = 1
356
+ db_fn = klass.database_field_name(f)
357
+ normalized_field_names.push(db_fn)
358
+
359
+ if Mongoid.legacy_pluck_distinct
360
+ hash[db_fn] = true
361
+ else
362
+ hash[klass.cleanse_localized_field_names(f)] = true
363
+ end
437
364
  hash
438
365
  end
439
366
 
440
367
  view.projection(normalized_select).reduce([]) do |plucked, doc|
441
- values = normalized_select.keys.map do |n|
442
- n =~ /\./ ? doc[n.partition('.')[0]] : doc[n]
368
+ values = normalized_field_names.map do |n|
369
+ if Mongoid.legacy_pluck_distinct
370
+ n.include?('.') ? doc[n.partition('.')[0]] : doc[n]
371
+ else
372
+ extract_value(doc, n)
373
+ end
443
374
  end
444
375
  plucked << (values.size == 1 ? values.first : values)
445
376
  end
446
377
  end
447
378
 
379
+ # Pick the single field values from the database.
380
+ #
381
+ # @example Pick a field.
382
+ # context.pick(:_id)
383
+ #
384
+ # @param [ [ String | Symbol ]... ] *fields Field(s) to pick.
385
+ #
386
+ # @return [ Object | Array<Object> ] The picked values.
387
+ def pick(*fields)
388
+ limit(1).pluck(*fields).first
389
+ end
390
+
391
+ # Take the given number of documents from the database.
392
+ #
393
+ # @example Take 10 documents
394
+ # context.take(10)
395
+ #
396
+ # @param [ Integer | nil ] limit The number of documents to return or nil.
397
+ #
398
+ # @return [ Document | Array<Document> ] The list of documents, or one
399
+ # document if no value was given.
400
+ def take(limit = nil)
401
+ if limit
402
+ limit(limit).to_a
403
+ else
404
+ # Do to_a first so that the Mongo#first method is not used and the
405
+ # result is not sorted.
406
+ limit(1).to_a.first
407
+ end
408
+ end
409
+
410
+ # Take one document from the database and raise an error if there are none.
411
+ #
412
+ # @example Take a document
413
+ # context.take!
414
+ #
415
+ # @return [ Document ] The document.
416
+ #
417
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
418
+ # documents to take.
419
+ def take!
420
+ # Do to_a first so that the Mongo#first method is not used and the
421
+ # result is not sorted.
422
+ if fst = limit(1).to_a.first
423
+ fst
424
+ else
425
+ raise Errors::DocumentNotFound.new(klass, nil, nil)
426
+ end
427
+ end
428
+
429
+ # Get a hash of counts for the values of a single field. For example,
430
+ # if the following documents were in the database:
431
+ #
432
+ # { _id: 1, age: 21 }
433
+ # { _id: 2, age: 21 }
434
+ # { _id: 3, age: 22 }
435
+ #
436
+ # Model.tally("age")
437
+ #
438
+ # would yield the following result:
439
+ #
440
+ # { 21 => 2, 22 => 1 }
441
+ #
442
+ # When tallying a field inside an array or embeds_many association:
443
+ #
444
+ # { _id: 1, array: [ { x: 1 }, { x: 2 } ] }
445
+ # { _id: 2, array: [ { x: 1 }, { x: 2 } ] }
446
+ # { _id: 3, array: [ { x: 1 }, { x: 3 } ] }
447
+ #
448
+ # Model.tally("array.x")
449
+ #
450
+ # The keys of the resulting hash are arrays:
451
+ #
452
+ # { [ 1, 2 ] => 2, [ 1, 3 ] => 1 }
453
+ #
454
+ # Note that if tallying an element in an array of hashes, and the key
455
+ # doesn't exist in some of the hashes, tally will not include those
456
+ # nil keys in the resulting hash:
457
+ #
458
+ # { _id: 1, array: [ { x: 1 }, { x: 2 }, { y: 3 } ] }
459
+ #
460
+ # Model.tally("array.x")
461
+ # # => { [ 1, 2 ] => 1 }
462
+ #
463
+ # @param [ String | Symbol ] field The field name.
464
+ #
465
+ # @return [ Hash ] The hash of counts.
466
+ def tally(field)
467
+ name = klass.cleanse_localized_field_names(field)
468
+
469
+ fld = klass.traverse_association_tree(name)
470
+ pipeline = [ { "$group" => { _id: "$#{name}", counts: { "$sum": 1 } } } ]
471
+ pipeline.unshift("$match" => view.filter) unless view.filter.blank?
472
+
473
+ collection.aggregate(pipeline).reduce({}) do |tallies, doc|
474
+ is_translation = "#{name}_translations" == field.to_s
475
+ val = doc["_id"]
476
+
477
+ key = if val.is_a?(Array)
478
+ val.map do |v|
479
+ demongoize_with_field(fld, v, is_translation)
480
+ end
481
+ else
482
+ demongoize_with_field(fld, val, is_translation)
483
+ end
484
+
485
+ # The only time where a key will already exist in the tallies hash
486
+ # is when the values are stored differently in the database, but
487
+ # demongoize to the same value. A good example of when this happens
488
+ # is when using localized fields. While the server query won't group
489
+ # together hashes that have other values in different languages, the
490
+ # demongoized value is just the translation in the current locale,
491
+ # which can be the same across multiple of those unequal hashes.
492
+ tallies[key] ||= 0
493
+ tallies[key] += doc["counts"]
494
+ tallies
495
+ end
496
+ end
497
+
448
498
  # Skips the provided number of documents.
449
499
  #
450
500
  # @example Skip the documents.
@@ -453,8 +503,6 @@ module Mongoid
453
503
  # @param [ Integer ] value The number of documents to skip.
454
504
  #
455
505
  # @return [ Mongo ] The context.
456
- #
457
- # @since 3.0.0
458
506
  def skip(value)
459
507
  @view = view.skip(value) and self
460
508
  end
@@ -468,8 +516,6 @@ module Mongoid
468
516
  # pairs.
469
517
  #
470
518
  # @return [ Mongo ] The context.
471
- #
472
- # @since 3.0.0
473
519
  def sort(values = nil, &block)
474
520
  if block_given?
475
521
  super(&block)
@@ -492,9 +538,7 @@ module Mongoid
492
538
  # @option opts [ Array ] :array_filters A set of filters specifying to which array elements
493
539
  # an update should apply.
494
540
  #
495
- # @return [ nil, false ] False if no attributes were provided.
496
- #
497
- # @since 3.0.0
541
+ # @return [ nil | false ] False if no attributes were provided.
498
542
  def update(attributes = nil, opts = {})
499
543
  update_documents(attributes, :update_one, opts)
500
544
  end
@@ -510,33 +554,257 @@ module Mongoid
510
554
  # @option opts [ Array ] :array_filters A set of filters specifying to which array elements
511
555
  # an update should apply.
512
556
  #
513
- # @return [ nil, false ] False if no attributes were provided.
514
- #
515
- # @since 3.0.0
557
+ # @return [ nil | false ] False if no attributes were provided.
516
558
  def update_all(attributes = nil, opts = {})
517
559
  update_documents(attributes, :update_many, opts)
518
560
  end
519
561
 
520
- private
562
+ # Get the first document in the database for the criteria's selector.
563
+ #
564
+ # @example Get the first document.
565
+ # context.first
566
+ #
567
+ # @note Automatically adding a sort on _id when no other sort is
568
+ # defined on the criteria has the potential to cause bad performance issues.
569
+ # If you experience unexpected poor performance when using #first or #last
570
+ # and have no sort defined on the criteria, use #take instead.
571
+ # Be aware that #take won't guarantee order.
572
+ #
573
+ # @param [ Integer ] limit The number of documents to return.
574
+ #
575
+ # @return [ Document | nil ] The first document or nil if none is found.
576
+ def first(limit = nil)
577
+ if limit.nil?
578
+ retrieve_nth(0)
579
+ else
580
+ retrieve_nth_with_limit(0, limit)
581
+ end
582
+ end
583
+ alias :one :first
521
584
 
522
- # yield the block given or return the cached value
585
+ # Get the first document in the database for the criteria's selector or
586
+ # raise an error if none is found.
523
587
  #
524
- # @param [ String, Symbol ] key The instance variable name
588
+ # @example Get the first document.
589
+ # context.first!
525
590
  #
526
- # @return the result of the block
591
+ # @note Automatically adding a sort on _id when no other sort is
592
+ # defined on the criteria has the potential to cause bad performance issues.
593
+ # If you experience unexpected poor performance when using #first! or #last!
594
+ # and have no sort defined on the criteria, use #take! instead.
595
+ # Be aware that #take! won't guarantee order.
596
+ #
597
+ # @return [ Document ] The first document.
527
598
  #
528
- # @since 3.1.4
529
- def try_cache(key, &block)
530
- unless cached?
531
- yield
599
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
600
+ # documents available.
601
+ def first!
602
+ first || raise_document_not_found_error
603
+ end
604
+
605
+ # Get the last document in the database for the criteria's selector.
606
+ #
607
+ # @example Get the last document.
608
+ # context.last
609
+ #
610
+ # @note Automatically adding a sort on _id when no other sort is
611
+ # defined on the criteria has the potential to cause bad performance issues.
612
+ # If you experience unexpected poor performance when using #first or #last
613
+ # and have no sort defined on the criteria, use #take instead.
614
+ # Be aware that #take won't guarantee order.
615
+ #
616
+ # @param [ Integer ] limit The number of documents to return.
617
+ #
618
+ # @return [ Document | nil ] The last document or nil if none is found.
619
+ def last(limit = nil)
620
+ if limit.nil?
621
+ retrieve_nth_to_last(0)
532
622
  else
533
- unless ret = instance_variable_get("@#{key}")
534
- instance_variable_set("@#{key}", ret = yield)
535
- end
536
- ret
623
+ retrieve_nth_to_last_with_limit(0, limit)
537
624
  end
538
625
  end
539
626
 
627
+ # Get the last document in the database for the criteria's selector or
628
+ # raise an error if none is found.
629
+ #
630
+ # @example Get the last document.
631
+ # context.last!
632
+ #
633
+ # @note Automatically adding a sort on _id when no other sort is
634
+ # defined on the criteria has the potential to cause bad performance issues.
635
+ # If you experience unexpected poor performance when using #first! or #last!
636
+ # and have no sort defined on the criteria, use #take! instead.
637
+ # Be aware that #take! won't guarantee order.
638
+ #
639
+ # @return [ Document ] The last document.
640
+ #
641
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
642
+ # documents available.
643
+ def last!
644
+ last || raise_document_not_found_error
645
+ end
646
+
647
+ # Get the second document in the database for the criteria's selector.
648
+ #
649
+ # @example Get the second document.
650
+ # context.second
651
+ #
652
+ # @return [ Document | nil ] The second document or nil if none is found.
653
+ def second
654
+ retrieve_nth(1)
655
+ end
656
+
657
+ # Get the second document in the database for the criteria's selector or
658
+ # raise an error if none is found.
659
+ #
660
+ # @example Get the second document.
661
+ # context.second!
662
+ #
663
+ # @return [ Document ] The second document.
664
+ #
665
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
666
+ # documents available.
667
+ def second!
668
+ second || raise_document_not_found_error
669
+ end
670
+
671
+ # Get the third document in the database for the criteria's selector.
672
+ #
673
+ # @example Get the third document.
674
+ # context.third
675
+ #
676
+ # @return [ Document | nil ] The third document or nil if none is found.
677
+ def third
678
+ retrieve_nth(2)
679
+ end
680
+
681
+ # Get the third document in the database for the criteria's selector or
682
+ # raise an error if none is found.
683
+ #
684
+ # @example Get the third document.
685
+ # context.third!
686
+ #
687
+ # @return [ Document ] The third document.
688
+ #
689
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
690
+ # documents available.
691
+ def third!
692
+ third || raise_document_not_found_error
693
+ end
694
+
695
+ # Get the fourth document in the database for the criteria's selector.
696
+ #
697
+ # @example Get the fourth document.
698
+ # context.fourth
699
+ #
700
+ # @return [ Document | nil ] The fourth document or nil if none is found.
701
+ def fourth
702
+ retrieve_nth(3)
703
+ end
704
+
705
+ # Get the fourth document in the database for the criteria's selector or
706
+ # raise an error if none is found.
707
+ #
708
+ # @example Get the fourth document.
709
+ # context.fourth!
710
+ #
711
+ # @return [ Document ] The fourth document.
712
+ #
713
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
714
+ # documents available.
715
+ def fourth!
716
+ fourth || raise_document_not_found_error
717
+ end
718
+
719
+ # Get the fifth document in the database for the criteria's selector.
720
+ #
721
+ # @example Get the fifth document.
722
+ # context.fifth
723
+ #
724
+ # @return [ Document | nil ] The fifth document or nil if none is found.
725
+ def fifth
726
+ retrieve_nth(4)
727
+ end
728
+
729
+ # Get the fifth document in the database for the criteria's selector or
730
+ # raise an error if none is found.
731
+ #
732
+ # @example Get the fifth document.
733
+ # context.fifth!
734
+ #
735
+ # @return [ Document ] The fifth document.
736
+ #
737
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
738
+ # documents available.
739
+ def fifth!
740
+ fifth || raise_document_not_found_error
741
+ end
742
+
743
+ # Get the second to last document in the database for the criteria's
744
+ # selector.
745
+ #
746
+ # @example Get the second to last document.
747
+ # context.second_to_last
748
+ #
749
+ # @return [ Document | nil ] The second to last document or nil if none
750
+ # is found.
751
+ def second_to_last
752
+ retrieve_nth_to_last(1)
753
+ end
754
+
755
+ # Get the second to last document in the database for the criteria's
756
+ # selector or raise an error if none is found.
757
+ #
758
+ # @example Get the second to last document.
759
+ # context.second_to_last!
760
+ #
761
+ # @return [ Document ] The second to last document.
762
+ #
763
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
764
+ # documents available.
765
+ def second_to_last!
766
+ second_to_last || raise_document_not_found_error
767
+ end
768
+
769
+ # Get the third to last document in the database for the criteria's
770
+ # selector.
771
+ #
772
+ # @example Get the third to last document.
773
+ # context.third_to_last
774
+ #
775
+ # @return [ Document | nil ] The third to last document or nil if none
776
+ # is found.
777
+ def third_to_last
778
+ retrieve_nth_to_last(2)
779
+ end
780
+
781
+ # Get the third to last document in the database for the criteria's
782
+ # selector or raise an error if none is found.
783
+ #
784
+ # @example Get the third to last document.
785
+ # context.third_to_last!
786
+ #
787
+ # @return [ Document ] The third to last document.
788
+ #
789
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
790
+ # documents available.
791
+ def third_to_last!
792
+ third_to_last || raise_document_not_found_error
793
+ end
794
+
795
+ # Schedule a task to load documents for the context.
796
+ #
797
+ # Depending on the Mongoid configuration, the scheduled task can be executed
798
+ # immediately on the caller's thread, or can be scheduled for an
799
+ # asynchronous execution.
800
+ #
801
+ # @api private
802
+ def load_async
803
+ @documents_loader ||= DocumentsLoader.new(view, klass, criteria)
804
+ end
805
+
806
+ private
807
+
540
808
  # Update the documents for the provided method.
541
809
  #
542
810
  # @api private
@@ -547,9 +815,7 @@ module Mongoid
547
815
  # @param [ Hash ] attributes The updates.
548
816
  # @param [ Symbol ] method The method to use.
549
817
  #
550
- # @return [ true, false ] If the update succeeded.
551
- #
552
- # @since 3.0.4
818
+ # @return [ true | false ] If the update succeeded.
553
819
  def update_documents(attributes, method = :update_one, opts = {})
554
820
  return false unless attributes
555
821
  attributes = Hash[attributes.map { |k, v| [klass.database_field_name(k.to_s), v] }]
@@ -562,8 +828,6 @@ module Mongoid
562
828
  #
563
829
  # @example Apply the field limitations.
564
830
  # context.apply_fields
565
- #
566
- # @since 3.0.0
567
831
  def apply_fields
568
832
  if spec = criteria.options[:fields]
569
833
  @view = view.projection(spec)
@@ -576,8 +840,6 @@ module Mongoid
576
840
  #
577
841
  # @example Apply all options.
578
842
  # context.apply_options
579
- #
580
- # @since 3.1.0
581
843
  def apply_options
582
844
  apply_fields
583
845
  OPTIONS.each do |name|
@@ -594,8 +856,6 @@ module Mongoid
594
856
  #
595
857
  # @example Apply the skip option.
596
858
  # context.apply_option(:skip)
597
- #
598
- # @since 3.1.0
599
859
  def apply_option(name)
600
860
  if spec = criteria.options[name]
601
861
  @view = view.send(name, spec)
@@ -605,115 +865,213 @@ module Mongoid
605
865
  # Map the inverse sort symbols to the correct MongoDB values.
606
866
  #
607
867
  # @api private
868
+ def inverse_sorting
869
+ sort = view.sort || { _id: 1 }
870
+ Hash[sort.map{|k, v| [k, -1*v]}]
871
+ end
872
+
873
+ # Get the documents the context should iterate.
874
+ #
875
+ # If the documents have been already preloaded by `Document::Loader`
876
+ # instance, they will be used.
608
877
  #
609
- # @example Apply the inverse sorting params to the given block
610
- # context.with_inverse_sorting
878
+ # @return [ Array<Document> | Mongo::Collection::View ] The docs to iterate.
611
879
  #
612
- # @since 3.0.0
613
- def with_inverse_sorting(opts = {})
614
- begin
615
- if sort = criteria.options[:sort] || ( { _id: 1 } unless opts[:id_sort] == :none )
616
- @view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
880
+ # @api private
881
+ def documents_for_iteration
882
+ if @documents_loader
883
+ if @documents_loader.started?
884
+ @documents_loader.value!
885
+ else
886
+ @documents_loader.unschedule
887
+ @documents_loader.execute
617
888
  end
618
- yield
619
- ensure
620
- apply_option(:sort)
889
+ else
890
+ return view unless eager_loadable?
891
+ docs = view.map do |doc|
892
+ Factory.from_db(klass, doc, criteria)
893
+ end
894
+ eager_load(docs)
621
895
  end
622
896
  end
623
897
 
624
- # Is the cache able to be added to?
898
+ # Yield to the document.
625
899
  #
626
900
  # @api private
627
901
  #
628
- # @example Is the context cacheable?
629
- # context.cacheable?
630
- #
631
- # @return [ true, false ] If caching, and the cache isn't loaded.
902
+ # @example Yield the document.
903
+ # context.yield_document(doc) do |doc|
904
+ # ...
905
+ # end
632
906
  #
633
- # @since 3.0.0
634
- def cacheable?
635
- cached? && !cache_loaded?
907
+ # @param [ Document ] document The document to yield to.
908
+ def yield_document(document, &block)
909
+ doc = document.respond_to?(:_id) ?
910
+ document : Factory.from_db(klass, document, criteria)
911
+ yield(doc)
636
912
  end
637
913
 
638
- # Is the cache fully loaded? Will be true if caching after one full
639
- # iteration.
640
- #
641
- # @api private
642
- #
643
- # @example Is the cache loaded?
644
- # context.cache_loaded?
645
- #
646
- # @return [ true, false ] If the cache is loaded.
647
- #
648
- # @since 3.0.0
649
- def cache_loaded?
650
- !!@cache_loaded
914
+ def _session
915
+ @criteria.send(:_session)
651
916
  end
652
917
 
653
- # Get the documents for cached queries.
654
- #
655
- # @api private
656
- #
657
- # @example Get the cached documents.
658
- # context.documents
659
- #
660
- # @return [ Array<Document> ] The documents.
661
- #
662
- # @since 3.0.0
663
- def documents
664
- @documents ||= []
918
+ def acknowledged_write?
919
+ collection.write_concern.nil? || collection.write_concern.acknowledged?
665
920
  end
666
921
 
667
- # Get the documents the context should iterate. This follows 3 rules:
922
+ # Fetch the element from the given hash and demongoize it using the
923
+ # given field. If the obj is an array, map over it and call this method
924
+ # on all of its elements.
668
925
  #
669
- # 1. If the query is cached, and we already have documents loaded, use
670
- # them.
671
- # 2. If we are eager loading, then eager load the documents and use
672
- # those.
673
- # 3. Use the query.
926
+ # @param [ Hash | Array<Hash> ] obj The hash or array of hashes to fetch from.
927
+ # @param [ String ] meth The key to fetch from the hash.
928
+ # @param [ Field ] field The field to use for demongoization.
674
929
  #
675
- # @api private
930
+ # @return [ Object ] The demongoized value.
676
931
  #
677
- # @example Get the documents for iteration.
678
- # context.documents_for_iteration
932
+ # @api private
933
+ def fetch_and_demongoize(obj, meth, field)
934
+ if obj.is_a?(Array)
935
+ obj.map { |doc| fetch_and_demongoize(doc, meth, field) }
936
+ else
937
+ res = obj.try(:fetch, meth, nil)
938
+ field ? field.demongoize(res) : res.class.demongoize(res)
939
+ end
940
+ end
941
+
942
+ # Extracts the value for the given field name from the given attribute
943
+ # hash.
679
944
  #
680
- # @return [ Array<Document>, Mongo::Collection::View ] The docs to iterate.
945
+ # @param [ Hash ] attrs The attributes hash.
946
+ # @param [ String ] field_name The name of the field to extract.
681
947
  #
682
- # @since 3.0.0
683
- def documents_for_iteration
684
- return documents if cached? && !documents.empty?
685
- return view unless eager_loadable?
686
- docs = view.map{ |doc| Factory.from_db(klass, doc, criteria) }
687
- eager_load(docs)
948
+ # @param [ Object ] The value for the given field name
949
+ def extract_value(attrs, field_name)
950
+ i = 1
951
+ num_meths = field_name.count('.') + 1
952
+ curr = attrs.dup
953
+
954
+ klass.traverse_association_tree(field_name) do |meth, obj, is_field|
955
+ field = obj if is_field
956
+ is_translation = false
957
+ # If no association or field was found, check if the meth is an
958
+ # _translations field.
959
+ if obj.nil? & tr = meth.match(/(.*)_translations\z/)&.captures&.first
960
+ is_translation = true
961
+ meth = tr
962
+ end
963
+
964
+ # 1. If curr is an array fetch from all elements in the array.
965
+ # 2. If the field is localized, and is not an _translations field
966
+ # (_translations fields don't show up in the fields hash).
967
+ # - If this is the end of the methods, return the translation for
968
+ # the current locale.
969
+ # - Otherwise, return the whole translations hash so the next method
970
+ # can select the language it wants.
971
+ # 3. If the meth is an _translations field, do not demongoize the
972
+ # value so the full hash is returned.
973
+ # 4. Otherwise, fetch and demongoize the value for the key meth.
974
+ curr = if curr.is_a? Array
975
+ res = fetch_and_demongoize(curr, meth, field)
976
+ res.empty? ? nil : res
977
+ elsif !is_translation && field&.localized?
978
+ if i < num_meths
979
+ curr.try(:fetch, meth, nil)
980
+ else
981
+ fetch_and_demongoize(curr, meth, field)
982
+ end
983
+ elsif is_translation
984
+ curr.try(:fetch, meth, nil)
985
+ else
986
+ fetch_and_demongoize(curr, meth, field)
987
+ end
988
+
989
+ i += 1
990
+ end
991
+ curr
688
992
  end
689
993
 
690
- # Yield to the document.
994
+ # Recursively demongoize the given value. This method recursively traverses
995
+ # the class tree to find the correct field to use to demongoize the value.
996
+ #
997
+ # @param [ String ] field_name The name of the field to demongoize.
998
+ # @param [ Object ] value The value to demongoize.
999
+ # @param [ true | false ] is_translation The field we are retrieving is an
1000
+ # _translations field.
1001
+ #
1002
+ # @return [ Object ] The demongoized value.
1003
+ def recursive_demongoize(field_name, value, is_translation)
1004
+ field = klass.traverse_association_tree(field_name)
1005
+ demongoize_with_field(field, value, is_translation)
1006
+ end
1007
+
1008
+ # Demongoize the value for the given field. If the field is nil or the
1009
+ # field is a translations field, the value is demongoized using its class.
691
1010
  #
692
- # @api private
1011
+ # @param [ Field ] field The field to use to demongoize.
1012
+ # @param [ Object ] value The value to demongoize.
1013
+ # @param [ true | false ] is_translation The field we are retrieving is an
1014
+ # _translations field.
693
1015
  #
694
- # @example Yield the document.
695
- # context.yield_document(doc) do |doc|
696
- # ...
697
- # end
1016
+ # @return [ Object ] The demongoized value.
698
1017
  #
699
- # @param [ Document ] document The document to yield to.
1018
+ # @api private
1019
+ def demongoize_with_field(field, value, is_translation)
1020
+ if field
1021
+ # If it's a localized field that's not a hash, don't demongoize
1022
+ # again, we already have the translation. If it's an _translations
1023
+ # field, don't demongoize, we want the full hash not just a
1024
+ # specific translation.
1025
+ # If it is a hash, and it's not a translations field, we need to
1026
+ # demongoize to get the correct translation.
1027
+ if field.localized? && (!value.is_a?(Hash) || is_translation)
1028
+ value.class.demongoize(value)
1029
+ else
1030
+ field.demongoize(value)
1031
+ end
1032
+ else
1033
+ value.class.demongoize(value)
1034
+ end
1035
+ end
1036
+
1037
+ # Process the raw documents retrieved for #first/#last.
700
1038
  #
701
- # @since 3.0.0
702
- def yield_document(document, &block)
703
- doc = document.respond_to?(:_id) ?
704
- document : Factory.from_db(klass, document, criteria)
705
- yield(doc)
706
- documents.push(doc) if cacheable?
1039
+ # @return [ Array<Document> | Document ] The list of documents or a
1040
+ # single document.
1041
+ def process_raw_docs(raw_docs, limit)
1042
+ docs = raw_docs.map do |d|
1043
+ Factory.from_db(klass, d, criteria)
1044
+ end
1045
+ docs = eager_load(docs)
1046
+ limit ? docs : docs.first
707
1047
  end
708
1048
 
709
- private
1049
+ def raise_document_not_found_error
1050
+ raise Errors::DocumentNotFound.new(klass, nil, nil)
1051
+ end
710
1052
 
711
- def _session
712
- @criteria.send(:_session)
1053
+ def retrieve_nth(n)
1054
+ retrieve_nth_with_limit(n, 1).first
713
1055
  end
714
1056
 
715
- def acknowledged_write?
716
- collection.write_concern.nil? || collection.write_concern.acknowledged?
1057
+ def retrieve_nth_with_limit(n, limit)
1058
+ sort = view.sort || { _id: 1 }
1059
+ v = view.sort(sort).limit(limit || 1)
1060
+ v = v.skip(n) if n > 0
1061
+ if raw_docs = v.to_a
1062
+ process_raw_docs(raw_docs, limit)
1063
+ end
1064
+ end
1065
+
1066
+ def retrieve_nth_to_last(n)
1067
+ retrieve_nth_to_last_with_limit(n, 1).first
1068
+ end
1069
+
1070
+ def retrieve_nth_to_last_with_limit(n, limit)
1071
+ v = view.sort(inverse_sorting).skip(n).limit(limit || 1)
1072
+ v = v.skip(n) if n > 0
1073
+ raw_docs = v.to_a.reverse
1074
+ process_raw_docs(raw_docs, limit)
717
1075
  end
718
1076
  end
719
1077
  end