mongoid 7.0.13 → 8.0.8

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 (1089) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +30 -30
  4. data/README.md +32 -19
  5. data/Rakefile +43 -0
  6. data/lib/config/locales/en.yml +178 -95
  7. data/lib/mongoid/association/accessors.rb +175 -83
  8. data/lib/mongoid/association/bindable.rb +57 -28
  9. data/lib/mongoid/association/builders.rb +8 -14
  10. data/lib/mongoid/association/constrainable.rb +5 -7
  11. data/lib/mongoid/association/depending.rb +9 -18
  12. data/lib/mongoid/association/eager_loadable.rb +31 -10
  13. data/lib/mongoid/association/embedded/batchable.rb +67 -53
  14. data/lib/mongoid/association/embedded/cyclic.rb +10 -17
  15. data/lib/mongoid/association/embedded/embedded_in/binding.rb +27 -9
  16. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +7 -4
  17. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +14 -24
  18. data/lib/mongoid/association/embedded/embedded_in.rb +9 -28
  19. data/lib/mongoid/association/embedded/embeds_many/binding.rb +5 -8
  20. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +8 -5
  21. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +143 -122
  22. data/lib/mongoid/association/embedded/embeds_many.rb +8 -36
  23. data/lib/mongoid/association/embedded/embeds_one/binding.rb +4 -8
  24. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +26 -9
  25. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +63 -29
  26. data/lib/mongoid/association/embedded/embeds_one.rb +9 -33
  27. data/lib/mongoid/association/embedded.rb +2 -0
  28. data/lib/mongoid/association/macros.rb +71 -41
  29. data/lib/mongoid/association/many.rb +25 -35
  30. data/lib/mongoid/association/marshalable.rb +3 -6
  31. data/lib/mongoid/association/nested/many.rb +22 -30
  32. data/lib/mongoid/association/nested/nested_buildable.rb +9 -15
  33. data/lib/mongoid/association/nested/one.rb +19 -30
  34. data/lib/mongoid/association/nested.rb +3 -3
  35. data/lib/mongoid/association/one.rb +5 -12
  36. data/lib/mongoid/association/options.rb +16 -46
  37. data/lib/mongoid/association/proxy.rb +37 -38
  38. data/lib/mongoid/association/referenced/auto_save.rb +9 -14
  39. data/lib/mongoid/association/referenced/belongs_to/binding.rb +5 -9
  40. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +11 -9
  41. data/lib/mongoid/association/referenced/belongs_to/eager.rb +40 -3
  42. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +19 -31
  43. data/lib/mongoid/association/referenced/belongs_to.rb +16 -38
  44. data/lib/mongoid/association/referenced/counter_cache.rb +14 -25
  45. data/lib/mongoid/association/referenced/eager.rb +41 -40
  46. data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +12 -11
  47. data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +5 -5
  48. data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +2 -1
  49. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +105 -68
  50. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +29 -46
  51. data/lib/mongoid/association/referenced/has_many/binding.rb +3 -6
  52. data/lib/mongoid/association/referenced/has_many/buildable.rb +5 -5
  53. data/lib/mongoid/association/referenced/has_many/eager.rb +2 -1
  54. data/lib/mongoid/association/referenced/has_many/enumerable.rb +440 -456
  55. data/lib/mongoid/association/referenced/has_many/proxy.rb +101 -124
  56. data/lib/mongoid/association/referenced/has_many.rb +21 -45
  57. data/lib/mongoid/association/referenced/has_one/binding.rb +4 -9
  58. data/lib/mongoid/association/referenced/has_one/buildable.rb +20 -6
  59. data/lib/mongoid/association/referenced/has_one/eager.rb +2 -1
  60. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +16 -29
  61. data/lib/mongoid/association/referenced/has_one/proxy.rb +25 -30
  62. data/lib/mongoid/association/referenced/has_one.rb +16 -36
  63. data/lib/mongoid/association/referenced/syncable.rb +11 -26
  64. data/lib/mongoid/association/referenced.rb +2 -0
  65. data/lib/mongoid/association/reflections.rb +7 -6
  66. data/lib/mongoid/association/relatable.rb +62 -84
  67. data/lib/mongoid/association.rb +13 -27
  68. data/lib/mongoid/atomic/modifiers.rb +29 -53
  69. data/lib/mongoid/atomic/paths/embedded/many.rb +23 -7
  70. data/lib/mongoid/atomic/paths/embedded/one.rb +4 -7
  71. data/lib/mongoid/atomic/paths/embedded.rb +2 -3
  72. data/lib/mongoid/atomic/paths/root.rb +4 -7
  73. data/lib/mongoid/atomic/paths.rb +2 -1
  74. data/lib/mongoid/atomic.rb +45 -51
  75. data/lib/mongoid/attributes/dynamic.rb +6 -21
  76. data/lib/mongoid/attributes/nested.rb +11 -14
  77. data/lib/mongoid/attributes/processing.rb +46 -30
  78. data/lib/mongoid/attributes/projector.rb +119 -0
  79. data/lib/mongoid/attributes/readonly.rb +5 -8
  80. data/lib/mongoid/attributes.rb +80 -98
  81. data/lib/mongoid/cacheable.rb +7 -10
  82. data/lib/mongoid/changeable.rb +49 -70
  83. data/lib/mongoid/clients/factory.rb +42 -17
  84. data/lib/mongoid/clients/options.rb +15 -14
  85. data/lib/mongoid/clients/sessions.rb +4 -20
  86. data/lib/mongoid/clients/storage_options.rb +7 -12
  87. data/lib/mongoid/clients/validators/storage.rb +5 -12
  88. data/lib/mongoid/clients/validators.rb +2 -1
  89. data/lib/mongoid/clients.rb +3 -10
  90. data/lib/mongoid/composable.rb +5 -9
  91. data/lib/mongoid/config/environment.rb +30 -5
  92. data/lib/mongoid/config/options.rb +23 -23
  93. data/lib/mongoid/config/validators/client.rb +8 -23
  94. data/lib/mongoid/config/validators/option.rb +2 -3
  95. data/lib/mongoid/config/validators.rb +2 -1
  96. data/lib/mongoid/config.rb +164 -48
  97. data/lib/mongoid/contextual/aggregable/memory.rb +40 -27
  98. data/lib/mongoid/contextual/aggregable/mongo.rb +32 -33
  99. data/lib/mongoid/contextual/aggregable/none.rb +65 -0
  100. data/lib/mongoid/contextual/aggregable.rb +17 -0
  101. data/lib/mongoid/contextual/atomic.rb +29 -31
  102. data/lib/mongoid/contextual/command.rb +2 -5
  103. data/lib/mongoid/contextual/geo_near.rb +13 -44
  104. data/lib/mongoid/contextual/map_reduce.rb +7 -35
  105. data/lib/mongoid/contextual/memory.rb +187 -81
  106. data/lib/mongoid/contextual/mongo.rb +360 -239
  107. data/lib/mongoid/contextual/none.rb +109 -31
  108. data/lib/mongoid/contextual/queryable.rb +3 -4
  109. data/lib/mongoid/contextual.rb +9 -11
  110. data/lib/mongoid/copyable.rb +42 -17
  111. data/lib/mongoid/criteria/findable.rb +19 -19
  112. data/lib/mongoid/criteria/includable.rb +30 -33
  113. data/lib/mongoid/criteria/inspectable.rb +2 -3
  114. data/lib/mongoid/criteria/marshalable.rb +12 -7
  115. data/lib/mongoid/criteria/modifiable.rb +2 -19
  116. data/lib/mongoid/criteria/options.rb +2 -3
  117. data/lib/mongoid/criteria/permission.rb +3 -2
  118. data/lib/mongoid/criteria/queryable/aggregable.rb +4 -15
  119. data/lib/mongoid/criteria/queryable/expandable.rb +68 -0
  120. data/lib/mongoid/criteria/queryable/extensions/array.rb +7 -41
  121. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +28 -8
  122. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +5 -6
  123. data/lib/mongoid/criteria/queryable/extensions/date.rb +9 -9
  124. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +11 -12
  125. data/lib/mongoid/criteria/queryable/extensions/hash.rb +4 -41
  126. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +3 -14
  127. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +4 -21
  128. data/lib/mongoid/criteria/queryable/extensions/object.rb +6 -30
  129. data/lib/mongoid/criteria/queryable/extensions/range.rb +49 -17
  130. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +9 -16
  131. data/lib/mongoid/criteria/queryable/extensions/set.rb +4 -5
  132. data/lib/mongoid/criteria/queryable/extensions/string.rb +7 -32
  133. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +7 -22
  134. data/lib/mongoid/criteria/queryable/extensions/time.rb +9 -9
  135. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +9 -9
  136. data/lib/mongoid/criteria/queryable/extensions.rb +1 -4
  137. data/lib/mongoid/criteria/queryable/key.rb +39 -24
  138. data/lib/mongoid/criteria/queryable/macroable.rb +3 -4
  139. data/lib/mongoid/criteria/queryable/mergeable.rb +200 -40
  140. data/lib/mongoid/criteria/queryable/optional.rb +10 -59
  141. data/lib/mongoid/criteria/queryable/options.rb +4 -21
  142. data/lib/mongoid/criteria/queryable/pipeline.rb +5 -15
  143. data/lib/mongoid/criteria/queryable/selectable.rb +417 -171
  144. data/lib/mongoid/criteria/queryable/selector.rb +127 -30
  145. data/lib/mongoid/criteria/queryable/smash.rb +42 -18
  146. data/lib/mongoid/criteria/queryable/storable.rb +237 -0
  147. data/lib/mongoid/criteria/queryable.rb +18 -15
  148. data/lib/mongoid/criteria/scopable.rb +29 -21
  149. data/lib/mongoid/criteria/translator.rb +45 -0
  150. data/lib/mongoid/criteria.rb +95 -107
  151. data/lib/mongoid/deprecable.rb +37 -0
  152. data/lib/mongoid/deprecation.rb +25 -0
  153. data/lib/mongoid/document.rb +148 -97
  154. data/lib/mongoid/equality.rb +35 -18
  155. data/lib/mongoid/errors/ambiguous_relationship.rb +4 -5
  156. data/lib/mongoid/errors/callback.rb +2 -3
  157. data/lib/mongoid/errors/criteria_argument_required.rb +18 -0
  158. data/lib/mongoid/errors/delete_restriction.rb +10 -13
  159. data/lib/mongoid/errors/document_not_destroyed.rb +4 -7
  160. data/lib/mongoid/errors/document_not_found.rb +35 -21
  161. data/lib/mongoid/errors/empty_config_file.rb +25 -0
  162. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +2 -3
  163. data/lib/mongoid/errors/invalid_collection.rb +2 -1
  164. data/lib/mongoid/errors/invalid_config_file.rb +25 -0
  165. data/lib/mongoid/errors/invalid_config_option.rb +3 -4
  166. data/lib/mongoid/errors/invalid_dependent_strategy.rb +3 -4
  167. data/lib/mongoid/errors/invalid_discriminator_key_target.rb +24 -0
  168. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  169. data/lib/mongoid/errors/invalid_elem_match_operator.rb +32 -0
  170. data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +25 -0
  171. data/lib/mongoid/errors/invalid_expression_operator.rb +27 -0
  172. data/lib/mongoid/errors/invalid_field.rb +8 -7
  173. data/lib/mongoid/errors/invalid_field_operator.rb +32 -0
  174. data/lib/mongoid/errors/invalid_field_option.rb +2 -3
  175. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  176. data/lib/mongoid/errors/invalid_find.rb +2 -3
  177. data/lib/mongoid/errors/invalid_includes.rb +2 -3
  178. data/lib/mongoid/errors/invalid_index.rb +2 -3
  179. data/lib/mongoid/errors/invalid_options.rb +4 -5
  180. data/lib/mongoid/errors/invalid_path.rb +2 -3
  181. data/lib/mongoid/errors/invalid_persistence_option.rb +2 -5
  182. data/lib/mongoid/errors/invalid_query.rb +40 -0
  183. data/lib/mongoid/errors/invalid_relation.rb +5 -10
  184. data/lib/mongoid/errors/invalid_relation_option.rb +4 -5
  185. data/lib/mongoid/errors/invalid_scope.rb +2 -3
  186. data/lib/mongoid/errors/invalid_session_use.rb +3 -6
  187. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +6 -5
  188. data/lib/mongoid/errors/invalid_storage_options.rb +3 -4
  189. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -3
  190. data/lib/mongoid/errors/invalid_time.rb +2 -3
  191. data/lib/mongoid/errors/inverse_not_found.rb +3 -4
  192. data/lib/mongoid/errors/mixed_client_configuration.rb +2 -3
  193. data/lib/mongoid/errors/mixed_relations.rb +2 -3
  194. data/lib/mongoid/errors/mongoid_error.rb +6 -13
  195. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +3 -4
  196. data/lib/mongoid/errors/no_client_config.rb +4 -5
  197. data/lib/mongoid/errors/no_client_database.rb +3 -4
  198. data/lib/mongoid/errors/no_client_hosts.rb +3 -4
  199. data/lib/mongoid/errors/no_clients_config.rb +2 -3
  200. data/lib/mongoid/errors/no_default_client.rb +3 -4
  201. data/lib/mongoid/errors/no_environment.rb +2 -3
  202. data/lib/mongoid/errors/no_map_reduce_output.rb +2 -3
  203. data/lib/mongoid/errors/no_metadata.rb +2 -3
  204. data/lib/mongoid/errors/no_parent.rb +2 -3
  205. data/lib/mongoid/errors/readonly_attribute.rb +3 -4
  206. data/lib/mongoid/errors/readonly_document.rb +3 -6
  207. data/lib/mongoid/errors/scope_overwrite.rb +2 -1
  208. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +3 -1
  209. data/lib/mongoid/errors/unknown_attribute.rb +3 -4
  210. data/lib/mongoid/errors/unknown_model.rb +2 -3
  211. data/lib/mongoid/errors/unsaved_document.rb +3 -2
  212. data/lib/mongoid/errors/unsupported_javascript.rb +2 -3
  213. data/lib/mongoid/errors/validations.rb +2 -1
  214. data/lib/mongoid/errors.rb +14 -3
  215. data/lib/mongoid/evolvable.rb +4 -5
  216. data/lib/mongoid/extensions/array.rb +37 -44
  217. data/lib/mongoid/extensions/big_decimal.rb +35 -21
  218. data/lib/mongoid/extensions/binary.rb +42 -0
  219. data/lib/mongoid/extensions/boolean.rb +10 -6
  220. data/lib/mongoid/extensions/date.rb +32 -25
  221. data/lib/mongoid/extensions/date_time.rb +5 -13
  222. data/lib/mongoid/extensions/decimal128.rb +2 -5
  223. data/lib/mongoid/extensions/false_class.rb +5 -8
  224. data/lib/mongoid/extensions/float.rb +12 -14
  225. data/lib/mongoid/extensions/hash.rb +87 -45
  226. data/lib/mongoid/extensions/integer.rb +12 -16
  227. data/lib/mongoid/extensions/module.rb +3 -4
  228. data/lib/mongoid/extensions/nil_class.rb +2 -5
  229. data/lib/mongoid/extensions/object.rb +25 -50
  230. data/lib/mongoid/extensions/object_id.rb +2 -7
  231. data/lib/mongoid/extensions/range.rb +42 -20
  232. data/lib/mongoid/extensions/regexp.rb +13 -7
  233. data/lib/mongoid/extensions/set.rb +13 -11
  234. data/lib/mongoid/extensions/string.rb +30 -61
  235. data/lib/mongoid/extensions/symbol.rb +6 -22
  236. data/lib/mongoid/extensions/time.rb +37 -23
  237. data/lib/mongoid/extensions/time_with_zone.rb +26 -9
  238. data/lib/mongoid/extensions/true_class.rb +5 -8
  239. data/lib/mongoid/extensions.rb +19 -3
  240. data/lib/mongoid/factory.rb +104 -17
  241. data/lib/mongoid/fields/foreign_key.rb +14 -26
  242. data/lib/mongoid/fields/localized.rb +11 -15
  243. data/lib/mongoid/fields/standard.rb +13 -43
  244. data/lib/mongoid/fields/validators/macro.rb +32 -20
  245. data/lib/mongoid/fields/validators.rb +2 -1
  246. data/lib/mongoid/fields.rb +328 -85
  247. data/lib/mongoid/findable.rb +90 -33
  248. data/lib/mongoid/indexable/specification.rb +5 -18
  249. data/lib/mongoid/indexable/validators/options.rb +8 -9
  250. data/lib/mongoid/indexable.rb +6 -21
  251. data/lib/mongoid/inspectable.rb +4 -11
  252. data/lib/mongoid/interceptable.rb +191 -41
  253. data/lib/mongoid/loggable.rb +13 -16
  254. data/lib/mongoid/matchable.rb +3 -154
  255. data/lib/mongoid/matcher/all.rb +22 -0
  256. data/lib/mongoid/matcher/and.rb +21 -0
  257. data/lib/mongoid/matcher/bits.rb +41 -0
  258. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  259. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  260. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  261. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  262. data/lib/mongoid/matcher/elem_match.rb +36 -0
  263. data/lib/mongoid/matcher/elem_match_expression.rb +20 -0
  264. data/lib/mongoid/matcher/eq.rb +11 -0
  265. data/lib/mongoid/matcher/eq_impl.rb +67 -0
  266. data/lib/mongoid/matcher/eq_impl_with_regexp.rb +26 -0
  267. data/lib/mongoid/matcher/exists.rb +15 -0
  268. data/lib/mongoid/matcher/expression.rb +35 -0
  269. data/lib/mongoid/matcher/expression_operator.rb +19 -0
  270. data/lib/mongoid/matcher/field_expression.rb +62 -0
  271. data/lib/mongoid/matcher/field_operator.rb +54 -0
  272. data/lib/mongoid/matcher/gt.rb +17 -0
  273. data/lib/mongoid/matcher/gte.rb +17 -0
  274. data/lib/mongoid/matcher/in.rb +25 -0
  275. data/lib/mongoid/matcher/lt.rb +17 -0
  276. data/lib/mongoid/matcher/lte.rb +17 -0
  277. data/lib/mongoid/matcher/mod.rb +17 -0
  278. data/lib/mongoid/matcher/ne.rb +16 -0
  279. data/lib/mongoid/matcher/nin.rb +11 -0
  280. data/lib/mongoid/matcher/nor.rb +25 -0
  281. data/lib/mongoid/matcher/not.rb +29 -0
  282. data/lib/mongoid/matcher/or.rb +21 -0
  283. data/lib/mongoid/matcher/regex.rb +41 -0
  284. data/lib/mongoid/matcher/size.rb +26 -0
  285. data/lib/mongoid/matcher/type.rb +99 -0
  286. data/lib/mongoid/matcher.rb +130 -0
  287. data/lib/mongoid/persistable/creatable.rb +22 -30
  288. data/lib/mongoid/persistable/deletable.rb +6 -22
  289. data/lib/mongoid/persistable/destroyable.rb +12 -11
  290. data/lib/mongoid/persistable/incrementable.rb +6 -7
  291. data/lib/mongoid/persistable/logical.rb +4 -6
  292. data/lib/mongoid/persistable/poppable.rb +3 -6
  293. data/lib/mongoid/persistable/pullable.rb +3 -8
  294. data/lib/mongoid/persistable/pushable.rb +3 -8
  295. data/lib/mongoid/persistable/renamable.rb +10 -8
  296. data/lib/mongoid/persistable/savable.rb +5 -10
  297. data/lib/mongoid/persistable/settable.rb +3 -6
  298. data/lib/mongoid/persistable/unsettable.rb +9 -9
  299. data/lib/mongoid/persistable/updatable.rb +50 -31
  300. data/lib/mongoid/persistable/upsertable.rb +5 -10
  301. data/lib/mongoid/persistable.rb +135 -40
  302. data/lib/mongoid/persistence_context.rb +85 -45
  303. data/lib/mongoid/positional.rb +2 -5
  304. data/lib/mongoid/query_cache.rb +13 -280
  305. data/lib/mongoid/railtie.rb +3 -16
  306. data/lib/mongoid/railties/controller_runtime.rb +4 -2
  307. data/lib/mongoid/railties/database.rake +9 -0
  308. data/lib/mongoid/reloadable.rb +19 -22
  309. data/lib/mongoid/scopable.rb +34 -57
  310. data/lib/mongoid/selectable.rb +8 -18
  311. data/lib/mongoid/serializable.rb +33 -34
  312. data/lib/mongoid/shardable.rb +108 -21
  313. data/lib/mongoid/stateful.rb +38 -19
  314. data/lib/mongoid/stringified_symbol.rb +52 -0
  315. data/lib/mongoid/tasks/database.rake +12 -5
  316. data/lib/mongoid/tasks/database.rb +85 -7
  317. data/lib/mongoid/threaded/lifecycle.rb +7 -26
  318. data/lib/mongoid/threaded.rb +44 -67
  319. data/lib/mongoid/timestamps/created/short.rb +2 -1
  320. data/lib/mongoid/timestamps/created.rb +4 -3
  321. data/lib/mongoid/timestamps/short.rb +2 -1
  322. data/lib/mongoid/timestamps/timeless.rb +6 -9
  323. data/lib/mongoid/timestamps/updated/short.rb +2 -1
  324. data/lib/mongoid/timestamps/updated.rb +5 -6
  325. data/lib/mongoid/timestamps.rb +3 -2
  326. data/lib/mongoid/touchable.rb +54 -25
  327. data/lib/mongoid/traversable.rb +185 -61
  328. data/lib/mongoid/validatable/associated.rb +99 -22
  329. data/lib/mongoid/validatable/format.rb +2 -1
  330. data/lib/mongoid/validatable/length.rb +2 -1
  331. data/lib/mongoid/validatable/localizable.rb +3 -4
  332. data/lib/mongoid/validatable/macros.rb +2 -9
  333. data/lib/mongoid/validatable/presence.rb +10 -15
  334. data/lib/mongoid/validatable/queryable.rb +2 -3
  335. data/lib/mongoid/validatable/uniqueness.rb +29 -41
  336. data/lib/mongoid/validatable.rb +22 -33
  337. data/lib/mongoid/version.rb +2 -2
  338. data/lib/mongoid/warnings.rb +28 -0
  339. data/lib/mongoid.rb +34 -15
  340. data/lib/rails/generators/mongoid/config/config_generator.rb +2 -1
  341. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +53 -32
  342. data/lib/rails/generators/mongoid/model/model_generator.rb +3 -2
  343. data/lib/rails/generators/mongoid_generator.rb +2 -1
  344. data/lib/rails/mongoid.rb +4 -5
  345. data/spec/README.md +19 -4
  346. data/spec/config/mongoid.yml +17 -0
  347. data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
  348. data/spec/integration/app_spec.rb +31 -27
  349. data/spec/integration/associations/belongs_to_spec.rb +20 -0
  350. data/spec/integration/associations/embedded_dirty_spec.rb +57 -0
  351. data/spec/integration/associations/embedded_spec.rb +162 -55
  352. data/spec/integration/associations/embeds_many_spec.rb +219 -0
  353. data/spec/integration/associations/embeds_one_spec.rb +41 -0
  354. data/spec/integration/associations/foreign_key_spec.rb +107 -0
  355. data/spec/integration/associations/foreign_key_spec_models.rb +64 -0
  356. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +61 -0
  357. data/spec/integration/associations/has_many_spec.rb +128 -0
  358. data/spec/integration/associations/has_one_spec.rb +272 -0
  359. data/spec/integration/associations/nested_attributes_assignment_spec.rb +115 -0
  360. data/spec/integration/associations/reverse_population_spec.rb +34 -0
  361. data/spec/integration/associations/reverse_population_spec_models.rb +36 -0
  362. data/spec/integration/associations/scope_option_spec.rb +101 -0
  363. data/spec/integration/atomic/modifiers_spec.rb +116 -0
  364. data/spec/integration/bson_regexp_raw_spec.rb +19 -0
  365. data/spec/integration/callbacks_models.rb +107 -1
  366. data/spec/integration/callbacks_spec.rb +262 -8
  367. data/spec/integration/contextual/empty_spec.rb +141 -0
  368. data/spec/integration/criteria/alias_query_spec.rb +161 -0
  369. data/spec/integration/criteria/date_field_spec.rb +1 -2
  370. data/spec/integration/criteria/default_scope_spec.rb +72 -0
  371. data/spec/integration/criteria/logical_spec.rb +124 -0
  372. data/spec/integration/criteria/range_spec.rb +359 -0
  373. data/spec/integration/criteria/time_with_zone_spec.rb +125 -15
  374. data/spec/integration/discriminator_key_spec.rb +392 -0
  375. data/spec/integration/discriminator_value_spec.rb +206 -0
  376. data/spec/integration/document_spec.rb +30 -1
  377. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  378. data/spec/integration/i18n_fallbacks_spec.rb +73 -0
  379. data/spec/integration/{matchable_spec.rb → matcher_examples_spec.rb} +130 -45
  380. data/spec/integration/matcher_operator_data/all.yml +140 -0
  381. data/spec/integration/matcher_operator_data/and.yml +93 -0
  382. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  383. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  384. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  385. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  386. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  387. data/spec/integration/matcher_operator_data/elem_match.yml +409 -0
  388. data/spec/integration/matcher_operator_data/elem_match_expr.yml +213 -0
  389. data/spec/integration/matcher_operator_data/eq.yml +191 -0
  390. data/spec/integration/matcher_operator_data/exists.yml +213 -0
  391. data/spec/integration/matcher_operator_data/generic_op.yml +17 -0
  392. data/spec/integration/matcher_operator_data/gt.yml +132 -0
  393. data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
  394. data/spec/integration/matcher_operator_data/gte.yml +132 -0
  395. data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
  396. data/spec/integration/matcher_operator_data/implicit.yml +331 -0
  397. data/spec/integration/matcher_operator_data/implicit_traversal.yml +112 -0
  398. data/spec/integration/matcher_operator_data/in.yml +210 -0
  399. data/spec/integration/matcher_operator_data/invalid_op.yml +59 -0
  400. data/spec/integration/matcher_operator_data/invalid_syntax.yml +39 -0
  401. data/spec/integration/matcher_operator_data/lt.yml +132 -0
  402. data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
  403. data/spec/integration/matcher_operator_data/lte.yml +132 -0
  404. data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
  405. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  406. data/spec/integration/matcher_operator_data/multiple.yml +29 -0
  407. data/spec/integration/matcher_operator_data/ne.yml +150 -0
  408. data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
  409. data/spec/integration/matcher_operator_data/nin.yml +114 -0
  410. data/spec/integration/matcher_operator_data/nor.yml +126 -0
  411. data/spec/integration/matcher_operator_data/not.yml +196 -0
  412. data/spec/integration/matcher_operator_data/or.yml +137 -0
  413. data/spec/integration/matcher_operator_data/regex.yml +174 -0
  414. data/spec/integration/matcher_operator_data/regex_options.yml +72 -0
  415. data/spec/integration/matcher_operator_data/size.yml +174 -0
  416. data/spec/integration/matcher_operator_data/type.yml +70 -0
  417. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  418. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  419. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  420. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  421. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  422. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  423. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  424. data/spec/integration/matcher_operator_data/type_decimal.yml +41 -0
  425. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  426. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  427. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  428. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  429. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  430. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  431. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  432. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  433. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  434. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  435. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  436. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  437. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  438. data/spec/integration/matcher_operator_spec.rb +122 -0
  439. data/spec/integration/matcher_spec.rb +283 -0
  440. data/spec/integration/persistence/range_field_spec.rb +350 -0
  441. data/spec/integration/server_query_spec.rb +141 -0
  442. data/spec/integration/shardable_spec.rb +148 -0
  443. data/spec/integration/stringified_symbol_field_spec.rb +203 -0
  444. data/spec/lite_spec_helper.rb +18 -6
  445. data/spec/mongoid/association/accessors_spec.rb +284 -77
  446. data/spec/mongoid/association/auto_save_spec.rb +74 -33
  447. data/spec/mongoid/association/builders_spec.rb +3 -1
  448. data/spec/mongoid/association/constrainable_spec.rb +2 -0
  449. data/spec/mongoid/association/counter_cache_spec.rb +35 -33
  450. data/spec/mongoid/association/depending_spec.rb +431 -338
  451. data/spec/mongoid/association/eager_spec.rb +8 -5
  452. data/spec/mongoid/association/embedded/cyclic_spec.rb +4 -2
  453. data/spec/mongoid/association/embedded/dirty_spec.rb +4 -2
  454. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +4 -1
  455. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +56 -0
  456. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +84 -22
  457. data/spec/mongoid/association/embedded/embedded_in_spec.rb +3 -1
  458. data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +2 -0
  459. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +114 -0
  460. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +687 -173
  461. data/spec/mongoid/association/embedded/embeds_many_models.rb +174 -1
  462. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +63 -0
  463. data/spec/mongoid/association/embedded/embeds_many_spec.rb +71 -1
  464. data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +2 -0
  465. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +27 -0
  466. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +23 -21
  467. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +2 -0
  468. data/spec/mongoid/association/embedded/embeds_one_models.rb +22 -0
  469. data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +28 -0
  470. data/spec/mongoid/association/embedded/embeds_one_spec.rb +31 -1
  471. data/spec/mongoid/association/macros_spec.rb +11 -9
  472. data/spec/mongoid/association/nested/many_spec.rb +2 -0
  473. data/spec/mongoid/association/nested/one_spec.rb +18 -12
  474. data/spec/mongoid/association/options_spec.rb +2 -0
  475. data/spec/mongoid/association/polymorphic_spec.rb +2 -0
  476. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +4 -1
  477. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +111 -16
  478. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +242 -12
  479. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +114 -58
  480. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  481. data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +57 -0
  482. data/spec/mongoid/association/referenced/belongs_to_spec.rb +26 -3
  483. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +3 -1
  484. data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +28 -1
  485. data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +46 -2
  486. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +25 -5
  487. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +418 -361
  488. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +68 -2
  489. data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +39 -0
  490. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +81 -4
  491. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +3 -1
  492. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +132 -0
  493. data/spec/mongoid/association/referenced/has_many/eager_spec.rb +40 -9
  494. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +314 -133
  495. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +848 -451
  496. data/spec/mongoid/association/referenced/has_many_models.rb +61 -1
  497. data/spec/mongoid/association/referenced/has_many_query_spec.rb +37 -0
  498. data/spec/mongoid/association/referenced/has_many_spec.rb +48 -0
  499. data/spec/mongoid/association/referenced/has_one/binding_spec.rb +2 -0
  500. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +55 -9
  501. data/spec/mongoid/association/referenced/has_one/eager_spec.rb +34 -4
  502. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +135 -27
  503. data/spec/mongoid/association/referenced/has_one_models.rb +65 -0
  504. data/spec/mongoid/association/referenced/has_one_query_spec.rb +37 -0
  505. data/spec/mongoid/association/referenced/has_one_spec.rb +24 -1
  506. data/spec/mongoid/association/reflections_spec.rb +2 -0
  507. data/spec/mongoid/association/syncable_spec.rb +47 -31
  508. data/spec/mongoid/association_spec.rb +2 -0
  509. data/spec/mongoid/atomic/modifiers_spec.rb +49 -0
  510. data/spec/mongoid/atomic/paths/embedded/many_spec.rb +2 -0
  511. data/spec/mongoid/atomic/paths/embedded/one_spec.rb +2 -0
  512. data/spec/mongoid/atomic/paths/root_spec.rb +2 -0
  513. data/spec/mongoid/atomic/paths_spec.rb +66 -26
  514. data/spec/mongoid/atomic_spec.rb +53 -6
  515. data/spec/mongoid/attributes/dynamic_spec.rb +0 -1
  516. data/spec/mongoid/attributes/nested_spec.rb +149 -78
  517. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  518. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  519. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  520. data/spec/mongoid/attributes/projector_spec.rb +40 -0
  521. data/spec/mongoid/attributes/readonly_spec.rb +24 -22
  522. data/spec/mongoid/attributes_spec.rb +683 -65
  523. data/spec/mongoid/cacheable_spec.rb +6 -4
  524. data/spec/mongoid/changeable_spec.rb +185 -43
  525. data/spec/mongoid/clients/factory_spec.rb +128 -28
  526. data/spec/mongoid/clients/options_spec.rb +45 -26
  527. data/spec/mongoid/clients/sessions_spec.rb +25 -66
  528. data/spec/mongoid/clients/transactions_spec.rb +54 -29
  529. data/spec/mongoid/clients_spec.rb +65 -8
  530. data/spec/mongoid/composable_spec.rb +2 -0
  531. data/spec/mongoid/config/environment_spec.rb +126 -8
  532. data/spec/mongoid/config/options_spec.rb +22 -3
  533. data/spec/mongoid/config_spec.rb +377 -1
  534. data/spec/mongoid/contextual/aggregable/memory_spec.rb +433 -153
  535. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  536. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  537. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +122 -20
  538. data/spec/mongoid/contextual/aggregable/none_spec.rb +60 -0
  539. data/spec/mongoid/contextual/atomic_spec.rb +205 -67
  540. data/spec/mongoid/contextual/geo_near_spec.rb +20 -18
  541. data/spec/mongoid/contextual/map_reduce_spec.rb +6 -18
  542. data/spec/mongoid/contextual/memory_spec.rb +1360 -91
  543. data/spec/mongoid/contextual/mongo_spec.rb +1871 -544
  544. data/spec/mongoid/contextual/none_spec.rb +39 -73
  545. data/spec/mongoid/copyable_spec.rb +657 -26
  546. data/spec/mongoid/copyable_spec_models.rb +30 -0
  547. data/spec/mongoid/criteria/findable_spec.rb +161 -228
  548. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  549. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  550. data/spec/mongoid/criteria/inspectable_spec.rb +2 -0
  551. data/spec/mongoid/criteria/marshalable_spec.rb +20 -1
  552. data/spec/mongoid/criteria/modifiable_spec.rb +43 -40
  553. data/spec/mongoid/criteria/options_spec.rb +2 -0
  554. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +3 -1
  555. data/spec/mongoid/criteria/queryable/expandable_spec.rb +61 -0
  556. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +9 -19
  557. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +136 -26
  558. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +2 -0
  559. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +3 -1
  560. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +13 -0
  561. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +46 -17
  562. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +2 -0
  563. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +2 -0
  564. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +2 -15
  565. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +2 -0
  566. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +2 -0
  567. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -8
  568. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +2 -0
  569. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +239 -178
  570. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +3 -1
  571. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +2 -0
  572. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +2 -0
  573. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +2 -59
  574. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +2 -59
  575. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +34 -16
  576. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +13 -0
  577. data/spec/mongoid/criteria/queryable/key_spec.rb +2 -0
  578. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +145 -12
  579. data/spec/mongoid/criteria/queryable/optional_spec.rb +18 -485
  580. data/spec/mongoid/criteria/queryable/options_spec.rb +2 -0
  581. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +2 -0
  582. data/spec/mongoid/criteria/queryable/queryable_spec.rb +3 -1
  583. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +1643 -286
  584. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +38 -0
  585. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1191 -2752
  586. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +589 -0
  587. data/spec/mongoid/criteria/queryable/selector_spec.rb +91 -4
  588. data/spec/mongoid/criteria/queryable/smash_spec.rb +2 -0
  589. data/spec/mongoid/criteria/queryable/storable_spec.rb +298 -0
  590. data/spec/mongoid/criteria/scopable_spec.rb +129 -0
  591. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  592. data/spec/mongoid/criteria_projection_spec.rb +409 -0
  593. data/spec/mongoid/criteria_spec.rb +1322 -1723
  594. data/spec/mongoid/document_fields_spec.rb +179 -5
  595. data/spec/mongoid/document_persistence_context_spec.rb +0 -1
  596. data/spec/mongoid/document_query_spec.rb +89 -0
  597. data/spec/mongoid/document_spec.rb +153 -87
  598. data/spec/mongoid/equality_spec.rb +144 -41
  599. data/spec/mongoid/errors/ambiguous_relationship_spec.rb +5 -3
  600. data/spec/mongoid/errors/callback_spec.rb +2 -0
  601. data/spec/mongoid/errors/delete_restriction_spec.rb +4 -2
  602. data/spec/mongoid/errors/document_not_destroyed_spec.rb +2 -0
  603. data/spec/mongoid/errors/document_not_found_spec.rb +78 -0
  604. data/spec/mongoid/errors/invalid_collection_spec.rb +2 -0
  605. data/spec/mongoid/errors/{eager_load_spec.rb → invalid_config_file_spec.rb} +7 -5
  606. data/spec/mongoid/errors/invalid_config_option_spec.rb +2 -0
  607. data/spec/mongoid/errors/invalid_field_option_spec.rb +2 -0
  608. data/spec/mongoid/errors/invalid_field_spec.rb +3 -1
  609. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  610. data/spec/mongoid/errors/invalid_find_spec.rb +2 -0
  611. data/spec/mongoid/errors/invalid_includes_spec.rb +2 -0
  612. data/spec/mongoid/errors/invalid_index_spec.rb +2 -0
  613. data/spec/mongoid/errors/invalid_options_spec.rb +4 -2
  614. data/spec/mongoid/errors/invalid_path_spec.rb +2 -0
  615. data/spec/mongoid/errors/invalid_relation_spec.rb +4 -2
  616. data/spec/mongoid/errors/invalid_scope_spec.rb +3 -1
  617. data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +2 -0
  618. data/spec/mongoid/errors/invalid_storage_options_spec.rb +2 -0
  619. data/spec/mongoid/errors/invalid_time_spec.rb +2 -0
  620. data/spec/mongoid/errors/inverse_not_found_spec.rb +3 -1
  621. data/spec/mongoid/errors/mixed_client_configuration_spec.rb +2 -0
  622. data/spec/mongoid/errors/mixed_relations_spec.rb +2 -0
  623. data/spec/mongoid/errors/mongoid_error_spec.rb +24 -8
  624. data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +5 -3
  625. data/spec/mongoid/errors/no_client_config_spec.rb +4 -2
  626. data/spec/mongoid/errors/no_client_database_spec.rb +5 -3
  627. data/spec/mongoid/errors/no_client_hosts_spec.rb +5 -3
  628. data/spec/mongoid/errors/no_clients_config_spec.rb +2 -0
  629. data/spec/mongoid/errors/no_environment_spec.rb +5 -3
  630. data/spec/mongoid/errors/no_map_reduce_output_spec.rb +2 -0
  631. data/spec/mongoid/errors/no_metadata_spec.rb +4 -2
  632. data/spec/mongoid/errors/no_parent_spec.rb +3 -1
  633. data/spec/mongoid/errors/readonly_attribute_spec.rb +2 -0
  634. data/spec/mongoid/errors/readonly_document_spec.rb +2 -0
  635. data/spec/mongoid/errors/scope_overwrite_spec.rb +2 -0
  636. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +3 -1
  637. data/spec/mongoid/errors/unknown_attribute_spec.rb +4 -2
  638. data/spec/mongoid/errors/unsaved_document_spec.rb +3 -1
  639. data/spec/mongoid/errors/unsupported_javascript_spec.rb +2 -0
  640. data/spec/mongoid/errors/validations_spec.rb +2 -0
  641. data/spec/mongoid/extensions/array_spec.rb +41 -45
  642. data/spec/mongoid/extensions/big_decimal_spec.rb +714 -212
  643. data/spec/mongoid/extensions/binary_spec.rb +46 -9
  644. data/spec/mongoid/extensions/boolean_spec.rb +70 -82
  645. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +339 -0
  646. data/spec/mongoid/extensions/date_spec.rb +58 -140
  647. data/spec/mongoid/extensions/date_time_spec.rb +32 -69
  648. data/spec/mongoid/extensions/decimal128_spec.rb +2 -0
  649. data/spec/mongoid/extensions/false_class_spec.rb +3 -1
  650. data/spec/mongoid/extensions/float_spec.rb +66 -73
  651. data/spec/mongoid/extensions/hash_spec.rb +138 -3
  652. data/spec/mongoid/extensions/integer_spec.rb +61 -63
  653. data/spec/mongoid/extensions/module_spec.rb +2 -0
  654. data/spec/mongoid/extensions/nil_class_spec.rb +2 -0
  655. data/spec/mongoid/extensions/object_id_spec.rb +2 -0
  656. data/spec/mongoid/extensions/object_spec.rb +13 -24
  657. data/spec/mongoid/extensions/range_spec.rb +257 -54
  658. data/spec/mongoid/extensions/regexp_spec.rb +60 -33
  659. data/spec/mongoid/extensions/set_spec.rb +108 -0
  660. data/spec/mongoid/extensions/string_spec.rb +111 -50
  661. data/spec/mongoid/extensions/stringified_symbol_spec.rb +84 -0
  662. data/spec/mongoid/extensions/symbol_spec.rb +20 -25
  663. data/spec/mongoid/extensions/time_spec.rb +663 -66
  664. data/spec/mongoid/extensions/time_with_zone_spec.rb +50 -31
  665. data/spec/mongoid/extensions/true_class_spec.rb +3 -1
  666. data/spec/mongoid/extensions_spec.rb +16 -2
  667. data/spec/mongoid/factory_spec.rb +347 -27
  668. data/spec/mongoid/fields/foreign_key_spec.rb +2 -0
  669. data/spec/mongoid/fields/localized_spec.rb +43 -16
  670. data/spec/mongoid/fields/standard_spec.rb +2 -0
  671. data/spec/mongoid/fields_spec.rb +776 -80
  672. data/spec/mongoid/findable_spec.rb +133 -34
  673. data/spec/mongoid/indexable/specification_spec.rb +4 -2
  674. data/spec/mongoid/indexable_spec.rb +65 -18
  675. data/spec/mongoid/inspectable_spec.rb +39 -2
  676. data/spec/mongoid/interceptable_spec.rb +955 -103
  677. data/spec/mongoid/interceptable_spec_models.rb +307 -0
  678. data/spec/mongoid/loggable_spec.rb +2 -0
  679. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  680. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +239 -0
  681. data/spec/mongoid/matcher/extract_attribute_spec.rb +36 -0
  682. data/spec/mongoid/mongoizable_spec.rb +285 -0
  683. data/spec/mongoid/persistable/creatable_spec.rb +114 -29
  684. data/spec/mongoid/persistable/deletable_spec.rb +274 -12
  685. data/spec/mongoid/persistable/destroyable_spec.rb +202 -12
  686. data/spec/mongoid/persistable/incrementable_spec.rb +23 -7
  687. data/spec/mongoid/persistable/logical_spec.rb +19 -3
  688. data/spec/mongoid/persistable/poppable_spec.rb +19 -3
  689. data/spec/mongoid/persistable/pullable_spec.rb +36 -6
  690. data/spec/mongoid/persistable/pushable_spec.rb +36 -6
  691. data/spec/mongoid/persistable/renamable_spec.rb +18 -2
  692. data/spec/mongoid/persistable/savable_spec.rb +188 -25
  693. data/spec/mongoid/persistable/settable_spec.rb +24 -8
  694. data/spec/mongoid/persistable/unsettable_spec.rb +19 -3
  695. data/spec/mongoid/persistable/updatable_spec.rb +45 -23
  696. data/spec/mongoid/persistable/upsertable_spec.rb +18 -2
  697. data/spec/mongoid/persistable_spec.rb +85 -9
  698. data/spec/mongoid/persistence_context_spec.rb +52 -1
  699. data/spec/mongoid/positional_spec.rb +2 -0
  700. data/spec/mongoid/query_cache_middleware_spec.rb +50 -0
  701. data/spec/mongoid/query_cache_spec.rb +339 -87
  702. data/spec/mongoid/relations/proxy_spec.rb +8 -6
  703. data/spec/mongoid/reloadable_spec.rb +357 -22
  704. data/spec/mongoid/scopable_spec.rb +121 -37
  705. data/spec/mongoid/selectable_spec.rb +8 -6
  706. data/spec/mongoid/serializable_spec.rb +160 -29
  707. data/spec/mongoid/shardable_models.rb +75 -0
  708. data/spec/mongoid/shardable_spec.rb +239 -34
  709. data/spec/mongoid/stateful_spec.rb +31 -1
  710. data/spec/mongoid/tasks/database_rake_spec.rb +2 -0
  711. data/spec/mongoid/tasks/database_spec.rb +2 -0
  712. data/spec/mongoid/threaded_spec.rb +4 -2
  713. data/spec/mongoid/timestamps/created/short_spec.rb +3 -1
  714. data/spec/mongoid/timestamps/created_spec.rb +3 -1
  715. data/spec/mongoid/timestamps/timeless_spec.rb +4 -2
  716. data/spec/mongoid/timestamps/updated/short_spec.rb +5 -3
  717. data/spec/mongoid/timestamps/updated_spec.rb +5 -3
  718. data/spec/mongoid/timestamps_spec.rb +398 -6
  719. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  720. data/spec/mongoid/touchable_spec.rb +296 -33
  721. data/spec/mongoid/touchable_spec_models.rb +57 -0
  722. data/spec/mongoid/traversable_spec.rb +1160 -1
  723. data/spec/mongoid/validatable/associated_spec.rb +15 -30
  724. data/spec/mongoid/validatable/format_spec.rb +2 -0
  725. data/spec/mongoid/validatable/length_spec.rb +2 -0
  726. data/spec/mongoid/validatable/numericality_spec.rb +2 -0
  727. data/spec/mongoid/validatable/presence_spec.rb +28 -22
  728. data/spec/mongoid/validatable/uniqueness_spec.rb +128 -98
  729. data/spec/mongoid/validatable_spec.rb +5 -3
  730. data/spec/mongoid/warnings_spec.rb +35 -0
  731. data/spec/mongoid_spec.rb +3 -1
  732. data/spec/rails/controller_extension/controller_runtime_spec.rb +5 -3
  733. data/spec/rails/mongoid_spec.rb +8 -18
  734. data/spec/shared/bin/s3-copy +45 -0
  735. data/spec/shared/bin/s3-upload +69 -0
  736. data/spec/shared/lib/mrss/cluster_config.rb +14 -4
  737. data/spec/shared/lib/mrss/constraints.rb +51 -27
  738. data/spec/shared/lib/mrss/docker_runner.rb +37 -4
  739. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  740. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  741. data/spec/shared/lib/mrss/lite_constraints.rb +48 -1
  742. data/spec/shared/lib/mrss/server_version_registry.rb +16 -18
  743. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  744. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  745. data/spec/shared/lib/mrss/spec_organizer.rb +18 -1
  746. data/spec/shared/lib/mrss/utils.rb +28 -6
  747. data/spec/shared/share/Dockerfile.erb +156 -66
  748. data/spec/shared/share/haproxy-1.conf +16 -0
  749. data/spec/shared/share/haproxy-2.conf +17 -0
  750. data/spec/shared/shlib/config.sh +27 -0
  751. data/spec/shared/shlib/distro.sh +2 -1
  752. data/spec/shared/shlib/server.sh +171 -45
  753. data/spec/shared/shlib/set_env.sh +47 -6
  754. data/spec/spec_helper.rb +38 -36
  755. data/spec/support/authorization.rb +2 -0
  756. data/spec/support/client_registry.rb +9 -0
  757. data/spec/support/constraints.rb +39 -8
  758. data/spec/support/expectations.rb +5 -1
  759. data/spec/support/helpers.rb +11 -0
  760. data/spec/support/macros.rb +77 -0
  761. data/spec/{app → support}/models/account.rb +3 -1
  762. data/spec/{app → support}/models/acolyte.rb +2 -0
  763. data/spec/{app → support}/models/actor.rb +3 -1
  764. data/spec/support/models/actress.rb +4 -0
  765. data/spec/{app → support}/models/address.rb +6 -0
  766. data/spec/{app → support}/models/address_component.rb +2 -0
  767. data/spec/{app → support}/models/address_number.rb +2 -0
  768. data/spec/{app → support}/models/agency.rb +2 -0
  769. data/spec/{app → support}/models/agent.rb +2 -0
  770. data/spec/{app → support}/models/album.rb +2 -0
  771. data/spec/{app → support}/models/alert.rb +2 -0
  772. data/spec/{app → support}/models/animal.rb +2 -0
  773. data/spec/{app → support}/models/answer.rb +2 -0
  774. data/spec/{app → support}/models/appointment.rb +2 -0
  775. data/spec/support/models/armrest.rb +9 -0
  776. data/spec/{app → support}/models/article.rb +2 -0
  777. data/spec/{app → support}/models/artist.rb +4 -0
  778. data/spec/{app → support}/models/artwork.rb +2 -0
  779. data/spec/support/models/audible_sound.rb +3 -0
  780. data/spec/{app → support}/models/audio.rb +2 -0
  781. data/spec/support/models/augmentation.rb +25 -0
  782. data/spec/{app → support}/models/author.rb +2 -0
  783. data/spec/{app → support}/models/baby.rb +2 -0
  784. data/spec/{app → support}/models/band.rb +9 -0
  785. data/spec/{app → support}/models/bar.rb +2 -0
  786. data/spec/{app → support}/models/basic.rb +2 -0
  787. data/spec/support/models/bed.rb +3 -0
  788. data/spec/{app → support}/models/big_palette.rb +2 -0
  789. data/spec/{app → support}/models/birthday.rb +2 -0
  790. data/spec/support/models/bolt.rb +7 -0
  791. data/spec/{app → support}/models/bomb.rb +2 -0
  792. data/spec/{app → support}/models/book.rb +2 -0
  793. data/spec/{app → support}/models/breed.rb +2 -0
  794. data/spec/{app → support}/models/browser.rb +3 -1
  795. data/spec/{app → support}/models/building.rb +2 -0
  796. data/spec/{app → support}/models/building_address.rb +2 -0
  797. data/spec/{app → support}/models/bus.rb +2 -0
  798. data/spec/{app → support}/models/business.rb +2 -0
  799. data/spec/{app → support}/models/callback_test.rb +2 -0
  800. data/spec/{app → support}/models/canvas.rb +3 -1
  801. data/spec/support/models/car.rb +3 -0
  802. data/spec/{app → support}/models/cat.rb +2 -0
  803. data/spec/support/models/catalog.rb +24 -0
  804. data/spec/{app → support}/models/category.rb +2 -0
  805. data/spec/{app → support}/models/child.rb +2 -0
  806. data/spec/{app → support}/models/child_doc.rb +5 -3
  807. data/spec/{app → support}/models/church.rb +2 -0
  808. data/spec/{app → support}/models/circle.rb +2 -0
  809. data/spec/{app → support}/models/circuit.rb +2 -0
  810. data/spec/support/models/circus.rb +12 -0
  811. data/spec/{app → support}/models/code.rb +4 -0
  812. data/spec/support/models/coding/pull_request.rb +11 -0
  813. data/spec/support/models/coding.rb +3 -0
  814. data/spec/{app → support}/models/comment.rb +2 -0
  815. data/spec/{app → support}/models/company.rb +2 -0
  816. data/spec/{app → support}/models/consumption_period.rb +2 -0
  817. data/spec/{app → support}/models/contextable_item.rb +2 -0
  818. data/spec/{app → support}/models/contractor.rb +2 -0
  819. data/spec/{app → support}/models/cookie.rb +2 -0
  820. data/spec/{app → support}/models/country_code.rb +4 -0
  821. data/spec/{app → support}/models/courier_job.rb +2 -0
  822. data/spec/support/models/crate.rb +12 -0
  823. data/spec/{app → support}/models/customer.rb +0 -1
  824. data/spec/{app → support}/models/customer_address.rb +0 -1
  825. data/spec/support/models/deed.rb +7 -0
  826. data/spec/{app → support}/models/definition.rb +2 -0
  827. data/spec/{app → support}/models/delegating_patient.rb +0 -1
  828. data/spec/{app → support}/models/description.rb +2 -0
  829. data/spec/{app → support}/models/dictionary.rb +8 -0
  830. data/spec/{app → support}/models/division.rb +2 -0
  831. data/spec/{app → support}/models/doctor.rb +2 -0
  832. data/spec/{app → support}/models/dog.rb +2 -0
  833. data/spec/{app → support}/models/dokument.rb +2 -0
  834. data/spec/{app → support}/models/draft.rb +2 -0
  835. data/spec/{app → support}/models/dragon.rb +2 -0
  836. data/spec/{app → support}/models/driver.rb +3 -1
  837. data/spec/{app → support}/models/drug.rb +2 -0
  838. data/spec/{app → support}/models/dungeon.rb +2 -0
  839. data/spec/{app → support}/models/edit.rb +2 -0
  840. data/spec/{app → support}/models/email.rb +2 -0
  841. data/spec/{app → support}/models/employer.rb +2 -0
  842. data/spec/{app → support}/models/entry.rb +2 -0
  843. data/spec/support/models/eraser.rb +3 -0
  844. data/spec/{app → support}/models/even.rb +2 -0
  845. data/spec/{app → support}/models/event.rb +2 -0
  846. data/spec/{app → support}/models/exhibition.rb +2 -0
  847. data/spec/{app → support}/models/exhibitor.rb +2 -0
  848. data/spec/{app → support}/models/explosion.rb +2 -0
  849. data/spec/{app → support}/models/eye.rb +2 -0
  850. data/spec/{app → support}/models/eye_bowl.rb +2 -0
  851. data/spec/{app → support}/models/face.rb +2 -0
  852. data/spec/support/models/fanatic.rb +8 -0
  853. data/spec/{app → support}/models/favorite.rb +2 -0
  854. data/spec/{app → support}/models/filesystem.rb +2 -0
  855. data/spec/{app → support}/models/fire_hydrant.rb +2 -0
  856. data/spec/{app → support}/models/firefox.rb +2 -0
  857. data/spec/{app → support}/models/fish.rb +2 -0
  858. data/spec/{app → support}/models/folder.rb +2 -0
  859. data/spec/{app → support}/models/folder_item.rb +2 -0
  860. data/spec/{app → support}/models/fruits.rb +2 -0
  861. data/spec/{app → support}/models/game.rb +2 -0
  862. data/spec/{app → support}/models/ghost.rb +2 -0
  863. data/spec/support/models/guitar.rb +4 -0
  864. data/spec/support/models/hole.rb +12 -0
  865. data/spec/{app → support}/models/home.rb +2 -0
  866. data/spec/{app → support}/models/house.rb +2 -0
  867. data/spec/{app → support}/models/html_writer.rb +2 -0
  868. data/spec/{app → support}/models/id_key.rb +2 -0
  869. data/spec/support/models/idnodef.rb +7 -0
  870. data/spec/{app → support}/models/image.rb +2 -0
  871. data/spec/{app → support}/models/implant.rb +11 -0
  872. data/spec/support/models/instrument.rb +8 -0
  873. data/spec/{app → support}/models/item.rb +3 -1
  874. data/spec/{app → support}/models/jar.rb +2 -0
  875. data/spec/{app → support}/models/kaleidoscope.rb +2 -0
  876. data/spec/{app → support}/models/kangaroo.rb +3 -1
  877. data/spec/{app → support}/models/label.rb +6 -1
  878. data/spec/{app → support}/models/language.rb +2 -0
  879. data/spec/{app → support}/models/lat_lng.rb +2 -0
  880. data/spec/{app → support}/models/league.rb +2 -0
  881. data/spec/support/models/learner.rb +4 -0
  882. data/spec/{app → support}/models/line_item.rb +2 -0
  883. data/spec/{app → support}/models/location.rb +2 -0
  884. data/spec/{app → support}/models/login.rb +2 -0
  885. data/spec/{app → support}/models/manufacturer.rb +2 -0
  886. data/spec/{app → support}/models/meat.rb +2 -0
  887. data/spec/{app → support}/models/membership.rb +3 -0
  888. data/spec/{app → support}/models/message.rb +2 -0
  889. data/spec/{app → support}/models/minim.rb +0 -1
  890. data/spec/{app → support}/models/mixed_drink.rb +2 -0
  891. data/spec/support/models/mop.rb +24 -0
  892. data/spec/{app → support}/models/movie.rb +2 -0
  893. data/spec/support/models/my_hash.rb +4 -0
  894. data/spec/{app → support}/models/name.rb +12 -0
  895. data/spec/support/models/name_only.rb +8 -0
  896. data/spec/{app → support}/models/node.rb +2 -0
  897. data/spec/{app → support}/models/note.rb +2 -0
  898. data/spec/support/models/nut.rb +7 -0
  899. data/spec/{app → support}/models/odd.rb +2 -0
  900. data/spec/support/models/order.rb +12 -0
  901. data/spec/{app → support}/models/ordered_post.rb +3 -1
  902. data/spec/{app → support}/models/ordered_preference.rb +2 -0
  903. data/spec/{app → support}/models/oscar.rb +2 -0
  904. data/spec/support/models/other_owner_object.rb +4 -0
  905. data/spec/{app → support}/models/override.rb +2 -0
  906. data/spec/{app → support}/models/ownable.rb +2 -0
  907. data/spec/{app → support}/models/owner.rb +4 -0
  908. data/spec/{app → support}/models/pack.rb +2 -0
  909. data/spec/{app → support}/models/page.rb +2 -0
  910. data/spec/{app → support}/models/page_question.rb +2 -0
  911. data/spec/{app → support}/models/palette.rb +3 -1
  912. data/spec/{app → support}/models/parent.rb +2 -0
  913. data/spec/{app → support}/models/parent_doc.rb +2 -0
  914. data/spec/support/models/passport.rb +22 -0
  915. data/spec/{app → support}/models/patient.rb +2 -0
  916. data/spec/{app → support}/models/pdf_writer.rb +2 -0
  917. data/spec/support/models/pencil.rb +3 -0
  918. data/spec/{app → support}/models/person.rb +23 -1
  919. data/spec/{app → support}/models/pet.rb +2 -0
  920. data/spec/{app → support}/models/pet_owner.rb +2 -0
  921. data/spec/{app → support}/models/phone.rb +5 -1
  922. data/spec/support/models/piano.rb +4 -0
  923. data/spec/{app → support}/models/pizza.rb +2 -0
  924. data/spec/{app → support}/models/player.rb +4 -0
  925. data/spec/{app → support}/models/post.rb +2 -0
  926. data/spec/{app → support}/models/post_genre.rb +2 -0
  927. data/spec/support/models/powerup.rb +25 -0
  928. data/spec/{app → support}/models/preference.rb +2 -0
  929. data/spec/{app → support}/models/princess.rb +2 -0
  930. data/spec/{app → support}/models/product.rb +2 -0
  931. data/spec/support/models/profile.rb +17 -0
  932. data/spec/{app → support}/models/pronunciation.rb +2 -0
  933. data/spec/{app → support}/models/pub.rb +2 -0
  934. data/spec/support/models/publication/encyclopedia.rb +11 -0
  935. data/spec/support/models/publication/review.rb +13 -0
  936. data/spec/support/models/publication.rb +4 -0
  937. data/spec/{app → support}/models/purchase.rb +2 -0
  938. data/spec/support/models/purchased_item.rb +10 -0
  939. data/spec/support/models/purse.rb +9 -0
  940. data/spec/{app → support}/models/question.rb +2 -0
  941. data/spec/{app → support}/models/quiz.rb +2 -0
  942. data/spec/{app → support}/models/rating.rb +2 -0
  943. data/spec/{app → support}/models/record.rb +2 -0
  944. data/spec/{app → support}/models/registry.rb +3 -0
  945. data/spec/{app → support}/models/role.rb +2 -0
  946. data/spec/{app → support}/models/root_category.rb +2 -0
  947. data/spec/{app → support}/models/sandwich.rb +2 -0
  948. data/spec/{app → support}/models/scheduler.rb +2 -0
  949. data/spec/support/models/school.rb +14 -0
  950. data/spec/support/models/scribe.rb +7 -0
  951. data/spec/support/models/sealer.rb +7 -0
  952. data/spec/support/models/seat.rb +24 -0
  953. data/spec/{app → support}/models/seo.rb +2 -0
  954. data/spec/support/models/series.rb +7 -0
  955. data/spec/{app → support}/models/server.rb +2 -0
  956. data/spec/{app → support}/models/service.rb +2 -0
  957. data/spec/{app → support}/models/shape.rb +4 -2
  958. data/spec/{app → support}/models/shelf.rb +2 -0
  959. data/spec/support/models/shield.rb +18 -0
  960. data/spec/{app → support}/models/shipment_address.rb +2 -0
  961. data/spec/{app → support}/models/shipping_container.rb +2 -0
  962. data/spec/{app → support}/models/shipping_pack.rb +2 -0
  963. data/spec/support/models/shirt.rb +11 -0
  964. data/spec/{app → support}/models/shop.rb +2 -0
  965. data/spec/{app → support}/models/short_agent.rb +2 -0
  966. data/spec/{app → support}/models/short_quiz.rb +2 -0
  967. data/spec/{app → support}/models/simple.rb +2 -0
  968. data/spec/{app → support}/models/slave.rb +2 -0
  969. data/spec/{app → support}/models/song.rb +2 -0
  970. data/spec/{app → support}/models/sound.rb +2 -0
  971. data/spec/support/models/spacer.rb +7 -0
  972. data/spec/{app → support}/models/square.rb +2 -0
  973. data/spec/{app → support}/models/staff.rb +2 -0
  974. data/spec/{app → support}/models/store_as_dup_test1.rb +2 -0
  975. data/spec/{app → support}/models/store_as_dup_test2.rb +2 -0
  976. data/spec/{app → support}/models/strategy.rb +2 -0
  977. data/spec/support/models/student.rb +14 -0
  978. data/spec/{app → support}/models/sub_item.rb +2 -0
  979. data/spec/{app → support}/models/subscription.rb +2 -0
  980. data/spec/{app → support}/models/survey.rb +2 -0
  981. data/spec/{app → support}/models/symptom.rb +2 -0
  982. data/spec/support/models/system_role.rb +7 -0
  983. data/spec/{app → support}/models/tag.rb +2 -0
  984. data/spec/{app → support}/models/target.rb +2 -0
  985. data/spec/{app → support}/models/template.rb +2 -0
  986. data/spec/{app → support}/models/thing.rb +2 -0
  987. data/spec/support/models/threadlocker.rb +7 -0
  988. data/spec/{app → support}/models/title.rb +2 -0
  989. data/spec/{app → support}/models/tool.rb +4 -2
  990. data/spec/{app → support}/models/topping.rb +2 -0
  991. data/spec/support/models/toy.rb +9 -0
  992. data/spec/{app → support}/models/track.rb +2 -0
  993. data/spec/{app → support}/models/translation.rb +2 -0
  994. data/spec/{app → support}/models/tree.rb +2 -0
  995. data/spec/support/models/truck.rb +7 -0
  996. data/spec/{app → support}/models/user.rb +2 -0
  997. data/spec/{app → support}/models/user_account.rb +2 -0
  998. data/spec/{app → support}/models/validation_callback.rb +2 -0
  999. data/spec/support/models/vehicle.rb +18 -0
  1000. data/spec/{app → support}/models/version.rb +2 -0
  1001. data/spec/{app → support}/models/vertex.rb +3 -1
  1002. data/spec/{app → support}/models/vet_visit.rb +2 -0
  1003. data/spec/{app → support}/models/video.rb +2 -0
  1004. data/spec/support/models/video_game.rb +3 -0
  1005. data/spec/support/models/washer.rb +7 -0
  1006. data/spec/support/models/weapon.rb +25 -0
  1007. data/spec/{app → support}/models/wiki_page.rb +3 -0
  1008. data/spec/{app → support}/models/word.rb +2 -0
  1009. data/spec/{app → support}/models/word_origin.rb +2 -0
  1010. data/spec/{app → support}/models/writer.rb +4 -2
  1011. data/spec/support/schema_maps/schema_map_aws.json +17 -0
  1012. data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  1013. data/spec/support/schema_maps/schema_map_azure.json +17 -0
  1014. data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  1015. data/spec/support/schema_maps/schema_map_gcp.json +17 -0
  1016. data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  1017. data/spec/support/schema_maps/schema_map_kmip.json +17 -0
  1018. data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  1019. data/spec/support/schema_maps/schema_map_local.json +18 -0
  1020. data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
  1021. data/spec/support/shared/time.rb +53 -0
  1022. data/spec/support/spec_config.rb +12 -3
  1023. data.tar.gz.sig +0 -0
  1024. metadata +1162 -764
  1025. metadata.gz.sig +0 -0
  1026. data/lib/mongoid/criteria/queryable/forwardable.rb +0 -65
  1027. data/lib/mongoid/errors/eager_load.rb +0 -22
  1028. data/lib/mongoid/errors/invalid_value.rb +0 -16
  1029. data/lib/mongoid/matchable/all.rb +0 -28
  1030. data/lib/mongoid/matchable/and.rb +0 -30
  1031. data/lib/mongoid/matchable/default.rb +0 -119
  1032. data/lib/mongoid/matchable/elem_match.rb +0 -34
  1033. data/lib/mongoid/matchable/eq.rb +0 -22
  1034. data/lib/mongoid/matchable/exists.rb +0 -23
  1035. data/lib/mongoid/matchable/gt.rb +0 -23
  1036. data/lib/mongoid/matchable/gte.rb +0 -23
  1037. data/lib/mongoid/matchable/in.rb +0 -24
  1038. data/lib/mongoid/matchable/lt.rb +0 -23
  1039. data/lib/mongoid/matchable/lte.rb +0 -23
  1040. data/lib/mongoid/matchable/ne.rb +0 -21
  1041. data/lib/mongoid/matchable/nin.rb +0 -22
  1042. data/lib/mongoid/matchable/nor.rb +0 -37
  1043. data/lib/mongoid/matchable/or.rb +0 -33
  1044. data/lib/mongoid/matchable/regexp.rb +0 -27
  1045. data/lib/mongoid/matchable/size.rb +0 -21
  1046. data/lib/support/ruby_version.rb +0 -26
  1047. data/spec/app/models/actress.rb +0 -2
  1048. data/spec/app/models/augmentation.rb +0 -11
  1049. data/spec/app/models/bed.rb +0 -1
  1050. data/spec/app/models/car.rb +0 -1
  1051. data/spec/app/models/circus.rb +0 -7
  1052. data/spec/app/models/eraser.rb +0 -1
  1053. data/spec/app/models/learner.rb +0 -2
  1054. data/spec/app/models/my_hash.rb +0 -2
  1055. data/spec/app/models/other_owner_object.rb +0 -2
  1056. data/spec/app/models/passport.rb +0 -5
  1057. data/spec/app/models/pencil.rb +0 -1
  1058. data/spec/app/models/powerup.rb +0 -11
  1059. data/spec/app/models/profile.rb +0 -5
  1060. data/spec/app/models/series.rb +0 -4
  1061. data/spec/app/models/truck.rb +0 -3
  1062. data/spec/app/models/vehicle.rb +0 -11
  1063. data/spec/app/models/video_game.rb +0 -1
  1064. data/spec/app/models/weapon.rb +0 -11
  1065. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +0 -87
  1066. data/spec/mongoid/matchable/all_spec.rb +0 -31
  1067. data/spec/mongoid/matchable/and_spec.rb +0 -187
  1068. data/spec/mongoid/matchable/default_spec.rb +0 -137
  1069. data/spec/mongoid/matchable/elem_match_spec.rb +0 -106
  1070. data/spec/mongoid/matchable/eq_spec.rb +0 -48
  1071. data/spec/mongoid/matchable/exists_spec.rb +0 -57
  1072. data/spec/mongoid/matchable/gt_spec.rb +0 -86
  1073. data/spec/mongoid/matchable/gte_spec.rb +0 -84
  1074. data/spec/mongoid/matchable/in_spec.rb +0 -49
  1075. data/spec/mongoid/matchable/lt_spec.rb +0 -85
  1076. data/spec/mongoid/matchable/lte_spec.rb +0 -85
  1077. data/spec/mongoid/matchable/ne_spec.rb +0 -46
  1078. data/spec/mongoid/matchable/nin_spec.rb +0 -48
  1079. data/spec/mongoid/matchable/nor_spec.rb +0 -209
  1080. data/spec/mongoid/matchable/or_spec.rb +0 -131
  1081. data/spec/mongoid/matchable/regexp_spec.rb +0 -59
  1082. data/spec/mongoid/matchable/size_spec.rb +0 -25
  1083. data/spec/mongoid/matchable_spec.rb +0 -853
  1084. data/spec/support/cluster_config.rb +0 -158
  1085. data/spec/support/session_registry.rb +0 -50
  1086. /data/spec/{app → support}/models/array_field.rb +0 -0
  1087. /data/spec/{app → support}/models/store_as_dup_test3.rb +0 -0
  1088. /data/spec/{app → support}/models/store_as_dup_test4.rb +0 -0
  1089. /data/spec/{app → support}/models/updatable.rb +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  describe Mongoid::Contextual::Mongo do
@@ -7,7 +9,7 @@ describe Mongoid::Contextual::Mongo do
7
9
  describe "##{method}" do
8
10
 
9
11
  before do
10
- Band.create(name: "Depeche Mode")
12
+ Band.create!(name: "Depeche Mode")
11
13
  end
12
14
 
13
15
  context "when the count is zero" do
@@ -42,47 +44,14 @@ describe Mongoid::Contextual::Mongo do
42
44
  end
43
45
  end
44
46
 
45
- describe "#cached?" do
46
-
47
- context "when the criteria is cached" do
48
-
49
- let(:criteria) do
50
- Band.all.cache
51
- end
52
-
53
- let(:context) do
54
- described_class.new(criteria)
55
- end
56
-
57
- it "returns true" do
58
- expect(context).to be_cached
59
- end
60
- end
61
-
62
- context "when the criteria is not cached" do
63
-
64
- let(:criteria) do
65
- Band.all
66
- end
67
-
68
- let(:context) do
69
- described_class.new(criteria)
70
- end
71
-
72
- it "returns false" do
73
- expect(context).to_not be_cached
74
- end
75
- end
76
- end
77
-
78
47
  describe "#count" do
79
48
 
80
49
  let!(:depeche) do
81
- Band.create(name: "Depeche Mode")
50
+ Band.create!(name: "Depeche Mode")
82
51
  end
83
52
 
84
53
  let!(:new_order) do
85
- Band.create(name: "New Order")
54
+ Band.create!(name: "New Order")
86
55
  end
87
56
 
88
57
  let(:criteria) do
@@ -100,18 +69,17 @@ describe Mongoid::Contextual::Mongo do
100
69
  end
101
70
  end
102
71
 
103
- context "when context is cached" do
72
+ context "when the query cache is enabled" do
73
+ query_cache_enabled
104
74
 
105
75
  let(:context) do
106
- described_class.new(criteria.cache)
107
- end
108
-
109
- before do
110
- expect(context.view).to receive(:count).once.and_return(1)
76
+ described_class.new(criteria)
111
77
  end
112
78
 
113
- it "returns the count cached value after first call" do
114
- 2.times { expect(context.count).to eq(1) }
79
+ it "only executes the count query once" do
80
+ expect_query(1) do
81
+ 2.times { expect(context.count).to eq(1) }
82
+ end
115
83
  end
116
84
  end
117
85
 
@@ -134,7 +102,7 @@ describe Mongoid::Contextual::Mongo do
134
102
  context "and a limit true" do
135
103
 
136
104
  before do
137
- 2.times { Band.create(name: "Depeche Mode", likes: 1) }
105
+ 2.times { Band.create!(name: "Depeche Mode", likes: 1) }
138
106
  end
139
107
 
140
108
  let(:count) do
@@ -152,7 +120,7 @@ describe Mongoid::Contextual::Mongo do
152
120
  context "when provided limit" do
153
121
 
154
122
  before do
155
- 2.times { Band.create(name: "Depeche Mode") }
123
+ 2.times { Band.create!(name: "Depeche Mode") }
156
124
  end
157
125
 
158
126
  let(:context) do
@@ -190,18 +158,95 @@ describe Mongoid::Contextual::Mongo do
190
158
  end
191
159
  end
192
160
  end
161
+
162
+ context 'when for_js is present' do
163
+ let(:context) do
164
+ Band.for_js('this.name == "Depeche Mode"')
165
+ end
166
+
167
+ it 'counts the expected records' do
168
+ expect(context.count).to eq(1)
169
+ end
170
+ end
171
+ end
172
+
173
+ describe "#estimated_count" do
174
+
175
+ let!(:depeche) do
176
+ Band.create!(name: "Depeche Mode")
177
+ end
178
+
179
+ let!(:new_order) do
180
+ Band.create!(name: "New Order")
181
+ end
182
+
183
+ let(:criteria) do
184
+ Band.where
185
+ end
186
+
187
+ context "when not providing options" do
188
+ it 'returns the correct count' do
189
+ expect(criteria.estimated_count).to eq(2)
190
+ end
191
+ end
192
+
193
+ context "when providing options" do
194
+ it 'returns the correct count' do
195
+ expect(criteria.estimated_count(maxTimeMS: 1000)).to eq(2)
196
+ end
197
+ end
198
+
199
+ context "when the query cache is enabled" do
200
+ query_cache_enabled
201
+
202
+ let(:context) do
203
+ described_class.new(criteria)
204
+ end
205
+
206
+ it "the results are not cached" do
207
+ expect_query(2) do
208
+ 2.times do
209
+ context.estimated_count
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ context "when the criteria contains a selector", :focus do
216
+ let(:criteria) do
217
+ Band.where(name: "New Order")
218
+ end
219
+
220
+ context "when not providing options" do
221
+ it 'raises an error' do
222
+ expect do
223
+ criteria.estimated_count
224
+ end.to raise_error(Mongoid::Errors::InvalidEstimatedCountCriteria)
225
+ end
226
+ end
227
+
228
+ context "when providing options" do
229
+ it 'raises an error' do
230
+ expect do
231
+ criteria.estimated_count(maxTimeMS: 1000)
232
+ end.to raise_error(Mongoid::Errors::InvalidEstimatedCountCriteria)
233
+ end
234
+ end
235
+ end
193
236
  end
194
237
 
238
+
239
+
195
240
  [ :delete, :delete_all ].each do |method|
196
241
 
197
242
  describe "##{method}" do
198
243
 
199
244
  let!(:depeche_mode) do
200
- Band.create(name: "Depeche Mode")
245
+ Band.create!(name: "Depeche Mode")
201
246
  end
202
247
 
203
248
  let!(:new_order) do
204
- Band.create(name: "New Order")
249
+ Band.create!(name: "New Order")
205
250
  end
206
251
 
207
252
  context "when the selector is contraining" do
@@ -302,11 +347,11 @@ describe Mongoid::Contextual::Mongo do
302
347
  describe "##{method}" do
303
348
 
304
349
  let!(:depeche_mode) do
305
- Band.create(name: "Depeche Mode")
350
+ Band.create!(name: "Depeche Mode")
306
351
  end
307
352
 
308
353
  let!(:new_order) do
309
- Band.create(name: "New Order")
354
+ Band.create!(name: "New Order")
310
355
  end
311
356
 
312
357
  context "when the selector is contraining" do
@@ -387,7 +432,7 @@ describe Mongoid::Contextual::Mongo do
387
432
  context 'when the write concern is unacknowledged' do
388
433
 
389
434
  before do
390
- 2.times { Band.create }
435
+ 2.times { Band.create! }
391
436
  end
392
437
 
393
438
  let(:criteria) do
@@ -409,42 +454,83 @@ describe Mongoid::Contextual::Mongo do
409
454
  describe "#distinct" do
410
455
 
411
456
  before do
412
- Band.create(name: "Depeche Mode", years: 30)
413
- Band.create(name: "New Order", years: 25)
457
+ Band.create!(name: "Depeche Mode", years: 30, sales: "1E2")
458
+ Band.create!(name: "New Order", years: 25, sales: "2E3")
459
+ Band.create!(name: "10,000 Maniacs", years: 20, sales: "1E2")
414
460
  end
415
461
 
416
- context "when limiting the result set" do
462
+ with_config_values :legacy_pluck_distinct, true, false do
463
+ context "when limiting the result set" do
417
464
 
418
- let(:criteria) do
419
- Band.where(name: "Depeche Mode")
420
- end
465
+ let(:criteria) do
466
+ Band.where(name: "Depeche Mode")
467
+ end
421
468
 
422
- let(:context) do
423
- described_class.new(criteria)
424
- end
469
+ let(:context) do
470
+ described_class.new(criteria)
471
+ end
425
472
 
426
- it "returns the distinct matching fields" do
427
- expect(context.distinct(:name)).to eq([ "Depeche Mode" ])
473
+ it "returns the distinct matching fields" do
474
+ expect(context.distinct(:name)).to eq([ "Depeche Mode" ])
475
+ end
428
476
  end
429
- end
430
477
 
431
- context "when not limiting the result set" do
478
+ context "when not limiting the result set" do
432
479
 
433
- let(:criteria) do
434
- Band.criteria
480
+ let(:criteria) do
481
+ Band.criteria
482
+ end
483
+
484
+ let(:context) do
485
+ described_class.new(criteria)
486
+ end
487
+
488
+ it "returns the distinct field values" do
489
+ expect(context.distinct(:name).sort).to eq([ "10,000 Maniacs", "Depeche Mode", "New Order" ].sort)
490
+ end
435
491
  end
436
492
 
437
- let(:context) do
438
- described_class.new(criteria)
493
+ context "when providing an aliased field" do
494
+
495
+ let(:criteria) do
496
+ Band.criteria
497
+ end
498
+
499
+ let(:context) do
500
+ described_class.new(criteria)
501
+ end
502
+
503
+ it "returns the distinct field values" do
504
+ expect(context.distinct(:years).sort).to eq([ 20, 25, 30 ])
505
+ end
439
506
  end
440
507
 
441
- it "returns the distinct field values" do
442
- expect(context.distinct(:name)).to eq([ "Depeche Mode", "New Order" ])
508
+ context 'when a collation is specified' do
509
+ min_server_version '3.4'
510
+
511
+ before do
512
+ Band.create!(name: 'DEPECHE MODE')
513
+ end
514
+
515
+ let(:context) do
516
+ described_class.new(criteria)
517
+ end
518
+
519
+ let(:expected_results) do
520
+ ["10,000 Maniacs", "Depeche Mode", "New Order"]
521
+ end
522
+
523
+ let(:criteria) do
524
+ Band.where({}).collation(locale: 'en_US', strength: 2)
525
+ end
526
+
527
+ it 'applies the collation' do
528
+ expect(context.distinct(:name).sort).to eq(expected_results.sort)
529
+ end
443
530
  end
444
531
  end
445
532
 
446
- context "when providing an aliased field" do
447
-
533
+ context "when providing a demongoizable field" do
448
534
  let(:criteria) do
449
535
  Band.criteria
450
536
  end
@@ -453,155 +539,836 @@ describe Mongoid::Contextual::Mongo do
453
539
  described_class.new(criteria)
454
540
  end
455
541
 
456
- it "returns the distinct field values" do
457
- expect(context.distinct(:years).sort).to eq([ 25, 30 ])
458
- end
459
- end
542
+ context "when legacy_pluck_distinct is set" do
543
+ config_override :legacy_pluck_distinct, true
460
544
 
461
- context 'when a collation is specified' do
462
- min_server_version '3.4'
545
+ context 'when storing BigDecimal as string' do
546
+ config_override :map_big_decimal_to_decimal128, false
463
547
 
464
- before do
465
- Band.create(name: 'DEPECHE MODE')
548
+ it "returns the non-demongoized distinct field values" do
549
+ expect(context.distinct(:sales).sort).to eq([ "1E2", "2E3" ])
550
+ end
551
+ end
552
+
553
+ context 'when storing BigDecimal as decimal128' do
554
+ config_override :map_big_decimal_to_decimal128, true
555
+ min_bson_version '4.15.0'
556
+ max_bson_version '4.99.99'
557
+
558
+ it "returns the non-demongoized distinct field values" do
559
+ expect(context.distinct(:sales).sort).to eq([ BSON::Decimal128.new("1E2"), BSON::Decimal128.new("2E3") ])
560
+ end
561
+ end
466
562
  end
467
563
 
468
- let(:context) do
469
- described_class.new(criteria)
564
+ context "when legacy_pluck_distinct is not set" do
565
+ config_override :legacy_pluck_distinct, false
566
+
567
+ it "returns the non-demongoized distinct field values" do
568
+ expect(context.distinct(:sales).sort).to eq([ BigDecimal("1E2"), BigDecimal("2E3") ])
569
+ end
470
570
  end
571
+ end
471
572
 
472
- let(:expected_results) do
473
- ["Depeche Mode", "New Order"]
573
+ context "when getting a localized field" do
574
+ before do
575
+ I18n.locale = :en
576
+ d = Dictionary.create!(description: 'english-text')
577
+ I18n.locale = :de
578
+ d.description = 'deutsch-text'
579
+ d.save!
474
580
  end
475
581
 
476
582
  let(:criteria) do
477
- Band.where({}).collation(locale: 'en_US', strength: 2)
583
+ Dictionary.criteria
478
584
  end
479
585
 
480
- it 'applies the collation' do
481
- expect(context.distinct(:name)).to eq(expected_results)
586
+ let(:context) do
587
+ described_class.new(criteria)
482
588
  end
483
- end
484
- end
485
589
 
486
- describe "#each" do
590
+ context "when getting the field without _translations" do
591
+ context "when legacy_pluck_distinct is set" do
592
+ config_override :legacy_pluck_distinct, true
487
593
 
488
- before do
489
- Band.create(name: "Depeche Mode")
490
- end
594
+ it "gets the full hash" do
595
+ expect(context.distinct(:description)).to eq([{ "de" => "deutsch-text", "en" => "english-text" }])
596
+ end
597
+ end
491
598
 
492
- let(:criteria) do
493
- Band.where(name: "Depeche Mode")
494
- end
599
+ context "when legacy_pluck_distinct is not set" do
600
+ config_override :legacy_pluck_distinct, false
495
601
 
496
- let(:context) do
497
- described_class.new(criteria)
498
- end
602
+ it "gets the demongoized localized field" do
603
+ expect(context.distinct(:description)).to eq([ 'deutsch-text' ])
604
+ end
605
+ end
606
+ end
499
607
 
500
- context 'when the criteria has a collation' do
501
- min_server_version '3.4'
608
+ context "when getting the field with _translations" do
609
+ context "when legacy_pluck_distinct is set" do
610
+ config_override :legacy_pluck_distinct, true
502
611
 
503
- let(:criteria) do
504
- Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
505
- end
612
+ it "gets an empty list" do
613
+ expect(context.distinct(:description_translations)).to eq([])
614
+ end
615
+ end
506
616
 
507
- it "yields mongoid documents to the block" do
508
- context.each do |doc|
509
- expect(doc).to be_a(Mongoid::Document)
617
+ context "when legacy_pluck_distinct is not set" do
618
+ config_override :legacy_pluck_distinct, false
619
+
620
+ it "gets the full hash" do
621
+ expect(context.distinct(:description_translations)).to eq([ { "de" => "deutsch-text", "en" => "english-text" } ])
622
+ end
510
623
  end
511
624
  end
512
625
 
513
- it "iterates over the matching documents" do
514
- context.each do |doc|
515
- expect(doc.name).to eq("Depeche Mode")
626
+ context 'when plucking a specific locale' do
627
+
628
+ let(:distinct) do
629
+ context.distinct(:'description.de')
516
630
  end
517
- end
518
631
 
519
- it "returns self" do
520
- expect(context.each{}).to be(context)
521
- end
522
- end
632
+ context "when legacy_pluck_distinct is set" do
633
+ config_override :legacy_pluck_distinct, true
523
634
 
524
- context "when providing a block" do
635
+ it 'returns the specific translation' do
636
+ expect(distinct).to eq([ 'deutsch-text' ])
637
+ end
638
+ end
525
639
 
526
- it "yields mongoid documents to the block" do
527
- context.each do |doc|
528
- expect(doc).to be_a(Mongoid::Document)
640
+ context "when legacy_pluck_distinct is not set" do
641
+ config_override :legacy_pluck_distinct, false
642
+
643
+ it 'returns the specific translation' do
644
+ expect(distinct).to eq([ "deutsch-text" ])
645
+ end
529
646
  end
530
647
  end
531
648
 
532
- it "iterates over the matching documents" do
533
- context.each do |doc|
534
- expect(doc.name).to eq("Depeche Mode")
649
+ context 'when plucking a specific locale from _translations field' do
650
+
651
+ let(:distinct) do
652
+ context.distinct(:'description_translations.de')
535
653
  end
536
- end
537
654
 
538
- it "returns self" do
539
- expect(context.each{}).to be(context)
540
- end
541
- end
655
+ context "when legacy_pluck_distinct is set" do
656
+ config_override :legacy_pluck_distinct, true
542
657
 
543
- context "when no block is provided" do
658
+ it 'returns the empty list' do
659
+ expect(distinct).to eq([])
660
+ end
661
+ end
544
662
 
545
- let(:enum) do
546
- context.each
547
- end
663
+ context "when legacy_pluck_distinct is not set" do
664
+ config_override :legacy_pluck_distinct, false
548
665
 
549
- it "returns an enumerator" do
550
- expect(enum).to be_a(Enumerator)
666
+ it 'returns the specific translations' do
667
+ expect(distinct).to eq(['deutsch-text'])
668
+ end
669
+ end
551
670
  end
552
671
 
553
- context "when iterating over the enumerator" do
554
-
555
- context "when iterating with each" do
672
+ context 'when fallbacks are enabled with a locale list' do
673
+ with_i18n_fallbacks
556
674
 
557
- it "yields mongoid documents to the block" do
558
- enum.each do |doc|
559
- expect(doc).to be_a(Mongoid::Document)
560
- end
561
- end
675
+ around(:all) do |example|
676
+ prev_fallbacks = I18n.fallbacks.dup
677
+ I18n.fallbacks[:he] = [ :en ]
678
+ example.run
679
+ I18n.fallbacks = prev_fallbacks
562
680
  end
563
681
 
564
- context "when iterating with next" do
682
+ let(:distinct) do
683
+ context.distinct(:description).first
684
+ end
565
685
 
566
- before do
567
- 10.times { |i| Band.create(name: "Test #{i}") }
568
- end
686
+ context "when legacy_pluck_distinct is set" do
687
+ config_override :legacy_pluck_distinct, true
569
688
 
570
- let(:criteria) do
571
- Band.batch_size(5)
689
+ it "does not correctly use the fallback" do
690
+ distinct.should == {"de"=>"deutsch-text", "en"=>"english-text"}
572
691
  end
692
+ end
573
693
 
574
- it "yields mongoid documents" do
575
- expect(enum.next).to be_a(Mongoid::Document)
576
- end
694
+ context "when legacy_pluck_distinct is not set" do
695
+ config_override :legacy_pluck_distinct, false
577
696
 
578
- it "does not load all documents" do
579
- expect(Mongo::Logger.logger).to receive(:debug?).exactly(2).times.and_call_original
580
- enum.next
697
+ it "correctly uses the fallback" do
698
+ I18n.locale = :en
699
+ Dictionary.create!(description: 'english-text')
700
+ I18n.locale = :he
701
+ distinct.should == "english-text"
581
702
  end
582
703
  end
583
704
  end
584
- end
585
705
 
586
- context 'when the criteria has a parent document' do
706
+ context "when the localized field is embedded" do
707
+ before do
708
+ p = Passport.new
709
+ I18n.locale = :en
710
+ p.name = "Neil"
711
+ I18n.locale = :he
712
+ p.name = "Nissim"
587
713
 
588
- before do
589
- Post.create(person: person)
590
- Post.create(person: person)
591
- Post.create(person: person)
592
- end
714
+ Person.create!(passport: p, employer_id: 12345)
715
+ end
593
716
 
594
- let(:person) do
595
- Person.new
596
- end
717
+ let(:criteria) do
718
+ Person.where(employer_id: 12345)
719
+ end
597
720
 
598
- let(:criteria) do
599
- person.posts.all
600
- end
721
+ let(:context) do
722
+ described_class.new(criteria)
723
+ end
601
724
 
602
- let(:persons) do
603
- criteria.collect(&:person)
604
- end
725
+ let(:distinct) do
726
+ context.distinct("pass.name").first
727
+ end
728
+
729
+ let(:distinct_translations) do
730
+ context.distinct("pass.name_translations").first
731
+ end
732
+
733
+ let(:distinct_translations_field) do
734
+ context.distinct("pass.name_translations.en").first
735
+ end
736
+
737
+ context "when legacy_pluck_distinct is set" do
738
+ config_override :legacy_pluck_distinct, true
739
+
740
+ it "returns the full hash" do
741
+ expect(distinct).to eq({ "en" => "Neil", "he" => "Nissim" })
742
+ end
743
+
744
+ it "returns the empty hash" do
745
+ expect(distinct_translations).to eq(nil)
746
+ end
747
+
748
+ it "returns the empty hash" do
749
+ expect(distinct_translations_field).to eq(nil)
750
+ end
751
+ end
752
+
753
+ context "when legacy_pluck_distinct is not set" do
754
+ config_override :legacy_pluck_distinct, false
755
+
756
+ it "returns the translation for the current locale" do
757
+ expect(distinct).to eq("Nissim")
758
+ end
759
+
760
+ it "returns the full _translation hash" do
761
+ expect(distinct_translations).to eq({ "en" => "Neil", "he" => "Nissim" })
762
+ end
763
+
764
+ it "returns the translation for the requested locale" do
765
+ expect(distinct_translations_field).to eq("Neil")
766
+ end
767
+ end
768
+ end
769
+ end
770
+
771
+ context "when getting an embedded field" do
772
+
773
+ let(:label) { Label.new(sales: "1E2") }
774
+ let!(:band) { Band.create!(label: label) }
775
+ let(:criteria) { Band.where(_id: band.id) }
776
+ let(:context) { described_class.new(criteria) }
777
+
778
+ context "when legacy_pluck_distinct is set" do
779
+ config_override :legacy_pluck_distinct, true
780
+ config_override :map_big_decimal_to_decimal128, true
781
+ max_bson_version '4.99.99'
782
+
783
+ it "returns the distinct matching fields" do
784
+ expect(context.distinct("label.sales")).to eq([ BSON::Decimal128.new('1E+2') ])
785
+ end
786
+ end
787
+
788
+ context "when legacy_pluck_distinct is not set" do
789
+ config_override :legacy_pluck_distinct, false
790
+ it "returns the distinct matching fields" do
791
+ expect(context.distinct("label.sales")).to eq([ BigDecimal("1E2") ])
792
+ end
793
+ end
794
+ end
795
+ end
796
+
797
+ describe "#tally" do
798
+ let(:fans1) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
799
+ let(:fans2) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
800
+ let(:fans3) { [ Fanatic.new(age:1), Fanatic.new(age:3) ] }
801
+
802
+ let(:genres1) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 3 } ]}
803
+ let(:genres2) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 4 } ]}
804
+ let(:genres3) { [ { x: 1, y: { z: 1 } }, { x: 3, y: { z: 3 } }, { y: 5 } ]}
805
+
806
+ let(:label1) { Label.new(name: "Atlantic") }
807
+ let(:label2) { Label.new(name: "Atlantic") }
808
+ let(:label3) { Label.new(name: "Columbia") }
809
+
810
+ before do
811
+ Band.create!(origin: "tally", name: "Depeche Mode", years: 30, sales: "1E2", label: label1, genres: genres1)
812
+ Band.create!(origin: "tally", name: "New Order", years: 30, sales: "2E3", label: label2, genres: genres2)
813
+ Band.create!(origin: "tally", name: "10,000 Maniacs", years: 30, sales: "1E2", label: label3, genres: genres3)
814
+ Band.create!(origin: "tally2", fanatics: fans1, genres: [1, 2])
815
+ Band.create!(origin: "tally2", fanatics: fans2, genres: [1, 2])
816
+ Band.create!(origin: "tally2", fanatics: fans3, genres: [1, 3])
817
+ end
818
+
819
+ let(:criteria) { Band.where(origin: "tally") }
820
+
821
+ context "when tallying a string" do
822
+ let(:tally) do
823
+ criteria.tally(:name)
824
+ end
825
+
826
+ it "returns the correct hash" do
827
+ expect(tally).to eq("Depeche Mode" => 1, "New Order" => 1, "10,000 Maniacs" => 1)
828
+ end
829
+ end
830
+
831
+ context "using an aliased field" do
832
+ let(:tally) do
833
+ criteria.tally(:years)
834
+ end
835
+
836
+ it "returns the correct hash" do
837
+ expect(tally).to eq(30 => 3)
838
+ end
839
+ end
840
+
841
+ context "when tallying a demongoizable field" do
842
+ let(:tally) do
843
+ criteria.tally(:sales)
844
+ end
845
+
846
+ it "returns the correct hash" do
847
+ expect(tally).to eq(BigDecimal("1E2") => 2, BigDecimal("2E3") => 1)
848
+ end
849
+ end
850
+
851
+ context "when tallying a localized field" do
852
+ before do
853
+ I18n.locale = :en
854
+ d1 = Dictionary.create!(description: 'en1')
855
+ d2 = Dictionary.create!(description: 'en1')
856
+ d3 = Dictionary.create!(description: 'en1')
857
+ d4 = Dictionary.create!(description: 'en2')
858
+ I18n.locale = :de
859
+ d1.description = 'de1'
860
+ d2.description = 'de1'
861
+ d3.description = 'de2'
862
+ d4.description = 'de3'
863
+ d1.save!
864
+ d2.save!
865
+ d3.save!
866
+ d4.save!
867
+ I18n.locale = :en
868
+ end
869
+
870
+ context "when getting the demongoized field" do
871
+ let(:tallied) do
872
+ Dictionary.tally(:description)
873
+ end
874
+
875
+ it "returns the translation for the current locale" do
876
+ expect(tallied).to eq("en1" => 3, "en2" => 1)
877
+ end
878
+ end
879
+
880
+ context "when getting a specific locale" do
881
+ let(:tallied) do
882
+ Dictionary.tally("description.de")
883
+ end
884
+
885
+ it "returns the translation for the the specific locale" do
886
+ expect(tallied).to eq("de1" => 2, "de2" => 1, "de3" => 1)
887
+ end
888
+ end
889
+
890
+ context "when getting the full hash" do
891
+ let(:tallied) do
892
+ Dictionary.tally("description_translations")
893
+ end
894
+
895
+ it "returns the correct hash" do
896
+ expect(tallied).to eq(
897
+ {"de" => "de1", "en" => "en1" } => 2,
898
+ {"de" => "de2", "en" => "en1" } => 1,
899
+ {"de" => "de3", "en" => "en2" } => 1
900
+ )
901
+ end
902
+ end
903
+ end
904
+
905
+ context "when tallying an embedded localized field" do
906
+
907
+ before do
908
+ I18n.locale = :en
909
+ address1a = Address.new(name: "en1")
910
+ address1b = Address.new(name: "en2")
911
+ address2a = Address.new(name: "en1")
912
+ address2b = Address.new(name: "en3")
913
+ I18n.locale = :de
914
+ address1a.name = "de1"
915
+ address1b.name = "de2"
916
+ address2a.name = "de1"
917
+ address2b.name = "de3"
918
+ Person.create!(addresses: [ address1a, address1b ])
919
+ Person.create!(addresses: [ address2a, address2b ])
920
+ I18n.locale = :en
921
+ end
922
+
923
+ context "when getting the demongoized field" do
924
+ let(:tallied) do
925
+ Person.tally("addresses.name")
926
+ end
927
+
928
+ it "returns the translation for the current locale" do
929
+ expect(tallied).to eq(
930
+ [ "en1", "en2" ] => 1,
931
+ [ "en1", "en3" ] => 1,
932
+ )
933
+ end
934
+ end
935
+
936
+ context "when getting a specific locale" do
937
+ let(:tallied) do
938
+ Person.tally("addresses.name.de")
939
+ end
940
+
941
+ it "returns the translation for the the specific locale" do
942
+ expect(tallied).to eq(
943
+ [ "de1", "de2" ] => 1,
944
+ [ "de1", "de3" ] => 1,
945
+ )
946
+ end
947
+ end
948
+
949
+ context "when getting the full hash" do
950
+ let(:tallied) do
951
+ Person.tally("addresses.name_translations")
952
+ end
953
+
954
+ it "returns the correct hash" do
955
+ expect(tallied).to eq(
956
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de2", "en" => "en2" }] => 1,
957
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de3", "en" => "en3" }] => 1,
958
+ )
959
+ end
960
+ end
961
+
962
+ end
963
+
964
+ context "when tallying an embedded field" do
965
+ let(:tally) do
966
+ criteria.tally("label.name")
967
+ end
968
+
969
+ it "returns the correct hash" do
970
+ expect(tally).to eq("Atlantic" => 2, "Columbia" => 1)
971
+ end
972
+ end
973
+
974
+ context "when tallying an element in an embeds_many field" do
975
+ let(:criteria) { Band.where(origin: "tally2") }
976
+
977
+ let(:tally) do
978
+ criteria.tally("fanatics.age")
979
+ end
980
+
981
+ it "returns the correct hash" do
982
+ expect(tally).to eq(
983
+ [1, 2] => 2,
984
+ [1, 3] => 1
985
+ )
986
+ end
987
+ end
988
+
989
+ context "when tallying an embeds_many field" do
990
+ let(:criteria) { Band.where(origin: "tally2") }
991
+
992
+ let(:tally) do
993
+ criteria.tally("fanatics")
994
+ end
995
+
996
+ it "returns the correct hash" do
997
+ expect(tally).to eq(
998
+ fans1.map(&:attributes) => 1,
999
+ fans2.map(&:attributes) => 1,
1000
+ fans3.map(&:attributes) => 1,
1001
+ )
1002
+ end
1003
+ end
1004
+
1005
+ context "when tallying a field of type array" do
1006
+ let(:criteria) { Band.where(origin: "tally2") }
1007
+
1008
+ let(:tally) do
1009
+ criteria.tally("genres")
1010
+ end
1011
+
1012
+ it "returns the correct hash" do
1013
+ expect(tally).to eq(
1014
+ [1, 2] => 2,
1015
+ [1, 3] => 1
1016
+ )
1017
+ end
1018
+ end
1019
+
1020
+ context "when tallying an element from an array of hashes" do
1021
+ let(:criteria) { Band.where(origin: "tally") }
1022
+
1023
+ let(:tally) do
1024
+ criteria.tally("genres.x")
1025
+ end
1026
+
1027
+ it "returns the correct hash without the nil keys" do
1028
+ expect(tally).to eq(
1029
+ [1, 2] => 2,
1030
+ [1, 3] => 1
1031
+ )
1032
+ end
1033
+ end
1034
+
1035
+ context "when tallying an element from an array of hashes; with duplicate" do
1036
+
1037
+ before do
1038
+ Band.create!(origin: "tally", genres: [ { x: 1 }, {x: 1} ] )
1039
+ end
1040
+
1041
+ let(:criteria) { Band.where(origin: "tally") }
1042
+
1043
+ let(:tally) do
1044
+ criteria.tally("genres.x")
1045
+ end
1046
+
1047
+ it "returns the correct hash without the nil keys" do
1048
+ expect(tally).to eq(
1049
+ [1, 2] => 2,
1050
+ [1, 3] => 1,
1051
+ [1, 1] => 1,
1052
+ )
1053
+ end
1054
+ end
1055
+
1056
+ context "when tallying an aliased field of type array" do
1057
+
1058
+ before do
1059
+ Person.create!(array: [ 1, 2 ])
1060
+ Person.create!(array: [ 1, 3 ])
1061
+ end
1062
+
1063
+ let(:tally) do
1064
+ Person.tally("array")
1065
+ end
1066
+
1067
+ it "returns the correct hash" do
1068
+ expect(tally).to eq(
1069
+ [1, 2] => 1,
1070
+ [1, 3] => 1
1071
+ )
1072
+ end
1073
+ end
1074
+
1075
+ context "when going multiple levels deep in arrays" do
1076
+ let(:criteria) { Band.where(origin: "tally") }
1077
+
1078
+ let(:tally) do
1079
+ criteria.tally("genres.y.z")
1080
+ end
1081
+
1082
+ it "returns the correct hash" do
1083
+ expect(tally).to eq(
1084
+ [1, 2] => 2,
1085
+ [1, 3] => 1
1086
+ )
1087
+ end
1088
+ end
1089
+
1090
+ context "when going multiple levels deep in an array" do
1091
+ let(:criteria) { Band.where(origin: "tally") }
1092
+
1093
+ let(:tally) do
1094
+ criteria.tally("genres.y.z")
1095
+ end
1096
+
1097
+ it "returns the correct hash" do
1098
+ expect(tally).to eq(
1099
+ [1, 2] => 2,
1100
+ [1, 3] => 1
1101
+ )
1102
+ end
1103
+ end
1104
+
1105
+ context "when tallying deeply nested arrays/embedded associations" do
1106
+
1107
+ before do
1108
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1109
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1110
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ])
1111
+ end
1112
+
1113
+ let(:tally) do
1114
+ Person.tally("addresses.code.deepest.array.y.z")
1115
+ end
1116
+
1117
+ it "returns the correct hash" do
1118
+ expect(tally).to eq(
1119
+ [ [ 1, 2 ] ] => 2,
1120
+ [ [ 1, 3 ] ] => 1
1121
+ )
1122
+ end
1123
+ end
1124
+
1125
+ context "when tallying deeply nested arrays/embedded associations" do
1126
+
1127
+ before do
1128
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
1129
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1130
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
1131
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1132
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))),
1133
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ])
1134
+ end
1135
+
1136
+ let(:tally) do
1137
+ Person.tally("addresses.code.deepest.array.y.z")
1138
+ end
1139
+
1140
+ it "returns the correct hash" do
1141
+ expect(tally).to eq(
1142
+ [ [ 1, 2 ], [ 1, 2 ] ] => 2,
1143
+ [ [ 1, 3 ], [ 1, 3 ] ] => 1
1144
+ )
1145
+ end
1146
+ end
1147
+
1148
+ context "when some keys are missing" do
1149
+ before do
1150
+ 3.times { Band.create!(origin: "tally") }
1151
+ end
1152
+
1153
+ let(:tally) do
1154
+ criteria.tally(:name)
1155
+ end
1156
+
1157
+ it "returns the correct hash" do
1158
+ expect(tally).to eq(
1159
+ "Depeche Mode" => 1,
1160
+ "New Order" => 1,
1161
+ "10,000 Maniacs" => 1,
1162
+ nil => 3
1163
+ )
1164
+ end
1165
+ end
1166
+
1167
+ context "when the first element is an embeds_one" do
1168
+ before do
1169
+ Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ]))
1170
+ Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ]))
1171
+ Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 3) ]))
1172
+ end
1173
+
1174
+ let(:tally) do
1175
+ Person.tally("name.translations.language")
1176
+ end
1177
+
1178
+ it "returns the correct hash" do
1179
+ expect(tally).to eq(
1180
+ [1, 2] => 2,
1181
+ [1, 3] => 1
1182
+ )
1183
+ end
1184
+ end
1185
+
1186
+ context "when tallying demongoizable values from typeless fields" do
1187
+
1188
+ let!(:person1) { Person.create!(ssn: /hello/) }
1189
+ let!(:person2) { Person.create!(ssn: BSON::Decimal128.new("1")) }
1190
+ let(:tally) { Person.tally("ssn") }
1191
+
1192
+ let(:tallied_classes) do
1193
+ tally.keys.map(&:class).sort do |a, b|
1194
+ a.to_s.casecmp(b.to_s)
1195
+ end
1196
+ end
1197
+
1198
+ context "< BSON 5" do
1199
+ max_bson_version '4.99.99'
1200
+
1201
+ it "stores the correct types in the database" do
1202
+ expect(Person.find(person1.id).attributes["ssn"]).to be_a BSON::Regexp::Raw
1203
+ expect(Person.find(person2.id).attributes["ssn"]).to be_a BSON::Decimal128
1204
+ end
1205
+
1206
+ it "tallies the correct type" do
1207
+ expect(tallied_classes).to be == [ BSON::Decimal128, BSON::Regexp::Raw ]
1208
+ end
1209
+ end
1210
+
1211
+ context '>= BSON 5' do
1212
+ min_bson_version "5.0"
1213
+
1214
+ it "stores the correct types in the database" do
1215
+ expect(Person.find(person1.id).ssn).to be_a BSON::Regexp::Raw
1216
+ expect(Person.find(person2.id).ssn).to be_a BigDecimal
1217
+ end
1218
+
1219
+ it "tallies the correct type" do
1220
+ expect(tallied_classes).to be == [ BigDecimal, BSON::Regexp::Raw ]
1221
+ end
1222
+ end
1223
+
1224
+ context '>= BSON 5 with decimal128 allowed' do
1225
+ min_bson_version "5.0"
1226
+ config_override :allow_bson5_decimal128, true
1227
+
1228
+ it "stores the correct types in the database" do
1229
+ expect(Person.find(person1.id).ssn).to be_a BSON::Regexp::Raw
1230
+ expect(Person.find(person2.id).ssn).to be_a BSON::Decimal128
1231
+ end
1232
+
1233
+ it "tallies the correct type" do
1234
+ expect(tallied_classes).to be == [ BSON::Decimal128, BSON::Regexp::Raw ]
1235
+ end
1236
+ end
1237
+ end
1238
+ end
1239
+
1240
+ describe "#each" do
1241
+
1242
+ before do
1243
+ Band.create!(name: "Depeche Mode")
1244
+ end
1245
+
1246
+ let(:criteria) do
1247
+ Band.where(name: "Depeche Mode")
1248
+ end
1249
+
1250
+ let(:context) do
1251
+ described_class.new(criteria)
1252
+ end
1253
+
1254
+ context 'when the criteria has a collation' do
1255
+ min_server_version '3.4'
1256
+
1257
+ let(:criteria) do
1258
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
1259
+ end
1260
+
1261
+ it "yields mongoid documents to the block" do
1262
+ context.each do |doc|
1263
+ expect(doc).to be_a(Mongoid::Document)
1264
+ end
1265
+ end
1266
+
1267
+ it "iterates over the matching documents" do
1268
+ context.each do |doc|
1269
+ expect(doc.name).to eq("Depeche Mode")
1270
+ end
1271
+ end
1272
+
1273
+ it "returns self" do
1274
+ expect(context.each{}).to be(context)
1275
+ end
1276
+ end
1277
+
1278
+ context "when providing a block" do
1279
+
1280
+ it "yields mongoid documents to the block" do
1281
+ context.each do |doc|
1282
+ expect(doc).to be_a(Mongoid::Document)
1283
+ end
1284
+ end
1285
+
1286
+ it "iterates over the matching documents" do
1287
+ context.each do |doc|
1288
+ expect(doc.name).to eq("Depeche Mode")
1289
+ end
1290
+ end
1291
+
1292
+ it "returns self" do
1293
+ expect(context.each{}).to be(context)
1294
+ end
1295
+ end
1296
+
1297
+ context "when no block is provided" do
1298
+
1299
+ let(:enum) do
1300
+ context.each
1301
+ end
1302
+
1303
+ it "returns an enumerator" do
1304
+ expect(enum).to be_a(Enumerator)
1305
+ end
1306
+
1307
+ context "when iterating over the enumerator" do
1308
+
1309
+ context "when iterating with each" do
1310
+
1311
+ it "yields mongoid documents to the block" do
1312
+ enum.each do |doc|
1313
+ expect(doc).to be_a(Mongoid::Document)
1314
+ end
1315
+ end
1316
+ end
1317
+
1318
+ context "when iterating with next" do
1319
+
1320
+ before do
1321
+ 10.times { |i| Band.create!(name: "Test #{i}") }
1322
+ end
1323
+
1324
+ let(:criteria) do
1325
+ Band.batch_size(5)
1326
+ end
1327
+
1328
+ it "yields mongoid documents" do
1329
+ expect(enum.next).to be_a(Mongoid::Document)
1330
+ end
1331
+
1332
+ it "does not load all documents" do
1333
+ subscriber = Mrss::EventSubscriber.new
1334
+ context.view.client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
1335
+
1336
+ enum.next
1337
+
1338
+ find_events = subscriber.all_events.select do |evt|
1339
+ evt.command_name == 'find'
1340
+ end
1341
+ expect(find_events.length).to be(2)
1342
+ get_more_events = subscriber.all_events.select do |evt|
1343
+ evt.command_name == 'getMore'
1344
+ end
1345
+ expect(get_more_events.length).to be(0)
1346
+ ensure
1347
+ context.view.client.unsubscribe(Mongo::Monitoring::COMMAND, subscriber)
1348
+ end
1349
+ end
1350
+ end
1351
+ end
1352
+
1353
+ context 'when the criteria has a parent document' do
1354
+
1355
+ before do
1356
+ Post.create!(person: person)
1357
+ Post.create!(person: person)
1358
+ Post.create!(person: person)
1359
+ end
1360
+
1361
+ let(:person) do
1362
+ Person.new
1363
+ end
1364
+
1365
+ let(:criteria) do
1366
+ person.posts.all
1367
+ end
1368
+
1369
+ let(:persons) do
1370
+ criteria.collect(&:person)
1371
+ end
605
1372
 
606
1373
  it 'sets the same parent object on each related object' do
607
1374
  expect(persons.uniq.size).to eq(1)
@@ -635,7 +1402,7 @@ describe Mongoid::Contextual::Mongo do
635
1402
  describe "#exists?" do
636
1403
 
637
1404
  before do
638
- Band.create(name: "Depeche Mode")
1405
+ Band.create!(name: "Depeche Mode")
639
1406
  end
640
1407
 
641
1408
  context "when the count is zero" do
@@ -648,111 +1415,231 @@ describe Mongoid::Contextual::Mongo do
648
1415
  described_class.new(criteria)
649
1416
  end
650
1417
 
651
- it "returns false" do
652
- expect(context).to_not be_exists
1418
+ it "returns false" do
1419
+ expect(context).to_not be_exists
1420
+ end
1421
+ end
1422
+
1423
+ context "when the count is greater than zero" do
1424
+
1425
+ let(:criteria) do
1426
+ Band.where(name: "Depeche Mode")
1427
+ end
1428
+
1429
+ let(:context) do
1430
+ described_class.new(criteria)
1431
+ end
1432
+
1433
+ it "returns true" do
1434
+ expect(context).to be_exists
1435
+ end
1436
+ end
1437
+
1438
+ context "when caching is not enabled" do
1439
+
1440
+ let(:criteria) do
1441
+ Band.where(name: "Depeche Mode")
1442
+ end
1443
+
1444
+ let(:context) do
1445
+ described_class.new(criteria)
1446
+ end
1447
+
1448
+ context "when exists? already called and query cache is enabled" do
1449
+ query_cache_enabled
1450
+
1451
+ before do
1452
+ context.exists?
1453
+ end
1454
+
1455
+ it "does not hit the database again" do
1456
+ expect_no_queries do
1457
+ expect(context).to be_exists
1458
+ end
1459
+ end
1460
+ end
1461
+ end
1462
+ end
1463
+
1464
+ describe "#explain" do
1465
+
1466
+ let(:criteria) do
1467
+ Band.where(name: "Depeche Mode")
1468
+ end
1469
+
1470
+ let(:context) do
1471
+ described_class.new(criteria)
1472
+ end
1473
+
1474
+ it "returns the criteria explain path" do
1475
+ expect(context.explain).to_not be_empty
1476
+ end
1477
+ end
1478
+
1479
+ describe "#find_one_and_replace" do
1480
+
1481
+ let!(:depeche) do
1482
+ Band.create!(name: "Depeche Mode")
1483
+ end
1484
+
1485
+ let!(:tool) do
1486
+ Band.create!(name: "Tool")
1487
+ end
1488
+
1489
+ context "when the selector matches" do
1490
+
1491
+ context "when not providing options" do
1492
+
1493
+ let(:criteria) do
1494
+ Band.where(name: "Depeche Mode")
1495
+ end
1496
+
1497
+ let(:context) do
1498
+ described_class.new(criteria)
1499
+ end
1500
+
1501
+ let!(:result) do
1502
+ context.find_one_and_replace(name: 'FKA Twigs')
1503
+ end
1504
+
1505
+ it "returns the first matching document" do
1506
+ expect(result).to eq(depeche)
1507
+ end
1508
+
1509
+ it "updates the document in the database" do
1510
+ expect(depeche.reload.name).to eq('FKA Twigs')
1511
+ end
1512
+ end
1513
+
1514
+ context "when sorting" do
1515
+
1516
+ let(:criteria) do
1517
+ Band.desc(:name)
1518
+ end
1519
+
1520
+ let(:context) do
1521
+ described_class.new(criteria)
1522
+ end
1523
+
1524
+ let!(:result) do
1525
+ context.find_one_and_replace(likes: 1)
1526
+ end
1527
+
1528
+ it "returns the first matching document" do
1529
+ expect(result).to eq(tool)
1530
+ end
1531
+
1532
+ it "updates the document in the database" do
1533
+ expect(tool.reload.likes).to eq(1)
1534
+ expect(tool.reload.name).to be_nil
1535
+ end
653
1536
  end
654
- end
655
1537
 
656
- context "when the count is greater than zero" do
1538
+ context "when limiting fields" do
657
1539
 
658
- let(:criteria) do
659
- Band.where(name: "Depeche Mode")
660
- end
1540
+ let(:criteria) do
1541
+ Band.only(:_id)
1542
+ end
661
1543
 
662
- let(:context) do
663
- described_class.new(criteria)
664
- end
1544
+ let(:context) do
1545
+ described_class.new(criteria)
1546
+ end
665
1547
 
666
- it "returns true" do
667
- expect(context).to be_exists
668
- end
669
- end
1548
+ let!(:result) do
1549
+ context.find_one_and_replace(name: 'FKA Twigs', likes: 1)
1550
+ end
670
1551
 
671
- context "when caching is not enabled" do
1552
+ it "returns the first matching document" do
1553
+ expect(result).to eq(depeche)
1554
+ end
672
1555
 
673
- let(:criteria) do
674
- Band.where(name: "Depeche Mode")
675
- end
1556
+ it "limits the returned fields" do
1557
+ expect(result.name).to be_nil
1558
+ end
676
1559
 
677
- let(:context) do
678
- described_class.new(criteria)
1560
+ it "updates the document in the database" do
1561
+ expect(depeche.reload.likes).to eq(1)
1562
+ end
679
1563
  end
680
1564
 
681
- context "when exists? already called" do
1565
+ context "when returning new" do
682
1566
 
683
- before do
684
- context.exists?
1567
+ let(:criteria) do
1568
+ Band.where(name: "Depeche Mode")
685
1569
  end
686
1570
 
687
- it "hits the database again" do
688
- expect(context).to receive(:view).once.and_call_original
689
- expect(context).to be_exists
1571
+ let(:context) do
1572
+ described_class.new(criteria)
690
1573
  end
691
- end
692
- end
693
1574
 
694
- context "when caching is enabled" do
1575
+ let!(:result) do
1576
+ context.find_one_and_replace({ likes: 1 }, return_document: :after)
1577
+ end
695
1578
 
696
- let(:criteria) do
697
- Band.where(name: "Depeche Mode").cache
698
- end
1579
+ it "returns the first matching document" do
1580
+ expect(result).to eq(depeche)
1581
+ end
699
1582
 
700
- let(:context) do
701
- described_class.new(criteria)
1583
+ it "returns the updated document" do
1584
+ expect(result.name).to be_nil
1585
+ expect(result.likes).to eq(1)
1586
+ end
702
1587
  end
703
1588
 
704
- context "when the cache is loaded" do
1589
+ context 'when a collation is specified on the criteria' do
1590
+ min_server_version '3.4'
705
1591
 
706
- before do
707
- context.to_a
1592
+ let(:criteria) do
1593
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
708
1594
  end
709
1595
 
710
- it "does not hit the database" do
711
- expect(context).to receive(:view).never
712
- expect(context).to be_exists
1596
+ let(:context) do
1597
+ described_class.new(criteria)
713
1598
  end
714
- end
715
-
716
- context "when the cache is not loaded" do
717
1599
 
718
- context "when a count has been executed" do
1600
+ let!(:result) do
1601
+ context.find_one_and_replace({ likes: 1 }, return_document: :after)
1602
+ end
719
1603
 
720
- before do
721
- context.count
722
- end
1604
+ it "returns the first matching document" do
1605
+ expect(result).to eq(depeche)
1606
+ end
723
1607
 
724
- it "does not hit the database" do
725
- expect(context).to receive(:view).never
726
- expect(context).to be_exists
727
- end
1608
+ it "returns the updated document" do
1609
+ expect(result.likes).to eq(1)
1610
+ expect(result.name).to be_nil
728
1611
  end
729
1612
  end
730
1613
  end
731
- end
732
1614
 
733
- describe "#explain" do
1615
+ context "when the selector does not match" do
734
1616
 
735
- let(:criteria) do
736
- Band.where(name: "Depeche Mode")
737
- end
1617
+ let(:criteria) do
1618
+ Band.where(name: "DEPECHE MODE")
1619
+ end
738
1620
 
739
- let(:context) do
740
- described_class.new(criteria)
741
- end
1621
+ let(:context) do
1622
+ described_class.new(criteria)
1623
+ end
742
1624
 
743
- it "returns the criteria explain path" do
744
- expect(context.explain).to_not be_empty
1625
+ let(:result) do
1626
+ context.find_one_and_replace(name: 'FKA Twigs')
1627
+ end
1628
+
1629
+ it "returns nil" do
1630
+ expect(result).to be_nil
1631
+ end
745
1632
  end
746
1633
  end
747
1634
 
748
- describe "#find_one_and_replace" do
1635
+ describe "#find_one_and_update" do
749
1636
 
750
1637
  let!(:depeche) do
751
- Band.create(name: "Depeche Mode")
1638
+ Band.create!(name: "Depeche Mode")
752
1639
  end
753
1640
 
754
1641
  let!(:tool) do
755
- Band.create(name: "Tool")
1642
+ Band.create!(name: "Tool")
756
1643
  end
757
1644
 
758
1645
  context "when the selector matches" do
@@ -768,7 +1655,7 @@ describe Mongoid::Contextual::Mongo do
768
1655
  end
769
1656
 
770
1657
  let!(:result) do
771
- context.find_one_and_replace(name: 'FKA Twigs')
1658
+ context.find_one_and_update("$inc" => { likes: 1 })
772
1659
  end
773
1660
 
774
1661
  it "returns the first matching document" do
@@ -776,7 +1663,7 @@ describe Mongoid::Contextual::Mongo do
776
1663
  end
777
1664
 
778
1665
  it "updates the document in the database" do
779
- expect(depeche.reload.name).to eq('FKA Twigs')
1666
+ expect(depeche.reload.likes).to eq(1)
780
1667
  end
781
1668
  end
782
1669
 
@@ -791,7 +1678,7 @@ describe Mongoid::Contextual::Mongo do
791
1678
  end
792
1679
 
793
1680
  let!(:result) do
794
- context.find_one_and_replace(likes: 1)
1681
+ context.find_one_and_update("$inc" => { likes: 1 })
795
1682
  end
796
1683
 
797
1684
  it "returns the first matching document" do
@@ -800,7 +1687,6 @@ describe Mongoid::Contextual::Mongo do
800
1687
 
801
1688
  it "updates the document in the database" do
802
1689
  expect(tool.reload.likes).to eq(1)
803
- expect(tool.reload.name).to be_nil
804
1690
  end
805
1691
  end
806
1692
 
@@ -815,7 +1701,7 @@ describe Mongoid::Contextual::Mongo do
815
1701
  end
816
1702
 
817
1703
  let!(:result) do
818
- context.find_one_and_replace(name: 'FKA Twigs', likes: 1)
1704
+ context.find_one_and_update("$inc" => { likes: 1 })
819
1705
  end
820
1706
 
821
1707
  it "returns the first matching document" do
@@ -842,7 +1728,7 @@ describe Mongoid::Contextual::Mongo do
842
1728
  end
843
1729
 
844
1730
  let!(:result) do
845
- context.find_one_and_replace({ likes: 1 }, return_document: :after)
1731
+ context.find_one_and_update({ "$inc" => { likes: 1 }}, return_document: :after)
846
1732
  end
847
1733
 
848
1734
  it "returns the first matching document" do
@@ -850,7 +1736,6 @@ describe Mongoid::Contextual::Mongo do
850
1736
  end
851
1737
 
852
1738
  it "returns the updated document" do
853
- expect(result.name).to be_nil
854
1739
  expect(result.likes).to eq(1)
855
1740
  end
856
1741
  end
@@ -867,7 +1752,7 @@ describe Mongoid::Contextual::Mongo do
867
1752
  end
868
1753
 
869
1754
  let!(:result) do
870
- context.find_one_and_replace({ likes: 1 }, return_document: :after)
1755
+ context.find_one_and_update({ "$inc" => { likes: 1 }}, return_document: :after)
871
1756
  end
872
1757
 
873
1758
  it "returns the first matching document" do
@@ -876,7 +1761,6 @@ describe Mongoid::Contextual::Mongo do
876
1761
 
877
1762
  it "returns the updated document" do
878
1763
  expect(result.likes).to eq(1)
879
- expect(result.name).to be_nil
880
1764
  end
881
1765
  end
882
1766
  end
@@ -884,7 +1768,7 @@ describe Mongoid::Contextual::Mongo do
884
1768
  context "when the selector does not match" do
885
1769
 
886
1770
  let(:criteria) do
887
- Band.where(name: "DEPECHE MODE")
1771
+ Band.where(name: "Placebo")
888
1772
  end
889
1773
 
890
1774
  let(:context) do
@@ -892,7 +1776,84 @@ describe Mongoid::Contextual::Mongo do
892
1776
  end
893
1777
 
894
1778
  let(:result) do
895
- context.find_one_and_replace(name: 'FKA Twigs')
1779
+ context.find_one_and_update("$inc" => { likes: 1 })
1780
+ end
1781
+
1782
+ it "returns nil" do
1783
+ expect(result).to be_nil
1784
+ end
1785
+ end
1786
+ end
1787
+
1788
+ describe "#find_one_and_delete" do
1789
+
1790
+ let!(:depeche) do
1791
+ Band.create!(name: "Depeche Mode")
1792
+ end
1793
+
1794
+ let(:criteria) do
1795
+ Band.where(name: "Depeche Mode")
1796
+ end
1797
+
1798
+ let(:context) do
1799
+ described_class.new(criteria)
1800
+ end
1801
+
1802
+ let!(:result) do
1803
+ context.find_one_and_delete
1804
+ end
1805
+
1806
+ context 'when the selector matches a document' do
1807
+
1808
+ it "returns the first matching document" do
1809
+ expect(result).to eq(depeche)
1810
+ end
1811
+
1812
+ it "deletes the document from the database" do
1813
+ expect {
1814
+ depeche.reload
1815
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Band with id\(s\)/)
1816
+ end
1817
+
1818
+ context 'when a collation is specified on the criteria' do
1819
+ min_server_version '3.4'
1820
+
1821
+ let(:criteria) do
1822
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
1823
+ end
1824
+
1825
+ let(:context) do
1826
+ described_class.new(criteria)
1827
+ end
1828
+
1829
+ let!(:result) do
1830
+ context.find_one_and_delete
1831
+ end
1832
+
1833
+ it "returns the first matching document" do
1834
+ expect(result).to eq(depeche)
1835
+ end
1836
+
1837
+ it "deletes the document from the database" do
1838
+ expect {
1839
+ depeche.reload
1840
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Band with id\(s\)/)
1841
+ end
1842
+ end
1843
+ end
1844
+
1845
+ context 'when the selector does not match a document' do
1846
+
1847
+ let(:criteria) do
1848
+ Band.where(name: "Placebo")
1849
+ end
1850
+
1851
+ let(:context) do
1852
+ described_class.new(criteria)
1853
+ end
1854
+
1855
+ let(:result) do
1856
+ context.find_one_and_delete
896
1857
  end
897
1858
 
898
1859
  it "returns nil" do
@@ -901,42 +1862,100 @@ describe Mongoid::Contextual::Mongo do
901
1862
  end
902
1863
  end
903
1864
 
904
- describe "#find_one_and_update" do
1865
+ [ :first, :one ].each do |method|
1866
+
1867
+ describe "##{method}" do
1868
+
1869
+ let!(:depeche_mode) do
1870
+ Band.create!(name: "Depeche Mode")
1871
+ end
1872
+
1873
+ let!(:new_order) do
1874
+ Band.create!(name: "New Order")
1875
+ end
1876
+
1877
+ let!(:rolling_stones) do
1878
+ Band.create!(name: "The Rolling Stones")
1879
+ end
1880
+
1881
+ context "when the context is not cached" do
1882
+
1883
+ let(:criteria) do
1884
+ Band.where(name: "Depeche Mode")
1885
+ end
1886
+
1887
+ let(:context) do
1888
+ described_class.new(criteria)
1889
+ end
1890
+
1891
+ it "returns the first matching document" do
1892
+ expect(context.send(method)).to eq(depeche_mode)
1893
+ end
1894
+
1895
+ context 'when the criteria has a collation' do
1896
+ min_server_version '3.4'
1897
+
1898
+ let(:criteria) do
1899
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
1900
+ end
1901
+
1902
+ it "returns the first matching document" do
1903
+ expect(context.send(method)).to eq(depeche_mode)
1904
+ end
1905
+ end
1906
+ end
1907
+
1908
+ context "when using .desc" do
1909
+
1910
+ let(:criteria) do
1911
+ Band.desc(:name)
1912
+ end
1913
+
1914
+ let(:context) do
1915
+ described_class.new(criteria)
1916
+ end
1917
+
1918
+ context "when there is sort on the context" do
905
1919
 
906
- let!(:depeche) do
907
- Band.create(name: "Depeche Mode")
908
- end
1920
+ it "follows the main sort" do
1921
+ expect(context.send(method)).to eq(rolling_stones)
1922
+ end
1923
+ end
909
1924
 
910
- let!(:tool) do
911
- Band.create(name: "Tool")
912
- end
1925
+ context "when subsequently calling #last" do
913
1926
 
914
- context "when the selector matches" do
1927
+ it "returns the correct document" do
1928
+ expect(context.send(method)).to eq(rolling_stones)
1929
+ expect(context.last).to eq(depeche_mode)
1930
+ end
1931
+ end
1932
+ end
915
1933
 
916
- context "when not providing options" do
1934
+ context 'when the criteria has no sort' do
917
1935
 
918
1936
  let(:criteria) do
919
- Band.where(name: "Depeche Mode")
1937
+ Band.all
920
1938
  end
921
1939
 
922
1940
  let(:context) do
923
1941
  described_class.new(criteria)
924
1942
  end
925
1943
 
926
- let!(:result) do
927
- context.find_one_and_update("$inc" => { likes: 1 })
928
- end
929
1944
 
930
- it "returns the first matching document" do
931
- expect(result).to eq(depeche)
1945
+ it 'applies a sort on _id' do
1946
+ expect(context.send(method)).to eq(depeche_mode)
932
1947
  end
933
1948
 
934
- it "updates the document in the database" do
935
- expect(depeche.reload.likes).to eq(1)
1949
+ context 'when calling #last' do
1950
+
1951
+ it 'returns the last document, sorted by _id' do
1952
+ expect(context.send(method)).to eq(depeche_mode)
1953
+ expect(context.last).to eq(rolling_stones)
1954
+ end
936
1955
  end
937
1956
  end
938
1957
 
939
- context "when sorting" do
1958
+ context 'when the criteria has a sort' do
940
1959
 
941
1960
  let(:criteria) do
942
1961
  Band.desc(:name)
@@ -946,47 +1965,47 @@ describe Mongoid::Contextual::Mongo do
946
1965
  described_class.new(criteria)
947
1966
  end
948
1967
 
949
- let!(:result) do
950
- context.find_one_and_update("$inc" => { likes: 1 })
1968
+ it 'applies the criteria sort' do
1969
+ expect(context.send(method)).to eq(rolling_stones)
951
1970
  end
952
1971
 
953
- it "returns the first matching document" do
954
- expect(result).to eq(tool)
955
- end
1972
+ context 'when calling #last' do
956
1973
 
957
- it "updates the document in the database" do
958
- expect(tool.reload.likes).to eq(1)
1974
+ it 'applies the criteria sort' do
1975
+ expect(context.send(method)).to eq(rolling_stones)
1976
+ expect(context.last).to eq(depeche_mode)
1977
+ end
959
1978
  end
960
1979
  end
961
1980
 
962
- context "when limiting fields" do
1981
+ context "when using .sort" do
963
1982
 
964
1983
  let(:criteria) do
965
- Band.only(:_id)
1984
+ Band.all.sort(:name => -1).criteria
966
1985
  end
967
1986
 
968
1987
  let(:context) do
969
1988
  described_class.new(criteria)
970
1989
  end
971
1990
 
972
- let!(:result) do
973
- context.find_one_and_update("$inc" => { likes: 1 })
974
- end
1991
+ context "when there is sort on the context" do
975
1992
 
976
- it "returns the first matching document" do
977
- expect(result).to eq(depeche)
1993
+ it "follows the main sort" do
1994
+ expect(context.send(method)).to eq(rolling_stones)
1995
+ end
978
1996
  end
979
1997
 
980
- it "limits the returned fields" do
981
- expect(result.name).to be_nil
982
- end
1998
+ context "when subsequently calling #last" do
983
1999
 
984
- it "updates the document in the database" do
985
- expect(depeche.reload.likes).to eq(1)
2000
+ it "returns the correct document" do
2001
+ expect(context.send(method)).to eq(rolling_stones)
2002
+ expect(context.last).to eq(depeche_mode)
2003
+ end
986
2004
  end
987
2005
  end
988
2006
 
989
- context "when returning new" do
2007
+ context "when the query cache is enabled" do
2008
+ query_cache_enabled
990
2009
 
991
2010
  let(:criteria) do
992
2011
  Band.where(name: "Depeche Mode")
@@ -996,350 +2015,546 @@ describe Mongoid::Contextual::Mongo do
996
2015
  described_class.new(criteria)
997
2016
  end
998
2017
 
999
- let!(:result) do
1000
- context.find_one_and_update({ "$inc" => { likes: 1 }}, return_document: :after)
1001
- end
2018
+ context "when first method was called before" do
1002
2019
 
1003
- it "returns the first matching document" do
1004
- expect(result).to eq(depeche)
1005
- end
2020
+ before do
2021
+ context.first
2022
+ end
1006
2023
 
1007
- it "returns the updated document" do
1008
- expect(result.likes).to eq(1)
2024
+ it "returns the first document without touching the database" do
2025
+ expect_no_queries do
2026
+ expect(context.send(method)).to eq(depeche_mode)
2027
+ end
2028
+ end
1009
2029
  end
1010
2030
  end
1011
2031
 
1012
- context 'when a collation is specified on the criteria' do
1013
- min_server_version '3.4'
2032
+ context "when including a limit" do
1014
2033
 
1015
- let(:criteria) do
1016
- Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
2034
+ context "when the context is not cached" do
2035
+
2036
+ let(:context) do
2037
+ described_class.new(criteria)
2038
+ end
2039
+
2040
+ context "when the limit is 1" do
2041
+ let(:criteria) do
2042
+ Band.criteria
2043
+ end
2044
+
2045
+ let(:docs) do
2046
+ context.send(method, 1)
2047
+ end
2048
+
2049
+ it "returns an array of documents" do
2050
+ expect(docs).to eq([ depeche_mode ])
2051
+ end
2052
+ end
2053
+
2054
+ context "when the limit is >1" do
2055
+ let(:criteria) do
2056
+ Band.criteria
2057
+ end
2058
+
2059
+ let(:docs) do
2060
+ context.send(method, 2)
2061
+ end
2062
+
2063
+ it "returns the number of documents in order" do
2064
+ expect(docs).to eq([ depeche_mode, new_order ])
2065
+ end
2066
+ end
2067
+
2068
+ context 'when the criteria has a collation' do
2069
+ min_server_version '3.4'
2070
+
2071
+ let(:criteria) do
2072
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
2073
+ end
2074
+
2075
+ it "returns the first matching document" do
2076
+ expect(context.send(method, 1)).to eq([ depeche_mode ])
2077
+ end
2078
+ end
2079
+ end
2080
+
2081
+ context "when the query cache is enabled" do
2082
+
2083
+ let(:context) do
2084
+ described_class.new(criteria)
2085
+ end
2086
+
2087
+ context "when calling first beforehand" do
2088
+ query_cache_enabled
2089
+
2090
+ let(:context) do
2091
+ described_class.new(criteria)
2092
+ end
2093
+
2094
+ let(:criteria) do
2095
+ Band.all
2096
+ end
2097
+
2098
+ before do
2099
+ context.first(before_limit)
2100
+ end
2101
+
2102
+ let(:docs) do
2103
+ context.send(method, limit)
2104
+ end
2105
+
2106
+ context "when getting all of the documents before" do
2107
+ let(:before_limit) { 3 }
2108
+
2109
+ context "when getting all of the documents" do
2110
+ let(:limit) { 3 }
2111
+
2112
+ it "returns all documents without touching the database" do
2113
+ expect_no_queries do
2114
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2115
+ end
2116
+ end
2117
+ end
2118
+
2119
+ context "when getting fewer documents" do
2120
+ let(:limit) { 2 }
2121
+
2122
+ it "returns the correct documents without touching the database" do
2123
+ expect_no_queries do
2124
+ expect(docs).to eq([ depeche_mode, new_order ])
2125
+ end
2126
+ end
2127
+ end
2128
+ end
2129
+
2130
+ context "when getting fewer documents before" do
2131
+ let(:before_limit) { 2 }
2132
+
2133
+ context "when getting the same number of documents" do
2134
+ let(:limit) { 2 }
2135
+
2136
+ it "returns the correct documents without touching the database" do
2137
+ expect_no_queries do
2138
+ expect(docs).to eq([ depeche_mode, new_order ])
2139
+ end
2140
+ end
2141
+ end
2142
+
2143
+ context "when getting more documents" do
2144
+ let(:limit) { 3 }
2145
+
2146
+ it "returns the correct documents and touches the database" do
2147
+ expect_query(1) do
2148
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2149
+ end
2150
+ end
2151
+ end
2152
+ end
2153
+
2154
+ context "when getting one document before" do
2155
+ let(:before_limit) { 1 }
2156
+
2157
+ context "when getting one document" do
2158
+ let(:limit) { 1 }
2159
+
2160
+ it "returns the correct documents without touching the database" do
2161
+ expect_no_queries do
2162
+ expect(docs).to eq([ depeche_mode ])
2163
+ end
2164
+ end
2165
+ end
2166
+
2167
+ context "when getting more than one document" do
2168
+ let(:limit) { 3 }
2169
+
2170
+ it "returns the correct documents and touches the database" do
2171
+ expect_query(1) do
2172
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2173
+ end
2174
+ end
2175
+ end
2176
+ end
2177
+ end
1017
2178
  end
2179
+ end
2180
+
2181
+ context "when calling #first then #last and the query cache is enabled" do
2182
+ query_cache_enabled
1018
2183
 
1019
2184
  let(:context) do
1020
2185
  described_class.new(criteria)
1021
2186
  end
1022
2187
 
1023
- let!(:result) do
1024
- context.find_one_and_update({ "$inc" => { likes: 1 }}, return_document: :after)
2188
+ let(:criteria) do
2189
+ Band.all
1025
2190
  end
1026
2191
 
1027
- it "returns the first matching document" do
1028
- expect(result).to eq(depeche)
2192
+ before do
2193
+ context.first(before_limit)
1029
2194
  end
1030
2195
 
1031
- it "returns the updated document" do
1032
- expect(result.likes).to eq(1)
2196
+ let(:docs) do
2197
+ context.last(limit)
1033
2198
  end
1034
- end
1035
- end
1036
-
1037
- context "when the selector does not match" do
1038
-
1039
- let(:criteria) do
1040
- Band.where(name: "Placebo")
1041
- end
1042
2199
 
1043
- let(:context) do
1044
- described_class.new(criteria)
1045
- end
1046
-
1047
- let(:result) do
1048
- context.find_one_and_update("$inc" => { likes: 1 })
1049
- end
2200
+ context "when getting one from the beginning and one from the end" do
2201
+ let(:before_limit) { 2 }
2202
+ let(:limit) { 1 }
1050
2203
 
1051
- it "returns nil" do
1052
- expect(result).to be_nil
2204
+ it "gets the correct document and hits the database" do
2205
+ expect_query(1) do
2206
+ expect(docs).to eq([rolling_stones])
2207
+ end
2208
+ end
2209
+ end
1053
2210
  end
1054
2211
  end
1055
2212
  end
1056
2213
 
1057
- describe "#find_one_and_delete" do
1058
-
1059
- let!(:depeche) do
1060
- Band.create(name: "Depeche Mode")
2214
+ describe "#last" do
2215
+ let!(:depeche_mode) do
2216
+ Band.create!(name: "Depeche Mode")
1061
2217
  end
1062
2218
 
1063
- let(:criteria) do
1064
- Band.where(name: "Depeche Mode")
2219
+ let!(:new_order) do
2220
+ Band.create!(name: "New Order")
1065
2221
  end
1066
2222
 
1067
- let(:context) do
1068
- described_class.new(criteria)
2223
+ let!(:rolling_stones) do
2224
+ Band.create!(name: "The Rolling Stones")
1069
2225
  end
1070
2226
 
1071
- let!(:result) do
1072
- context.find_one_and_delete
1073
- end
2227
+ context "when the context is not cached" do
1074
2228
 
1075
- context 'when the selector matches a document' do
2229
+ let(:criteria) do
2230
+ Band.where(name: "Depeche Mode")
2231
+ end
1076
2232
 
1077
- it "returns the first matching document" do
1078
- expect(result).to eq(depeche)
2233
+ let(:context) do
2234
+ described_class.new(criteria)
1079
2235
  end
1080
2236
 
1081
- it "deletes the document from the database" do
1082
- expect {
1083
- depeche.reload
1084
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2237
+ it "returns the last matching document" do
2238
+ expect(context.last).to eq(depeche_mode)
1085
2239
  end
1086
2240
 
1087
- context 'when a collation is specified on the criteria' do
2241
+ context 'when the criteria has a collation' do
1088
2242
  min_server_version '3.4'
1089
2243
 
1090
2244
  let(:criteria) do
1091
2245
  Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
1092
2246
  end
1093
2247
 
1094
- let(:context) do
1095
- described_class.new(criteria)
2248
+ it "returns the last matching document" do
2249
+ expect(context.last).to eq(depeche_mode)
1096
2250
  end
2251
+ end
2252
+ end
1097
2253
 
1098
- let!(:result) do
1099
- context.find_one_and_delete
1100
- end
2254
+ context "when using .desc" do
1101
2255
 
1102
- it "returns the first matching document" do
1103
- expect(result).to eq(depeche)
2256
+ let(:criteria) do
2257
+ Band.desc(:name)
2258
+ end
2259
+
2260
+ let(:context) do
2261
+ described_class.new(criteria)
2262
+ end
2263
+
2264
+ context "when there is sort on the context" do
2265
+
2266
+ it "follows the main sort" do
2267
+ expect(context.last).to eq(depeche_mode)
1104
2268
  end
2269
+ end
1105
2270
 
1106
- it "deletes the document from the database" do
1107
- expect {
1108
- depeche.reload
1109
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2271
+ context "when subsequently calling #first" do
2272
+
2273
+ it "returns the correct document" do
2274
+ expect(context.last).to eq(depeche_mode)
2275
+ expect(context.first).to eq(rolling_stones)
1110
2276
  end
1111
2277
  end
1112
2278
  end
1113
2279
 
1114
- context 'when the selector does not match a document' do
2280
+ context 'when the criteria has no sort' do
1115
2281
 
1116
2282
  let(:criteria) do
1117
- Band.where(name: "Placebo")
2283
+ Band.all
1118
2284
  end
1119
2285
 
1120
2286
  let(:context) do
1121
2287
  described_class.new(criteria)
1122
2288
  end
1123
2289
 
1124
- let(:result) do
1125
- context.find_one_and_delete
2290
+ it 'applies a sort on _id' do
2291
+ expect(context.last).to eq(rolling_stones)
1126
2292
  end
1127
2293
 
1128
- it "returns nil" do
1129
- expect(result).to be_nil
2294
+ context 'when calling #first' do
2295
+
2296
+ it 'returns the first document, sorted by _id' do
2297
+ expect(context.last).to eq(rolling_stones)
2298
+ expect(context.first).to eq(depeche_mode)
2299
+ end
1130
2300
  end
1131
2301
  end
1132
- end
1133
2302
 
1134
- [ :first, :one ].each do |method|
2303
+ context 'when the criteria has a sort' do
1135
2304
 
1136
- describe "##{method}" do
2305
+ let(:criteria) do
2306
+ Band.desc(:name)
2307
+ end
2308
+
2309
+ let(:context) do
2310
+ described_class.new(criteria)
2311
+ end
2312
+
2313
+
2314
+ it 'applies the criteria sort' do
2315
+ expect(context.last).to eq(depeche_mode)
2316
+ end
2317
+
2318
+ context 'when calling #first' do
2319
+
2320
+ it 'applies the criteria sort' do
2321
+ expect(context.last).to eq(depeche_mode)
2322
+ expect(context.first).to eq(rolling_stones)
2323
+ end
2324
+ end
2325
+ end
2326
+
2327
+ context "when using .sort" do
1137
2328
 
1138
- let!(:depeche_mode) do
1139
- Band.create(name: "Depeche Mode")
2329
+ let(:criteria) do
2330
+ Band.all.sort(:name => -1).criteria
1140
2331
  end
1141
2332
 
1142
- let!(:new_order) do
1143
- Band.create(name: "New Order")
2333
+ let(:context) do
2334
+ described_class.new(criteria)
1144
2335
  end
1145
2336
 
1146
- context "when the context is not cached" do
1147
-
1148
- let(:criteria) do
1149
- Band.where(name: "Depeche Mode")
1150
- end
1151
-
1152
- let(:context) do
1153
- described_class.new(criteria)
1154
- end
2337
+ context "when there is sort on the context" do
1155
2338
 
1156
- it "returns the first matching document" do
1157
- expect(context.send(method)).to eq(depeche_mode)
2339
+ it "follows the main sort" do
2340
+ expect(context.last).to eq(depeche_mode)
1158
2341
  end
2342
+ end
1159
2343
 
1160
- context 'when the criteria has a collation' do
1161
- min_server_version '3.4'
1162
-
1163
- let(:criteria) do
1164
- Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
1165
- end
2344
+ context "when subsequently calling #first" do
1166
2345
 
1167
- it "returns the first matching document" do
1168
- expect(context.send(method)).to eq(depeche_mode)
1169
- end
2346
+ it "returns the correct document" do
2347
+ expect(context.last).to eq(depeche_mode)
2348
+ expect(context.first).to eq(rolling_stones)
1170
2349
  end
1171
2350
  end
2351
+ end
1172
2352
 
1173
- context "when using .desc" do
2353
+ context "when the query cache is enabled" do
2354
+ query_cache_enabled
1174
2355
 
1175
- let(:criteria) do
1176
- Band.desc(:name)
1177
- end
2356
+ let(:criteria) do
2357
+ Band.where(name: "Depeche Mode")
2358
+ end
1178
2359
 
1179
- let(:context) do
1180
- described_class.new(criteria)
1181
- end
2360
+ let(:context) do
2361
+ described_class.new(criteria)
2362
+ end
1182
2363
 
1183
- context "when there is sort on the context" do
2364
+ context "when last method was called before" do
1184
2365
 
1185
- it "follows the main sort" do
1186
- expect(context.send(method)).to eq(new_order)
1187
- end
2366
+ before do
2367
+ context.last
1188
2368
  end
1189
2369
 
1190
- context "when subsequently calling #last" do
1191
-
1192
- it "returns the correct document" do
1193
- expect(context.send(method)).to eq(new_order)
2370
+ it "returns the last document without touching the database" do
2371
+ expect_no_queries do
1194
2372
  expect(context.last).to eq(depeche_mode)
1195
2373
  end
1196
2374
  end
1197
2375
  end
2376
+ end
1198
2377
 
1199
- context 'when the criteria has no sort' do
2378
+ context "when including a limit" do
1200
2379
 
1201
- let(:criteria) do
1202
- Band.all
1203
- end
2380
+ context "when the context is not cached" do
1204
2381
 
1205
2382
  let(:context) do
1206
2383
  described_class.new(criteria)
1207
2384
  end
1208
2385
 
2386
+ context "when the limit is 1" do
2387
+ let(:criteria) do
2388
+ Band.criteria
2389
+ end
1209
2390
 
1210
- it 'applies a sort on _id' do
1211
- expect(context.send(method)).to eq(depeche_mode)
1212
- end
1213
-
1214
- context 'when calling #last' do
2391
+ let(:docs) do
2392
+ context.last(1)
2393
+ end
1215
2394
 
1216
- it 'returns the last document, sorted by _id' do
1217
- expect(context.send(method)).to eq(depeche_mode)
1218
- expect(context.last).to eq(new_order)
2395
+ it "returns an array of documents" do
2396
+ expect(docs).to eq([ rolling_stones ])
1219
2397
  end
1220
2398
  end
1221
2399
 
1222
- context 'with option { sort: :none }' do
2400
+ context "when the limit is >1" do
2401
+ let(:criteria) do
2402
+ Band.criteria
2403
+ end
1223
2404
 
1224
- let(:opts) do
1225
- { id_sort: :none }
2405
+ let(:docs) do
2406
+ context.last(2)
1226
2407
  end
1227
2408
 
1228
- it 'does not apply the sort on _id' do
1229
- expect(context.send(method, opts)).to eq(depeche_mode)
2409
+ it "returns the number of documents in order" do
2410
+ expect(docs).to eq([ new_order, rolling_stones ])
1230
2411
  end
2412
+ end
1231
2413
 
1232
- context 'when calling #last' do
2414
+ context 'when the criteria has a collation' do
2415
+ min_server_version '3.4'
1233
2416
 
1234
- it 'does not apply a sort on _id' do
1235
- expect(context.send(method, opts)).to eq(depeche_mode)
1236
- expect(context.last(opts)).to eq(depeche_mode)
1237
- end
2417
+ let(:criteria) do
2418
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
2419
+ end
2420
+
2421
+ it "returns the first matching document" do
2422
+ expect(context.last(1)).to eq([ depeche_mode ])
1238
2423
  end
1239
2424
  end
1240
2425
  end
1241
2426
 
1242
- context 'when the criteria has a sort' do
1243
-
1244
- let(:criteria) do
1245
- Band.desc(:name)
1246
- end
2427
+ context "when the context is cached" do
1247
2428
 
1248
2429
  let(:context) do
1249
2430
  described_class.new(criteria)
1250
2431
  end
1251
2432
 
2433
+ context "when query cache is enabled" do
2434
+ query_cache_enabled
1252
2435
 
1253
- it 'applies the criteria sort' do
1254
- expect(context.send(method)).to eq(new_order)
1255
- end
1256
-
1257
- context 'when calling #last' do
1258
-
1259
- it 'applies the criteria sort' do
1260
- expect(context.send(method)).to eq(new_order)
1261
- expect(context.last).to eq(depeche_mode)
2436
+ let(:context) do
2437
+ described_class.new(criteria)
1262
2438
  end
1263
- end
1264
2439
 
1265
- context 'with option { sort: :none }' do
2440
+ let(:criteria) do
2441
+ Band.all
2442
+ end
1266
2443
 
1267
- let(:opts) do
1268
- { id_sort: :none }
2444
+ before do
2445
+ context.last(before_limit)
1269
2446
  end
1270
2447
 
1271
- it 'applies the criteria sort' do
1272
- expect(context.send(method, opts)).to eq(new_order)
2448
+ let(:docs) do
2449
+ context.last(limit)
1273
2450
  end
1274
2451
 
1275
- context 'when calling #last' do
2452
+ context "when getting all of the documents before" do
2453
+ let(:before_limit) { 3 }
2454
+
2455
+ context "when getting all of the documents" do
2456
+ let(:limit) { 3 }
2457
+
2458
+ it "returns all documents without touching the db" do
2459
+ expect_no_queries do
2460
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2461
+ end
2462
+ end
2463
+ end
2464
+
2465
+ context "when getting fewer documents" do
2466
+ let(:limit) { 2 }
1276
2467
 
1277
- it 'applies the criteria sort' do
1278
- expect(context.send(method, opts)).to eq(new_order)
1279
- expect(context.last(opts)).to eq(depeche_mode)
2468
+ it "returns the correct documents without touching the db" do
2469
+ expect_no_queries do
2470
+ expect(docs).to eq([ new_order, rolling_stones ])
2471
+ end
2472
+ end
1280
2473
  end
1281
2474
  end
1282
- end
1283
- end
1284
2475
 
1285
- context "when using .sort" do
2476
+ context "when getting fewer documents before" do
2477
+ let(:before_limit) { 2 }
1286
2478
 
1287
- let(:criteria) do
1288
- Band.all.sort(:name => -1).criteria
1289
- end
2479
+ context "when getting the same number of documents" do
2480
+ let(:limit) { 2 }
1290
2481
 
1291
- let(:context) do
1292
- described_class.new(criteria)
1293
- end
2482
+ it "returns the correct documents without touching the db" do
2483
+ expect_no_queries do
2484
+ expect(docs).to eq([ new_order, rolling_stones ])
2485
+ end
2486
+ end
2487
+ end
1294
2488
 
1295
- context "when there is sort on the context" do
2489
+ context "when getting more documents" do
2490
+ let(:limit) { 3 }
1296
2491
 
1297
- it "follows the main sort" do
1298
- expect(context.send(method)).to eq(new_order)
2492
+ it "returns the correct documents and touches the database" do
2493
+ expect_query(1) do
2494
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2495
+ end
2496
+ end
2497
+ end
1299
2498
  end
1300
- end
1301
2499
 
1302
- context "when subsequently calling #last" do
2500
+ context "when getting one document before" do
2501
+ let(:before_limit) { 1 }
1303
2502
 
1304
- it "returns the correct document" do
1305
- expect(context.send(method)).to eq(new_order)
1306
- expect(context.last).to eq(depeche_mode)
2503
+ context "when getting one document" do
2504
+ let(:limit) { 1 }
2505
+
2506
+ it "returns the correct documents without touching the database" do
2507
+ expect_no_queries do
2508
+ expect(docs).to eq([ rolling_stones ])
2509
+ end
2510
+ end
2511
+ end
2512
+
2513
+ context "when getting more than one document" do
2514
+ let(:limit) { 3 }
2515
+
2516
+ it "returns the correct documents and touches the database" do
2517
+ expect_query(1) do
2518
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2519
+ end
2520
+ end
2521
+ end
1307
2522
  end
1308
2523
  end
1309
2524
  end
2525
+ end
1310
2526
 
1311
- context "when the context is cached" do
1312
-
1313
- let(:criteria) do
1314
- Band.where(name: "Depeche Mode").cache
1315
- end
2527
+ context "when calling #last then #first and the query cache is enabled" do
2528
+ query_cache_enabled
1316
2529
 
1317
- let(:context) do
1318
- described_class.new(criteria)
1319
- end
2530
+ let(:context) do
2531
+ described_class.new(criteria)
2532
+ end
1320
2533
 
1321
- context "when the cache is loaded" do
2534
+ let(:criteria) do
2535
+ Band.all
2536
+ end
1322
2537
 
1323
- before do
1324
- context.to_a
1325
- end
2538
+ before do
2539
+ context.last(before_limit)
2540
+ end
1326
2541
 
1327
- it "returns the first document without touching the database" do
1328
- expect(context).to receive(:view).never
1329
- expect(context.send(method)).to eq(depeche_mode)
1330
- end
1331
- end
2542
+ let(:docs) do
2543
+ context.first(limit)
2544
+ end
1332
2545
 
1333
- context "when first method was called before" do
2546
+ context "when getting one from the beginning and one from the end" do
2547
+ let(:before_limit) { 2 }
2548
+ let(:limit) { 1 }
1334
2549
 
1335
- before do
1336
- context.first
2550
+ it "hits the database" do
2551
+ expect_query(1) do
2552
+ docs
1337
2553
  end
2554
+ end
1338
2555
 
1339
- it "returns the first document without touching the database" do
1340
- expect(context).to receive(:view).never
1341
- expect(context.send(method)).to eq(depeche_mode)
1342
- end
2556
+ it "gets the correct document" do
2557
+ expect(docs).to eq([ depeche_mode ])
1343
2558
  end
1344
2559
  end
1345
2560
  end
@@ -1377,8 +2592,8 @@ describe Mongoid::Contextual::Mongo do
1377
2592
  describe "##{method}" do
1378
2593
 
1379
2594
  before do
1380
- Band.create(name: "Depeche Mode")
1381
- Band.create(name: "New Order")
2595
+ Band.create!(name: "Depeche Mode")
2596
+ Band.create!(name: "New Order")
1382
2597
  end
1383
2598
 
1384
2599
  context "when the criteria has a limit" do
@@ -1391,41 +2606,28 @@ describe Mongoid::Contextual::Mongo do
1391
2606
  described_class.new(criteria)
1392
2607
  end
1393
2608
 
1394
- it "returns the number of documents that match" do
1395
- expect(context.send(method)).to eq(2)
1396
- end
1397
-
1398
- context "when calling more than once" do
1399
-
1400
- before do
1401
- expect(context.view).to receive(:count).once.and_return(2)
1402
- end
2609
+ context "when broken_view_options is false" do
2610
+ driver_config_override :broken_view_options, false
1403
2611
 
1404
- it "returns the cached value for subsequent calls" do
1405
- 2.times { expect(context.send(method)).to eq(2) }
2612
+ it "returns the number of documents that match" do
2613
+ expect(context.send(method)).to eq(1)
1406
2614
  end
1407
2615
  end
1408
2616
 
1409
- context "when the results have been iterated over" do
1410
-
1411
- before do
1412
- context.entries
1413
- expect(context.view).to receive(:count).once.and_return(2)
1414
- end
2617
+ context "when broken_view_options is true" do
2618
+ driver_config_override :broken_view_options, true
1415
2619
 
1416
- it "returns the cached value for all calls" do
2620
+ it "returns the number of documents that match" do
1417
2621
  expect(context.send(method)).to eq(2)
1418
2622
  end
2623
+ end
1419
2624
 
1420
- context "when the results have been iterated over multiple times" do
1421
-
1422
- before do
1423
- context.entries
1424
- end
2625
+ context "when calling more than once with different limits" do
2626
+ driver_config_override :broken_view_options, false
1425
2627
 
1426
- it "resets the length on each full iteration" do
1427
- expect(context.size).to eq(2)
1428
- end
2628
+ it "does not cache the value" do
2629
+ expect(context.limit(1).send(method)).to eq(1)
2630
+ expect(context.limit(2).send(method)).to eq(2)
1429
2631
  end
1430
2632
  end
1431
2633
  end
@@ -1444,14 +2646,12 @@ describe Mongoid::Contextual::Mongo do
1444
2646
  expect(context.send(method)).to eq(1)
1445
2647
  end
1446
2648
 
1447
- context "when calling more than once" do
1448
-
1449
- before do
1450
- expect(context.view).to receive(:count).once.and_return(1)
1451
- end
2649
+ context "when calling more than once with different skips" do
2650
+ driver_config_override :broken_view_options, false
1452
2651
 
1453
- it "returns the cached value for subsequent calls" do
1454
- 2.times { expect(context.send(method)).to eq(1) }
2652
+ it "does not cache the value" do
2653
+ expect(context.skip(0).send(method)).to eq(1)
2654
+ expect(context.skip(1).send(method)).to eq(0)
1455
2655
  end
1456
2656
  end
1457
2657
 
@@ -1459,10 +2659,10 @@ describe Mongoid::Contextual::Mongo do
1459
2659
 
1460
2660
  before do
1461
2661
  context.entries
1462
- expect(context.view).to receive(:count).once.and_return(1)
1463
2662
  end
1464
2663
 
1465
2664
  it "returns the cached value for all calls" do
2665
+ expect(context.view).to receive(:count_documents).once.and_return(1)
1466
2666
  expect(context.send(method)).to eq(1)
1467
2667
  end
1468
2668
 
@@ -1484,11 +2684,11 @@ describe Mongoid::Contextual::Mongo do
1484
2684
  describe "#limit" do
1485
2685
 
1486
2686
  let!(:depeche_mode) do
1487
- Band.create(name: "Depeche Mode")
2687
+ Band.create!(name: "Depeche Mode")
1488
2688
  end
1489
2689
 
1490
2690
  let!(:new_order) do
1491
- Band.create(name: "New Order")
2691
+ Band.create!(name: "New Order")
1492
2692
  end
1493
2693
 
1494
2694
  let(:criteria) do
@@ -1504,11 +2704,85 @@ describe Mongoid::Contextual::Mongo do
1504
2704
  end
1505
2705
  end
1506
2706
 
2707
+ describe "#take" do
2708
+
2709
+ let!(:depeche_mode) do
2710
+ Band.create!(name: "Depeche Mode")
2711
+ end
2712
+
2713
+ let!(:new_order) do
2714
+ Band.create!(name: "New Order")
2715
+ end
2716
+
2717
+ let!(:rolling_stones) do
2718
+ Band.create!(name: "The Rolling Stones")
2719
+ end
2720
+
2721
+ let(:criteria) do
2722
+ Band.all
2723
+ end
2724
+
2725
+ let(:context) do
2726
+ described_class.new(criteria)
2727
+ end
2728
+
2729
+ it "takes the correct number results" do
2730
+ expect(context.take(2)).to eq([ depeche_mode, new_order ])
2731
+ end
2732
+
2733
+ it "returns an array when passing 1" do
2734
+ expect(context.take(1)).to eq([ depeche_mode ])
2735
+ end
2736
+
2737
+ it "does not return an array when not passing an argument" do
2738
+ expect(context.take).to eq(depeche_mode)
2739
+ end
2740
+
2741
+ it "returns all the documents taking more than whats in the db" do
2742
+ expect(context.take(5)).to eq([ depeche_mode, new_order, rolling_stones ])
2743
+ end
2744
+ end
2745
+
2746
+ describe "#take!" do
2747
+
2748
+ let!(:depeche_mode) do
2749
+ Band.create!(name: "Depeche Mode")
2750
+ end
2751
+
2752
+ let!(:new_order) do
2753
+ Band.create!(name: "New Order")
2754
+ end
2755
+
2756
+ let!(:rolling_stones) do
2757
+ Band.create!(name: "The Rolling Stones")
2758
+ end
2759
+
2760
+ let(:criteria) do
2761
+ Band.all
2762
+ end
2763
+
2764
+ let(:context) do
2765
+ described_class.new(criteria)
2766
+ end
2767
+
2768
+ it "takes the first document" do
2769
+ expect(context.take!).to eq(depeche_mode)
2770
+ end
2771
+
2772
+ context "when there are no documents" do
2773
+ it "raises an error" do
2774
+ expect do
2775
+ Person.take!
2776
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Person./)
2777
+ end
2778
+ end
2779
+ end
2780
+
1507
2781
  describe "#map" do
1508
2782
 
1509
2783
  before do
1510
- Band.create(name: "Depeche Mode")
1511
- Band.create(name: "New Order")
2784
+ Band.create!(name: "Depeche Mode")
2785
+ Band.create!(name: "New Order")
1512
2786
  end
1513
2787
 
1514
2788
  let(:criteria) do
@@ -1521,8 +2795,10 @@ describe Mongoid::Contextual::Mongo do
1521
2795
 
1522
2796
  context "when passed the symbol field name" do
1523
2797
 
1524
- it "performs mapping" do
1525
- expect(context.map(:name)).to eq ["Depeche Mode", "New Order"]
2798
+ it "raises an error" do
2799
+ expect do
2800
+ context.map(:name)
2801
+ end.to raise_error(ArgumentError)
1526
2802
  end
1527
2803
  end
1528
2804
 
@@ -1537,11 +2813,11 @@ describe Mongoid::Contextual::Mongo do
1537
2813
  describe "#map_reduce" do
1538
2814
 
1539
2815
  let!(:depeche_mode) do
1540
- Band.create(name: "Depeche Mode", likes: 200)
2816
+ Band.create!(name: "Depeche Mode", likes: 200)
1541
2817
  end
1542
2818
 
1543
2819
  let!(:tool) do
1544
- Band.create(name: "Tool", likes: 100)
2820
+ Band.create!(name: "Tool", likes: 100)
1545
2821
  end
1546
2822
 
1547
2823
  let(:map) do
@@ -1848,6 +3124,8 @@ describe Mongoid::Contextual::Mongo do
1848
3124
  end
1849
3125
 
1850
3126
  context "when the output specifies a different db" do
3127
+ # Limit is not supported in sharded clusters
3128
+ require_topology :single, :replica_set
1851
3129
 
1852
3130
  let(:criteria) do
1853
3131
  Band.limit(1)
@@ -1964,11 +3242,11 @@ describe Mongoid::Contextual::Mongo do
1964
3242
  describe "#skip" do
1965
3243
 
1966
3244
  let!(:depeche_mode) do
1967
- Band.create(name: "Depeche Mode")
3245
+ Band.create!(name: "Depeche Mode")
1968
3246
  end
1969
3247
 
1970
3248
  let!(:new_order) do
1971
- Band.create(name: "New Order")
3249
+ Band.create!(name: "New Order")
1972
3250
  end
1973
3251
 
1974
3252
  let(:criteria) do
@@ -1987,11 +3265,11 @@ describe Mongoid::Contextual::Mongo do
1987
3265
  describe "#sort" do
1988
3266
 
1989
3267
  let!(:depeche_mode) do
1990
- Band.create(name: "Depeche Mode")
3268
+ Band.create!(name: "Depeche Mode")
1991
3269
  end
1992
3270
 
1993
3271
  let!(:new_order) do
1994
- Band.create(name: "New Order")
3272
+ Band.create!(name: "New Order")
1995
3273
  end
1996
3274
 
1997
3275
  let(:criteria) do
@@ -2030,11 +3308,11 @@ describe Mongoid::Contextual::Mongo do
2030
3308
  describe "#update" do
2031
3309
 
2032
3310
  let!(:depeche_mode) do
2033
- Band.create(name: "Depeche Mode")
3311
+ Band.create!(name: "Depeche Mode")
2034
3312
  end
2035
3313
 
2036
3314
  let!(:new_order) do
2037
- Band.create(name: "New Order")
3315
+ Band.create!(name: "New Order")
2038
3316
  end
2039
3317
 
2040
3318
  let(:criteria) do
@@ -2048,11 +3326,11 @@ describe Mongoid::Contextual::Mongo do
2048
3326
  context "when adding an element to a HABTM set" do
2049
3327
 
2050
3328
  let(:person) do
2051
- Person.create
3329
+ Person.create!
2052
3330
  end
2053
3331
 
2054
3332
  let(:preference) do
2055
- Preference.create
3333
+ Preference.create!
2056
3334
  end
2057
3335
 
2058
3336
  before do
@@ -2191,12 +3469,12 @@ describe Mongoid::Contextual::Mongo do
2191
3469
  b.labels << Label.new(name: 'Warner')
2192
3470
  b.labels << Label.new(name: 'Sony')
2193
3471
  b.labels << Label.new(name: 'Cbs')
2194
- b.save
3472
+ b.save!
2195
3473
 
2196
3474
  b = Band.new(name: 'FKA Twigs')
2197
3475
  b.labels << Label.new(name: 'Warner')
2198
3476
  b.labels << Label.new(name: 'Cbs')
2199
- b.save
3477
+ b.save!
2200
3478
  end
2201
3479
 
2202
3480
 
@@ -2222,11 +3500,11 @@ describe Mongoid::Contextual::Mongo do
2222
3500
  describe "#update_all" do
2223
3501
 
2224
3502
  let!(:depeche_mode) do
2225
- Band.create(name: "Depeche Mode", origin: "Essex")
3503
+ Band.create!(name: "Depeche Mode", origin: "Essex")
2226
3504
  end
2227
3505
 
2228
3506
  let!(:new_order) do
2229
- Band.create(name: "New Order")
3507
+ Band.create!(name: "New Order")
2230
3508
  end
2231
3509
 
2232
3510
  let(:criteria) do
@@ -2295,16 +3573,65 @@ describe Mongoid::Contextual::Mongo do
2295
3573
 
2296
3574
  context "when the attributes are in the correct type" do
2297
3575
 
3576
+ context "when operation is $set" do
3577
+
3578
+ before do
3579
+ context.update_all("$set" => { name: "Smiths" })
3580
+ end
3581
+
3582
+ it "updates the first matching document" do
3583
+ expect(depeche_mode.reload.name).to eq("Smiths")
3584
+ end
3585
+
3586
+ it "updates the last matching document" do
3587
+ expect(new_order.reload.name).to eq("Smiths")
3588
+ end
3589
+ end
3590
+
3591
+ context "when operation is $push" do
3592
+
3593
+ before do
3594
+ depeche_mode.update_attribute(:genres, ["electronic"])
3595
+ new_order.update_attribute(:genres, ["electronic"])
3596
+ context.update_all("$push" => { genres: "pop" })
3597
+ end
3598
+
3599
+ it "updates the first matching document" do
3600
+ expect(depeche_mode.reload.genres).to eq(["electronic", "pop"])
3601
+ end
3602
+
3603
+ it "updates the last matching document" do
3604
+ expect(new_order.reload.genres).to eq(["electronic", "pop"])
3605
+ end
3606
+ end
3607
+
3608
+ context "when operation is $addToSet" do
3609
+
3610
+ before do
3611
+ context.update_all("$addToSet" => { genres: "electronic" })
3612
+ end
3613
+
3614
+ it "updates the first matching document" do
3615
+ expect(depeche_mode.reload.genres).to eq(["electronic"])
3616
+ end
3617
+
3618
+ it "updates the last matching document" do
3619
+ expect(new_order.reload.genres).to eq(["electronic"])
3620
+ end
3621
+ end
3622
+ end
3623
+
3624
+ context 'when using aliased field names' do
2298
3625
  before do
2299
- context.update_all("$set" => { name: "Smiths" })
3626
+ context.update_all('$set' => { years: 100 })
2300
3627
  end
2301
3628
 
2302
3629
  it "updates the first matching document" do
2303
- expect(depeche_mode.reload.name).to eq("Smiths")
3630
+ expect(depeche_mode.reload.years).to eq(100)
2304
3631
  end
2305
3632
 
2306
3633
  it "updates the last matching document" do
2307
- expect(new_order.reload.name).to eq("Smiths")
3634
+ expect(new_order.reload.years).to eq(100)
2308
3635
  end
2309
3636
  end
2310
3637
 
@@ -2364,12 +3691,12 @@ describe Mongoid::Contextual::Mongo do
2364
3691
  b.labels << Label.new(name: 'Warner')
2365
3692
  b.labels << Label.new(name: 'Sony')
2366
3693
  b.labels << Label.new(name: 'Cbs')
2367
- b.save
3694
+ b.save!
2368
3695
 
2369
3696
  b = Band.new(name: 'FKA Twigs')
2370
3697
  b.labels << Label.new(name: 'Warner')
2371
3698
  b.labels << Label.new(name: 'Cbs')
2372
- b.save
3699
+ b.save!
2373
3700
  end
2374
3701
 
2375
3702