mongoid 7.0.5 → 8.1.5

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