mongoid 7.1.1 → 8.1.0

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