mongoid 7.0.2 → 8.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1104) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +33 -33
  4. data/LICENSE +1 -0
  5. data/README.md +34 -20
  6. data/Rakefile +100 -5
  7. data/lib/config/locales/en.yml +220 -105
  8. data/lib/mongoid/association/accessors.rb +176 -84
  9. data/lib/mongoid/association/bindable.rb +57 -28
  10. data/lib/mongoid/association/builders.rb +9 -15
  11. data/lib/mongoid/association/constrainable.rb +5 -7
  12. data/lib/mongoid/association/depending.rb +9 -18
  13. data/lib/mongoid/association/eager_loadable.rb +31 -10
  14. data/lib/mongoid/association/embedded/batchable.rb +68 -54
  15. data/lib/mongoid/association/embedded/cyclic.rb +10 -17
  16. data/lib/mongoid/association/embedded/embedded_in/binding.rb +27 -9
  17. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +9 -6
  18. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +16 -25
  19. data/lib/mongoid/association/embedded/embedded_in.rb +9 -28
  20. data/lib/mongoid/association/embedded/embeds_many/binding.rb +5 -8
  21. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +10 -6
  22. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +156 -135
  23. data/lib/mongoid/association/embedded/embeds_many.rb +10 -37
  24. data/lib/mongoid/association/embedded/embeds_one/binding.rb +4 -8
  25. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +27 -10
  26. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +64 -30
  27. data/lib/mongoid/association/embedded/embeds_one.rb +11 -34
  28. data/lib/mongoid/association/embedded.rb +2 -0
  29. data/lib/mongoid/association/macros.rb +65 -41
  30. data/lib/mongoid/association/many.rb +25 -35
  31. data/lib/mongoid/association/marshalable.rb +3 -6
  32. data/lib/mongoid/association/nested/many.rb +22 -30
  33. data/lib/mongoid/association/nested/nested_buildable.rb +9 -15
  34. data/lib/mongoid/association/nested/one.rb +57 -30
  35. data/lib/mongoid/association/nested.rb +3 -3
  36. data/lib/mongoid/association/one.rb +5 -12
  37. data/lib/mongoid/association/options.rb +16 -46
  38. data/lib/mongoid/association/proxy.rb +52 -40
  39. data/lib/mongoid/association/referenced/auto_save.rb +9 -14
  40. data/lib/mongoid/association/referenced/belongs_to/binding.rb +5 -9
  41. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +11 -9
  42. data/lib/mongoid/association/referenced/belongs_to/eager.rb +40 -3
  43. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +19 -31
  44. data/lib/mongoid/association/referenced/belongs_to.rb +16 -38
  45. data/lib/mongoid/association/referenced/counter_cache.rb +14 -25
  46. data/lib/mongoid/association/referenced/eager.rb +42 -38
  47. data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +12 -11
  48. data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +5 -5
  49. data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +2 -1
  50. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +106 -67
  51. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +29 -46
  52. data/lib/mongoid/association/referenced/has_many/binding.rb +3 -6
  53. data/lib/mongoid/association/referenced/has_many/buildable.rb +5 -5
  54. data/lib/mongoid/association/referenced/has_many/eager.rb +2 -1
  55. data/lib/mongoid/association/referenced/has_many/enumerable.rb +440 -456
  56. data/lib/mongoid/association/referenced/has_many/proxy.rb +104 -127
  57. data/lib/mongoid/association/referenced/has_many.rb +21 -45
  58. data/lib/mongoid/association/referenced/has_one/binding.rb +4 -9
  59. data/lib/mongoid/association/referenced/has_one/buildable.rb +20 -6
  60. data/lib/mongoid/association/referenced/has_one/eager.rb +2 -1
  61. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +16 -29
  62. data/lib/mongoid/association/referenced/has_one/proxy.rb +25 -30
  63. data/lib/mongoid/association/referenced/has_one.rb +16 -36
  64. data/lib/mongoid/association/referenced/syncable.rb +11 -26
  65. data/lib/mongoid/association/referenced.rb +2 -0
  66. data/lib/mongoid/association/reflections.rb +7 -6
  67. data/lib/mongoid/association/relatable.rb +149 -89
  68. data/lib/mongoid/association.rb +13 -27
  69. data/lib/mongoid/atomic/modifiers.rb +29 -53
  70. data/lib/mongoid/atomic/paths/embedded/many.rb +23 -7
  71. data/lib/mongoid/atomic/paths/embedded/one.rb +4 -7
  72. data/lib/mongoid/atomic/paths/embedded.rb +3 -4
  73. data/lib/mongoid/atomic/paths/root.rb +4 -7
  74. data/lib/mongoid/atomic/paths.rb +2 -1
  75. data/lib/mongoid/atomic.rb +49 -47
  76. data/lib/mongoid/attributes/dynamic.rb +22 -36
  77. data/lib/mongoid/attributes/nested.rb +12 -15
  78. data/lib/mongoid/attributes/processing.rb +19 -27
  79. data/lib/mongoid/attributes/projector.rb +119 -0
  80. data/lib/mongoid/attributes/readonly.rb +6 -9
  81. data/lib/mongoid/attributes.rb +103 -100
  82. data/lib/mongoid/cacheable.rb +7 -10
  83. data/lib/mongoid/changeable.rb +152 -73
  84. data/lib/mongoid/clients/factory.rb +42 -17
  85. data/lib/mongoid/clients/options.rb +21 -18
  86. data/lib/mongoid/clients/sessions.rb +10 -10
  87. data/lib/mongoid/clients/storage_options.rb +9 -17
  88. data/lib/mongoid/clients/validators/storage.rb +5 -24
  89. data/lib/mongoid/clients/validators.rb +2 -1
  90. data/lib/mongoid/clients.rb +3 -10
  91. data/lib/mongoid/collection_configurable.rb +58 -0
  92. data/lib/mongoid/composable.rb +7 -9
  93. data/lib/mongoid/config/defaults.rb +60 -0
  94. data/lib/mongoid/config/environment.rb +51 -13
  95. data/lib/mongoid/config/options.rb +20 -23
  96. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  97. data/lib/mongoid/config/validators/client.rb +8 -23
  98. data/lib/mongoid/config/validators/option.rb +2 -3
  99. data/lib/mongoid/config/validators.rb +3 -1
  100. data/lib/mongoid/config.rb +235 -48
  101. data/lib/mongoid/contextual/aggregable/memory.rb +40 -27
  102. data/lib/mongoid/contextual/aggregable/mongo.rb +32 -33
  103. data/lib/mongoid/contextual/aggregable/none.rb +65 -0
  104. data/lib/mongoid/contextual/aggregable.rb +17 -0
  105. data/lib/mongoid/contextual/atomic.rb +29 -31
  106. data/lib/mongoid/contextual/command.rb +2 -5
  107. data/lib/mongoid/contextual/geo_near.rb +13 -44
  108. data/lib/mongoid/contextual/map_reduce.rb +7 -35
  109. data/lib/mongoid/contextual/memory.rb +387 -81
  110. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  111. data/lib/mongoid/contextual/mongo.rb +641 -283
  112. data/lib/mongoid/contextual/none.rb +264 -31
  113. data/lib/mongoid/contextual/queryable.rb +3 -4
  114. data/lib/mongoid/contextual.rb +21 -11
  115. data/lib/mongoid/copyable.rb +46 -17
  116. data/lib/mongoid/criteria/findable.rb +20 -20
  117. data/lib/mongoid/criteria/includable.rb +32 -34
  118. data/lib/mongoid/criteria/inspectable.rb +2 -3
  119. data/lib/mongoid/criteria/marshalable.rb +12 -7
  120. data/lib/mongoid/criteria/modifiable.rb +15 -21
  121. data/lib/mongoid/criteria/options.rb +4 -5
  122. data/lib/mongoid/criteria/permission.rb +3 -2
  123. data/lib/mongoid/criteria/queryable/aggregable.rb +4 -15
  124. data/lib/mongoid/criteria/queryable/expandable.rb +68 -0
  125. data/lib/mongoid/criteria/queryable/extensions/array.rb +7 -41
  126. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +28 -8
  127. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +5 -6
  128. data/lib/mongoid/criteria/queryable/extensions/date.rb +9 -9
  129. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +11 -12
  130. data/lib/mongoid/criteria/queryable/extensions/hash.rb +4 -41
  131. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +3 -14
  132. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +4 -21
  133. data/lib/mongoid/criteria/queryable/extensions/object.rb +6 -30
  134. data/lib/mongoid/criteria/queryable/extensions/range.rb +49 -17
  135. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +12 -19
  136. data/lib/mongoid/criteria/queryable/extensions/set.rb +4 -5
  137. data/lib/mongoid/criteria/queryable/extensions/string.rb +7 -32
  138. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +7 -22
  139. data/lib/mongoid/criteria/queryable/extensions/time.rb +10 -10
  140. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +19 -7
  141. data/lib/mongoid/criteria/queryable/extensions.rb +1 -4
  142. data/lib/mongoid/criteria/queryable/key.rb +105 -31
  143. data/lib/mongoid/criteria/queryable/macroable.rb +3 -4
  144. data/lib/mongoid/criteria/queryable/mergeable.rb +205 -44
  145. data/lib/mongoid/criteria/queryable/optional.rb +16 -65
  146. data/lib/mongoid/criteria/queryable/options.rb +4 -21
  147. data/lib/mongoid/criteria/queryable/pipeline.rb +5 -15
  148. data/lib/mongoid/criteria/queryable/selectable.rb +471 -168
  149. data/lib/mongoid/criteria/queryable/selector.rb +133 -58
  150. data/lib/mongoid/criteria/queryable/smash.rb +42 -18
  151. data/lib/mongoid/criteria/queryable/storable.rb +237 -0
  152. data/lib/mongoid/criteria/queryable.rb +18 -15
  153. data/lib/mongoid/criteria/scopable.rb +29 -21
  154. data/lib/mongoid/criteria/translator.rb +45 -0
  155. data/lib/mongoid/criteria.rb +106 -111
  156. data/lib/mongoid/deprecable.rb +36 -0
  157. data/lib/mongoid/deprecation.rb +25 -0
  158. data/lib/mongoid/document.rb +162 -103
  159. data/lib/mongoid/equality.rb +35 -18
  160. data/lib/mongoid/errors/ambiguous_relationship.rb +4 -5
  161. data/lib/mongoid/errors/callback.rb +2 -3
  162. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  163. data/lib/mongoid/errors/criteria_argument_required.rb +18 -0
  164. data/lib/mongoid/errors/delete_restriction.rb +10 -13
  165. data/lib/mongoid/errors/document_not_destroyed.rb +4 -7
  166. data/lib/mongoid/errors/document_not_found.rb +35 -21
  167. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  168. data/lib/mongoid/errors/empty_config_file.rb +25 -0
  169. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  170. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +2 -3
  171. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  172. data/lib/mongoid/errors/invalid_collection.rb +2 -1
  173. data/lib/mongoid/errors/invalid_config_file.rb +25 -0
  174. data/lib/mongoid/errors/invalid_config_option.rb +3 -4
  175. data/lib/mongoid/errors/invalid_dependent_strategy.rb +3 -4
  176. data/lib/mongoid/errors/invalid_discriminator_key_target.rb +24 -0
  177. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  178. data/lib/mongoid/errors/invalid_elem_match_operator.rb +32 -0
  179. data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +25 -0
  180. data/lib/mongoid/errors/invalid_expression_operator.rb +27 -0
  181. data/lib/mongoid/errors/invalid_field.rb +8 -7
  182. data/lib/mongoid/errors/invalid_field_operator.rb +32 -0
  183. data/lib/mongoid/errors/invalid_field_option.rb +2 -3
  184. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  185. data/lib/mongoid/errors/invalid_find.rb +2 -3
  186. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  187. data/lib/mongoid/errors/invalid_includes.rb +2 -3
  188. data/lib/mongoid/errors/invalid_index.rb +2 -3
  189. data/lib/mongoid/errors/invalid_options.rb +4 -5
  190. data/lib/mongoid/errors/invalid_path.rb +2 -3
  191. data/lib/mongoid/errors/invalid_persistence_option.rb +2 -5
  192. data/lib/mongoid/errors/invalid_query.rb +40 -0
  193. data/lib/mongoid/errors/invalid_relation.rb +5 -10
  194. data/lib/mongoid/errors/invalid_relation_option.rb +4 -5
  195. data/lib/mongoid/errors/invalid_scope.rb +2 -3
  196. data/lib/mongoid/errors/invalid_session_use.rb +3 -6
  197. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +6 -5
  198. data/lib/mongoid/errors/invalid_storage_options.rb +3 -4
  199. data/lib/mongoid/errors/invalid_storage_parent.rb +4 -3
  200. data/lib/mongoid/errors/invalid_time.rb +2 -3
  201. data/lib/mongoid/errors/inverse_not_found.rb +3 -4
  202. data/lib/mongoid/errors/mixed_client_configuration.rb +2 -3
  203. data/lib/mongoid/errors/mixed_relations.rb +2 -3
  204. data/lib/mongoid/errors/mongoid_error.rb +6 -13
  205. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +3 -4
  206. data/lib/mongoid/errors/no_client_config.rb +4 -5
  207. data/lib/mongoid/errors/no_client_database.rb +3 -4
  208. data/lib/mongoid/errors/no_client_hosts.rb +3 -4
  209. data/lib/mongoid/errors/no_clients_config.rb +2 -3
  210. data/lib/mongoid/errors/no_default_client.rb +3 -4
  211. data/lib/mongoid/errors/no_environment.rb +2 -3
  212. data/lib/mongoid/errors/no_map_reduce_output.rb +2 -3
  213. data/lib/mongoid/errors/no_metadata.rb +2 -3
  214. data/lib/mongoid/errors/no_parent.rb +2 -3
  215. data/lib/mongoid/errors/readonly_attribute.rb +3 -4
  216. data/lib/mongoid/errors/readonly_document.rb +3 -6
  217. data/lib/mongoid/errors/scope_overwrite.rb +2 -1
  218. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +3 -1
  219. data/lib/mongoid/errors/unknown_attribute.rb +3 -4
  220. data/lib/mongoid/errors/unknown_model.rb +2 -3
  221. data/lib/mongoid/errors/unsaved_document.rb +3 -2
  222. data/lib/mongoid/errors/unsupported_javascript.rb +2 -3
  223. data/lib/mongoid/errors/validations.rb +2 -1
  224. data/lib/mongoid/errors.rb +18 -4
  225. data/lib/mongoid/evolvable.rb +4 -5
  226. data/lib/mongoid/extensions/array.rb +37 -44
  227. data/lib/mongoid/extensions/big_decimal.rb +35 -21
  228. data/lib/mongoid/extensions/binary.rb +42 -0
  229. data/lib/mongoid/extensions/boolean.rb +10 -6
  230. data/lib/mongoid/extensions/date.rb +32 -25
  231. data/lib/mongoid/extensions/date_time.rb +5 -13
  232. data/lib/mongoid/extensions/decimal128.rb +2 -5
  233. data/lib/mongoid/extensions/false_class.rb +5 -8
  234. data/lib/mongoid/extensions/float.rb +12 -14
  235. data/lib/mongoid/extensions/hash.rb +64 -42
  236. data/lib/mongoid/extensions/integer.rb +12 -16
  237. data/lib/mongoid/extensions/module.rb +3 -4
  238. data/lib/mongoid/extensions/nil_class.rb +2 -5
  239. data/lib/mongoid/extensions/object.rb +27 -52
  240. data/lib/mongoid/extensions/object_id.rb +2 -7
  241. data/lib/mongoid/extensions/range.rb +42 -20
  242. data/lib/mongoid/extensions/regexp.rb +14 -7
  243. data/lib/mongoid/extensions/set.rb +13 -11
  244. data/lib/mongoid/extensions/string.rb +35 -64
  245. data/lib/mongoid/extensions/symbol.rb +6 -22
  246. data/lib/mongoid/extensions/time.rb +38 -22
  247. data/lib/mongoid/extensions/time_with_zone.rb +26 -9
  248. data/lib/mongoid/extensions/true_class.rb +5 -8
  249. data/lib/mongoid/extensions.rb +19 -3
  250. data/lib/mongoid/factory.rb +104 -17
  251. data/lib/mongoid/fields/foreign_key.rb +14 -26
  252. data/lib/mongoid/fields/localized.rb +21 -15
  253. data/lib/mongoid/fields/standard.rb +23 -43
  254. data/lib/mongoid/fields/validators/macro.rb +32 -20
  255. data/lib/mongoid/fields/validators.rb +2 -1
  256. data/lib/mongoid/fields.rb +349 -76
  257. data/lib/mongoid/findable.rb +115 -34
  258. data/lib/mongoid/indexable/specification.rb +5 -18
  259. data/lib/mongoid/indexable/validators/options.rb +8 -9
  260. data/lib/mongoid/indexable.rb +6 -21
  261. data/lib/mongoid/inspectable.rb +4 -11
  262. data/lib/mongoid/interceptable.rb +85 -41
  263. data/lib/mongoid/loggable.rb +13 -16
  264. data/lib/mongoid/matchable.rb +4 -154
  265. data/lib/mongoid/matcher/all.rb +22 -0
  266. data/lib/mongoid/matcher/and.rb +21 -0
  267. data/lib/mongoid/matcher/bits.rb +41 -0
  268. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  269. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  270. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  271. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  272. data/lib/mongoid/matcher/elem_match.rb +36 -0
  273. data/lib/mongoid/matcher/elem_match_expression.rb +20 -0
  274. data/lib/mongoid/matcher/eq.rb +11 -0
  275. data/lib/mongoid/matcher/eq_impl.rb +67 -0
  276. data/lib/mongoid/matcher/eq_impl_with_regexp.rb +26 -0
  277. data/lib/mongoid/matcher/exists.rb +15 -0
  278. data/lib/mongoid/matcher/expression.rb +35 -0
  279. data/lib/mongoid/matcher/expression_operator.rb +19 -0
  280. data/lib/mongoid/matcher/field_expression.rb +62 -0
  281. data/lib/mongoid/matcher/field_operator.rb +54 -0
  282. data/lib/mongoid/matcher/gt.rb +17 -0
  283. data/lib/mongoid/matcher/gte.rb +17 -0
  284. data/lib/mongoid/matcher/in.rb +25 -0
  285. data/lib/mongoid/matcher/lt.rb +17 -0
  286. data/lib/mongoid/matcher/lte.rb +17 -0
  287. data/lib/mongoid/matcher/mod.rb +17 -0
  288. data/lib/mongoid/matcher/ne.rb +16 -0
  289. data/lib/mongoid/matcher/nin.rb +11 -0
  290. data/lib/mongoid/matcher/nor.rb +25 -0
  291. data/lib/mongoid/matcher/not.rb +29 -0
  292. data/lib/mongoid/matcher/or.rb +21 -0
  293. data/lib/mongoid/matcher/regex.rb +41 -0
  294. data/lib/mongoid/matcher/size.rb +26 -0
  295. data/lib/mongoid/matcher/type.rb +99 -0
  296. data/lib/mongoid/matcher.rb +130 -0
  297. data/lib/mongoid/persistable/creatable.rb +23 -30
  298. data/lib/mongoid/persistable/deletable.rb +7 -23
  299. data/lib/mongoid/persistable/destroyable.rb +12 -11
  300. data/lib/mongoid/persistable/incrementable.rb +6 -7
  301. data/lib/mongoid/persistable/logical.rb +4 -6
  302. data/lib/mongoid/persistable/poppable.rb +3 -6
  303. data/lib/mongoid/persistable/pullable.rb +3 -8
  304. data/lib/mongoid/persistable/pushable.rb +14 -10
  305. data/lib/mongoid/persistable/renamable.rb +10 -8
  306. data/lib/mongoid/persistable/savable.rb +16 -9
  307. data/lib/mongoid/persistable/settable.rb +3 -6
  308. data/lib/mongoid/persistable/unsettable.rb +10 -10
  309. data/lib/mongoid/persistable/updatable.rb +99 -30
  310. data/lib/mongoid/persistable/upsertable.rb +23 -9
  311. data/lib/mongoid/persistable.rb +138 -40
  312. data/lib/mongoid/persistence_context.rb +107 -52
  313. data/lib/mongoid/positional.rb +3 -6
  314. data/lib/mongoid/query_cache.rb +18 -234
  315. data/lib/mongoid/railtie.rb +20 -16
  316. data/lib/mongoid/railties/controller_runtime.rb +88 -0
  317. data/lib/mongoid/railties/database.rake +16 -2
  318. data/lib/mongoid/reloadable.rb +19 -22
  319. data/lib/mongoid/scopable.rb +37 -60
  320. data/lib/mongoid/selectable.rb +8 -18
  321. data/lib/mongoid/serializable.rb +33 -34
  322. data/lib/mongoid/shardable.rb +108 -21
  323. data/lib/mongoid/stateful.rb +60 -20
  324. data/lib/mongoid/stringified_symbol.rb +52 -0
  325. data/lib/mongoid/tasks/database.rake +24 -5
  326. data/lib/mongoid/tasks/database.rb +105 -7
  327. data/lib/mongoid/threaded/lifecycle.rb +7 -26
  328. data/lib/mongoid/threaded.rb +80 -67
  329. data/lib/mongoid/timestamps/created/short.rb +2 -1
  330. data/lib/mongoid/timestamps/created.rb +4 -3
  331. data/lib/mongoid/timestamps/short.rb +2 -1
  332. data/lib/mongoid/timestamps/timeless.rb +6 -9
  333. data/lib/mongoid/timestamps/updated/short.rb +2 -1
  334. data/lib/mongoid/timestamps/updated.rb +5 -6
  335. data/lib/mongoid/timestamps.rb +3 -2
  336. data/lib/mongoid/touchable.rb +54 -25
  337. data/lib/mongoid/traversable.rb +185 -61
  338. data/lib/mongoid/utils.rb +22 -0
  339. data/lib/mongoid/validatable/associated.rb +5 -6
  340. data/lib/mongoid/validatable/format.rb +2 -1
  341. data/lib/mongoid/validatable/length.rb +2 -1
  342. data/lib/mongoid/validatable/localizable.rb +3 -4
  343. data/lib/mongoid/validatable/macros.rb +8 -15
  344. data/lib/mongoid/validatable/presence.rb +10 -15
  345. data/lib/mongoid/validatable/queryable.rb +2 -3
  346. data/lib/mongoid/validatable/uniqueness.rb +30 -42
  347. data/lib/mongoid/validatable.rb +16 -32
  348. data/lib/mongoid/version.rb +3 -2
  349. data/lib/mongoid/warnings.rb +44 -0
  350. data/lib/mongoid.rb +50 -17
  351. data/lib/rails/generators/mongoid/config/config_generator.rb +10 -2
  352. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +53 -32
  353. data/lib/rails/generators/mongoid/model/model_generator.rb +3 -2
  354. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  355. data/lib/rails/generators/mongoid_generator.rb +2 -1
  356. data/lib/rails/mongoid.rb +4 -5
  357. data/spec/README.md +33 -0
  358. data/spec/config/mongoid.yml +29 -3
  359. data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
  360. data/spec/integration/app_spec.rb +345 -0
  361. data/spec/integration/associations/belongs_to_spec.rb +33 -0
  362. data/spec/integration/associations/embedded_dirty_spec.rb +57 -0
  363. data/spec/integration/associations/embedded_spec.rb +283 -0
  364. data/spec/integration/associations/embeds_many_spec.rb +219 -0
  365. data/spec/integration/associations/embeds_one_spec.rb +41 -0
  366. data/spec/integration/associations/foreign_key_spec.rb +107 -0
  367. data/spec/integration/associations/foreign_key_spec_models.rb +64 -0
  368. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  369. data/spec/integration/associations/has_many_spec.rb +128 -0
  370. data/spec/integration/associations/has_one_spec.rb +272 -0
  371. data/spec/integration/associations/nested_attributes_assignment_spec.rb +115 -0
  372. data/spec/integration/associations/reverse_population_spec.rb +34 -0
  373. data/spec/integration/associations/reverse_population_spec_models.rb +36 -0
  374. data/spec/integration/associations/scope_option_spec.rb +101 -0
  375. data/spec/integration/atomic/modifiers_spec.rb +116 -0
  376. data/spec/integration/bson_regexp_raw_spec.rb +19 -0
  377. data/spec/integration/callbacks_models.rb +192 -0
  378. data/spec/integration/callbacks_spec.rb +584 -0
  379. data/spec/integration/contextual/empty_spec.rb +141 -0
  380. data/spec/integration/criteria/alias_query_spec.rb +161 -0
  381. data/spec/integration/criteria/date_field_spec.rb +40 -0
  382. data/spec/integration/criteria/default_scope_spec.rb +72 -0
  383. data/spec/integration/criteria/logical_spec.rb +124 -0
  384. data/spec/integration/criteria/range_spec.rb +359 -0
  385. data/spec/integration/criteria/time_with_zone_spec.rb +142 -0
  386. data/spec/integration/discriminator_key_spec.rb +391 -0
  387. data/spec/integration/discriminator_value_spec.rb +206 -0
  388. data/spec/integration/document_spec.rb +51 -0
  389. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  390. data/spec/integration/i18n_fallbacks_spec.rb +74 -0
  391. data/spec/integration/matcher_examples_spec.rb +765 -0
  392. data/spec/integration/matcher_operator_data/all.yml +140 -0
  393. data/spec/integration/matcher_operator_data/and.yml +93 -0
  394. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  395. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  396. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  397. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  398. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  399. data/spec/integration/matcher_operator_data/elem_match.yml +409 -0
  400. data/spec/integration/matcher_operator_data/elem_match_expr.yml +213 -0
  401. data/spec/integration/matcher_operator_data/eq.yml +191 -0
  402. data/spec/integration/matcher_operator_data/exists.yml +213 -0
  403. data/spec/integration/matcher_operator_data/generic_op.yml +17 -0
  404. data/spec/integration/matcher_operator_data/gt.yml +132 -0
  405. data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
  406. data/spec/integration/matcher_operator_data/gte.yml +132 -0
  407. data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
  408. data/spec/integration/matcher_operator_data/implicit.yml +331 -0
  409. data/spec/integration/matcher_operator_data/implicit_traversal.yml +112 -0
  410. data/spec/integration/matcher_operator_data/in.yml +210 -0
  411. data/spec/integration/matcher_operator_data/invalid_op.yml +59 -0
  412. data/spec/integration/matcher_operator_data/invalid_syntax.yml +39 -0
  413. data/spec/integration/matcher_operator_data/lt.yml +132 -0
  414. data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
  415. data/spec/integration/matcher_operator_data/lte.yml +132 -0
  416. data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
  417. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  418. data/spec/integration/matcher_operator_data/multiple.yml +29 -0
  419. data/spec/integration/matcher_operator_data/ne.yml +150 -0
  420. data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
  421. data/spec/integration/matcher_operator_data/nin.yml +114 -0
  422. data/spec/integration/matcher_operator_data/nor.yml +126 -0
  423. data/spec/integration/matcher_operator_data/not.yml +196 -0
  424. data/spec/integration/matcher_operator_data/or.yml +137 -0
  425. data/spec/integration/matcher_operator_data/regex.yml +174 -0
  426. data/spec/integration/matcher_operator_data/regex_options.yml +72 -0
  427. data/spec/integration/matcher_operator_data/size.yml +174 -0
  428. data/spec/integration/matcher_operator_data/type.yml +70 -0
  429. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  430. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  431. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  432. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  433. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  434. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  435. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  436. data/spec/integration/matcher_operator_data/type_decimal.yml +41 -0
  437. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  438. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  439. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  440. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  441. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  442. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  443. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  444. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  445. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  446. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  447. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  448. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  449. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  450. data/spec/integration/matcher_operator_spec.rb +122 -0
  451. data/spec/integration/matcher_spec.rb +283 -0
  452. data/spec/integration/persistence/range_field_spec.rb +350 -0
  453. data/spec/integration/server_query_spec.rb +141 -0
  454. data/spec/integration/shardable_spec.rb +148 -0
  455. data/spec/integration/stringified_symbol_field_spec.rb +203 -0
  456. data/spec/lite_spec_helper.rb +83 -0
  457. data/spec/mongoid/association/accessors_spec.rb +284 -77
  458. data/spec/mongoid/association/auto_save_spec.rb +74 -33
  459. data/spec/mongoid/association/builders_spec.rb +3 -1
  460. data/spec/mongoid/association/constrainable_spec.rb +2 -0
  461. data/spec/mongoid/association/counter_cache_spec.rb +35 -33
  462. data/spec/mongoid/association/depending_spec.rb +431 -338
  463. data/spec/mongoid/association/eager_spec.rb +8 -5
  464. data/spec/mongoid/association/embedded/cyclic_spec.rb +4 -2
  465. data/spec/mongoid/association/embedded/dirty_spec.rb +4 -2
  466. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +4 -1
  467. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +56 -0
  468. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +152 -13
  469. data/spec/mongoid/association/embedded/embedded_in_spec.rb +61 -1
  470. data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +2 -0
  471. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +114 -0
  472. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +706 -197
  473. data/spec/mongoid/association/embedded/embeds_many_models.rb +227 -0
  474. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +63 -0
  475. data/spec/mongoid/association/embedded/embeds_many_spec.rb +81 -1
  476. data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +2 -0
  477. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +27 -0
  478. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +38 -23
  479. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +8 -0
  480. data/spec/mongoid/association/embedded/embeds_one_models.rb +73 -0
  481. data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +28 -0
  482. data/spec/mongoid/association/embedded/embeds_one_spec.rb +77 -1
  483. data/spec/mongoid/association/macros_spec.rb +11 -9
  484. data/spec/mongoid/association/nested/many_spec.rb +2 -0
  485. data/spec/mongoid/association/nested/one_spec.rb +18 -12
  486. data/spec/mongoid/association/options_spec.rb +2 -0
  487. data/spec/mongoid/association/polymorphic_spec.rb +2 -0
  488. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +4 -1
  489. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +111 -16
  490. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +266 -17
  491. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +114 -58
  492. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  493. data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +57 -0
  494. data/spec/mongoid/association/referenced/belongs_to_spec.rb +96 -29
  495. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +3 -1
  496. data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +28 -1
  497. data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +67 -4
  498. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +76 -0
  499. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +559 -385
  500. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +92 -0
  501. data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +39 -0
  502. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +84 -7
  503. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +3 -1
  504. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +132 -0
  505. data/spec/mongoid/association/referenced/has_many/eager_spec.rb +40 -9
  506. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +415 -129
  507. data/spec/mongoid/association/referenced/has_many/proxy_query_spec.rb +23 -0
  508. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +859 -502
  509. data/spec/mongoid/association/referenced/has_many_models.rb +97 -0
  510. data/spec/mongoid/association/referenced/has_many_query_spec.rb +37 -0
  511. data/spec/mongoid/association/referenced/has_many_spec.rb +51 -3
  512. data/spec/mongoid/association/referenced/has_one/binding_spec.rb +2 -0
  513. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +55 -9
  514. data/spec/mongoid/association/referenced/has_one/eager_spec.rb +34 -4
  515. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +135 -27
  516. data/spec/mongoid/association/referenced/has_one_models.rb +113 -0
  517. data/spec/mongoid/association/referenced/has_one_query_spec.rb +37 -0
  518. data/spec/mongoid/association/referenced/has_one_spec.rb +87 -7
  519. data/spec/mongoid/association/reflections_spec.rb +2 -0
  520. data/spec/mongoid/association/syncable_spec.rb +48 -32
  521. data/spec/mongoid/association_spec.rb +2 -0
  522. data/spec/mongoid/atomic/modifiers_spec.rb +49 -0
  523. data/spec/mongoid/atomic/paths/embedded/many_spec.rb +2 -0
  524. data/spec/mongoid/atomic/paths/embedded/one_spec.rb +2 -0
  525. data/spec/mongoid/atomic/paths/root_spec.rb +2 -0
  526. data/spec/mongoid/atomic/paths_spec.rb +93 -12
  527. data/spec/mongoid/atomic_spec.rb +53 -6
  528. data/spec/mongoid/attributes/dynamic_spec.rb +152 -0
  529. data/spec/mongoid/attributes/nested_spec.rb +149 -78
  530. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  531. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  532. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  533. data/spec/mongoid/attributes/projector_spec.rb +40 -0
  534. data/spec/mongoid/attributes/readonly_spec.rb +24 -22
  535. data/spec/mongoid/attributes_spec.rb +895 -54
  536. data/spec/mongoid/cacheable_spec.rb +6 -4
  537. data/spec/mongoid/changeable_spec.rb +484 -67
  538. data/spec/mongoid/clients/factory_spec.rb +139 -33
  539. data/spec/mongoid/clients/options_spec.rb +76 -54
  540. data/spec/mongoid/clients/sessions_spec.rb +35 -63
  541. data/spec/mongoid/clients/transactions_spec.rb +87 -41
  542. data/spec/mongoid/clients_spec.rb +257 -31
  543. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  544. data/spec/mongoid/composable_spec.rb +2 -0
  545. data/spec/mongoid/config/defaults_spec.rb +160 -0
  546. data/spec/mongoid/config/environment_spec.rb +126 -8
  547. data/spec/mongoid/config/options_spec.rb +22 -3
  548. data/spec/mongoid/config_spec.rb +507 -2
  549. data/spec/mongoid/contextual/aggregable/memory_spec.rb +433 -153
  550. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  551. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  552. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +122 -20
  553. data/spec/mongoid/contextual/aggregable/none_spec.rb +60 -0
  554. data/spec/mongoid/contextual/atomic_spec.rb +242 -81
  555. data/spec/mongoid/contextual/geo_near_spec.rb +31 -19
  556. data/spec/mongoid/contextual/map_reduce_spec.rb +22 -19
  557. data/spec/mongoid/contextual/memory_spec.rb +1828 -303
  558. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  559. data/spec/mongoid/contextual/mongo_spec.rb +3505 -1268
  560. data/spec/mongoid/contextual/none_spec.rb +80 -67
  561. data/spec/mongoid/copyable_spec.rb +697 -40
  562. data/spec/mongoid/copyable_spec_models.rb +47 -0
  563. data/spec/mongoid/criteria/findable_spec.rb +161 -228
  564. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  565. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  566. data/spec/mongoid/criteria/inspectable_spec.rb +2 -0
  567. data/spec/mongoid/criteria/marshalable_spec.rb +20 -1
  568. data/spec/mongoid/criteria/modifiable_spec.rb +100 -48
  569. data/spec/mongoid/criteria/options_spec.rb +2 -0
  570. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +3 -1
  571. data/spec/mongoid/criteria/queryable/expandable_spec.rb +61 -0
  572. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +9 -19
  573. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +136 -26
  574. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +3 -1
  575. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +13 -0
  576. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +46 -17
  577. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +2 -0
  578. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +2 -15
  579. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +2 -0
  580. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +2 -0
  581. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +119 -0
  582. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +2 -0
  583. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +239 -178
  584. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +3 -1
  585. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +9 -7
  586. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +2 -0
  587. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +7 -70
  588. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +2 -59
  589. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +53 -23
  590. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +41 -1
  591. data/spec/mongoid/criteria/queryable/key_spec.rb +50 -6
  592. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +145 -12
  593. data/spec/mongoid/criteria/queryable/optional_spec.rb +18 -485
  594. data/spec/mongoid/criteria/queryable/options_spec.rb +3 -1
  595. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +2 -0
  596. data/spec/mongoid/criteria/queryable/queryable_spec.rb +3 -1
  597. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +2538 -0
  598. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +38 -0
  599. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1193 -2934
  600. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +589 -0
  601. data/spec/mongoid/criteria/queryable/selector_spec.rb +56 -5
  602. data/spec/mongoid/criteria/queryable/smash_spec.rb +2 -0
  603. data/spec/mongoid/criteria/queryable/storable_spec.rb +226 -0
  604. data/spec/mongoid/criteria/scopable_spec.rb +210 -0
  605. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  606. data/spec/mongoid/criteria_projection_spec.rb +406 -0
  607. data/spec/mongoid/criteria_spec.rb +1334 -1719
  608. data/spec/mongoid/document_fields_spec.rb +262 -0
  609. data/spec/mongoid/document_persistence_context_spec.rb +32 -0
  610. data/spec/mongoid/document_query_spec.rb +89 -0
  611. data/spec/mongoid/document_spec.rb +212 -67
  612. data/spec/mongoid/equality_spec.rb +144 -41
  613. data/spec/mongoid/errors/ambiguous_relationship_spec.rb +5 -3
  614. data/spec/mongoid/errors/callback_spec.rb +2 -0
  615. data/spec/mongoid/errors/delete_restriction_spec.rb +4 -2
  616. data/spec/mongoid/errors/document_not_destroyed_spec.rb +2 -0
  617. data/spec/mongoid/errors/document_not_found_spec.rb +78 -0
  618. data/spec/mongoid/errors/invalid_collection_spec.rb +2 -0
  619. data/spec/mongoid/errors/{eager_load_spec.rb → invalid_config_file_spec.rb} +7 -5
  620. data/spec/mongoid/errors/invalid_config_option_spec.rb +2 -0
  621. data/spec/mongoid/errors/invalid_field_option_spec.rb +2 -0
  622. data/spec/mongoid/errors/invalid_field_spec.rb +3 -1
  623. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  624. data/spec/mongoid/errors/invalid_find_spec.rb +2 -0
  625. data/spec/mongoid/errors/invalid_includes_spec.rb +2 -0
  626. data/spec/mongoid/errors/invalid_index_spec.rb +2 -0
  627. data/spec/mongoid/errors/invalid_options_spec.rb +4 -2
  628. data/spec/mongoid/errors/invalid_path_spec.rb +2 -0
  629. data/spec/mongoid/errors/invalid_relation_spec.rb +4 -2
  630. data/spec/mongoid/errors/invalid_scope_spec.rb +3 -1
  631. data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +2 -0
  632. data/spec/mongoid/errors/invalid_storage_options_spec.rb +2 -0
  633. data/spec/mongoid/errors/invalid_time_spec.rb +2 -0
  634. data/spec/mongoid/errors/inverse_not_found_spec.rb +3 -1
  635. data/spec/mongoid/errors/mixed_client_configuration_spec.rb +2 -0
  636. data/spec/mongoid/errors/mixed_relations_spec.rb +2 -0
  637. data/spec/mongoid/errors/mongoid_error_spec.rb +24 -8
  638. data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +5 -3
  639. data/spec/mongoid/errors/no_client_config_spec.rb +4 -2
  640. data/spec/mongoid/errors/no_client_database_spec.rb +5 -3
  641. data/spec/mongoid/errors/no_client_hosts_spec.rb +5 -3
  642. data/spec/mongoid/errors/no_clients_config_spec.rb +2 -0
  643. data/spec/mongoid/errors/no_environment_spec.rb +5 -3
  644. data/spec/mongoid/errors/no_map_reduce_output_spec.rb +2 -0
  645. data/spec/mongoid/errors/no_metadata_spec.rb +4 -2
  646. data/spec/mongoid/errors/no_parent_spec.rb +3 -1
  647. data/spec/mongoid/errors/readonly_attribute_spec.rb +2 -0
  648. data/spec/mongoid/errors/readonly_document_spec.rb +4 -2
  649. data/spec/mongoid/errors/scope_overwrite_spec.rb +2 -0
  650. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +3 -1
  651. data/spec/mongoid/errors/unknown_attribute_spec.rb +4 -2
  652. data/spec/mongoid/errors/unsaved_document_spec.rb +3 -1
  653. data/spec/mongoid/errors/unsupported_javascript_spec.rb +2 -0
  654. data/spec/mongoid/errors/validations_spec.rb +2 -0
  655. data/spec/mongoid/extensions/array_spec.rb +41 -45
  656. data/spec/mongoid/extensions/big_decimal_spec.rb +715 -213
  657. data/spec/mongoid/extensions/binary_spec.rb +46 -9
  658. data/spec/mongoid/extensions/boolean_spec.rb +70 -82
  659. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +339 -0
  660. data/spec/mongoid/extensions/date_spec.rb +58 -140
  661. data/spec/mongoid/extensions/date_time_spec.rb +32 -69
  662. data/spec/mongoid/extensions/decimal128_spec.rb +2 -0
  663. data/spec/mongoid/extensions/false_class_spec.rb +3 -1
  664. data/spec/mongoid/extensions/float_spec.rb +66 -73
  665. data/spec/mongoid/extensions/hash_spec.rb +135 -0
  666. data/spec/mongoid/extensions/integer_spec.rb +61 -63
  667. data/spec/mongoid/extensions/module_spec.rb +2 -0
  668. data/spec/mongoid/extensions/nil_class_spec.rb +2 -0
  669. data/spec/mongoid/extensions/object_id_spec.rb +2 -0
  670. data/spec/mongoid/extensions/object_spec.rb +13 -24
  671. data/spec/mongoid/extensions/range_spec.rb +257 -54
  672. data/spec/mongoid/extensions/regexp_spec.rb +70 -20
  673. data/spec/mongoid/extensions/set_spec.rb +108 -0
  674. data/spec/mongoid/extensions/string_spec.rb +146 -57
  675. data/spec/mongoid/extensions/stringified_symbol_spec.rb +84 -0
  676. data/spec/mongoid/extensions/symbol_spec.rb +20 -25
  677. data/spec/mongoid/extensions/time_spec.rb +668 -106
  678. data/spec/mongoid/extensions/time_with_zone_spec.rb +57 -83
  679. data/spec/mongoid/extensions/true_class_spec.rb +3 -1
  680. data/spec/mongoid/extensions_spec.rb +16 -2
  681. data/spec/mongoid/factory_spec.rb +347 -27
  682. data/spec/mongoid/fields/foreign_key_spec.rb +2 -0
  683. data/spec/mongoid/fields/localized_spec.rb +86 -41
  684. data/spec/mongoid/fields/standard_spec.rb +2 -0
  685. data/spec/mongoid/fields_spec.rb +869 -114
  686. data/spec/mongoid/findable_spec.rb +521 -65
  687. data/spec/mongoid/indexable/specification_spec.rb +4 -2
  688. data/spec/mongoid/indexable_spec.rb +87 -32
  689. data/spec/mongoid/inspectable_spec.rb +39 -2
  690. data/spec/mongoid/interceptable_spec.rb +761 -98
  691. data/spec/mongoid/interceptable_spec_models.rb +307 -0
  692. data/spec/mongoid/loggable_spec.rb +2 -0
  693. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  694. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +239 -0
  695. data/spec/mongoid/matcher/extract_attribute_spec.rb +36 -0
  696. data/spec/mongoid/mongoizable_spec.rb +285 -0
  697. data/spec/mongoid/persistable/creatable_spec.rb +114 -29
  698. data/spec/mongoid/persistable/deletable_spec.rb +300 -18
  699. data/spec/mongoid/persistable/destroyable_spec.rb +228 -18
  700. data/spec/mongoid/persistable/incrementable_spec.rb +66 -13
  701. data/spec/mongoid/persistable/logical_spec.rb +56 -3
  702. data/spec/mongoid/persistable/poppable_spec.rb +55 -3
  703. data/spec/mongoid/persistable/pullable_spec.rb +108 -6
  704. data/spec/mongoid/persistable/pushable_spec.rb +163 -7
  705. data/spec/mongoid/persistable/renamable_spec.rb +54 -2
  706. data/spec/mongoid/persistable/savable_spec.rb +284 -25
  707. data/spec/mongoid/persistable/settable_spec.rb +91 -8
  708. data/spec/mongoid/persistable/unsettable_spec.rb +55 -3
  709. data/spec/mongoid/persistable/updatable_spec.rb +63 -49
  710. data/spec/mongoid/persistable/upsertable_spec.rb +93 -3
  711. data/spec/mongoid/persistable_spec.rb +85 -9
  712. data/spec/mongoid/persistence_context_spec.rb +60 -59
  713. data/spec/mongoid/positional_spec.rb +2 -0
  714. data/spec/mongoid/query_cache_middleware_spec.rb +50 -0
  715. data/spec/mongoid/query_cache_spec.rb +446 -78
  716. data/spec/mongoid/relations/proxy_spec.rb +9 -7
  717. data/spec/mongoid/reloadable_spec.rb +381 -26
  718. data/spec/mongoid/scopable_spec.rb +206 -38
  719. data/spec/mongoid/selectable_spec.rb +8 -6
  720. data/spec/mongoid/serializable_spec.rb +148 -38
  721. data/spec/mongoid/shardable_models.rb +75 -0
  722. data/spec/mongoid/shardable_spec.rb +239 -34
  723. data/spec/mongoid/stateful_spec.rb +153 -9
  724. data/spec/mongoid/tasks/database_rake_spec.rb +89 -13
  725. data/spec/mongoid/tasks/database_spec.rb +130 -1
  726. data/spec/mongoid/threaded_spec.rb +72 -2
  727. data/spec/mongoid/timestamps/created/short_spec.rb +3 -1
  728. data/spec/mongoid/timestamps/created_spec.rb +3 -1
  729. data/spec/mongoid/timestamps/timeless_spec.rb +4 -2
  730. data/spec/mongoid/timestamps/updated/short_spec.rb +5 -3
  731. data/spec/mongoid/timestamps/updated_spec.rb +5 -3
  732. data/spec/mongoid/timestamps_spec.rb +400 -10
  733. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  734. data/spec/mongoid/touchable_spec.rb +568 -33
  735. data/spec/mongoid/touchable_spec_models.rb +59 -0
  736. data/spec/mongoid/traversable_spec.rb +1145 -1
  737. data/spec/mongoid/validatable/associated_spec.rb +2 -0
  738. data/spec/mongoid/validatable/format_spec.rb +2 -0
  739. data/spec/mongoid/validatable/length_spec.rb +2 -0
  740. data/spec/mongoid/validatable/numericality_spec.rb +2 -0
  741. data/spec/mongoid/validatable/presence_spec.rb +28 -22
  742. data/spec/mongoid/validatable/uniqueness_spec.rb +159 -103
  743. data/spec/mongoid/validatable_spec.rb +5 -3
  744. data/spec/mongoid/warnings_spec.rb +35 -0
  745. data/spec/mongoid_spec.rb +36 -10
  746. data/spec/rails/controller_extension/controller_runtime_spec.rb +112 -0
  747. data/spec/rails/mongoid_spec.rb +8 -18
  748. data/spec/shared/LICENSE +20 -0
  749. data/spec/shared/bin/get-mongodb-download-url +17 -0
  750. data/spec/shared/bin/s3-copy +45 -0
  751. data/spec/shared/bin/s3-upload +69 -0
  752. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  753. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  754. data/spec/shared/lib/mrss/constraints.rb +378 -0
  755. data/spec/shared/lib/mrss/docker_runner.rb +298 -0
  756. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  757. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  758. data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
  759. data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
  760. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  761. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  762. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  763. data/spec/shared/lib/mrss/utils.rb +37 -0
  764. data/spec/shared/share/Dockerfile.erb +321 -0
  765. data/spec/shared/share/haproxy-1.conf +16 -0
  766. data/spec/shared/share/haproxy-2.conf +17 -0
  767. data/spec/shared/shlib/config.sh +27 -0
  768. data/spec/shared/shlib/distro.sh +74 -0
  769. data/spec/shared/shlib/server.sh +416 -0
  770. data/spec/shared/shlib/set_env.sh +169 -0
  771. data/spec/spec_helper.rb +74 -88
  772. data/spec/support/authorization.rb +2 -0
  773. data/spec/support/client_registry.rb +9 -0
  774. data/spec/support/constraints.rb +77 -0
  775. data/spec/support/expectations.rb +21 -3
  776. data/spec/support/helpers.rb +11 -0
  777. data/spec/support/immutable_ids.rb +118 -0
  778. data/spec/support/macros.rb +129 -0
  779. data/spec/{app → support}/models/account.rb +3 -1
  780. data/spec/{app → support}/models/acolyte.rb +2 -0
  781. data/spec/{app → support}/models/actor.rb +3 -1
  782. data/spec/support/models/actress.rb +4 -0
  783. data/spec/{app → support}/models/address.rb +6 -0
  784. data/spec/{app → support}/models/address_component.rb +2 -0
  785. data/spec/{app → support}/models/address_number.rb +2 -0
  786. data/spec/{app → support}/models/agency.rb +2 -0
  787. data/spec/{app → support}/models/agent.rb +2 -0
  788. data/spec/{app → support}/models/album.rb +2 -0
  789. data/spec/{app → support}/models/alert.rb +2 -0
  790. data/spec/{app → support}/models/animal.rb +2 -0
  791. data/spec/{app → support}/models/answer.rb +2 -0
  792. data/spec/{app → support}/models/appointment.rb +2 -0
  793. data/spec/support/models/armrest.rb +9 -0
  794. data/spec/{app → support}/models/article.rb +2 -0
  795. data/spec/{app → support}/models/artist.rb +4 -1
  796. data/spec/{app → support}/models/artwork.rb +2 -0
  797. data/spec/support/models/audible_sound.rb +3 -0
  798. data/spec/{app → support}/models/audio.rb +2 -0
  799. data/spec/support/models/augmentation.rb +25 -0
  800. data/spec/{app → support}/models/author.rb +2 -0
  801. data/spec/{app → support}/models/baby.rb +2 -0
  802. data/spec/{app → support}/models/band.rb +10 -0
  803. data/spec/{app → support}/models/bar.rb +2 -0
  804. data/spec/{app → support}/models/basic.rb +2 -0
  805. data/spec/support/models/bed.rb +3 -0
  806. data/spec/{app → support}/models/big_palette.rb +2 -0
  807. data/spec/{app → support}/models/birthday.rb +2 -0
  808. data/spec/support/models/bolt.rb +7 -0
  809. data/spec/{app → support}/models/bomb.rb +2 -0
  810. data/spec/{app → support}/models/book.rb +3 -0
  811. data/spec/{app → support}/models/breed.rb +2 -0
  812. data/spec/{app → support}/models/browser.rb +3 -1
  813. data/spec/{app → support}/models/building.rb +4 -0
  814. data/spec/{app → support}/models/building_address.rb +2 -0
  815. data/spec/{app → support}/models/bus.rb +2 -0
  816. data/spec/{app → support}/models/business.rb +2 -0
  817. data/spec/{app → support}/models/callback_test.rb +2 -0
  818. data/spec/{app → support}/models/canvas.rb +3 -1
  819. data/spec/support/models/car.rb +3 -0
  820. data/spec/{app → support}/models/cat.rb +2 -0
  821. data/spec/support/models/catalog.rb +24 -0
  822. data/spec/{app → support}/models/category.rb +2 -0
  823. data/spec/{app → support}/models/child.rb +2 -0
  824. data/spec/{app → support}/models/child_doc.rb +5 -3
  825. data/spec/{app → support}/models/church.rb +2 -0
  826. data/spec/{app → support}/models/circle.rb +2 -0
  827. data/spec/{app → support}/models/circuit.rb +2 -0
  828. data/spec/support/models/circus.rb +12 -0
  829. data/spec/{app → support}/models/code.rb +4 -0
  830. data/spec/support/models/coding/pull_request.rb +11 -0
  831. data/spec/support/models/coding.rb +3 -0
  832. data/spec/{app → support}/models/comment.rb +2 -0
  833. data/spec/{app → support}/models/company.rb +2 -0
  834. data/spec/{app → support}/models/consumption_period.rb +2 -0
  835. data/spec/{app → support}/models/contextable_item.rb +2 -0
  836. data/spec/{app → support}/models/contractor.rb +2 -0
  837. data/spec/{app → support}/models/cookie.rb +2 -0
  838. data/spec/{app → support}/models/country_code.rb +4 -0
  839. data/spec/{app → support}/models/courier_job.rb +2 -0
  840. data/spec/support/models/cover.rb +10 -0
  841. data/spec/support/models/crate.rb +12 -0
  842. data/spec/support/models/customer.rb +10 -0
  843. data/spec/support/models/customer_address.rb +11 -0
  844. data/spec/support/models/deed.rb +7 -0
  845. data/spec/{app → support}/models/definition.rb +2 -0
  846. data/spec/support/models/delegating_patient.rb +15 -0
  847. data/spec/{app → support}/models/description.rb +2 -0
  848. data/spec/{app → support}/models/dictionary.rb +8 -0
  849. data/spec/{app → support}/models/division.rb +2 -0
  850. data/spec/{app → support}/models/doctor.rb +2 -0
  851. data/spec/{app → support}/models/dog.rb +2 -0
  852. data/spec/{app → support}/models/dokument.rb +2 -0
  853. data/spec/{app → support}/models/draft.rb +2 -0
  854. data/spec/{app → support}/models/dragon.rb +2 -0
  855. data/spec/{app → support}/models/driver.rb +3 -1
  856. data/spec/{app → support}/models/drug.rb +2 -0
  857. data/spec/{app → support}/models/dungeon.rb +2 -0
  858. data/spec/{app → support}/models/edit.rb +2 -0
  859. data/spec/{app → support}/models/email.rb +2 -0
  860. data/spec/{app → support}/models/employer.rb +2 -0
  861. data/spec/{app → support}/models/entry.rb +2 -0
  862. data/spec/support/models/eraser.rb +3 -0
  863. data/spec/{app → support}/models/even.rb +2 -0
  864. data/spec/{app → support}/models/event.rb +2 -0
  865. data/spec/{app → support}/models/exhibition.rb +2 -0
  866. data/spec/{app → support}/models/exhibitor.rb +2 -0
  867. data/spec/{app → support}/models/explosion.rb +2 -0
  868. data/spec/{app → support}/models/eye.rb +2 -0
  869. data/spec/{app → support}/models/eye_bowl.rb +2 -0
  870. data/spec/{app → support}/models/face.rb +2 -0
  871. data/spec/support/models/fanatic.rb +8 -0
  872. data/spec/{app → support}/models/favorite.rb +2 -0
  873. data/spec/{app → support}/models/filesystem.rb +2 -0
  874. data/spec/{app → support}/models/fire_hydrant.rb +2 -0
  875. data/spec/{app → support}/models/firefox.rb +2 -0
  876. data/spec/{app → support}/models/fish.rb +2 -0
  877. data/spec/{app → support}/models/folder.rb +2 -0
  878. data/spec/{app → support}/models/folder_item.rb +2 -0
  879. data/spec/{app → support}/models/fruits.rb +2 -0
  880. data/spec/{app → support}/models/game.rb +2 -0
  881. data/spec/{app → support}/models/ghost.rb +2 -0
  882. data/spec/support/models/guitar.rb +4 -0
  883. data/spec/support/models/hole.rb +12 -0
  884. data/spec/{app → support}/models/home.rb +2 -0
  885. data/spec/{app → support}/models/house.rb +2 -0
  886. data/spec/{app → support}/models/html_writer.rb +2 -0
  887. data/spec/{app → support}/models/id_key.rb +2 -0
  888. data/spec/support/models/idnodef.rb +7 -0
  889. data/spec/{app → support}/models/image.rb +2 -0
  890. data/spec/{app → support}/models/implant.rb +11 -0
  891. data/spec/support/models/instrument.rb +8 -0
  892. data/spec/{app → support}/models/item.rb +3 -1
  893. data/spec/{app → support}/models/jar.rb +2 -0
  894. data/spec/{app → support}/models/kaleidoscope.rb +2 -0
  895. data/spec/{app → support}/models/kangaroo.rb +3 -1
  896. data/spec/{app → support}/models/label.rb +6 -1
  897. data/spec/{app → support}/models/language.rb +2 -0
  898. data/spec/{app → support}/models/lat_lng.rb +2 -0
  899. data/spec/{app → support}/models/league.rb +2 -0
  900. data/spec/support/models/learner.rb +4 -0
  901. data/spec/{app → support}/models/line_item.rb +2 -0
  902. data/spec/{app → support}/models/location.rb +2 -0
  903. data/spec/{app → support}/models/login.rb +2 -0
  904. data/spec/{app → support}/models/manufacturer.rb +2 -0
  905. data/spec/{app → support}/models/meat.rb +2 -0
  906. data/spec/{app → support}/models/membership.rb +3 -0
  907. data/spec/{app → support}/models/message.rb +2 -0
  908. data/spec/support/models/minim.rb +6 -0
  909. data/spec/{app → support}/models/mixed_drink.rb +2 -0
  910. data/spec/support/models/mop.rb +24 -0
  911. data/spec/{app → support}/models/movie.rb +2 -0
  912. data/spec/support/models/my_hash.rb +4 -0
  913. data/spec/{app → support}/models/name.rb +2 -0
  914. data/spec/support/models/name_only.rb +8 -0
  915. data/spec/{app → support}/models/node.rb +2 -0
  916. data/spec/{app → support}/models/note.rb +2 -0
  917. data/spec/support/models/nut.rb +7 -0
  918. data/spec/{app → support}/models/odd.rb +2 -0
  919. data/spec/support/models/order.rb +12 -0
  920. data/spec/{app → support}/models/ordered_post.rb +3 -1
  921. data/spec/{app → support}/models/ordered_preference.rb +2 -0
  922. data/spec/{app → support}/models/oscar.rb +2 -0
  923. data/spec/support/models/other_owner_object.rb +4 -0
  924. data/spec/{app → support}/models/override.rb +2 -0
  925. data/spec/{app → support}/models/ownable.rb +2 -0
  926. data/spec/{app → support}/models/owner.rb +4 -0
  927. data/spec/{app → support}/models/pack.rb +2 -0
  928. data/spec/{app → support}/models/page.rb +2 -0
  929. data/spec/{app → support}/models/page_question.rb +2 -0
  930. data/spec/{app → support}/models/palette.rb +3 -1
  931. data/spec/{app → support}/models/parent.rb +2 -0
  932. data/spec/{app → support}/models/parent_doc.rb +2 -0
  933. data/spec/support/models/passport.rb +22 -0
  934. data/spec/{app → support}/models/patient.rb +2 -0
  935. data/spec/{app → support}/models/pdf_writer.rb +2 -0
  936. data/spec/support/models/pencil.rb +3 -0
  937. data/spec/{app → support}/models/person.rb +22 -1
  938. data/spec/{app → support}/models/pet.rb +2 -0
  939. data/spec/{app → support}/models/pet_owner.rb +2 -0
  940. data/spec/{app → support}/models/phone.rb +5 -1
  941. data/spec/support/models/piano.rb +4 -0
  942. data/spec/{app → support}/models/pizza.rb +2 -0
  943. data/spec/{app → support}/models/player.rb +4 -0
  944. data/spec/{app → support}/models/post.rb +2 -0
  945. data/spec/{app → support}/models/post_genre.rb +2 -0
  946. data/spec/support/models/powerup.rb +25 -0
  947. data/spec/{app → support}/models/preference.rb +2 -0
  948. data/spec/{app → support}/models/princess.rb +2 -0
  949. data/spec/{app → support}/models/product.rb +3 -0
  950. data/spec/support/models/profile.rb +17 -0
  951. data/spec/{app → support}/models/pronunciation.rb +2 -0
  952. data/spec/{app → support}/models/pub.rb +2 -0
  953. data/spec/support/models/publication/encyclopedia.rb +11 -0
  954. data/spec/support/models/publication/review.rb +13 -0
  955. data/spec/support/models/publication.rb +4 -0
  956. data/spec/{app → support}/models/purchase.rb +2 -0
  957. data/spec/support/models/purchased_item.rb +10 -0
  958. data/spec/{app → support}/models/question.rb +2 -0
  959. data/spec/{app → support}/models/quiz.rb +2 -0
  960. data/spec/{app → support}/models/rating.rb +2 -0
  961. data/spec/{app → support}/models/record.rb +2 -0
  962. data/spec/{app → support}/models/registry.rb +3 -0
  963. data/spec/{app → support}/models/role.rb +2 -0
  964. data/spec/{app → support}/models/root_category.rb +2 -0
  965. data/spec/{app → support}/models/sandwich.rb +2 -0
  966. data/spec/{app → support}/models/scheduler.rb +2 -0
  967. data/spec/support/models/school.rb +14 -0
  968. data/spec/support/models/scribe.rb +7 -0
  969. data/spec/support/models/sealer.rb +7 -0
  970. data/spec/support/models/seat.rb +24 -0
  971. data/spec/{app → support}/models/seo.rb +2 -0
  972. data/spec/support/models/series.rb +7 -0
  973. data/spec/{app → support}/models/server.rb +2 -0
  974. data/spec/{app → support}/models/service.rb +2 -0
  975. data/spec/{app → support}/models/shape.rb +4 -2
  976. data/spec/{app → support}/models/shelf.rb +2 -0
  977. data/spec/support/models/shield.rb +18 -0
  978. data/spec/{app → support}/models/shipment_address.rb +2 -0
  979. data/spec/{app → support}/models/shipping_container.rb +2 -0
  980. data/spec/{app → support}/models/shipping_pack.rb +2 -0
  981. data/spec/support/models/shirt.rb +11 -0
  982. data/spec/{app → support}/models/shop.rb +2 -0
  983. data/spec/{app → support}/models/short_agent.rb +2 -0
  984. data/spec/{app → support}/models/short_quiz.rb +2 -0
  985. data/spec/{app → support}/models/simple.rb +2 -0
  986. data/spec/{app → support}/models/slave.rb +2 -0
  987. data/spec/{app → support}/models/song.rb +2 -0
  988. data/spec/{app → support}/models/sound.rb +2 -0
  989. data/spec/support/models/spacer.rb +7 -0
  990. data/spec/{app → support}/models/square.rb +2 -0
  991. data/spec/{app → support}/models/staff.rb +2 -0
  992. data/spec/{app → support}/models/store_as_dup_test1.rb +2 -0
  993. data/spec/{app → support}/models/store_as_dup_test2.rb +2 -0
  994. data/spec/support/models/store_as_dup_test3.rb +7 -0
  995. data/spec/support/models/store_as_dup_test4.rb +7 -0
  996. data/spec/{app → support}/models/strategy.rb +2 -0
  997. data/spec/support/models/student.rb +14 -0
  998. data/spec/{app → support}/models/sub_item.rb +2 -0
  999. data/spec/{app → support}/models/subscription.rb +2 -0
  1000. data/spec/{app → support}/models/survey.rb +2 -0
  1001. data/spec/{app → support}/models/symptom.rb +2 -0
  1002. data/spec/support/models/system_role.rb +7 -0
  1003. data/spec/{app → support}/models/tag.rb +2 -0
  1004. data/spec/{app → support}/models/target.rb +2 -0
  1005. data/spec/{app → support}/models/template.rb +2 -0
  1006. data/spec/{app → support}/models/thing.rb +2 -0
  1007. data/spec/support/models/threadlocker.rb +7 -0
  1008. data/spec/{app → support}/models/title.rb +2 -0
  1009. data/spec/{app → support}/models/tool.rb +4 -2
  1010. data/spec/{app → support}/models/topping.rb +2 -0
  1011. data/spec/support/models/toy.rb +9 -0
  1012. data/spec/{app → support}/models/track.rb +2 -0
  1013. data/spec/{app → support}/models/translation.rb +2 -0
  1014. data/spec/{app → support}/models/tree.rb +2 -0
  1015. data/spec/support/models/truck.rb +7 -0
  1016. data/spec/{app → support}/models/user.rb +2 -0
  1017. data/spec/{app → support}/models/user_account.rb +2 -0
  1018. data/spec/{app → support}/models/validation_callback.rb +2 -0
  1019. data/spec/support/models/vehicle.rb +18 -0
  1020. data/spec/{app → support}/models/version.rb +2 -0
  1021. data/spec/{app → support}/models/vertex.rb +3 -1
  1022. data/spec/{app → support}/models/vet_visit.rb +2 -0
  1023. data/spec/{app → support}/models/video.rb +2 -0
  1024. data/spec/support/models/video_game.rb +3 -0
  1025. data/spec/support/models/washer.rb +7 -0
  1026. data/spec/support/models/weapon.rb +25 -0
  1027. data/spec/{app → support}/models/wiki_page.rb +3 -0
  1028. data/spec/{app → support}/models/word.rb +2 -0
  1029. data/spec/{app → support}/models/word_origin.rb +2 -0
  1030. data/spec/{app → support}/models/writer.rb +4 -2
  1031. data/spec/support/schema_maps/schema_map_aws.json +17 -0
  1032. data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  1033. data/spec/support/schema_maps/schema_map_azure.json +17 -0
  1034. data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  1035. data/spec/support/schema_maps/schema_map_gcp.json +17 -0
  1036. data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  1037. data/spec/support/schema_maps/schema_map_kmip.json +17 -0
  1038. data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  1039. data/spec/support/schema_maps/schema_map_local.json +18 -0
  1040. data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
  1041. data/spec/support/shared/time.rb +53 -0
  1042. data/spec/support/spec_config.rb +64 -0
  1043. data.tar.gz.sig +1 -2
  1044. metadata +1158 -615
  1045. metadata.gz.sig +0 -0
  1046. data/lib/mongoid/criteria/queryable/forwardable.rb +0 -65
  1047. data/lib/mongoid/errors/eager_load.rb +0 -22
  1048. data/lib/mongoid/errors/invalid_value.rb +0 -16
  1049. data/lib/mongoid/matchable/all.rb +0 -27
  1050. data/lib/mongoid/matchable/and.rb +0 -30
  1051. data/lib/mongoid/matchable/default.rb +0 -72
  1052. data/lib/mongoid/matchable/elem_match.rb +0 -34
  1053. data/lib/mongoid/matchable/exists.rb +0 -23
  1054. data/lib/mongoid/matchable/gt.rb +0 -23
  1055. data/lib/mongoid/matchable/gte.rb +0 -23
  1056. data/lib/mongoid/matchable/in.rb +0 -24
  1057. data/lib/mongoid/matchable/lt.rb +0 -23
  1058. data/lib/mongoid/matchable/lte.rb +0 -23
  1059. data/lib/mongoid/matchable/ne.rb +0 -21
  1060. data/lib/mongoid/matchable/nin.rb +0 -22
  1061. data/lib/mongoid/matchable/nor.rb +0 -37
  1062. data/lib/mongoid/matchable/or.rb +0 -33
  1063. data/lib/mongoid/matchable/regexp.rb +0 -27
  1064. data/lib/mongoid/matchable/size.rb +0 -21
  1065. data/lib/support/ruby_version.rb +0 -26
  1066. data/spec/app/models/actress.rb +0 -2
  1067. data/spec/app/models/augmentation.rb +0 -11
  1068. data/spec/app/models/bed.rb +0 -1
  1069. data/spec/app/models/car.rb +0 -1
  1070. data/spec/app/models/circus.rb +0 -7
  1071. data/spec/app/models/eraser.rb +0 -1
  1072. data/spec/app/models/learner.rb +0 -2
  1073. data/spec/app/models/my_hash.rb +0 -2
  1074. data/spec/app/models/passport.rb +0 -5
  1075. data/spec/app/models/pencil.rb +0 -1
  1076. data/spec/app/models/powerup.rb +0 -11
  1077. data/spec/app/models/profile.rb +0 -5
  1078. data/spec/app/models/series.rb +0 -4
  1079. data/spec/app/models/truck.rb +0 -3
  1080. data/spec/app/models/vehicle.rb +0 -11
  1081. data/spec/app/models/video_game.rb +0 -1
  1082. data/spec/app/models/weapon.rb +0 -11
  1083. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -58
  1084. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -58
  1085. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +0 -87
  1086. data/spec/mongoid/matchable/all_spec.rb +0 -31
  1087. data/spec/mongoid/matchable/and_spec.rb +0 -187
  1088. data/spec/mongoid/matchable/default_spec.rb +0 -130
  1089. data/spec/mongoid/matchable/elem_match_spec.rb +0 -106
  1090. data/spec/mongoid/matchable/exists_spec.rb +0 -57
  1091. data/spec/mongoid/matchable/gt_spec.rb +0 -86
  1092. data/spec/mongoid/matchable/gte_spec.rb +0 -84
  1093. data/spec/mongoid/matchable/in_spec.rb +0 -49
  1094. data/spec/mongoid/matchable/lt_spec.rb +0 -85
  1095. data/spec/mongoid/matchable/lte_spec.rb +0 -85
  1096. data/spec/mongoid/matchable/ne_spec.rb +0 -46
  1097. data/spec/mongoid/matchable/nin_spec.rb +0 -48
  1098. data/spec/mongoid/matchable/nor_spec.rb +0 -209
  1099. data/spec/mongoid/matchable/or_spec.rb +0 -131
  1100. data/spec/mongoid/matchable/regexp_spec.rb +0 -59
  1101. data/spec/mongoid/matchable/size_spec.rb +0 -25
  1102. data/spec/mongoid/matchable_spec.rb +0 -853
  1103. /data/spec/{app → support}/models/array_field.rb +0 -0
  1104. /data/spec/{app → support}/models/updatable.rb +0 -0
@@ -1,7 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  describe Mongoid::Contextual::Memory do
4
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
+
5
37
  [ :blank?, :empty? ].each do |method|
6
38
 
7
39
  describe "##{method}" do
@@ -165,19 +197,19 @@ describe Mongoid::Contextual::Memory do
165
197
  [ :delete, :delete_all ].each do |method|
166
198
 
167
199
  let(:person) do
168
- Person.create
200
+ Person.create!
169
201
  end
170
202
 
171
203
  let(:hobrecht) do
172
- person.addresses.create(street: "hobrecht")
204
+ person.addresses.create!(street: "hobrecht")
173
205
  end
174
206
 
175
207
  let(:friedel) do
176
- person.addresses.create(street: "friedel")
208
+ person.addresses.create!(street: "friedel")
177
209
  end
178
210
 
179
211
  let(:pfluger) do
180
- person.addresses.create(street: "pfluger")
212
+ person.addresses.create!(street: "pfluger")
181
213
  end
182
214
 
183
215
  describe "##{method}" do
@@ -230,11 +262,11 @@ describe Mongoid::Contextual::Memory do
230
262
  context "when embedded multiple levels" do
231
263
 
232
264
  let!(:home) do
233
- hobrecht.locations.create(name: "home")
265
+ hobrecht.locations.create!(name: "home")
234
266
  end
235
267
 
236
268
  let!(:work) do
237
- hobrecht.locations.create(name: "work")
269
+ hobrecht.locations.create!(name: "work")
238
270
  end
239
271
 
240
272
  let(:criteria) do
@@ -296,19 +328,19 @@ describe Mongoid::Contextual::Memory do
296
328
  [ :destroy, :destroy_all ].each do |method|
297
329
 
298
330
  let(:person) do
299
- Person.create
331
+ Person.create!
300
332
  end
301
333
 
302
334
  let(:hobrecht) do
303
- person.addresses.create(street: "hobrecht")
335
+ person.addresses.create!(street: "hobrecht")
304
336
  end
305
337
 
306
338
  let(:friedel) do
307
- person.addresses.create(street: "friedel")
339
+ person.addresses.create!(street: "friedel")
308
340
  end
309
341
 
310
342
  let(:pfluger) do
311
- person.addresses.create(street: "pfluger")
343
+ person.addresses.create!(street: "pfluger")
312
344
  end
313
345
 
314
346
  let(:criteria) do
@@ -377,36 +409,77 @@ describe Mongoid::Contextual::Memory do
377
409
 
378
410
  describe "#distinct" do
379
411
 
380
- let(:hobrecht) do
381
- Address.new(street: "hobrecht")
382
- end
412
+ context "when legacy_pluck_distinct is true" do
413
+ config_override :legacy_pluck_distinct, true
383
414
 
384
- let(:friedel) do
385
- Address.new(street: "friedel")
386
- end
415
+ let(:hobrecht) do
416
+ Address.new(street: "hobrecht")
417
+ end
418
+
419
+ let(:friedel) do
420
+ Address.new(street: "friedel")
421
+ end
387
422
 
388
- context "when limiting the result set" do
423
+ context "when limiting the result set" do
389
424
 
390
- let(:criteria) do
391
- Address.where(street: "hobrecht").tap do |crit|
392
- 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" ])
393
437
  end
394
438
  end
395
439
 
396
- let(:context) do
397
- 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
398
455
  end
399
456
 
400
- it "returns the distinct field values" do
401
- 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
402
470
  end
403
471
  end
404
472
 
405
- 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") }
406
479
 
407
480
  let(:criteria) do
408
- Address.all.tap do |crit|
409
- crit.documents = [ hobrecht, friedel, friedel ]
481
+ Band.all.tap do |crit|
482
+ crit.documents = [ depeche, new_order, maniacs ]
410
483
  end
411
484
  end
412
485
 
@@ -414,23 +487,170 @@ describe Mongoid::Contextual::Memory do
414
487
  described_class.new(criteria)
415
488
  end
416
489
 
417
- it "returns the distinct field values" do
418
- 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
419
501
  end
420
- end
421
502
 
422
- context 'when there is a collation on the criteria' do
503
+ context "when not limiting the result set" do
423
504
 
424
- let(:criteria) do
425
- Address.where(street: "hobrecht").tap do |crit|
426
- crit.documents = [ hobrecht, hobrecht, friedel ]
427
- 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
428
508
  end
429
509
 
430
- it "raises an exception" do
431
- expect {
432
- context.distinct(:street)
433
- }.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
434
654
  end
435
655
  end
436
656
  end
@@ -546,244 +766,168 @@ describe Mongoid::Contextual::Memory do
546
766
  Address.new(street: "friedel")
547
767
  end
548
768
 
549
- context "when there are matching documents" do
550
-
551
- let(:criteria) do
552
- Address.where(street: "hobrecht").tap do |crit|
553
- crit.documents = [ hobrecht, friedel ]
554
- end
555
- end
556
-
557
- let(:context) do
558
- described_class.new(criteria)
559
- end
560
-
561
- it "returns true" do
562
- expect(context).to be_exists
563
- end
564
- end
565
-
566
- context "when there are no matching documents" do
567
-
568
- let(:criteria) do
569
- Address.where(street: "pfluger").tap do |crit|
570
- crit.documents = [ hobrecht, friedel ]
571
- end
572
- end
573
-
574
- let(:context) do
575
- described_class.new(criteria)
576
- end
577
-
578
- it "returns false" do
579
- expect(context).to_not be_exists
769
+ let(:criteria) do
770
+ Address.where(street: "hobrecht").tap do |crit|
771
+ crit.documents = [ hobrecht, friedel ]
580
772
  end
581
773
  end
582
774
 
583
- context 'when there is a collation on the criteria' do
584
-
585
- let(:criteria) do
586
- Address.where(street: "pfluger").tap do |crit|
587
- crit.documents = [ hobrecht, friedel ]
588
- end.collation(locale: 'en_US', strength: 2)
589
- end
590
-
591
- it "raises an exception" do
592
- expect {
593
- context
594
- }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
595
- end
596
- end
597
- end
775
+ context "when not passing options" do
598
776
 
599
- [ :first, :one ].each do |method|
777
+ context "when there are matching documents" do
600
778
 
601
- describe "##{method}" do
779
+ let(:context) do
780
+ described_class.new(criteria)
781
+ end
602
782
 
603
- let(:hobrecht) do
604
- Address.new(street: "hobrecht")
783
+ it "returns true" do
784
+ expect(context).to be_exists
785
+ end
605
786
  end
606
787
 
607
- let(:friedel) do
608
- Address.new(street: "friedel")
609
- end
788
+ context "when there are no matching documents" do
610
789
 
611
- let(:criteria) do
612
- Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
613
- crit.documents = [ hobrecht, friedel ]
790
+ let(:criteria) do
791
+ Address.where(street: "pfluger").tap do |crit|
792
+ crit.documents = [ hobrecht, friedel ]
793
+ end
614
794
  end
615
- end
616
795
 
617
- let(:context) do
618
- described_class.new(criteria)
619
- end
796
+ let(:context) do
797
+ described_class.new(criteria)
798
+ end
620
799
 
621
- it "returns the first matching document" do
622
- expect(context.send(method)).to eq(hobrecht)
800
+ it "returns false" do
801
+ expect(context).to_not be_exists
802
+ end
623
803
  end
624
804
 
625
805
  context 'when there is a collation on the criteria' do
626
806
 
627
807
  let(:criteria) do
628
- Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
808
+ Address.where(street: "pfluger").tap do |crit|
629
809
  crit.documents = [ hobrecht, friedel ]
630
810
  end.collation(locale: 'en_US', strength: 2)
631
811
  end
632
812
 
633
813
  it "raises an exception" do
634
814
  expect {
635
- context.send(method)
815
+ context
636
816
  }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
637
817
  end
638
818
  end
639
819
  end
640
- end
641
820
 
642
- describe "#initialize" do
821
+ context "when passing an _id" do
643
822
 
644
- context "when the criteria has no options" do
823
+ context "when its of type BSON::ObjectId" do
645
824
 
646
- let(:hobrecht) do
647
- Address.new(street: "hobrecht")
648
- end
825
+ context "when calling it on an empty criteria" do
649
826
 
650
- let(:friedel) do
651
- Address.new(street: "friedel")
652
- end
827
+ it "returns true" do
828
+ expect(criteria.exists?(hobrecht._id)).to be true
829
+ end
830
+ end
653
831
 
654
- let(:criteria) do
655
- Address.where(street: "hobrecht").tap do |crit|
656
- 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
657
837
  end
658
- end
659
838
 
660
- let(:context) do
661
- described_class.new(criteria)
662
- end
839
+ context "when calling it on a criteria that does not include the object" do
663
840
 
664
- it "sets the criteria" do
665
- expect(context.criteria).to eq(criteria)
666
- end
841
+ it "returns false" do
842
+ expect(criteria.where(street: "bogus").exists?(hobrecht._id)).to be false
843
+ end
844
+ end
667
845
 
668
- it "sets the klass" do
669
- expect(context.klass).to eq(Address)
670
- end
846
+ context "when the id does not exist" do
671
847
 
672
- it "sets the matching documents" do
673
- 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
674
852
  end
675
- end
676
853
 
677
- context "when the criteria skips" do
678
-
679
- let(:hobrecht) do
680
- Address.new(street: "hobrecht")
681
- end
854
+ context "when its of type String" do
682
855
 
683
- let(:friedel) do
684
- Address.new(street: "friedel")
685
- end
856
+ context "when the id exists" do
686
857
 
687
- let(:criteria) do
688
- Address.all.skip(1).tap do |crit|
689
- crit.documents = [ hobrecht, friedel ]
858
+ it "returns true" do
859
+ expect(criteria.exists?(hobrecht._id.to_s)).to be true
860
+ end
690
861
  end
691
- end
692
862
 
693
- let(:context) do
694
- described_class.new(criteria)
695
- end
863
+ context "when the id does not exist" do
696
864
 
697
- it "limits the matching documents" do
698
- 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
699
869
  end
700
870
  end
701
871
 
702
- context "when the criteria limits" do
703
-
704
- let(:hobrecht) do
705
- Address.new(street: "hobrecht")
706
- end
872
+ context "when passing a hash" do
707
873
 
708
- let(:friedel) do
709
- Address.new(street: "friedel")
710
- end
874
+ context "when calling it on an empty criteria" do
711
875
 
712
- let(:criteria) do
713
- Address.all.limit(1).tap do |crit|
714
- crit.documents = [ hobrecht, friedel ]
876
+ it "returns true" do
877
+ expect(criteria.exists?(street: hobrecht.street)).to be true
715
878
  end
716
879
  end
717
880
 
718
- let(:context) do
719
- described_class.new(criteria)
720
- end
881
+ context "when calling it on a criteria that includes the object" do
721
882
 
722
- it "limits the matching documents" do
723
- 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
724
886
  end
725
- end
726
887
 
727
- context 'when there is a collation on the criteria' do
728
-
729
- let(:criteria) do
730
- Address.all.limit(1).tap do |crit|
731
- crit.documents = [ hobrecht, friedel ]
732
- end.collation(locale: 'en_US', strength: 2)
733
- end
888
+ context "when calling it on a criteria that does not include the object" do
734
889
 
735
- it "raises an exception" do
736
- expect {
737
- context
738
- }.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
739
893
  end
740
- end
741
- end
742
894
 
743
- describe "#last" do
895
+ context "when the conditions don't match" do
744
896
 
745
- let(:hobrecht) do
746
- Address.new(street: "hobrecht")
897
+ it "returns false" do
898
+ expect(criteria.exists?(street: "bogus")).to be false
899
+ end
900
+ end
747
901
  end
748
902
 
749
- let(:friedel) do
750
- Address.new(street: "friedel")
751
- end
903
+ context "when passing false" do
752
904
 
753
- let(:criteria) do
754
- Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
755
- crit.documents = [ hobrecht, friedel ]
905
+ it "returns false" do
906
+ expect(criteria.exists?(false)).to be false
756
907
  end
757
908
  end
758
909
 
759
- let(:context) do
760
- described_class.new(criteria)
761
- end
910
+ context "when passing nil" do
762
911
 
763
- it "returns the last matching document" do
764
- expect(context.last).to eq(friedel)
912
+ it "returns false" do
913
+ expect(criteria.exists?(nil)).to be false
914
+ end
765
915
  end
766
916
 
767
- context 'when there is a collation on the criteria' do
768
-
769
- let(:criteria) do
770
- Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
771
- crit.documents = [ hobrecht, friedel ]
772
- end.collation(locale: 'en_US', strength: 2)
773
- end
917
+ context "when the limit is 0" do
774
918
 
775
- it "raises an exception" do
776
- expect {
777
- context.last
778
- }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
919
+ it "returns false" do
920
+ expect(criteria.limit(0).exists?).to be false
779
921
  end
780
922
  end
781
923
  end
782
924
 
783
- [ :length, :size ].each do |method|
925
+ [ :first, :one ].each do |method|
784
926
 
785
927
  describe "##{method}" do
786
928
 
929
+ let(:method) { method }
930
+
787
931
  let(:hobrecht) do
788
932
  Address.new(street: "hobrecht")
789
933
  end
@@ -792,44 +936,34 @@ describe Mongoid::Contextual::Memory do
792
936
  Address.new(street: "friedel")
793
937
  end
794
938
 
795
- context "when there are matching documents" do
796
-
797
- let(:criteria) do
798
- Address.where(street: "hobrecht").tap do |crit|
799
- crit.documents = [ hobrecht, friedel ]
800
- end
801
- end
802
-
803
- let(:context) do
804
- described_class.new(criteria)
805
- end
806
-
807
- it "returns the number of matches" do
808
- 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 ]
809
942
  end
810
943
  end
811
944
 
812
- context "when there are no matching documents" do
945
+ let(:context) do
946
+ described_class.new(criteria)
947
+ end
813
948
 
814
- let(:criteria) do
815
- Address.where(street: "pfluger").tap do |crit|
816
- crit.documents = [ hobrecht, friedel ]
817
- end
818
- end
949
+ it "returns the first matching document" do
950
+ expect(context.send(method)).to eq(hobrecht)
951
+ end
819
952
 
820
- let(:context) do
821
- described_class.new(criteria)
822
- end
953
+ it "returns a list when passing a limit" do
954
+ expect(context.send(method, 2)).to eq([ hobrecht, friedel ])
955
+ end
823
956
 
824
- it "returns zero" do
825
- expect(context.send(method)).to eq(0)
826
- end
957
+ it "returns a list when passing 1" do
958
+ expect(context.send(method, 1)).to eq([ hobrecht ])
827
959
  end
828
960
 
961
+ include_examples "returns nil when no documents"
962
+
829
963
  context 'when there is a collation on the criteria' do
830
964
 
831
965
  let(:criteria) do
832
- Address.where(street: "hobrecht").tap do |crit|
966
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
833
967
  crit.documents = [ hobrecht, friedel ]
834
968
  end.collation(locale: 'en_US', strength: 2)
835
969
  end
@@ -843,7 +977,9 @@ describe Mongoid::Contextual::Memory do
843
977
  end
844
978
  end
845
979
 
846
- describe "#limit" do
980
+ describe "#first!" do
981
+
982
+ let(:method) { :first! }
847
983
 
848
984
  let(:hobrecht) do
849
985
  Address.new(street: "hobrecht")
@@ -853,13 +989,9 @@ describe Mongoid::Contextual::Memory do
853
989
  Address.new(street: "friedel")
854
990
  end
855
991
 
856
- let(:pfluger) do
857
- Address.new(street: "pfluger")
858
- end
859
-
860
992
  let(:criteria) do
861
- Address.all.tap do |crit|
862
- crit.documents = [ hobrecht, friedel, pfluger ]
993
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
994
+ crit.documents = [ hobrecht, friedel ]
863
995
  end
864
996
  end
865
997
 
@@ -867,55 +999,68 @@ describe Mongoid::Contextual::Memory do
867
999
  described_class.new(criteria)
868
1000
  end
869
1001
 
870
- 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
871
1005
 
872
- let!(:limit) do
873
- context.limit(2)
874
- end
1006
+ include_examples "raises an error when no documents"
1007
+ end
875
1008
 
876
- it "returns the context" do
877
- expect(limit).to eq(context)
878
- end
1009
+ describe "#take" do
879
1010
 
880
- context "when asking for all documents" do
1011
+ let(:method) { :take }
881
1012
 
882
- context "when only a limit exists" do
1013
+ let(:hobrecht) do
1014
+ Address.new(street: "hobrecht")
1015
+ end
883
1016
 
884
- it "only returns the limited documents" do
885
- expect(context.entries).to eq([ hobrecht, friedel ])
886
- end
887
- end
1017
+ let(:friedel) do
1018
+ Address.new(street: "friedel")
1019
+ end
888
1020
 
889
- 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
890
1026
 
891
- before do
892
- limit.skip(1)
893
- end
1027
+ let(:context) do
1028
+ described_class.new(criteria)
1029
+ end
894
1030
 
895
- it "applies the skip before the limit" do
896
- expect(context.entries).to eq([ friedel, pfluger ])
897
- end
898
- end
899
- 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 ])
900
1041
  end
901
1042
 
1043
+ include_examples "returns nil when no documents"
1044
+
902
1045
  context 'when there is a collation on the criteria' do
903
1046
 
904
1047
  let(:criteria) do
905
- Address.all.tap do |crit|
906
- crit.documents = [ hobrecht, friedel, pfluger ]
1048
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
1049
+ crit.documents = [ hobrecht, friedel ]
907
1050
  end.collation(locale: 'en_US', strength: 2)
908
1051
  end
909
1052
 
910
1053
  it "raises an exception" do
911
1054
  expect {
912
- context.limit(2)
1055
+ context.take
913
1056
  }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
914
1057
  end
915
1058
  end
916
1059
  end
917
1060
 
918
- describe "#pluck" do
1061
+ describe "#take!" do
1062
+
1063
+ let(:method) { :take! }
919
1064
 
920
1065
  let(:hobrecht) do
921
1066
  Address.new(street: "hobrecht")
@@ -926,7 +1071,7 @@ describe Mongoid::Contextual::Memory do
926
1071
  end
927
1072
 
928
1073
  let(:criteria) do
929
- Address.all.tap do |crit|
1074
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
930
1075
  crit.documents = [ hobrecht, friedel ]
931
1076
  end
932
1077
  end
@@ -935,54 +1080,1434 @@ describe Mongoid::Contextual::Memory do
935
1080
  described_class.new(criteria)
936
1081
  end
937
1082
 
938
- 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"
1088
+
1089
+ context 'when there is a collation on the criteria' do
939
1090
 
940
- let!(:plucked) do
941
- context.pluck(:street)
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)
942
1095
  end
943
1096
 
944
- it "returns the values" do
945
- expect(plucked).to eq([ "hobrecht", "friedel" ])
1097
+ it "raises an exception" do
1098
+ expect {
1099
+ context.take
1100
+ }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
946
1101
  end
947
1102
  end
1103
+ end
1104
+
1105
+ describe "#initialize" do
948
1106
 
949
- context "when plucking a field that doesnt exist" do
1107
+ context "when the criteria has no options" do
950
1108
 
951
- context "when pluck one field" do
1109
+ let(:hobrecht) do
1110
+ Address.new(street: "hobrecht")
1111
+ end
952
1112
 
953
- let(:plucked) do
954
- context.pluck(:foo)
955
- end
1113
+ let(:friedel) do
1114
+ Address.new(street: "friedel")
1115
+ end
956
1116
 
957
- it "returns a empty array" do
958
- expect(plucked).to eq([])
1117
+ let(:criteria) do
1118
+ Address.where(street: "hobrecht").tap do |crit|
1119
+ crit.documents = [ hobrecht, friedel ]
959
1120
  end
960
1121
  end
961
1122
 
962
- context "when pluck multiple fields" do
1123
+ let(:context) do
1124
+ described_class.new(criteria)
1125
+ end
963
1126
 
964
- let(:plucked) do
965
- context.pluck(:foo, :bar)
966
- end
1127
+ it "sets the criteria" do
1128
+ expect(context.criteria).to eq(criteria)
1129
+ end
967
1130
 
968
- it "returns a empty array" do
969
- expect(plucked).to eq([[], []])
970
- 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 ])
971
1137
  end
972
1138
  end
973
1139
 
974
- context 'when there is a collation on the criteria' do
1140
+ context "when the criteria skips" do
975
1141
 
976
- let(:criteria) do
977
- Address.all.tap do |crit|
978
- crit.documents = [ hobrecht, friedel ]
979
- end.collation(locale: 'en_US', strength: 2)
1142
+ let(:hobrecht) do
1143
+ Address.new(street: "hobrecht")
980
1144
  end
981
1145
 
982
- it "raises an exception" do
983
- expect {
984
- context.pluck(:foo, :bar)
985
- }.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
+ )
986
2511
  end
987
2512
  end
988
2513
  end
@@ -1249,19 +2774,19 @@ describe Mongoid::Contextual::Memory do
1249
2774
  describe "#update" do
1250
2775
 
1251
2776
  let(:person) do
1252
- Person.create
2777
+ Person.create!
1253
2778
  end
1254
2779
 
1255
2780
  let(:hobrecht) do
1256
- person.addresses.create(street: "hobrecht")
2781
+ person.addresses.create!(street: "hobrecht")
1257
2782
  end
1258
2783
 
1259
2784
  let(:friedel) do
1260
- person.addresses.create(street: "friedel")
2785
+ person.addresses.create!(street: "friedel")
1261
2786
  end
1262
2787
 
1263
2788
  let(:pfluger) do
1264
- person.addresses.create(street: "pfluger")
2789
+ person.addresses.create!(street: "pfluger")
1265
2790
  end
1266
2791
 
1267
2792
  context "when the documents are embedded one level" do
@@ -1321,11 +2846,11 @@ describe Mongoid::Contextual::Memory do
1321
2846
  context "when the documents are embedded multiple levels" do
1322
2847
 
1323
2848
  let!(:home) do
1324
- hobrecht.locations.create(name: "home")
2849
+ hobrecht.locations.create!(name: "home")
1325
2850
  end
1326
2851
 
1327
2852
  let!(:work) do
1328
- hobrecht.locations.create(name: "work")
2853
+ hobrecht.locations.create!(name: "work")
1329
2854
  end
1330
2855
 
1331
2856
  let(:criteria) do
@@ -1389,19 +2914,19 @@ describe Mongoid::Contextual::Memory do
1389
2914
  describe "#update_all" do
1390
2915
 
1391
2916
  let(:person) do
1392
- Person.create
2917
+ Person.create!
1393
2918
  end
1394
2919
 
1395
2920
  let(:hobrecht) do
1396
- person.addresses.create(street: "hobrecht")
2921
+ person.addresses.create!(street: "hobrecht")
1397
2922
  end
1398
2923
 
1399
2924
  let(:friedel) do
1400
- person.addresses.create(street: "friedel")
2925
+ person.addresses.create!(street: "friedel")
1401
2926
  end
1402
2927
 
1403
2928
  let(:pfluger) do
1404
- person.addresses.create(street: "pfluger")
2929
+ person.addresses.create!(street: "pfluger")
1405
2930
  end
1406
2931
 
1407
2932
  context 'when there is a collation on the criteria' do
@@ -1420,7 +2945,7 @@ describe Mongoid::Contextual::Memory do
1420
2945
  context "when the documents are empty" do
1421
2946
 
1422
2947
  let(:person_two) do
1423
- Person.create
2948
+ Person.create!
1424
2949
  end
1425
2950
 
1426
2951
  let(:criteria) do
@@ -1523,11 +3048,11 @@ describe Mongoid::Contextual::Memory do
1523
3048
  context "when the documents are embedded multiple levels" do
1524
3049
 
1525
3050
  let!(:home) do
1526
- hobrecht.locations.create(name: "home")
3051
+ hobrecht.locations.create!(name: "home")
1527
3052
  end
1528
3053
 
1529
3054
  let!(:work) do
1530
- hobrecht.locations.create(name: "work")
3055
+ hobrecht.locations.create!(name: "work")
1531
3056
  end
1532
3057
 
1533
3058
  let(:criteria) do