mongoid 7.0.13 → 8.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1089) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +30 -30
  4. data/README.md +32 -19
  5. data/Rakefile +43 -0
  6. data/lib/config/locales/en.yml +178 -95
  7. data/lib/mongoid/association/accessors.rb +175 -83
  8. data/lib/mongoid/association/bindable.rb +57 -28
  9. data/lib/mongoid/association/builders.rb +8 -14
  10. data/lib/mongoid/association/constrainable.rb +5 -7
  11. data/lib/mongoid/association/depending.rb +9 -18
  12. data/lib/mongoid/association/eager_loadable.rb +31 -10
  13. data/lib/mongoid/association/embedded/batchable.rb +67 -53
  14. data/lib/mongoid/association/embedded/cyclic.rb +10 -17
  15. data/lib/mongoid/association/embedded/embedded_in/binding.rb +27 -9
  16. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +7 -4
  17. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +14 -24
  18. data/lib/mongoid/association/embedded/embedded_in.rb +9 -28
  19. data/lib/mongoid/association/embedded/embeds_many/binding.rb +5 -8
  20. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +8 -5
  21. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +143 -122
  22. data/lib/mongoid/association/embedded/embeds_many.rb +8 -36
  23. data/lib/mongoid/association/embedded/embeds_one/binding.rb +4 -8
  24. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +26 -9
  25. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +63 -29
  26. data/lib/mongoid/association/embedded/embeds_one.rb +9 -33
  27. data/lib/mongoid/association/embedded.rb +2 -0
  28. data/lib/mongoid/association/macros.rb +71 -41
  29. data/lib/mongoid/association/many.rb +25 -35
  30. data/lib/mongoid/association/marshalable.rb +3 -6
  31. data/lib/mongoid/association/nested/many.rb +22 -30
  32. data/lib/mongoid/association/nested/nested_buildable.rb +9 -15
  33. data/lib/mongoid/association/nested/one.rb +19 -30
  34. data/lib/mongoid/association/nested.rb +3 -3
  35. data/lib/mongoid/association/one.rb +5 -12
  36. data/lib/mongoid/association/options.rb +16 -46
  37. data/lib/mongoid/association/proxy.rb +37 -38
  38. data/lib/mongoid/association/referenced/auto_save.rb +9 -14
  39. data/lib/mongoid/association/referenced/belongs_to/binding.rb +5 -9
  40. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +11 -9
  41. data/lib/mongoid/association/referenced/belongs_to/eager.rb +40 -3
  42. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +19 -31
  43. data/lib/mongoid/association/referenced/belongs_to.rb +16 -38
  44. data/lib/mongoid/association/referenced/counter_cache.rb +14 -25
  45. data/lib/mongoid/association/referenced/eager.rb +41 -40
  46. data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +12 -11
  47. data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +5 -5
  48. data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +2 -1
  49. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +105 -68
  50. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +29 -46
  51. data/lib/mongoid/association/referenced/has_many/binding.rb +3 -6
  52. data/lib/mongoid/association/referenced/has_many/buildable.rb +5 -5
  53. data/lib/mongoid/association/referenced/has_many/eager.rb +2 -1
  54. data/lib/mongoid/association/referenced/has_many/enumerable.rb +440 -456
  55. data/lib/mongoid/association/referenced/has_many/proxy.rb +101 -124
  56. data/lib/mongoid/association/referenced/has_many.rb +21 -45
  57. data/lib/mongoid/association/referenced/has_one/binding.rb +4 -9
  58. data/lib/mongoid/association/referenced/has_one/buildable.rb +20 -6
  59. data/lib/mongoid/association/referenced/has_one/eager.rb +2 -1
  60. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +16 -29
  61. data/lib/mongoid/association/referenced/has_one/proxy.rb +25 -30
  62. data/lib/mongoid/association/referenced/has_one.rb +16 -36
  63. data/lib/mongoid/association/referenced/syncable.rb +11 -26
  64. data/lib/mongoid/association/referenced.rb +2 -0
  65. data/lib/mongoid/association/reflections.rb +7 -6
  66. data/lib/mongoid/association/relatable.rb +62 -84
  67. data/lib/mongoid/association.rb +13 -27
  68. data/lib/mongoid/atomic/modifiers.rb +29 -53
  69. data/lib/mongoid/atomic/paths/embedded/many.rb +23 -7
  70. data/lib/mongoid/atomic/paths/embedded/one.rb +4 -7
  71. data/lib/mongoid/atomic/paths/embedded.rb +2 -3
  72. data/lib/mongoid/atomic/paths/root.rb +4 -7
  73. data/lib/mongoid/atomic/paths.rb +2 -1
  74. data/lib/mongoid/atomic.rb +45 -51
  75. data/lib/mongoid/attributes/dynamic.rb +6 -21
  76. data/lib/mongoid/attributes/nested.rb +11 -14
  77. data/lib/mongoid/attributes/processing.rb +46 -30
  78. data/lib/mongoid/attributes/projector.rb +119 -0
  79. data/lib/mongoid/attributes/readonly.rb +5 -8
  80. data/lib/mongoid/attributes.rb +80 -98
  81. data/lib/mongoid/cacheable.rb +7 -10
  82. data/lib/mongoid/changeable.rb +49 -70
  83. data/lib/mongoid/clients/factory.rb +42 -17
  84. data/lib/mongoid/clients/options.rb +15 -14
  85. data/lib/mongoid/clients/sessions.rb +4 -20
  86. data/lib/mongoid/clients/storage_options.rb +7 -12
  87. data/lib/mongoid/clients/validators/storage.rb +5 -12
  88. data/lib/mongoid/clients/validators.rb +2 -1
  89. data/lib/mongoid/clients.rb +3 -10
  90. data/lib/mongoid/composable.rb +5 -9
  91. data/lib/mongoid/config/environment.rb +30 -5
  92. data/lib/mongoid/config/options.rb +23 -23
  93. data/lib/mongoid/config/validators/client.rb +8 -23
  94. data/lib/mongoid/config/validators/option.rb +2 -3
  95. data/lib/mongoid/config/validators.rb +2 -1
  96. data/lib/mongoid/config.rb +164 -48
  97. data/lib/mongoid/contextual/aggregable/memory.rb +40 -27
  98. data/lib/mongoid/contextual/aggregable/mongo.rb +32 -33
  99. data/lib/mongoid/contextual/aggregable/none.rb +65 -0
  100. data/lib/mongoid/contextual/aggregable.rb +17 -0
  101. data/lib/mongoid/contextual/atomic.rb +29 -31
  102. data/lib/mongoid/contextual/command.rb +2 -5
  103. data/lib/mongoid/contextual/geo_near.rb +13 -44
  104. data/lib/mongoid/contextual/map_reduce.rb +7 -35
  105. data/lib/mongoid/contextual/memory.rb +187 -81
  106. data/lib/mongoid/contextual/mongo.rb +360 -239
  107. data/lib/mongoid/contextual/none.rb +109 -31
  108. data/lib/mongoid/contextual/queryable.rb +3 -4
  109. data/lib/mongoid/contextual.rb +9 -11
  110. data/lib/mongoid/copyable.rb +42 -17
  111. data/lib/mongoid/criteria/findable.rb +19 -19
  112. data/lib/mongoid/criteria/includable.rb +30 -33
  113. data/lib/mongoid/criteria/inspectable.rb +2 -3
  114. data/lib/mongoid/criteria/marshalable.rb +12 -7
  115. data/lib/mongoid/criteria/modifiable.rb +2 -19
  116. data/lib/mongoid/criteria/options.rb +2 -3
  117. data/lib/mongoid/criteria/permission.rb +3 -2
  118. data/lib/mongoid/criteria/queryable/aggregable.rb +4 -15
  119. data/lib/mongoid/criteria/queryable/expandable.rb +68 -0
  120. data/lib/mongoid/criteria/queryable/extensions/array.rb +7 -41
  121. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +28 -8
  122. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +5 -6
  123. data/lib/mongoid/criteria/queryable/extensions/date.rb +9 -9
  124. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +11 -12
  125. data/lib/mongoid/criteria/queryable/extensions/hash.rb +4 -41
  126. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +3 -14
  127. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +4 -21
  128. data/lib/mongoid/criteria/queryable/extensions/object.rb +6 -30
  129. data/lib/mongoid/criteria/queryable/extensions/range.rb +49 -17
  130. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +9 -16
  131. data/lib/mongoid/criteria/queryable/extensions/set.rb +4 -5
  132. data/lib/mongoid/criteria/queryable/extensions/string.rb +7 -32
  133. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +7 -22
  134. data/lib/mongoid/criteria/queryable/extensions/time.rb +9 -9
  135. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +9 -9
  136. data/lib/mongoid/criteria/queryable/extensions.rb +1 -4
  137. data/lib/mongoid/criteria/queryable/key.rb +39 -24
  138. data/lib/mongoid/criteria/queryable/macroable.rb +3 -4
  139. data/lib/mongoid/criteria/queryable/mergeable.rb +200 -40
  140. data/lib/mongoid/criteria/queryable/optional.rb +10 -59
  141. data/lib/mongoid/criteria/queryable/options.rb +4 -21
  142. data/lib/mongoid/criteria/queryable/pipeline.rb +5 -15
  143. data/lib/mongoid/criteria/queryable/selectable.rb +417 -171
  144. data/lib/mongoid/criteria/queryable/selector.rb +127 -30
  145. data/lib/mongoid/criteria/queryable/smash.rb +42 -18
  146. data/lib/mongoid/criteria/queryable/storable.rb +237 -0
  147. data/lib/mongoid/criteria/queryable.rb +18 -15
  148. data/lib/mongoid/criteria/scopable.rb +29 -21
  149. data/lib/mongoid/criteria/translator.rb +45 -0
  150. data/lib/mongoid/criteria.rb +95 -107
  151. data/lib/mongoid/deprecable.rb +37 -0
  152. data/lib/mongoid/deprecation.rb +25 -0
  153. data/lib/mongoid/document.rb +148 -97
  154. data/lib/mongoid/equality.rb +35 -18
  155. data/lib/mongoid/errors/ambiguous_relationship.rb +4 -5
  156. data/lib/mongoid/errors/callback.rb +2 -3
  157. data/lib/mongoid/errors/criteria_argument_required.rb +18 -0
  158. data/lib/mongoid/errors/delete_restriction.rb +10 -13
  159. data/lib/mongoid/errors/document_not_destroyed.rb +4 -7
  160. data/lib/mongoid/errors/document_not_found.rb +35 -21
  161. data/lib/mongoid/errors/empty_config_file.rb +25 -0
  162. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +2 -3
  163. data/lib/mongoid/errors/invalid_collection.rb +2 -1
  164. data/lib/mongoid/errors/invalid_config_file.rb +25 -0
  165. data/lib/mongoid/errors/invalid_config_option.rb +3 -4
  166. data/lib/mongoid/errors/invalid_dependent_strategy.rb +3 -4
  167. data/lib/mongoid/errors/invalid_discriminator_key_target.rb +24 -0
  168. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  169. data/lib/mongoid/errors/invalid_elem_match_operator.rb +32 -0
  170. data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +25 -0
  171. data/lib/mongoid/errors/invalid_expression_operator.rb +27 -0
  172. data/lib/mongoid/errors/invalid_field.rb +8 -7
  173. data/lib/mongoid/errors/invalid_field_operator.rb +32 -0
  174. data/lib/mongoid/errors/invalid_field_option.rb +2 -3
  175. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  176. data/lib/mongoid/errors/invalid_find.rb +2 -3
  177. data/lib/mongoid/errors/invalid_includes.rb +2 -3
  178. data/lib/mongoid/errors/invalid_index.rb +2 -3
  179. data/lib/mongoid/errors/invalid_options.rb +4 -5
  180. data/lib/mongoid/errors/invalid_path.rb +2 -3
  181. data/lib/mongoid/errors/invalid_persistence_option.rb +2 -5
  182. data/lib/mongoid/errors/invalid_query.rb +40 -0
  183. data/lib/mongoid/errors/invalid_relation.rb +5 -10
  184. data/lib/mongoid/errors/invalid_relation_option.rb +4 -5
  185. data/lib/mongoid/errors/invalid_scope.rb +2 -3
  186. data/lib/mongoid/errors/invalid_session_use.rb +3 -6
  187. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +6 -5
  188. data/lib/mongoid/errors/invalid_storage_options.rb +3 -4
  189. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -3
  190. data/lib/mongoid/errors/invalid_time.rb +2 -3
  191. data/lib/mongoid/errors/inverse_not_found.rb +3 -4
  192. data/lib/mongoid/errors/mixed_client_configuration.rb +2 -3
  193. data/lib/mongoid/errors/mixed_relations.rb +2 -3
  194. data/lib/mongoid/errors/mongoid_error.rb +6 -13
  195. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +3 -4
  196. data/lib/mongoid/errors/no_client_config.rb +4 -5
  197. data/lib/mongoid/errors/no_client_database.rb +3 -4
  198. data/lib/mongoid/errors/no_client_hosts.rb +3 -4
  199. data/lib/mongoid/errors/no_clients_config.rb +2 -3
  200. data/lib/mongoid/errors/no_default_client.rb +3 -4
  201. data/lib/mongoid/errors/no_environment.rb +2 -3
  202. data/lib/mongoid/errors/no_map_reduce_output.rb +2 -3
  203. data/lib/mongoid/errors/no_metadata.rb +2 -3
  204. data/lib/mongoid/errors/no_parent.rb +2 -3
  205. data/lib/mongoid/errors/readonly_attribute.rb +3 -4
  206. data/lib/mongoid/errors/readonly_document.rb +3 -6
  207. data/lib/mongoid/errors/scope_overwrite.rb +2 -1
  208. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +3 -1
  209. data/lib/mongoid/errors/unknown_attribute.rb +3 -4
  210. data/lib/mongoid/errors/unknown_model.rb +2 -3
  211. data/lib/mongoid/errors/unsaved_document.rb +3 -2
  212. data/lib/mongoid/errors/unsupported_javascript.rb +2 -3
  213. data/lib/mongoid/errors/validations.rb +2 -1
  214. data/lib/mongoid/errors.rb +14 -3
  215. data/lib/mongoid/evolvable.rb +4 -5
  216. data/lib/mongoid/extensions/array.rb +37 -44
  217. data/lib/mongoid/extensions/big_decimal.rb +35 -21
  218. data/lib/mongoid/extensions/binary.rb +42 -0
  219. data/lib/mongoid/extensions/boolean.rb +10 -6
  220. data/lib/mongoid/extensions/date.rb +32 -25
  221. data/lib/mongoid/extensions/date_time.rb +5 -13
  222. data/lib/mongoid/extensions/decimal128.rb +2 -5
  223. data/lib/mongoid/extensions/false_class.rb +5 -8
  224. data/lib/mongoid/extensions/float.rb +12 -14
  225. data/lib/mongoid/extensions/hash.rb +87 -45
  226. data/lib/mongoid/extensions/integer.rb +12 -16
  227. data/lib/mongoid/extensions/module.rb +3 -4
  228. data/lib/mongoid/extensions/nil_class.rb +2 -5
  229. data/lib/mongoid/extensions/object.rb +25 -50
  230. data/lib/mongoid/extensions/object_id.rb +2 -7
  231. data/lib/mongoid/extensions/range.rb +42 -20
  232. data/lib/mongoid/extensions/regexp.rb +13 -7
  233. data/lib/mongoid/extensions/set.rb +13 -11
  234. data/lib/mongoid/extensions/string.rb +30 -61
  235. data/lib/mongoid/extensions/symbol.rb +6 -22
  236. data/lib/mongoid/extensions/time.rb +37 -23
  237. data/lib/mongoid/extensions/time_with_zone.rb +26 -9
  238. data/lib/mongoid/extensions/true_class.rb +5 -8
  239. data/lib/mongoid/extensions.rb +19 -3
  240. data/lib/mongoid/factory.rb +104 -17
  241. data/lib/mongoid/fields/foreign_key.rb +14 -26
  242. data/lib/mongoid/fields/localized.rb +11 -15
  243. data/lib/mongoid/fields/standard.rb +13 -43
  244. data/lib/mongoid/fields/validators/macro.rb +32 -20
  245. data/lib/mongoid/fields/validators.rb +2 -1
  246. data/lib/mongoid/fields.rb +328 -85
  247. data/lib/mongoid/findable.rb +90 -33
  248. data/lib/mongoid/indexable/specification.rb +5 -18
  249. data/lib/mongoid/indexable/validators/options.rb +8 -9
  250. data/lib/mongoid/indexable.rb +6 -21
  251. data/lib/mongoid/inspectable.rb +4 -11
  252. data/lib/mongoid/interceptable.rb +191 -41
  253. data/lib/mongoid/loggable.rb +13 -16
  254. data/lib/mongoid/matchable.rb +3 -154
  255. data/lib/mongoid/matcher/all.rb +22 -0
  256. data/lib/mongoid/matcher/and.rb +21 -0
  257. data/lib/mongoid/matcher/bits.rb +41 -0
  258. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  259. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  260. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  261. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  262. data/lib/mongoid/matcher/elem_match.rb +36 -0
  263. data/lib/mongoid/matcher/elem_match_expression.rb +20 -0
  264. data/lib/mongoid/matcher/eq.rb +11 -0
  265. data/lib/mongoid/matcher/eq_impl.rb +67 -0
  266. data/lib/mongoid/matcher/eq_impl_with_regexp.rb +26 -0
  267. data/lib/mongoid/matcher/exists.rb +15 -0
  268. data/lib/mongoid/matcher/expression.rb +35 -0
  269. data/lib/mongoid/matcher/expression_operator.rb +19 -0
  270. data/lib/mongoid/matcher/field_expression.rb +62 -0
  271. data/lib/mongoid/matcher/field_operator.rb +54 -0
  272. data/lib/mongoid/matcher/gt.rb +17 -0
  273. data/lib/mongoid/matcher/gte.rb +17 -0
  274. data/lib/mongoid/matcher/in.rb +25 -0
  275. data/lib/mongoid/matcher/lt.rb +17 -0
  276. data/lib/mongoid/matcher/lte.rb +17 -0
  277. data/lib/mongoid/matcher/mod.rb +17 -0
  278. data/lib/mongoid/matcher/ne.rb +16 -0
  279. data/lib/mongoid/matcher/nin.rb +11 -0
  280. data/lib/mongoid/matcher/nor.rb +25 -0
  281. data/lib/mongoid/matcher/not.rb +29 -0
  282. data/lib/mongoid/matcher/or.rb +21 -0
  283. data/lib/mongoid/matcher/regex.rb +41 -0
  284. data/lib/mongoid/matcher/size.rb +26 -0
  285. data/lib/mongoid/matcher/type.rb +99 -0
  286. data/lib/mongoid/matcher.rb +130 -0
  287. data/lib/mongoid/persistable/creatable.rb +22 -30
  288. data/lib/mongoid/persistable/deletable.rb +6 -22
  289. data/lib/mongoid/persistable/destroyable.rb +12 -11
  290. data/lib/mongoid/persistable/incrementable.rb +6 -7
  291. data/lib/mongoid/persistable/logical.rb +4 -6
  292. data/lib/mongoid/persistable/poppable.rb +3 -6
  293. data/lib/mongoid/persistable/pullable.rb +3 -8
  294. data/lib/mongoid/persistable/pushable.rb +3 -8
  295. data/lib/mongoid/persistable/renamable.rb +10 -8
  296. data/lib/mongoid/persistable/savable.rb +5 -10
  297. data/lib/mongoid/persistable/settable.rb +3 -6
  298. data/lib/mongoid/persistable/unsettable.rb +9 -9
  299. data/lib/mongoid/persistable/updatable.rb +50 -31
  300. data/lib/mongoid/persistable/upsertable.rb +5 -10
  301. data/lib/mongoid/persistable.rb +135 -40
  302. data/lib/mongoid/persistence_context.rb +85 -45
  303. data/lib/mongoid/positional.rb +2 -5
  304. data/lib/mongoid/query_cache.rb +13 -280
  305. data/lib/mongoid/railtie.rb +3 -16
  306. data/lib/mongoid/railties/controller_runtime.rb +4 -2
  307. data/lib/mongoid/railties/database.rake +9 -0
  308. data/lib/mongoid/reloadable.rb +19 -22
  309. data/lib/mongoid/scopable.rb +34 -57
  310. data/lib/mongoid/selectable.rb +8 -18
  311. data/lib/mongoid/serializable.rb +33 -34
  312. data/lib/mongoid/shardable.rb +108 -21
  313. data/lib/mongoid/stateful.rb +38 -19
  314. data/lib/mongoid/stringified_symbol.rb +52 -0
  315. data/lib/mongoid/tasks/database.rake +12 -5
  316. data/lib/mongoid/tasks/database.rb +85 -7
  317. data/lib/mongoid/threaded/lifecycle.rb +7 -26
  318. data/lib/mongoid/threaded.rb +44 -67
  319. data/lib/mongoid/timestamps/created/short.rb +2 -1
  320. data/lib/mongoid/timestamps/created.rb +4 -3
  321. data/lib/mongoid/timestamps/short.rb +2 -1
  322. data/lib/mongoid/timestamps/timeless.rb +6 -9
  323. data/lib/mongoid/timestamps/updated/short.rb +2 -1
  324. data/lib/mongoid/timestamps/updated.rb +5 -6
  325. data/lib/mongoid/timestamps.rb +3 -2
  326. data/lib/mongoid/touchable.rb +54 -25
  327. data/lib/mongoid/traversable.rb +185 -61
  328. data/lib/mongoid/validatable/associated.rb +99 -22
  329. data/lib/mongoid/validatable/format.rb +2 -1
  330. data/lib/mongoid/validatable/length.rb +2 -1
  331. data/lib/mongoid/validatable/localizable.rb +3 -4
  332. data/lib/mongoid/validatable/macros.rb +2 -9
  333. data/lib/mongoid/validatable/presence.rb +10 -15
  334. data/lib/mongoid/validatable/queryable.rb +2 -3
  335. data/lib/mongoid/validatable/uniqueness.rb +29 -41
  336. data/lib/mongoid/validatable.rb +22 -33
  337. data/lib/mongoid/version.rb +2 -2
  338. data/lib/mongoid/warnings.rb +28 -0
  339. data/lib/mongoid.rb +34 -15
  340. data/lib/rails/generators/mongoid/config/config_generator.rb +2 -1
  341. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +53 -32
  342. data/lib/rails/generators/mongoid/model/model_generator.rb +3 -2
  343. data/lib/rails/generators/mongoid_generator.rb +2 -1
  344. data/lib/rails/mongoid.rb +4 -5
  345. data/spec/README.md +19 -4
  346. data/spec/config/mongoid.yml +17 -0
  347. data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
  348. data/spec/integration/app_spec.rb +31 -27
  349. data/spec/integration/associations/belongs_to_spec.rb +20 -0
  350. data/spec/integration/associations/embedded_dirty_spec.rb +57 -0
  351. data/spec/integration/associations/embedded_spec.rb +162 -55
  352. data/spec/integration/associations/embeds_many_spec.rb +219 -0
  353. data/spec/integration/associations/embeds_one_spec.rb +41 -0
  354. data/spec/integration/associations/foreign_key_spec.rb +107 -0
  355. data/spec/integration/associations/foreign_key_spec_models.rb +64 -0
  356. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +61 -0
  357. data/spec/integration/associations/has_many_spec.rb +128 -0
  358. data/spec/integration/associations/has_one_spec.rb +272 -0
  359. data/spec/integration/associations/nested_attributes_assignment_spec.rb +115 -0
  360. data/spec/integration/associations/reverse_population_spec.rb +34 -0
  361. data/spec/integration/associations/reverse_population_spec_models.rb +36 -0
  362. data/spec/integration/associations/scope_option_spec.rb +101 -0
  363. data/spec/integration/atomic/modifiers_spec.rb +116 -0
  364. data/spec/integration/bson_regexp_raw_spec.rb +19 -0
  365. data/spec/integration/callbacks_models.rb +107 -1
  366. data/spec/integration/callbacks_spec.rb +262 -8
  367. data/spec/integration/contextual/empty_spec.rb +141 -0
  368. data/spec/integration/criteria/alias_query_spec.rb +161 -0
  369. data/spec/integration/criteria/date_field_spec.rb +1 -2
  370. data/spec/integration/criteria/default_scope_spec.rb +72 -0
  371. data/spec/integration/criteria/logical_spec.rb +124 -0
  372. data/spec/integration/criteria/range_spec.rb +359 -0
  373. data/spec/integration/criteria/time_with_zone_spec.rb +125 -15
  374. data/spec/integration/discriminator_key_spec.rb +392 -0
  375. data/spec/integration/discriminator_value_spec.rb +206 -0
  376. data/spec/integration/document_spec.rb +30 -1
  377. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  378. data/spec/integration/i18n_fallbacks_spec.rb +73 -0
  379. data/spec/integration/{matchable_spec.rb → matcher_examples_spec.rb} +130 -45
  380. data/spec/integration/matcher_operator_data/all.yml +140 -0
  381. data/spec/integration/matcher_operator_data/and.yml +93 -0
  382. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  383. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  384. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  385. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  386. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  387. data/spec/integration/matcher_operator_data/elem_match.yml +409 -0
  388. data/spec/integration/matcher_operator_data/elem_match_expr.yml +213 -0
  389. data/spec/integration/matcher_operator_data/eq.yml +191 -0
  390. data/spec/integration/matcher_operator_data/exists.yml +213 -0
  391. data/spec/integration/matcher_operator_data/generic_op.yml +17 -0
  392. data/spec/integration/matcher_operator_data/gt.yml +132 -0
  393. data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
  394. data/spec/integration/matcher_operator_data/gte.yml +132 -0
  395. data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
  396. data/spec/integration/matcher_operator_data/implicit.yml +331 -0
  397. data/spec/integration/matcher_operator_data/implicit_traversal.yml +112 -0
  398. data/spec/integration/matcher_operator_data/in.yml +210 -0
  399. data/spec/integration/matcher_operator_data/invalid_op.yml +59 -0
  400. data/spec/integration/matcher_operator_data/invalid_syntax.yml +39 -0
  401. data/spec/integration/matcher_operator_data/lt.yml +132 -0
  402. data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
  403. data/spec/integration/matcher_operator_data/lte.yml +132 -0
  404. data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
  405. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  406. data/spec/integration/matcher_operator_data/multiple.yml +29 -0
  407. data/spec/integration/matcher_operator_data/ne.yml +150 -0
  408. data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
  409. data/spec/integration/matcher_operator_data/nin.yml +114 -0
  410. data/spec/integration/matcher_operator_data/nor.yml +126 -0
  411. data/spec/integration/matcher_operator_data/not.yml +196 -0
  412. data/spec/integration/matcher_operator_data/or.yml +137 -0
  413. data/spec/integration/matcher_operator_data/regex.yml +174 -0
  414. data/spec/integration/matcher_operator_data/regex_options.yml +72 -0
  415. data/spec/integration/matcher_operator_data/size.yml +174 -0
  416. data/spec/integration/matcher_operator_data/type.yml +70 -0
  417. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  418. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  419. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  420. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  421. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  422. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  423. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  424. data/spec/integration/matcher_operator_data/type_decimal.yml +41 -0
  425. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  426. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  427. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  428. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  429. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  430. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  431. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  432. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  433. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  434. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  435. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  436. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  437. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  438. data/spec/integration/matcher_operator_spec.rb +122 -0
  439. data/spec/integration/matcher_spec.rb +283 -0
  440. data/spec/integration/persistence/range_field_spec.rb +350 -0
  441. data/spec/integration/server_query_spec.rb +141 -0
  442. data/spec/integration/shardable_spec.rb +148 -0
  443. data/spec/integration/stringified_symbol_field_spec.rb +203 -0
  444. data/spec/lite_spec_helper.rb +18 -6
  445. data/spec/mongoid/association/accessors_spec.rb +284 -77
  446. data/spec/mongoid/association/auto_save_spec.rb +74 -33
  447. data/spec/mongoid/association/builders_spec.rb +3 -1
  448. data/spec/mongoid/association/constrainable_spec.rb +2 -0
  449. data/spec/mongoid/association/counter_cache_spec.rb +35 -33
  450. data/spec/mongoid/association/depending_spec.rb +431 -338
  451. data/spec/mongoid/association/eager_spec.rb +8 -5
  452. data/spec/mongoid/association/embedded/cyclic_spec.rb +4 -2
  453. data/spec/mongoid/association/embedded/dirty_spec.rb +4 -2
  454. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +4 -1
  455. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +56 -0
  456. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +84 -22
  457. data/spec/mongoid/association/embedded/embedded_in_spec.rb +3 -1
  458. data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +2 -0
  459. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +114 -0
  460. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +687 -173
  461. data/spec/mongoid/association/embedded/embeds_many_models.rb +174 -1
  462. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +63 -0
  463. data/spec/mongoid/association/embedded/embeds_many_spec.rb +71 -1
  464. data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +2 -0
  465. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +27 -0
  466. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +23 -21
  467. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +2 -0
  468. data/spec/mongoid/association/embedded/embeds_one_models.rb +22 -0
  469. data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +28 -0
  470. data/spec/mongoid/association/embedded/embeds_one_spec.rb +31 -1
  471. data/spec/mongoid/association/macros_spec.rb +11 -9
  472. data/spec/mongoid/association/nested/many_spec.rb +2 -0
  473. data/spec/mongoid/association/nested/one_spec.rb +18 -12
  474. data/spec/mongoid/association/options_spec.rb +2 -0
  475. data/spec/mongoid/association/polymorphic_spec.rb +2 -0
  476. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +4 -1
  477. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +111 -16
  478. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +242 -12
  479. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +114 -58
  480. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  481. data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +57 -0
  482. data/spec/mongoid/association/referenced/belongs_to_spec.rb +26 -3
  483. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +3 -1
  484. data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +28 -1
  485. data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +46 -2
  486. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +25 -5
  487. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +418 -361
  488. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +68 -2
  489. data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +39 -0
  490. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +81 -4
  491. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +3 -1
  492. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +132 -0
  493. data/spec/mongoid/association/referenced/has_many/eager_spec.rb +40 -9
  494. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +314 -133
  495. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +848 -451
  496. data/spec/mongoid/association/referenced/has_many_models.rb +61 -1
  497. data/spec/mongoid/association/referenced/has_many_query_spec.rb +37 -0
  498. data/spec/mongoid/association/referenced/has_many_spec.rb +48 -0
  499. data/spec/mongoid/association/referenced/has_one/binding_spec.rb +2 -0
  500. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +55 -9
  501. data/spec/mongoid/association/referenced/has_one/eager_spec.rb +34 -4
  502. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +135 -27
  503. data/spec/mongoid/association/referenced/has_one_models.rb +65 -0
  504. data/spec/mongoid/association/referenced/has_one_query_spec.rb +37 -0
  505. data/spec/mongoid/association/referenced/has_one_spec.rb +24 -1
  506. data/spec/mongoid/association/reflections_spec.rb +2 -0
  507. data/spec/mongoid/association/syncable_spec.rb +47 -31
  508. data/spec/mongoid/association_spec.rb +2 -0
  509. data/spec/mongoid/atomic/modifiers_spec.rb +49 -0
  510. data/spec/mongoid/atomic/paths/embedded/many_spec.rb +2 -0
  511. data/spec/mongoid/atomic/paths/embedded/one_spec.rb +2 -0
  512. data/spec/mongoid/atomic/paths/root_spec.rb +2 -0
  513. data/spec/mongoid/atomic/paths_spec.rb +66 -26
  514. data/spec/mongoid/atomic_spec.rb +53 -6
  515. data/spec/mongoid/attributes/dynamic_spec.rb +0 -1
  516. data/spec/mongoid/attributes/nested_spec.rb +149 -78
  517. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  518. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  519. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  520. data/spec/mongoid/attributes/projector_spec.rb +40 -0
  521. data/spec/mongoid/attributes/readonly_spec.rb +24 -22
  522. data/spec/mongoid/attributes_spec.rb +683 -65
  523. data/spec/mongoid/cacheable_spec.rb +6 -4
  524. data/spec/mongoid/changeable_spec.rb +185 -43
  525. data/spec/mongoid/clients/factory_spec.rb +128 -28
  526. data/spec/mongoid/clients/options_spec.rb +45 -26
  527. data/spec/mongoid/clients/sessions_spec.rb +25 -66
  528. data/spec/mongoid/clients/transactions_spec.rb +54 -29
  529. data/spec/mongoid/clients_spec.rb +65 -8
  530. data/spec/mongoid/composable_spec.rb +2 -0
  531. data/spec/mongoid/config/environment_spec.rb +126 -8
  532. data/spec/mongoid/config/options_spec.rb +22 -3
  533. data/spec/mongoid/config_spec.rb +377 -1
  534. data/spec/mongoid/contextual/aggregable/memory_spec.rb +433 -153
  535. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  536. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  537. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +122 -20
  538. data/spec/mongoid/contextual/aggregable/none_spec.rb +60 -0
  539. data/spec/mongoid/contextual/atomic_spec.rb +205 -67
  540. data/spec/mongoid/contextual/geo_near_spec.rb +20 -18
  541. data/spec/mongoid/contextual/map_reduce_spec.rb +6 -18
  542. data/spec/mongoid/contextual/memory_spec.rb +1360 -91
  543. data/spec/mongoid/contextual/mongo_spec.rb +1871 -544
  544. data/spec/mongoid/contextual/none_spec.rb +39 -73
  545. data/spec/mongoid/copyable_spec.rb +657 -26
  546. data/spec/mongoid/copyable_spec_models.rb +30 -0
  547. data/spec/mongoid/criteria/findable_spec.rb +161 -228
  548. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  549. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  550. data/spec/mongoid/criteria/inspectable_spec.rb +2 -0
  551. data/spec/mongoid/criteria/marshalable_spec.rb +20 -1
  552. data/spec/mongoid/criteria/modifiable_spec.rb +43 -40
  553. data/spec/mongoid/criteria/options_spec.rb +2 -0
  554. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +3 -1
  555. data/spec/mongoid/criteria/queryable/expandable_spec.rb +61 -0
  556. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +9 -19
  557. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +136 -26
  558. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +2 -0
  559. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +3 -1
  560. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +13 -0
  561. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +46 -17
  562. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +2 -0
  563. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +2 -0
  564. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +2 -15
  565. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +2 -0
  566. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +2 -0
  567. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -8
  568. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +2 -0
  569. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +239 -178
  570. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +3 -1
  571. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +2 -0
  572. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +2 -0
  573. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +2 -59
  574. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +2 -59
  575. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +34 -16
  576. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +13 -0
  577. data/spec/mongoid/criteria/queryable/key_spec.rb +2 -0
  578. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +145 -12
  579. data/spec/mongoid/criteria/queryable/optional_spec.rb +18 -485
  580. data/spec/mongoid/criteria/queryable/options_spec.rb +2 -0
  581. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +2 -0
  582. data/spec/mongoid/criteria/queryable/queryable_spec.rb +3 -1
  583. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +1643 -286
  584. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +38 -0
  585. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1191 -2752
  586. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +589 -0
  587. data/spec/mongoid/criteria/queryable/selector_spec.rb +91 -4
  588. data/spec/mongoid/criteria/queryable/smash_spec.rb +2 -0
  589. data/spec/mongoid/criteria/queryable/storable_spec.rb +298 -0
  590. data/spec/mongoid/criteria/scopable_spec.rb +129 -0
  591. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  592. data/spec/mongoid/criteria_projection_spec.rb +409 -0
  593. data/spec/mongoid/criteria_spec.rb +1322 -1723
  594. data/spec/mongoid/document_fields_spec.rb +179 -5
  595. data/spec/mongoid/document_persistence_context_spec.rb +0 -1
  596. data/spec/mongoid/document_query_spec.rb +89 -0
  597. data/spec/mongoid/document_spec.rb +153 -87
  598. data/spec/mongoid/equality_spec.rb +144 -41
  599. data/spec/mongoid/errors/ambiguous_relationship_spec.rb +5 -3
  600. data/spec/mongoid/errors/callback_spec.rb +2 -0
  601. data/spec/mongoid/errors/delete_restriction_spec.rb +4 -2
  602. data/spec/mongoid/errors/document_not_destroyed_spec.rb +2 -0
  603. data/spec/mongoid/errors/document_not_found_spec.rb +78 -0
  604. data/spec/mongoid/errors/invalid_collection_spec.rb +2 -0
  605. data/spec/mongoid/errors/{eager_load_spec.rb → invalid_config_file_spec.rb} +7 -5
  606. data/spec/mongoid/errors/invalid_config_option_spec.rb +2 -0
  607. data/spec/mongoid/errors/invalid_field_option_spec.rb +2 -0
  608. data/spec/mongoid/errors/invalid_field_spec.rb +3 -1
  609. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  610. data/spec/mongoid/errors/invalid_find_spec.rb +2 -0
  611. data/spec/mongoid/errors/invalid_includes_spec.rb +2 -0
  612. data/spec/mongoid/errors/invalid_index_spec.rb +2 -0
  613. data/spec/mongoid/errors/invalid_options_spec.rb +4 -2
  614. data/spec/mongoid/errors/invalid_path_spec.rb +2 -0
  615. data/spec/mongoid/errors/invalid_relation_spec.rb +4 -2
  616. data/spec/mongoid/errors/invalid_scope_spec.rb +3 -1
  617. data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +2 -0
  618. data/spec/mongoid/errors/invalid_storage_options_spec.rb +2 -0
  619. data/spec/mongoid/errors/invalid_time_spec.rb +2 -0
  620. data/spec/mongoid/errors/inverse_not_found_spec.rb +3 -1
  621. data/spec/mongoid/errors/mixed_client_configuration_spec.rb +2 -0
  622. data/spec/mongoid/errors/mixed_relations_spec.rb +2 -0
  623. data/spec/mongoid/errors/mongoid_error_spec.rb +24 -8
  624. data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +5 -3
  625. data/spec/mongoid/errors/no_client_config_spec.rb +4 -2
  626. data/spec/mongoid/errors/no_client_database_spec.rb +5 -3
  627. data/spec/mongoid/errors/no_client_hosts_spec.rb +5 -3
  628. data/spec/mongoid/errors/no_clients_config_spec.rb +2 -0
  629. data/spec/mongoid/errors/no_environment_spec.rb +5 -3
  630. data/spec/mongoid/errors/no_map_reduce_output_spec.rb +2 -0
  631. data/spec/mongoid/errors/no_metadata_spec.rb +4 -2
  632. data/spec/mongoid/errors/no_parent_spec.rb +3 -1
  633. data/spec/mongoid/errors/readonly_attribute_spec.rb +2 -0
  634. data/spec/mongoid/errors/readonly_document_spec.rb +2 -0
  635. data/spec/mongoid/errors/scope_overwrite_spec.rb +2 -0
  636. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +3 -1
  637. data/spec/mongoid/errors/unknown_attribute_spec.rb +4 -2
  638. data/spec/mongoid/errors/unsaved_document_spec.rb +3 -1
  639. data/spec/mongoid/errors/unsupported_javascript_spec.rb +2 -0
  640. data/spec/mongoid/errors/validations_spec.rb +2 -0
  641. data/spec/mongoid/extensions/array_spec.rb +41 -45
  642. data/spec/mongoid/extensions/big_decimal_spec.rb +714 -212
  643. data/spec/mongoid/extensions/binary_spec.rb +46 -9
  644. data/spec/mongoid/extensions/boolean_spec.rb +70 -82
  645. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +339 -0
  646. data/spec/mongoid/extensions/date_spec.rb +58 -140
  647. data/spec/mongoid/extensions/date_time_spec.rb +32 -69
  648. data/spec/mongoid/extensions/decimal128_spec.rb +2 -0
  649. data/spec/mongoid/extensions/false_class_spec.rb +3 -1
  650. data/spec/mongoid/extensions/float_spec.rb +66 -73
  651. data/spec/mongoid/extensions/hash_spec.rb +138 -3
  652. data/spec/mongoid/extensions/integer_spec.rb +61 -63
  653. data/spec/mongoid/extensions/module_spec.rb +2 -0
  654. data/spec/mongoid/extensions/nil_class_spec.rb +2 -0
  655. data/spec/mongoid/extensions/object_id_spec.rb +2 -0
  656. data/spec/mongoid/extensions/object_spec.rb +13 -24
  657. data/spec/mongoid/extensions/range_spec.rb +257 -54
  658. data/spec/mongoid/extensions/regexp_spec.rb +60 -33
  659. data/spec/mongoid/extensions/set_spec.rb +108 -0
  660. data/spec/mongoid/extensions/string_spec.rb +111 -50
  661. data/spec/mongoid/extensions/stringified_symbol_spec.rb +84 -0
  662. data/spec/mongoid/extensions/symbol_spec.rb +20 -25
  663. data/spec/mongoid/extensions/time_spec.rb +663 -66
  664. data/spec/mongoid/extensions/time_with_zone_spec.rb +50 -31
  665. data/spec/mongoid/extensions/true_class_spec.rb +3 -1
  666. data/spec/mongoid/extensions_spec.rb +16 -2
  667. data/spec/mongoid/factory_spec.rb +347 -27
  668. data/spec/mongoid/fields/foreign_key_spec.rb +2 -0
  669. data/spec/mongoid/fields/localized_spec.rb +43 -16
  670. data/spec/mongoid/fields/standard_spec.rb +2 -0
  671. data/spec/mongoid/fields_spec.rb +776 -80
  672. data/spec/mongoid/findable_spec.rb +133 -34
  673. data/spec/mongoid/indexable/specification_spec.rb +4 -2
  674. data/spec/mongoid/indexable_spec.rb +65 -18
  675. data/spec/mongoid/inspectable_spec.rb +39 -2
  676. data/spec/mongoid/interceptable_spec.rb +955 -103
  677. data/spec/mongoid/interceptable_spec_models.rb +307 -0
  678. data/spec/mongoid/loggable_spec.rb +2 -0
  679. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  680. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +239 -0
  681. data/spec/mongoid/matcher/extract_attribute_spec.rb +36 -0
  682. data/spec/mongoid/mongoizable_spec.rb +285 -0
  683. data/spec/mongoid/persistable/creatable_spec.rb +114 -29
  684. data/spec/mongoid/persistable/deletable_spec.rb +274 -12
  685. data/spec/mongoid/persistable/destroyable_spec.rb +202 -12
  686. data/spec/mongoid/persistable/incrementable_spec.rb +23 -7
  687. data/spec/mongoid/persistable/logical_spec.rb +19 -3
  688. data/spec/mongoid/persistable/poppable_spec.rb +19 -3
  689. data/spec/mongoid/persistable/pullable_spec.rb +36 -6
  690. data/spec/mongoid/persistable/pushable_spec.rb +36 -6
  691. data/spec/mongoid/persistable/renamable_spec.rb +18 -2
  692. data/spec/mongoid/persistable/savable_spec.rb +188 -25
  693. data/spec/mongoid/persistable/settable_spec.rb +24 -8
  694. data/spec/mongoid/persistable/unsettable_spec.rb +19 -3
  695. data/spec/mongoid/persistable/updatable_spec.rb +45 -23
  696. data/spec/mongoid/persistable/upsertable_spec.rb +18 -2
  697. data/spec/mongoid/persistable_spec.rb +85 -9
  698. data/spec/mongoid/persistence_context_spec.rb +52 -1
  699. data/spec/mongoid/positional_spec.rb +2 -0
  700. data/spec/mongoid/query_cache_middleware_spec.rb +50 -0
  701. data/spec/mongoid/query_cache_spec.rb +339 -87
  702. data/spec/mongoid/relations/proxy_spec.rb +8 -6
  703. data/spec/mongoid/reloadable_spec.rb +357 -22
  704. data/spec/mongoid/scopable_spec.rb +121 -37
  705. data/spec/mongoid/selectable_spec.rb +8 -6
  706. data/spec/mongoid/serializable_spec.rb +160 -29
  707. data/spec/mongoid/shardable_models.rb +75 -0
  708. data/spec/mongoid/shardable_spec.rb +239 -34
  709. data/spec/mongoid/stateful_spec.rb +31 -1
  710. data/spec/mongoid/tasks/database_rake_spec.rb +2 -0
  711. data/spec/mongoid/tasks/database_spec.rb +2 -0
  712. data/spec/mongoid/threaded_spec.rb +4 -2
  713. data/spec/mongoid/timestamps/created/short_spec.rb +3 -1
  714. data/spec/mongoid/timestamps/created_spec.rb +3 -1
  715. data/spec/mongoid/timestamps/timeless_spec.rb +4 -2
  716. data/spec/mongoid/timestamps/updated/short_spec.rb +5 -3
  717. data/spec/mongoid/timestamps/updated_spec.rb +5 -3
  718. data/spec/mongoid/timestamps_spec.rb +398 -6
  719. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  720. data/spec/mongoid/touchable_spec.rb +296 -33
  721. data/spec/mongoid/touchable_spec_models.rb +57 -0
  722. data/spec/mongoid/traversable_spec.rb +1160 -1
  723. data/spec/mongoid/validatable/associated_spec.rb +15 -30
  724. data/spec/mongoid/validatable/format_spec.rb +2 -0
  725. data/spec/mongoid/validatable/length_spec.rb +2 -0
  726. data/spec/mongoid/validatable/numericality_spec.rb +2 -0
  727. data/spec/mongoid/validatable/presence_spec.rb +28 -22
  728. data/spec/mongoid/validatable/uniqueness_spec.rb +128 -98
  729. data/spec/mongoid/validatable_spec.rb +5 -3
  730. data/spec/mongoid/warnings_spec.rb +35 -0
  731. data/spec/mongoid_spec.rb +3 -1
  732. data/spec/rails/controller_extension/controller_runtime_spec.rb +5 -3
  733. data/spec/rails/mongoid_spec.rb +8 -18
  734. data/spec/shared/bin/s3-copy +45 -0
  735. data/spec/shared/bin/s3-upload +69 -0
  736. data/spec/shared/lib/mrss/cluster_config.rb +14 -4
  737. data/spec/shared/lib/mrss/constraints.rb +51 -27
  738. data/spec/shared/lib/mrss/docker_runner.rb +37 -4
  739. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  740. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  741. data/spec/shared/lib/mrss/lite_constraints.rb +48 -1
  742. data/spec/shared/lib/mrss/server_version_registry.rb +16 -18
  743. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  744. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  745. data/spec/shared/lib/mrss/spec_organizer.rb +18 -1
  746. data/spec/shared/lib/mrss/utils.rb +28 -6
  747. data/spec/shared/share/Dockerfile.erb +156 -66
  748. data/spec/shared/share/haproxy-1.conf +16 -0
  749. data/spec/shared/share/haproxy-2.conf +17 -0
  750. data/spec/shared/shlib/config.sh +27 -0
  751. data/spec/shared/shlib/distro.sh +2 -1
  752. data/spec/shared/shlib/server.sh +171 -45
  753. data/spec/shared/shlib/set_env.sh +47 -6
  754. data/spec/spec_helper.rb +38 -36
  755. data/spec/support/authorization.rb +2 -0
  756. data/spec/support/client_registry.rb +9 -0
  757. data/spec/support/constraints.rb +39 -8
  758. data/spec/support/expectations.rb +5 -1
  759. data/spec/support/helpers.rb +11 -0
  760. data/spec/support/macros.rb +77 -0
  761. data/spec/{app → support}/models/account.rb +3 -1
  762. data/spec/{app → support}/models/acolyte.rb +2 -0
  763. data/spec/{app → support}/models/actor.rb +3 -1
  764. data/spec/support/models/actress.rb +4 -0
  765. data/spec/{app → support}/models/address.rb +6 -0
  766. data/spec/{app → support}/models/address_component.rb +2 -0
  767. data/spec/{app → support}/models/address_number.rb +2 -0
  768. data/spec/{app → support}/models/agency.rb +2 -0
  769. data/spec/{app → support}/models/agent.rb +2 -0
  770. data/spec/{app → support}/models/album.rb +2 -0
  771. data/spec/{app → support}/models/alert.rb +2 -0
  772. data/spec/{app → support}/models/animal.rb +2 -0
  773. data/spec/{app → support}/models/answer.rb +2 -0
  774. data/spec/{app → support}/models/appointment.rb +2 -0
  775. data/spec/support/models/armrest.rb +9 -0
  776. data/spec/{app → support}/models/article.rb +2 -0
  777. data/spec/{app → support}/models/artist.rb +4 -0
  778. data/spec/{app → support}/models/artwork.rb +2 -0
  779. data/spec/support/models/audible_sound.rb +3 -0
  780. data/spec/{app → support}/models/audio.rb +2 -0
  781. data/spec/support/models/augmentation.rb +25 -0
  782. data/spec/{app → support}/models/author.rb +2 -0
  783. data/spec/{app → support}/models/baby.rb +2 -0
  784. data/spec/{app → support}/models/band.rb +9 -0
  785. data/spec/{app → support}/models/bar.rb +2 -0
  786. data/spec/{app → support}/models/basic.rb +2 -0
  787. data/spec/support/models/bed.rb +3 -0
  788. data/spec/{app → support}/models/big_palette.rb +2 -0
  789. data/spec/{app → support}/models/birthday.rb +2 -0
  790. data/spec/support/models/bolt.rb +7 -0
  791. data/spec/{app → support}/models/bomb.rb +2 -0
  792. data/spec/{app → support}/models/book.rb +2 -0
  793. data/spec/{app → support}/models/breed.rb +2 -0
  794. data/spec/{app → support}/models/browser.rb +3 -1
  795. data/spec/{app → support}/models/building.rb +2 -0
  796. data/spec/{app → support}/models/building_address.rb +2 -0
  797. data/spec/{app → support}/models/bus.rb +2 -0
  798. data/spec/{app → support}/models/business.rb +2 -0
  799. data/spec/{app → support}/models/callback_test.rb +2 -0
  800. data/spec/{app → support}/models/canvas.rb +3 -1
  801. data/spec/support/models/car.rb +3 -0
  802. data/spec/{app → support}/models/cat.rb +2 -0
  803. data/spec/support/models/catalog.rb +24 -0
  804. data/spec/{app → support}/models/category.rb +2 -0
  805. data/spec/{app → support}/models/child.rb +2 -0
  806. data/spec/{app → support}/models/child_doc.rb +5 -3
  807. data/spec/{app → support}/models/church.rb +2 -0
  808. data/spec/{app → support}/models/circle.rb +2 -0
  809. data/spec/{app → support}/models/circuit.rb +2 -0
  810. data/spec/support/models/circus.rb +12 -0
  811. data/spec/{app → support}/models/code.rb +4 -0
  812. data/spec/support/models/coding/pull_request.rb +11 -0
  813. data/spec/support/models/coding.rb +3 -0
  814. data/spec/{app → support}/models/comment.rb +2 -0
  815. data/spec/{app → support}/models/company.rb +2 -0
  816. data/spec/{app → support}/models/consumption_period.rb +2 -0
  817. data/spec/{app → support}/models/contextable_item.rb +2 -0
  818. data/spec/{app → support}/models/contractor.rb +2 -0
  819. data/spec/{app → support}/models/cookie.rb +2 -0
  820. data/spec/{app → support}/models/country_code.rb +4 -0
  821. data/spec/{app → support}/models/courier_job.rb +2 -0
  822. data/spec/support/models/crate.rb +12 -0
  823. data/spec/{app → support}/models/customer.rb +0 -1
  824. data/spec/{app → support}/models/customer_address.rb +0 -1
  825. data/spec/support/models/deed.rb +7 -0
  826. data/spec/{app → support}/models/definition.rb +2 -0
  827. data/spec/{app → support}/models/delegating_patient.rb +0 -1
  828. data/spec/{app → support}/models/description.rb +2 -0
  829. data/spec/{app → support}/models/dictionary.rb +8 -0
  830. data/spec/{app → support}/models/division.rb +2 -0
  831. data/spec/{app → support}/models/doctor.rb +2 -0
  832. data/spec/{app → support}/models/dog.rb +2 -0
  833. data/spec/{app → support}/models/dokument.rb +2 -0
  834. data/spec/{app → support}/models/draft.rb +2 -0
  835. data/spec/{app → support}/models/dragon.rb +2 -0
  836. data/spec/{app → support}/models/driver.rb +3 -1
  837. data/spec/{app → support}/models/drug.rb +2 -0
  838. data/spec/{app → support}/models/dungeon.rb +2 -0
  839. data/spec/{app → support}/models/edit.rb +2 -0
  840. data/spec/{app → support}/models/email.rb +2 -0
  841. data/spec/{app → support}/models/employer.rb +2 -0
  842. data/spec/{app → support}/models/entry.rb +2 -0
  843. data/spec/support/models/eraser.rb +3 -0
  844. data/spec/{app → support}/models/even.rb +2 -0
  845. data/spec/{app → support}/models/event.rb +2 -0
  846. data/spec/{app → support}/models/exhibition.rb +2 -0
  847. data/spec/{app → support}/models/exhibitor.rb +2 -0
  848. data/spec/{app → support}/models/explosion.rb +2 -0
  849. data/spec/{app → support}/models/eye.rb +2 -0
  850. data/spec/{app → support}/models/eye_bowl.rb +2 -0
  851. data/spec/{app → support}/models/face.rb +2 -0
  852. data/spec/support/models/fanatic.rb +8 -0
  853. data/spec/{app → support}/models/favorite.rb +2 -0
  854. data/spec/{app → support}/models/filesystem.rb +2 -0
  855. data/spec/{app → support}/models/fire_hydrant.rb +2 -0
  856. data/spec/{app → support}/models/firefox.rb +2 -0
  857. data/spec/{app → support}/models/fish.rb +2 -0
  858. data/spec/{app → support}/models/folder.rb +2 -0
  859. data/spec/{app → support}/models/folder_item.rb +2 -0
  860. data/spec/{app → support}/models/fruits.rb +2 -0
  861. data/spec/{app → support}/models/game.rb +2 -0
  862. data/spec/{app → support}/models/ghost.rb +2 -0
  863. data/spec/support/models/guitar.rb +4 -0
  864. data/spec/support/models/hole.rb +12 -0
  865. data/spec/{app → support}/models/home.rb +2 -0
  866. data/spec/{app → support}/models/house.rb +2 -0
  867. data/spec/{app → support}/models/html_writer.rb +2 -0
  868. data/spec/{app → support}/models/id_key.rb +2 -0
  869. data/spec/support/models/idnodef.rb +7 -0
  870. data/spec/{app → support}/models/image.rb +2 -0
  871. data/spec/{app → support}/models/implant.rb +11 -0
  872. data/spec/support/models/instrument.rb +8 -0
  873. data/spec/{app → support}/models/item.rb +3 -1
  874. data/spec/{app → support}/models/jar.rb +2 -0
  875. data/spec/{app → support}/models/kaleidoscope.rb +2 -0
  876. data/spec/{app → support}/models/kangaroo.rb +3 -1
  877. data/spec/{app → support}/models/label.rb +6 -1
  878. data/spec/{app → support}/models/language.rb +2 -0
  879. data/spec/{app → support}/models/lat_lng.rb +2 -0
  880. data/spec/{app → support}/models/league.rb +2 -0
  881. data/spec/support/models/learner.rb +4 -0
  882. data/spec/{app → support}/models/line_item.rb +2 -0
  883. data/spec/{app → support}/models/location.rb +2 -0
  884. data/spec/{app → support}/models/login.rb +2 -0
  885. data/spec/{app → support}/models/manufacturer.rb +2 -0
  886. data/spec/{app → support}/models/meat.rb +2 -0
  887. data/spec/{app → support}/models/membership.rb +3 -0
  888. data/spec/{app → support}/models/message.rb +2 -0
  889. data/spec/{app → support}/models/minim.rb +0 -1
  890. data/spec/{app → support}/models/mixed_drink.rb +2 -0
  891. data/spec/support/models/mop.rb +24 -0
  892. data/spec/{app → support}/models/movie.rb +2 -0
  893. data/spec/support/models/my_hash.rb +4 -0
  894. data/spec/{app → support}/models/name.rb +12 -0
  895. data/spec/support/models/name_only.rb +8 -0
  896. data/spec/{app → support}/models/node.rb +2 -0
  897. data/spec/{app → support}/models/note.rb +2 -0
  898. data/spec/support/models/nut.rb +7 -0
  899. data/spec/{app → support}/models/odd.rb +2 -0
  900. data/spec/support/models/order.rb +12 -0
  901. data/spec/{app → support}/models/ordered_post.rb +3 -1
  902. data/spec/{app → support}/models/ordered_preference.rb +2 -0
  903. data/spec/{app → support}/models/oscar.rb +2 -0
  904. data/spec/support/models/other_owner_object.rb +4 -0
  905. data/spec/{app → support}/models/override.rb +2 -0
  906. data/spec/{app → support}/models/ownable.rb +2 -0
  907. data/spec/{app → support}/models/owner.rb +4 -0
  908. data/spec/{app → support}/models/pack.rb +2 -0
  909. data/spec/{app → support}/models/page.rb +2 -0
  910. data/spec/{app → support}/models/page_question.rb +2 -0
  911. data/spec/{app → support}/models/palette.rb +3 -1
  912. data/spec/{app → support}/models/parent.rb +2 -0
  913. data/spec/{app → support}/models/parent_doc.rb +2 -0
  914. data/spec/support/models/passport.rb +22 -0
  915. data/spec/{app → support}/models/patient.rb +2 -0
  916. data/spec/{app → support}/models/pdf_writer.rb +2 -0
  917. data/spec/support/models/pencil.rb +3 -0
  918. data/spec/{app → support}/models/person.rb +23 -1
  919. data/spec/{app → support}/models/pet.rb +2 -0
  920. data/spec/{app → support}/models/pet_owner.rb +2 -0
  921. data/spec/{app → support}/models/phone.rb +5 -1
  922. data/spec/support/models/piano.rb +4 -0
  923. data/spec/{app → support}/models/pizza.rb +2 -0
  924. data/spec/{app → support}/models/player.rb +4 -0
  925. data/spec/{app → support}/models/post.rb +2 -0
  926. data/spec/{app → support}/models/post_genre.rb +2 -0
  927. data/spec/support/models/powerup.rb +25 -0
  928. data/spec/{app → support}/models/preference.rb +2 -0
  929. data/spec/{app → support}/models/princess.rb +2 -0
  930. data/spec/{app → support}/models/product.rb +2 -0
  931. data/spec/support/models/profile.rb +17 -0
  932. data/spec/{app → support}/models/pronunciation.rb +2 -0
  933. data/spec/{app → support}/models/pub.rb +2 -0
  934. data/spec/support/models/publication/encyclopedia.rb +11 -0
  935. data/spec/support/models/publication/review.rb +13 -0
  936. data/spec/support/models/publication.rb +4 -0
  937. data/spec/{app → support}/models/purchase.rb +2 -0
  938. data/spec/support/models/purchased_item.rb +10 -0
  939. data/spec/support/models/purse.rb +9 -0
  940. data/spec/{app → support}/models/question.rb +2 -0
  941. data/spec/{app → support}/models/quiz.rb +2 -0
  942. data/spec/{app → support}/models/rating.rb +2 -0
  943. data/spec/{app → support}/models/record.rb +2 -0
  944. data/spec/{app → support}/models/registry.rb +3 -0
  945. data/spec/{app → support}/models/role.rb +2 -0
  946. data/spec/{app → support}/models/root_category.rb +2 -0
  947. data/spec/{app → support}/models/sandwich.rb +2 -0
  948. data/spec/{app → support}/models/scheduler.rb +2 -0
  949. data/spec/support/models/school.rb +14 -0
  950. data/spec/support/models/scribe.rb +7 -0
  951. data/spec/support/models/sealer.rb +7 -0
  952. data/spec/support/models/seat.rb +24 -0
  953. data/spec/{app → support}/models/seo.rb +2 -0
  954. data/spec/support/models/series.rb +7 -0
  955. data/spec/{app → support}/models/server.rb +2 -0
  956. data/spec/{app → support}/models/service.rb +2 -0
  957. data/spec/{app → support}/models/shape.rb +4 -2
  958. data/spec/{app → support}/models/shelf.rb +2 -0
  959. data/spec/support/models/shield.rb +18 -0
  960. data/spec/{app → support}/models/shipment_address.rb +2 -0
  961. data/spec/{app → support}/models/shipping_container.rb +2 -0
  962. data/spec/{app → support}/models/shipping_pack.rb +2 -0
  963. data/spec/support/models/shirt.rb +11 -0
  964. data/spec/{app → support}/models/shop.rb +2 -0
  965. data/spec/{app → support}/models/short_agent.rb +2 -0
  966. data/spec/{app → support}/models/short_quiz.rb +2 -0
  967. data/spec/{app → support}/models/simple.rb +2 -0
  968. data/spec/{app → support}/models/slave.rb +2 -0
  969. data/spec/{app → support}/models/song.rb +2 -0
  970. data/spec/{app → support}/models/sound.rb +2 -0
  971. data/spec/support/models/spacer.rb +7 -0
  972. data/spec/{app → support}/models/square.rb +2 -0
  973. data/spec/{app → support}/models/staff.rb +2 -0
  974. data/spec/{app → support}/models/store_as_dup_test1.rb +2 -0
  975. data/spec/{app → support}/models/store_as_dup_test2.rb +2 -0
  976. data/spec/{app → support}/models/strategy.rb +2 -0
  977. data/spec/support/models/student.rb +14 -0
  978. data/spec/{app → support}/models/sub_item.rb +2 -0
  979. data/spec/{app → support}/models/subscription.rb +2 -0
  980. data/spec/{app → support}/models/survey.rb +2 -0
  981. data/spec/{app → support}/models/symptom.rb +2 -0
  982. data/spec/support/models/system_role.rb +7 -0
  983. data/spec/{app → support}/models/tag.rb +2 -0
  984. data/spec/{app → support}/models/target.rb +2 -0
  985. data/spec/{app → support}/models/template.rb +2 -0
  986. data/spec/{app → support}/models/thing.rb +2 -0
  987. data/spec/support/models/threadlocker.rb +7 -0
  988. data/spec/{app → support}/models/title.rb +2 -0
  989. data/spec/{app → support}/models/tool.rb +4 -2
  990. data/spec/{app → support}/models/topping.rb +2 -0
  991. data/spec/support/models/toy.rb +9 -0
  992. data/spec/{app → support}/models/track.rb +2 -0
  993. data/spec/{app → support}/models/translation.rb +2 -0
  994. data/spec/{app → support}/models/tree.rb +2 -0
  995. data/spec/support/models/truck.rb +7 -0
  996. data/spec/{app → support}/models/user.rb +2 -0
  997. data/spec/{app → support}/models/user_account.rb +2 -0
  998. data/spec/{app → support}/models/validation_callback.rb +2 -0
  999. data/spec/support/models/vehicle.rb +18 -0
  1000. data/spec/{app → support}/models/version.rb +2 -0
  1001. data/spec/{app → support}/models/vertex.rb +3 -1
  1002. data/spec/{app → support}/models/vet_visit.rb +2 -0
  1003. data/spec/{app → support}/models/video.rb +2 -0
  1004. data/spec/support/models/video_game.rb +3 -0
  1005. data/spec/support/models/washer.rb +7 -0
  1006. data/spec/support/models/weapon.rb +25 -0
  1007. data/spec/{app → support}/models/wiki_page.rb +3 -0
  1008. data/spec/{app → support}/models/word.rb +2 -0
  1009. data/spec/{app → support}/models/word_origin.rb +2 -0
  1010. data/spec/{app → support}/models/writer.rb +4 -2
  1011. data/spec/support/schema_maps/schema_map_aws.json +17 -0
  1012. data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  1013. data/spec/support/schema_maps/schema_map_azure.json +17 -0
  1014. data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  1015. data/spec/support/schema_maps/schema_map_gcp.json +17 -0
  1016. data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  1017. data/spec/support/schema_maps/schema_map_kmip.json +17 -0
  1018. data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  1019. data/spec/support/schema_maps/schema_map_local.json +18 -0
  1020. data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
  1021. data/spec/support/shared/time.rb +53 -0
  1022. data/spec/support/spec_config.rb +12 -3
  1023. data.tar.gz.sig +0 -0
  1024. metadata +1162 -764
  1025. metadata.gz.sig +0 -0
  1026. data/lib/mongoid/criteria/queryable/forwardable.rb +0 -65
  1027. data/lib/mongoid/errors/eager_load.rb +0 -22
  1028. data/lib/mongoid/errors/invalid_value.rb +0 -16
  1029. data/lib/mongoid/matchable/all.rb +0 -28
  1030. data/lib/mongoid/matchable/and.rb +0 -30
  1031. data/lib/mongoid/matchable/default.rb +0 -119
  1032. data/lib/mongoid/matchable/elem_match.rb +0 -34
  1033. data/lib/mongoid/matchable/eq.rb +0 -22
  1034. data/lib/mongoid/matchable/exists.rb +0 -23
  1035. data/lib/mongoid/matchable/gt.rb +0 -23
  1036. data/lib/mongoid/matchable/gte.rb +0 -23
  1037. data/lib/mongoid/matchable/in.rb +0 -24
  1038. data/lib/mongoid/matchable/lt.rb +0 -23
  1039. data/lib/mongoid/matchable/lte.rb +0 -23
  1040. data/lib/mongoid/matchable/ne.rb +0 -21
  1041. data/lib/mongoid/matchable/nin.rb +0 -22
  1042. data/lib/mongoid/matchable/nor.rb +0 -37
  1043. data/lib/mongoid/matchable/or.rb +0 -33
  1044. data/lib/mongoid/matchable/regexp.rb +0 -27
  1045. data/lib/mongoid/matchable/size.rb +0 -21
  1046. data/lib/support/ruby_version.rb +0 -26
  1047. data/spec/app/models/actress.rb +0 -2
  1048. data/spec/app/models/augmentation.rb +0 -11
  1049. data/spec/app/models/bed.rb +0 -1
  1050. data/spec/app/models/car.rb +0 -1
  1051. data/spec/app/models/circus.rb +0 -7
  1052. data/spec/app/models/eraser.rb +0 -1
  1053. data/spec/app/models/learner.rb +0 -2
  1054. data/spec/app/models/my_hash.rb +0 -2
  1055. data/spec/app/models/other_owner_object.rb +0 -2
  1056. data/spec/app/models/passport.rb +0 -5
  1057. data/spec/app/models/pencil.rb +0 -1
  1058. data/spec/app/models/powerup.rb +0 -11
  1059. data/spec/app/models/profile.rb +0 -5
  1060. data/spec/app/models/series.rb +0 -4
  1061. data/spec/app/models/truck.rb +0 -3
  1062. data/spec/app/models/vehicle.rb +0 -11
  1063. data/spec/app/models/video_game.rb +0 -1
  1064. data/spec/app/models/weapon.rb +0 -11
  1065. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +0 -87
  1066. data/spec/mongoid/matchable/all_spec.rb +0 -31
  1067. data/spec/mongoid/matchable/and_spec.rb +0 -187
  1068. data/spec/mongoid/matchable/default_spec.rb +0 -137
  1069. data/spec/mongoid/matchable/elem_match_spec.rb +0 -106
  1070. data/spec/mongoid/matchable/eq_spec.rb +0 -48
  1071. data/spec/mongoid/matchable/exists_spec.rb +0 -57
  1072. data/spec/mongoid/matchable/gt_spec.rb +0 -86
  1073. data/spec/mongoid/matchable/gte_spec.rb +0 -84
  1074. data/spec/mongoid/matchable/in_spec.rb +0 -49
  1075. data/spec/mongoid/matchable/lt_spec.rb +0 -85
  1076. data/spec/mongoid/matchable/lte_spec.rb +0 -85
  1077. data/spec/mongoid/matchable/ne_spec.rb +0 -46
  1078. data/spec/mongoid/matchable/nin_spec.rb +0 -48
  1079. data/spec/mongoid/matchable/nor_spec.rb +0 -209
  1080. data/spec/mongoid/matchable/or_spec.rb +0 -131
  1081. data/spec/mongoid/matchable/regexp_spec.rb +0 -59
  1082. data/spec/mongoid/matchable/size_spec.rb +0 -25
  1083. data/spec/mongoid/matchable_spec.rb +0 -853
  1084. data/spec/support/cluster_config.rb +0 -158
  1085. data/spec/support/session_registry.rb +0 -50
  1086. /data/spec/{app → support}/models/array_field.rb +0 -0
  1087. /data/spec/{app → support}/models/store_as_dup_test3.rb +0 -0
  1088. /data/spec/{app → support}/models/store_as_dup_test4.rb +0 -0
  1089. /data/spec/{app → support}/models/updatable.rb +0 -0
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # encoding: utf-8
3
2
 
4
3
  require "spec_helper"
5
4
 
@@ -9,138 +8,1084 @@ describe Mongoid::Criteria::Queryable::Selectable do
9
8
  Mongoid::Query.new("id" => "_id")
10
9
  end
11
10
 
11
+ shared_examples_for 'returns a cloned query' do
12
+
13
+ it "returns a cloned query" do
14
+ expect(selection).to_not equal(query)
15
+ end
16
+ end
17
+
18
+ # Hoisting means the operator can be elided, for example
19
+ # Foo.and(a: 1) produces simply {'a' => 1}.
20
+ shared_examples_for 'a hoisting logical operation' do
21
+
22
+ let(:query) do
23
+ Mongoid::Query.new
24
+ end
25
+
26
+ context "when provided a single criterion" do
27
+
28
+ shared_examples_for 'adds the conditions to top level' do
29
+
30
+ it "adds the conditions to top level" do
31
+ expect(selection.selector).to eq(
32
+ "field" => [ 1, 2 ]
33
+ )
34
+ end
35
+
36
+ it_behaves_like 'returns a cloned query'
37
+ end
38
+
39
+ let(:selection) do
40
+ query.send(tested_method, field: [ 1, 2 ])
41
+ end
42
+
43
+ it_behaves_like 'adds the conditions to top level'
44
+
45
+ context 'when the criterion is wrapped in an array' do
46
+ let(:selection) do
47
+ query.send(tested_method, [{field: [ 1, 2 ] }])
48
+ end
49
+
50
+ it_behaves_like 'adds the conditions to top level'
51
+ end
52
+
53
+ context 'when the criterion is wrapped in a deep array with nil elements' do
54
+ let(:selection) do
55
+ query.send(tested_method, [[[{field: [ 1, 2 ] }]], [nil]])
56
+ end
57
+
58
+ it_behaves_like 'adds the conditions to top level'
59
+ end
60
+ end
61
+
62
+ context 'when argument is a Criteria' do
63
+ let(:base) do
64
+ query.where(hello: 'world')
65
+ end
66
+
67
+ let(:other) do
68
+ query.where(foo: 'bar')
69
+ end
70
+
71
+ let(:result) { base.send(tested_method, other) }
72
+
73
+ it 'combines' do
74
+ expect(result.selector).to eq(
75
+ 'hello' => 'world',
76
+ 'foo' => 'bar',
77
+ )
78
+ end
79
+ end
80
+
81
+ context "when provided a single criterion that is handled via Key" do
82
+
83
+ shared_examples_for 'adds the conditions to top level' do
84
+
85
+ it "adds the conditions to top level" do
86
+ expect(selection.selector).to eq({
87
+ "field" => {'$gt' => 3},
88
+ })
89
+ end
90
+
91
+ it_behaves_like 'returns a cloned query'
92
+ end
93
+
94
+ let(:selection) do
95
+ query.send(tested_method, :field.gt => 3)
96
+ end
97
+
98
+ it_behaves_like 'adds the conditions to top level'
99
+
100
+ context 'when the criterion is wrapped in an array' do
101
+ let(:selection) do
102
+ query.send(tested_method, [{ :field.gt => 3 }])
103
+ end
104
+
105
+ it_behaves_like 'adds the conditions to top level'
106
+ end
107
+
108
+ context 'when the criterion is wrapped in a deep array with nil elements' do
109
+ let(:selection) do
110
+ query.send(tested_method, [[[{ :field.gt => 3 }]], [nil]])
111
+ end
112
+
113
+ it_behaves_like 'adds the conditions to top level'
114
+ end
115
+
116
+ context 'when the criterion is a time' do
117
+ let(:selection) do
118
+ query.send(tested_method, :field.gte => Time.new(2020, 1, 1))
119
+ end
120
+
121
+ it 'adds the conditions' do
122
+ expect(selection.selector).to eq({
123
+ "field" => {'$gte' => Time.new(2020, 1, 1)},
124
+ })
125
+ end
126
+
127
+ it 'keeps argument type' do
128
+ selection.selector['field']['$gte'].should be_a(Time)
129
+ end
130
+ end
131
+
132
+ context 'when the criterion is a datetime' do
133
+ let(:selection) do
134
+ query.send(tested_method, :field.gte => DateTime.new(2020, 1, 1))
135
+ end
136
+
137
+ it 'adds the conditions' do
138
+ expect(selection.selector).to eq({
139
+ "field" => {'$gte' => Time.utc(2020, 1, 1)},
140
+ })
141
+ end
142
+
143
+ it 'converts argument to a time' do
144
+ selection.selector['field']['$gte'].should be_a(Time)
145
+ end
146
+ end
147
+
148
+ context 'when the criterion is a date' do
149
+ let(:selection) do
150
+ query.send(tested_method, :field.gte => Date.new(2020, 1, 1))
151
+ end
152
+
153
+ it 'adds the conditions' do
154
+ expect(selection.selector).to eq({
155
+ "field" => {'$gte' => Time.utc(2020, 1, 1)},
156
+ })
157
+ end
158
+
159
+ it 'converts argument to a time' do
160
+ selection.selector['field']['$gte'].should be_a(Time)
161
+ end
162
+ end
163
+ end
164
+
165
+ context "when provided a nested criterion" do
166
+
167
+ let(:selection) do
168
+ query.send(tested_method, :test.elem_match => { :field.in => [ 1, 2 ] })
169
+ end
170
+
171
+ it "builds the correct selector" do
172
+ expect(selection.selector).to eq({
173
+ "test" => { "$elemMatch" => { "field" => { "$in" => [ 1, 2 ] }}}
174
+ })
175
+ end
176
+
177
+ it_behaves_like 'returns a cloned query'
178
+ end
179
+
180
+ context "when chaining the criteria" do
181
+
182
+ context "when the criteria are for different fields" do
183
+
184
+ let(:selection) do
185
+ query.and(first: [ 1, 2 ]).send(tested_method, second: [ 3, 4 ])
186
+ end
187
+
188
+ it "adds the conditions to top level" do
189
+ expect(selection.selector).to eq({
190
+ "first" => [ 1, 2 ],
191
+ "second" => [ 3, 4 ],
192
+ })
193
+ end
194
+
195
+ it_behaves_like 'returns a cloned query'
196
+ end
197
+
198
+ context "when the criteria are on the same field" do
199
+
200
+ let(:selection) do
201
+ query.and(first: [ 1, 2 ]).send(tested_method, first: [ 3, 4 ])
202
+ end
203
+
204
+ it "combines via $and operator" do
205
+ expect(selection.selector).to eq({
206
+ "first" => [ 1, 2 ],
207
+ "$and" => [
208
+ { "first" => [ 3, 4 ] }
209
+ ]
210
+ })
211
+ end
212
+
213
+ it_behaves_like 'returns a cloned query'
214
+ end
215
+ end
216
+ end
217
+
218
+ # Non-hoisting means the operator is always present, for example
219
+ # Foo.or(a: 1) produces {'$or' => [{'a' => 1}]}.
220
+ shared_examples_for 'a non-hoisting logical operation' do
221
+
222
+ context 'when there is a single predicate' do
223
+ let(:query) do
224
+ Mongoid::Query.new.send(tested_method, hello: 'world')
225
+ end
226
+
227
+ it 'adds the predicate' do
228
+ expect(query.selector).to eq(expected_operator => [{'hello' => 'world'}])
229
+ end
230
+ end
231
+
232
+ context 'when the single predicate is wrapped in an array' do
233
+ let(:query) do
234
+ Mongoid::Query.new.send(tested_method, [{hello: 'world'}])
235
+ end
236
+
237
+ it 'adds the predicate' do
238
+ expect(query.selector).to eq(expected_operator => [{'hello' => 'world'}])
239
+ end
240
+ end
241
+
242
+ context 'when argument is a Criteria' do
243
+ let(:query) do
244
+ Mongoid::Query.new.where(hello: 'world')
245
+ end
246
+
247
+ let(:other) do
248
+ Mongoid::Query.new.where(foo: 'bar')
249
+ end
250
+
251
+ let(:result) { query.send(tested_method, other) }
252
+
253
+ it 'combines' do
254
+ # This is used for $or / $nor, the two conditions should remain
255
+ # as separate hashes
256
+ expect(result.selector).to eq(expected_operator => [{'hello' => 'world'}, {'foo' => 'bar'}])
257
+ end
258
+ end
259
+
260
+ context 'when argument is a mix of Criteria and hashes' do
261
+ let(:query) do
262
+ Mongoid::Query.new.where(hello: 'world')
263
+ end
264
+
265
+ let(:other1) do
266
+ Mongoid::Query.new.where(foo: 'bar')
267
+ end
268
+
269
+ let(:other2) do
270
+ {bar: 42}
271
+ end
272
+
273
+ let(:other3) do
274
+ Mongoid::Query.new.where(a: 2)
275
+ end
276
+
277
+ let(:result) { query.send(tested_method, other1, other2, other3) }
278
+
279
+ it 'combines' do
280
+ expect(result.selector).to eq(expected_operator => [
281
+ {'hello' => 'world'},
282
+ {'foo' => 'bar'},
283
+ {'bar' => 42},
284
+ {'a' => 2},
285
+ ])
286
+ end
287
+ end
288
+ end
289
+
12
290
  describe "#and" do
13
291
 
14
- context "when provided no criterion" do
292
+ let(:tested_method) { :and }
293
+ let(:expected_operator) { '$and' }
294
+
295
+ it_behaves_like 'a hoisting logical operation'
296
+
297
+ context "when provided no criterion" do
298
+
299
+ let(:selection) do
300
+ query.and
301
+ end
302
+
303
+ it "does not add any criterion" do
304
+ expect(selection.selector).to eq({})
305
+ end
306
+
307
+ it "returns the query" do
308
+ expect(selection).to eq(query)
309
+ end
310
+
311
+ it_behaves_like 'returns a cloned query'
312
+ end
313
+
314
+ context "when provided nil" do
315
+
316
+ let(:selection) do
317
+ query.and(nil)
318
+ end
319
+
320
+ it "does not add any criterion" do
321
+ expect(selection.selector).to eq({})
322
+ end
323
+
324
+ it "returns the query" do
325
+ expect(selection).to eq(query)
326
+ end
327
+
328
+ it_behaves_like 'returns a cloned query'
329
+ end
330
+
331
+ context "when provided multiple criteria" do
332
+
333
+ context "when the criterion is already included" do
334
+
335
+ context 'simple criterion' do
336
+ let(:selection) do
337
+ query.and({ first: [ 1, 2 ] }).and({ first: [ 1, 2 ] })
338
+ end
339
+
340
+ it "adds all conditions" do
341
+ expect(selection.selector).to eq({
342
+ 'first' => [1, 2],
343
+ "$and" => [
344
+ { "first" => [ 1, 2 ] }
345
+ ]
346
+ })
347
+ end
348
+
349
+ it_behaves_like 'returns a cloned query'
350
+ end
351
+
352
+ context 'Key criterion' do
353
+ let(:selection) do
354
+ query.and({ first: [ 1, 2 ] }).and(:first.gt => 3)
355
+ end
356
+
357
+ it "adds all conditions" do
358
+ expect(selection.selector).to eq({
359
+ 'first' => [1, 2],
360
+ "$and" => [
361
+ { "first" => {'$gt' => 3} }
362
+ ]
363
+ })
364
+ end
365
+
366
+ it_behaves_like 'returns a cloned query'
367
+ end
368
+
369
+ context 'Key criterion when existing criterion is an operator' do
370
+ let(:selection) do
371
+ query.and(:first.lt => 5).and(:first.gt => 3)
372
+ end
373
+
374
+ it "adds all conditions" do
375
+ expect(selection.selector).to eq({
376
+ 'first' => {'$lt' => 5, '$gt' => 3},
377
+ })
378
+ end
379
+
380
+ it_behaves_like 'returns a cloned query'
381
+ end
382
+ end
383
+
384
+ context "when the new criteria are for different fields" do
385
+
386
+ let(:selection) do
387
+ query.and({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
388
+ end
389
+
390
+ it "adds all conditions to top level" do
391
+ expect(selection.selector).to eq({
392
+ "first" => [ 1, 2 ],
393
+ "second" => [ 3, 4 ],
394
+ })
395
+ end
396
+
397
+ it_behaves_like 'returns a cloned query'
398
+ end
399
+
400
+ context "when the new criteria are for the same field" do
401
+
402
+ context 'when criteria are simple' do
403
+ let(:selection) do
404
+ query.and({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
405
+ end
406
+
407
+ it "combines via $and operator" do
408
+ expect(selection.selector).to eq({
409
+ "first" => [ 1, 2 ],
410
+ "$and" => [
411
+ { "first" => [ 3, 4 ] }
412
+ ]
413
+ })
414
+ end
415
+
416
+ it_behaves_like 'returns a cloned query'
417
+ end
418
+
419
+ context 'when criteria use operators' do
420
+ shared_examples 'behave correctly' do
421
+ let(:selection) do
422
+ query.and(
423
+ { field: {first_operator => [ 1, 2 ] }},
424
+ { field: {second_operator => [ 3, 4 ] }},
425
+ )
426
+ end
427
+
428
+ it "combines via $and operator and stringifies all keys" do
429
+ expect(selection.selector).to eq({
430
+ "field" => {'$in' => [ 1, 2 ]},
431
+ "$and" => [
432
+ { "field" => {'$in' => [ 3, 4 ] }}
433
+ ]
434
+ })
435
+ end
436
+ end
437
+
438
+ [
439
+ ['$in', '$in'],
440
+ [:$in, '$in'],
441
+ ['$in', :$in],
442
+ [:$in, :$in],
443
+ ].each do |first_operator, second_operator|
444
+ context "when first operator is #{first_operator.inspect} and second operator is #{second_operator.inspect}" do
445
+ let(:first_operator) { first_operator }
446
+ let(:second_operator) { second_operator }
447
+
448
+ include_examples 'behave correctly'
449
+ end
450
+ end
451
+ end
452
+
453
+ context 'when criteria are handled via Key' do
454
+ shared_examples_for 'adds the conditions to top level' do
455
+
456
+ it "adds the conditions to top level" do
457
+ expect(selection.selector).to eq({
458
+ "field" => {'$gt' => 3, '$lt' => 5},
459
+ })
460
+ end
461
+
462
+ it_behaves_like 'returns a cloned query'
463
+ end
464
+
465
+ context 'criteria are provided in the same hash' do
466
+ let(:selection) do
467
+ query.send(tested_method, :field.gt => 3, :field.lt => 5)
468
+ end
469
+
470
+ it_behaves_like 'adds the conditions to top level'
471
+ end
472
+
473
+ context 'criteria are provided in separate hashes' do
474
+ let(:selection) do
475
+ query.send(tested_method, {:field.gt => 3}, {:field.lt => 5})
476
+ end
477
+
478
+ it_behaves_like 'adds the conditions to top level'
479
+ end
480
+
481
+ context 'when the criterion is wrapped in an array' do
482
+ let(:selection) do
483
+ query.send(tested_method, [:field.gt => 3], [:field.lt => 5])
484
+ end
485
+
486
+ it_behaves_like 'adds the conditions to top level'
487
+ end
488
+ end
489
+
490
+ context 'when criteria are simple and handled via Key' do
491
+ shared_examples_for 'combines conditions with $and' do
492
+
493
+ it "combines conditions with $and" do
494
+ expect(selection.selector).to eq({
495
+ "field" => 3,
496
+ '$and' => ['field' => {'$lt' => 5}],
497
+ })
498
+ end
499
+
500
+ it_behaves_like 'returns a cloned query'
501
+ end
502
+
503
+ shared_examples_for 'combines conditions with $eq' do
504
+
505
+ it "combines conditions with $eq" do
506
+ expect(selection.selector).to eq({
507
+ "field" => {'$eq' => 3, '$lt' => 5},
508
+ })
509
+ end
510
+
511
+ it_behaves_like 'returns a cloned query'
512
+ end
513
+
514
+ shared_examples_for 'combines conditions with $regex' do
515
+
516
+ it "combines conditions with $regex" do
517
+ expect(selection.selector).to eq({
518
+ "field" => {'$regex' => /t/, '$lt' => 5},
519
+ })
520
+ end
521
+
522
+ it_behaves_like 'returns a cloned query'
523
+ end
524
+
525
+ context 'criteria are provided in the same hash' do
526
+ context 'non-regexp argument' do
527
+ let(:selection) do
528
+ query.send(tested_method, :field => 3, :field.lt => 5)
529
+ end
530
+
531
+ it_behaves_like 'combines conditions with $eq'
532
+ end
533
+
534
+ context 'regexp argument' do
535
+ let(:selection) do
536
+ query.send(tested_method, :field => /t/, :field.lt => 5)
537
+ end
538
+
539
+ it_behaves_like 'combines conditions with $regex'
540
+ end
541
+ end
542
+
543
+ context 'criteria are provided in separate hashes' do
544
+ let(:selection) do
545
+ query.send(tested_method, {:field => 3}, {:field.lt => 5})
546
+ end
547
+
548
+ it_behaves_like 'combines conditions with $and'
549
+ end
550
+
551
+ context 'when the criterion is wrapped in an array' do
552
+ let(:selection) do
553
+ query.send(tested_method, [:field => 3], [:field.lt => 5])
554
+ end
555
+
556
+ it_behaves_like 'combines conditions with $and'
557
+ end
558
+ end
559
+
560
+ context 'when criteria are handled via Key and simple' do
561
+ shared_examples_for 'combines conditions with $and' do
562
+
563
+ it "combines conditions with $and" do
564
+ expect(selection.selector).to eq({
565
+ "field" => {'$gt' => 3},
566
+ '$and' => ['field' => 5],
567
+ })
568
+ end
569
+
570
+ it_behaves_like 'returns a cloned query'
571
+ end
572
+
573
+ shared_examples_for 'combines conditions with $eq' do
574
+
575
+ it "combines conditions with $eq" do
576
+ expect(selection.selector).to eq({
577
+ "field" => {'$gt' => 3, '$eq' => 5},
578
+ })
579
+ end
580
+
581
+ it_behaves_like 'returns a cloned query'
582
+ end
583
+
584
+ shared_examples_for 'combines conditions with $regex' do
585
+
586
+ it "combines conditions with $regex" do
587
+ expect(selection.selector).to eq({
588
+ "field" => {'$gt' => 3, '$regex' => /t/},
589
+ })
590
+ end
591
+
592
+ it_behaves_like 'returns a cloned query'
593
+ end
594
+
595
+ context 'criteria are provided in the same hash' do
596
+ context 'non-regexp argument' do
597
+ let(:selection) do
598
+ query.send(tested_method, :field.gt => 3, :field => 5)
599
+ end
600
+
601
+ it_behaves_like 'combines conditions with $eq'
602
+ end
603
+
604
+ context 'regexp argument' do
605
+ let(:selection) do
606
+ query.send(tested_method, :field.gt => 3, :field => /t/)
607
+ end
608
+
609
+ it_behaves_like 'combines conditions with $regex'
610
+ end
611
+ end
612
+
613
+ context 'criteria are provided in separate hashes' do
614
+ let(:selection) do
615
+ query.send(tested_method, {:field.gt => 3}, {:field => 5})
616
+ end
617
+
618
+ it_behaves_like 'combines conditions with $and'
619
+ end
620
+
621
+ context 'when the criterion is wrapped in an array' do
622
+ let(:selection) do
623
+ query.send(tested_method, [:field.gt => 3], [:field => 5])
624
+ end
625
+
626
+ it_behaves_like 'combines conditions with $and'
627
+ end
628
+ end
629
+ end
630
+ end
631
+
632
+ context 'when argument is a Criteria' do
633
+ let(:query) do
634
+ Mongoid::Query.new.where(hello: 'world')
635
+ end
636
+
637
+ let(:result) { query.and(other) }
638
+
639
+ context 'different fields' do
640
+
641
+ let(:other) do
642
+ Mongoid::Query.new.where(foo: 'bar')
643
+ end
644
+
645
+ it 'combines both fields at top level' do
646
+ expect(result.selector).to eq('hello' => 'world', 'foo' => 'bar')
647
+ end
648
+ end
649
+
650
+ context 'same field' do
651
+
652
+ let(:other) do
653
+ Mongoid::Query.new.where(hello: /bar/)
654
+ end
655
+
656
+ it 'combines fields with $and' do
657
+ expect(result.selector).to eq('hello' => 'world', '$and' => [{'hello' => /bar/}])
658
+ end
659
+ end
660
+ end
661
+
662
+ context 'when argument is a mix of Criteria and hashes' do
663
+ let(:query) do
664
+ Mongoid::Query.new.where(hello: 'world')
665
+ end
666
+
667
+ let(:other1) do
668
+ Mongoid::Query.new.where(foo: 'bar')
669
+ end
670
+
671
+ let(:other2) do
672
+ {bar: 42}
673
+ end
674
+
675
+ let(:other3) do
676
+ Mongoid::Query.new.where(a: 2)
677
+ end
678
+
679
+ let(:result) { query.and(other1, other2, other3) }
680
+
681
+ it 'combines' do
682
+ expect(result.selector).to eq('hello' => 'world',
683
+ 'foo' => 'bar',
684
+ 'bar' => 42,
685
+ 'a' => 2,
686
+ )
687
+ end
688
+ end
689
+
690
+ context 'when Key instances are used and types involved have serializers' do
691
+ let(:time) { Time.now }
692
+
693
+ let(:query) do
694
+ Band.all.and(:created_at.gt => time)
695
+ end
696
+
697
+ let(:expected) do
698
+ {'created_at' => {'$gt' => time.utc}}
699
+ end
700
+
701
+ it 'combines and evolves' do
702
+ expect(query.selector).to eq(expected)
703
+ end
704
+ end
705
+
706
+ describe 'query shape' do
707
+ shared_examples_for 'adds most recent criterion as $and' do
708
+ let(:selector) { scope.selector }
709
+
710
+ it 'adds most recent criterion as $and' do
711
+ expect(selector).to eq('foo' => 1, '$and' => [{'foo' => 2}])
712
+ end
713
+ end
714
+
715
+ context 'and/and' do
716
+ let(:scope) do
717
+ Band.and(foo: 1).and(foo: 2)
718
+ end
719
+
720
+ it_behaves_like 'adds most recent criterion as $and'
721
+ end
722
+
723
+ context 'and/and' do
724
+ let(:scope) do
725
+ Band.and(foo: 1).and(foo: 2)
726
+ end
727
+
728
+ it_behaves_like 'adds most recent criterion as $and'
729
+ end
730
+
731
+ context 'and/where' do
732
+ let(:scope) do
733
+ Band.and(foo: 1).where(foo: 2)
734
+ end
735
+
736
+ it_behaves_like 'adds most recent criterion as $and'
737
+ end
738
+
739
+ context 'where/and' do
740
+ let(:scope) do
741
+ Band.where(foo: 1).and(foo: 2)
742
+ end
743
+
744
+ it_behaves_like 'adds most recent criterion as $and'
745
+ end
746
+
747
+ context 'where/where' do
748
+ let(:scope) do
749
+ Band.where(foo: 1).where(foo: 2)
750
+ end
751
+
752
+ it_behaves_like 'adds most recent criterion as $and'
753
+ end
754
+ end
755
+
756
+ context 'when conditions already exist in criteria' do
757
+ let(:base_selection) do
758
+ query.where(foo: 'bar')
759
+ end
760
+
761
+ context 'when hash conditions are given' do
762
+ let(:selection) do
763
+ base_selection.and(hello: 'world')
764
+ end
765
+
766
+ it 'adds new conditions to top level' do
767
+ selection.selector.should == {
768
+ 'foo' => 'bar',
769
+ 'hello' => 'world',
770
+ }
771
+ end
772
+ end
773
+
774
+ context 'when criteria conditions are given' do
775
+ let(:selection) do
776
+ base_selection.and(query.where(hello: 'world'))
777
+ end
778
+
779
+ it 'adds new conditions to top level' do
780
+ selection.selector.should == {
781
+ 'foo' => 'bar',
782
+ 'hello' => 'world',
783
+ }
784
+ end
785
+ end
786
+
787
+ context 'when complex criteria conditions are given' do
788
+ let(:selection) do
789
+ base_selection.and(query.or([one: 'one'], [two: 'two']))
790
+ end
791
+
792
+ it 'adds new conditions to top level' do
793
+ selection.selector.should == {
794
+ 'foo' => 'bar',
795
+ '$or' => [
796
+ {'one' => 'one'},
797
+ {'two' => 'two'},
798
+ ],
799
+ }
800
+ end
801
+ end
802
+ end
803
+ end
804
+
805
+ shared_examples '$or/$nor' do
806
+
807
+ it_behaves_like 'a non-hoisting logical operation'
808
+
809
+ context "when provided no arguments" do
15
810
 
16
811
  let(:selection) do
17
- query.and
812
+ query.send(tested_method)
18
813
  end
19
814
 
20
- it "does not add any criterion" do
815
+ it_behaves_like 'returns a cloned query'
816
+
817
+ it "does not add any criteria" do
21
818
  expect(selection.selector).to eq({})
22
819
  end
23
820
 
24
821
  it "returns the query" do
25
822
  expect(selection).to eq(query)
26
823
  end
27
-
28
- it "returns a cloned query" do
29
- expect(selection).to_not equal(query)
30
- end
31
824
  end
32
825
 
33
826
  context "when provided nil" do
34
827
 
35
828
  let(:selection) do
36
- query.and(nil)
829
+ query.send(tested_method, nil)
37
830
  end
38
831
 
39
- it "does not add any criterion" do
832
+ it_behaves_like 'returns a cloned query'
833
+
834
+ it "does not add any criteria" do
40
835
  expect(selection.selector).to eq({})
41
836
  end
42
837
 
43
838
  it "returns the query" do
44
839
  expect(selection).to eq(query)
45
840
  end
46
-
47
- it "returns a cloned query" do
48
- expect(selection).to_not equal(query)
49
- end
50
841
  end
51
842
 
52
843
  context "when provided a single criterion" do
53
844
 
54
845
  let(:selection) do
55
- query.and(field: [ 1, 2 ])
846
+ query.send(tested_method, field: [ 1, 2 ])
56
847
  end
57
848
 
58
- it "adds the $and selector" do
849
+ it_behaves_like 'returns a cloned query'
850
+
851
+ it "adds the $or/$nor selector" do
59
852
  expect(selection.selector).to eq({
60
- "$and" => [{ "field" => [ 1, 2 ] }]
853
+ expected_operator => [{ "field" => [ 1, 2 ] }]
61
854
  })
62
855
  end
63
856
 
64
- it "returns a cloned query" do
65
- expect(selection).to_not equal(query)
66
- end
67
- end
857
+ context 'when the criterion is wrapped in array' do
68
858
 
69
- context "when provided a nested criterion" do
859
+ let(:selection) do
860
+ query.send(tested_method, [{ field: [ 1, 2 ] }])
861
+ end
70
862
 
71
- let(:selection) do
72
- query.and(:test.elem_match => { :field.in => [ 1, 2 ] })
863
+ it_behaves_like 'returns a cloned query'
864
+
865
+ it "adds the $or/$nor selector" do
866
+ expect(selection.selector).to eq({
867
+ expected_operator => [{ "field" => [ 1, 2 ] }]
868
+ })
869
+ end
870
+
871
+ context 'when the array has nil as one of the elements' do
872
+
873
+ let(:selection) do
874
+ query.send(tested_method, [{ field: [ 1, 2 ] }, nil])
875
+ end
876
+
877
+ it_behaves_like 'returns a cloned query'
878
+
879
+ it "adds the $or/$nor selector ignoring the nil element" do
880
+ expect(selection.selector).to eq({
881
+ expected_operator => [{ "field" => [ 1, 2 ] }]
882
+ })
883
+ end
884
+ end
73
885
  end
74
886
 
75
- it "adds the $and selector" do
76
- expect(selection.selector).to eq({
77
- "$and" => [{ "test" => { "$elemMatch" => { "field" => { "$in" => [ 1, 2 ] }}}}]
78
- })
887
+ context 'when query already has a condition on another field' do
888
+
889
+ let(:selection) do
890
+ query.where(foo: 'bar').send(tested_method, field: [ 1, 2 ])
891
+ end
892
+
893
+ it 'moves original conditions under $or/$nor' do
894
+ expect(selection.selector).to eq({
895
+ expected_operator => [{'foo' => 'bar'}, { "field" => [ 1, 2 ] }]
896
+ })
897
+ end
79
898
  end
80
899
 
81
- it "returns a cloned query" do
82
- expect(selection).to_not equal(query)
900
+ context 'when query already has an $or/$nor condition and another condition' do
901
+
902
+ let(:selection) do
903
+ query.send(tested_method, field: [ 1, 2 ]).where(foo: 'bar').send(tested_method, test: 1)
904
+ end
905
+
906
+ it 'unions existing conditions' do
907
+ expect(selection.selector).to eq(
908
+ expected_operator => [
909
+ {
910
+ expected_operator => [{ "field" => [ 1, 2 ] }],
911
+ 'foo' => 'bar',
912
+ },
913
+ {'test' => 1},
914
+ ]
915
+ )
916
+ end
83
917
  end
84
918
  end
85
919
 
86
- context "when provided multiple criterion" do
920
+ context "when provided multiple criteria" do
87
921
 
88
- context "when the criterion is already included" do
922
+ context "when the criteria are for different fields" do
89
923
 
90
924
  let(:selection) do
91
- query.and({ first: [ 1, 2 ] }).and({ first: [ 1, 2 ] })
925
+ query.send(tested_method, { first: [ 1, 2 ] }, { second: [ 3, 4 ] })
92
926
  end
93
927
 
94
- it "does not duplicate the $and selector" do
928
+ it_behaves_like 'returns a cloned query'
929
+
930
+ it "adds the $or/$nor selector" do
95
931
  expect(selection.selector).to eq({
96
- "$and" => [
97
- { "first" => [ 1, 2 ] }
932
+ expected_operator => [
933
+ { "first" => [ 1, 2 ] },
934
+ { "second" => [ 3, 4 ] }
98
935
  ]
99
936
  })
100
937
  end
101
-
102
- it "returns a cloned query" do
103
- expect(selection).to_not equal(query)
104
- end
105
938
  end
106
939
 
107
- context "when the criterion are for different fields" do
940
+ context "when the criteria uses a Key instance" do
108
941
 
109
942
  let(:selection) do
110
- query.and({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
943
+ query.send(tested_method, { first: [ 1, 2 ] }, { :second.gt => 3 })
111
944
  end
112
945
 
113
- it "adds the $and selector" do
946
+ it "adds the $or/$nor selector" do
114
947
  expect(selection.selector).to eq({
115
- "$and" => [
948
+ expected_operator => [
116
949
  { "first" => [ 1, 2 ] },
117
- { "second" => [ 3, 4 ] }
950
+ { "second" => { "$gt" => 3 }}
118
951
  ]
119
952
  })
120
953
  end
121
954
 
122
- it "returns a cloned query" do
123
- expect(selection).to_not equal(query)
955
+ it_behaves_like 'returns a cloned query'
956
+
957
+ context 'when the criterion is a time' do
958
+ let(:selection) do
959
+ query.send(tested_method, :field.gte => Time.new(2020, 1, 1))
960
+ end
961
+
962
+ it 'adds the conditions' do
963
+ expect(selection.selector).to eq(expected_operator => [
964
+ "field" => {'$gte' => Time.new(2020, 1, 1)},
965
+ ])
966
+ end
967
+
968
+ it 'keeps the type' do
969
+ selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
970
+ end
971
+ end
972
+
973
+ context 'when the criterion is a datetime' do
974
+ let(:selection) do
975
+ query.send(tested_method, :field.gte => DateTime.new(2020, 1, 1))
976
+ end
977
+
978
+ it 'adds the conditions' do
979
+ expect(selection.selector).to eq(expected_operator => [
980
+ "field" => {'$gte' => Time.utc(2020, 1, 1)},
981
+ ])
982
+ end
983
+
984
+ it 'converts argument to a time' do
985
+ selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
986
+ end
987
+ end
988
+
989
+ context 'when the criterion is a date' do
990
+ let(:selection) do
991
+ query.send(tested_method, :field.gte => Date.new(2020, 1, 1))
992
+ end
993
+
994
+ it 'adds the conditions' do
995
+ expect(selection.selector).to eq(expected_operator => [
996
+ "field" => {'$gte' => Time.utc(2020, 1, 1)},
997
+ ])
998
+ end
999
+
1000
+ it 'converts argument to a time' do
1001
+ selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
1002
+ end
124
1003
  end
125
1004
  end
126
1005
 
127
- context "when the criterion are on the same field" do
1006
+ context "when a criterion has an aliased field" do
128
1007
 
129
1008
  let(:selection) do
130
- query.and({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
1009
+ query.send(tested_method, { id: 1 })
131
1010
  end
132
1011
 
133
- it "appends both $and expressions" do
1012
+ it "adds the $or/$nor selector and aliases the field" do
134
1013
  expect(selection.selector).to eq({
135
- "$and" => [
1014
+ expected_operator => [ { "_id" => 1 } ]
1015
+ })
1016
+ end
1017
+
1018
+ it_behaves_like 'returns a cloned query'
1019
+ end
1020
+
1021
+ context "when a criterion is wrapped in an array" do
1022
+
1023
+ let(:selection) do
1024
+ query.send(tested_method, [{ first: [ 1, 2 ] }, { :second.gt => 3 }])
1025
+ end
1026
+
1027
+ it_behaves_like 'returns a cloned query'
1028
+
1029
+ it "adds the $or/$nor selector" do
1030
+ expect(selection.selector).to eq({
1031
+ expected_operator => [
136
1032
  { "first" => [ 1, 2 ] },
137
- { "first" => [ 3, 4 ] }
1033
+ { "second" => { "$gt" => 3 }}
138
1034
  ]
139
1035
  })
140
1036
  end
1037
+ end
1038
+
1039
+ context "when the criteria are on the same field" do
1040
+
1041
+ context 'simple criteria' do
1042
+ let(:selection) do
1043
+ query.send(tested_method, { first: [ 1, 2 ] }, { first: [ 3, 4 ] })
1044
+ end
1045
+
1046
+ it_behaves_like 'returns a cloned query'
1047
+
1048
+ it "appends both $or/$nor expressions" do
1049
+ expect(selection.selector).to eq({
1050
+ expected_operator => [
1051
+ { "first" => [ 1, 2 ] },
1052
+ { "first" => [ 3, 4 ] }
1053
+ ]
1054
+ })
1055
+ end
1056
+ end
1057
+
1058
+ context 'Key criteria as one argument' do
1059
+ let(:selection) do
1060
+ query.send(tested_method, :first.gt => 3, :first.lt => 5)
1061
+ end
1062
+
1063
+ it_behaves_like 'returns a cloned query'
1064
+
1065
+ it "adds all criteria" do
1066
+ expect(selection.selector).to eq({
1067
+ expected_operator => [
1068
+ { "first" => {'$gt' => 3, '$lt' => 5} },
1069
+ ]
1070
+ })
1071
+ end
1072
+ end
141
1073
 
142
- it "returns a cloned query" do
143
- expect(selection).to_not equal(query)
1074
+ context 'Key criteria as multiple arguments' do
1075
+ let(:selection) do
1076
+ query.send(tested_method, {:first.gt => 3}, {:first.lt => 5})
1077
+ end
1078
+
1079
+ it_behaves_like 'returns a cloned query'
1080
+
1081
+ it "adds all criteria" do
1082
+ expect(selection.selector).to eq({
1083
+ expected_operator => [
1084
+ { "first" => {'$gt' => 3} },
1085
+ { "first" => {'$lt' => 5} },
1086
+ ]
1087
+ })
1088
+ end
144
1089
  end
145
1090
  end
146
1091
  end
@@ -150,211 +1095,296 @@ describe Mongoid::Criteria::Queryable::Selectable do
150
1095
  context "when the criterion are for different fields" do
151
1096
 
152
1097
  let(:selection) do
153
- query.and(first: [ 1, 2 ]).and(second: [ 3, 4 ])
1098
+ query.send(tested_method, first: [ 1, 2 ]).send(tested_method, second: [ 3, 4 ])
154
1099
  end
155
1100
 
156
- it "adds the $and selectors" do
1101
+ it_behaves_like 'returns a cloned query'
1102
+
1103
+ it "adds the $or/$nor selectors" do
157
1104
  expect(selection.selector).to eq({
158
- "$and" => [
1105
+ expected_operator => [
159
1106
  { "first" => [ 1, 2 ] },
160
1107
  { "second" => [ 3, 4 ] }
161
1108
  ]
162
1109
  })
163
1110
  end
164
-
165
- it "returns a cloned query" do
166
- expect(selection).to_not equal(query)
167
- end
168
1111
  end
169
1112
 
170
1113
  context "when the criterion are on the same field" do
171
1114
 
172
1115
  let(:selection) do
173
- query.and(first: [ 1, 2 ]).and(first: [ 3, 4 ])
1116
+ query.send(tested_method, first: [ 1, 2 ]).send(tested_method, first: [ 3, 4 ])
174
1117
  end
175
1118
 
176
- it "appends both $and expressions" do
1119
+ it_behaves_like 'returns a cloned query'
1120
+
1121
+ it "appends both $or/$nor expressions" do
177
1122
  expect(selection.selector).to eq({
178
- "$and" => [
1123
+ expected_operator => [
179
1124
  { "first" => [ 1, 2 ] },
180
1125
  { "first" => [ 3, 4 ] }
181
1126
  ]
182
1127
  })
183
1128
  end
1129
+ end
1130
+ end
1131
+
1132
+ context 'when giving multiple conditions in one call on the same key with symbol operator' do
1133
+
1134
+ context 'non-regexp argument' do
1135
+ let(:selection) do
1136
+ query.send(tested_method, field: 1, :field.gt => 0)
1137
+ end
1138
+
1139
+ it 'combines conditions with $eq' do
1140
+ selection.selector.should == {
1141
+ expected_operator => [
1142
+ 'field' => {'$eq' => 1, '$gt' => 0},
1143
+ ]
1144
+ }
1145
+ end
1146
+ end
1147
+
1148
+ context 'regexp argument' do
1149
+ let(:selection) do
1150
+ query.send(tested_method, field: /t/, :field.gt => 0)
1151
+ end
184
1152
 
185
- it "returns a cloned query" do
186
- expect(selection).to_not equal(query)
1153
+ it 'combines conditions with $regex' do
1154
+ selection.selector.should == {
1155
+ expected_operator => [
1156
+ 'field' => {'$regex' => /t/, '$gt' => 0},
1157
+ ]
1158
+ }
187
1159
  end
188
1160
  end
1161
+
189
1162
  end
190
1163
  end
191
1164
 
192
1165
  describe "#or" do
193
1166
 
194
- context "when provided no criterion" do
1167
+ let(:tested_method) { :or }
1168
+ let(:expected_operator) { '$or' }
1169
+
1170
+ it_behaves_like '$or/$nor'
1171
+ end
1172
+
1173
+ describe "#nor" do
1174
+
1175
+ let(:tested_method) { :nor }
1176
+ let(:expected_operator) { '$nor' }
1177
+
1178
+ it_behaves_like '$or/$nor'
1179
+ end
1180
+
1181
+ describe "#any_of" do
1182
+
1183
+ let(:tested_method) { :any_of }
1184
+ let(:expected_operator) { '$or' }
1185
+
1186
+ it_behaves_like 'a hoisting logical operation'
1187
+
1188
+ # When multiple arguments are given to any_of, it behaves differently
1189
+ # from and.
1190
+ context 'when argument is a mix of Criteria and hashes' do
1191
+ let(:query) do
1192
+ Mongoid::Query.new.where(hello: 'world')
1193
+ end
1194
+
1195
+ let(:other1) do
1196
+ Mongoid::Query.new.where(foo: 'bar')
1197
+ end
1198
+
1199
+ let(:other2) do
1200
+ {bar: 42}
1201
+ end
1202
+
1203
+ let(:other3) do
1204
+ Mongoid::Query.new.where(a: 2)
1205
+ end
1206
+
1207
+ let(:result) { query.send(tested_method, other1, other2, other3) }
1208
+
1209
+ it 'combines' do
1210
+ expect(result.selector).to eq(
1211
+ 'hello' => 'world',
1212
+ expected_operator => [
1213
+ {'foo' => 'bar'},
1214
+ {'bar' => 42},
1215
+ {'a' => 2},
1216
+ ],
1217
+ )
1218
+ end
1219
+ end
1220
+
1221
+ context "when provided no arguments" do
195
1222
 
196
1223
  let(:selection) do
197
- query.or
1224
+ query.any_of
198
1225
  end
199
1226
 
200
- it "does not add any criterion" do
1227
+ it_behaves_like 'returns a cloned query'
1228
+
1229
+ it "does not add any criteria" do
201
1230
  expect(selection.selector).to eq({})
202
1231
  end
203
1232
 
204
1233
  it "returns the query" do
205
1234
  expect(selection).to eq(query)
206
1235
  end
207
-
208
- it "returns a cloned query" do
209
- expect(selection).to_not equal(query)
210
- end
211
1236
  end
212
1237
 
213
1238
  context "when provided nil" do
214
1239
 
215
1240
  let(:selection) do
216
- query.or(nil)
1241
+ query.any_of(nil)
217
1242
  end
218
1243
 
219
- it "does not add any criterion" do
1244
+ it_behaves_like 'returns a cloned query'
1245
+
1246
+ it "does not add any criteria" do
220
1247
  expect(selection.selector).to eq({})
221
1248
  end
222
1249
 
223
1250
  it "returns the query" do
224
1251
  expect(selection).to eq(query)
225
1252
  end
226
-
227
- it "returns a cloned query" do
228
- expect(selection).to_not equal(query)
229
- end
230
1253
  end
231
1254
 
232
1255
  context "when provided a single criterion" do
233
1256
 
234
1257
  let(:selection) do
235
- query.or(field: [ 1, 2 ])
1258
+ query.any_of(field: [ 1, 2 ])
236
1259
  end
237
1260
 
238
- it "adds the $or selector" do
239
- expect(selection.selector).to eq({
240
- "$or" => [{ "field" => [ 1, 2 ] }]
241
- })
242
- end
1261
+ it_behaves_like 'returns a cloned query'
243
1262
 
244
- it "returns a cloned query" do
245
- expect(selection).to_not equal(query)
1263
+ it "adds the $or selector" do
1264
+ expect(selection.selector).to eq(
1265
+ "field" => [ 1, 2 ],
1266
+ )
246
1267
  end
247
- end
248
1268
 
249
- context "when provided multiple criterion" do
250
-
251
- context "when the criterion are for different fields" do
1269
+ context 'when the criterion is wrapped in array' do
252
1270
 
253
1271
  let(:selection) do
254
- query.or({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
1272
+ query.any_of([{ field: [ 1, 2 ] }])
255
1273
  end
256
1274
 
257
- it "adds the $or selector" do
258
- expect(selection.selector).to eq({
259
- "$or" => [
260
- { "first" => [ 1, 2 ] },
261
- { "second" => [ 3, 4 ] }
262
- ]
263
- })
264
- end
1275
+ it_behaves_like 'returns a cloned query'
265
1276
 
266
- it "returns a cloned query" do
267
- expect(selection).to_not equal(query)
1277
+ it "adds the condition" do
1278
+ expect(selection.selector).to eq(
1279
+ "field" => [ 1, 2 ],
1280
+ )
268
1281
  end
269
- end
270
1282
 
271
- context "when a criterion has a selectable key" do
1283
+ context 'when the array has nil as one of the elements' do
272
1284
 
273
- let(:selection) do
274
- query.or({ first: [ 1, 2 ] }, { :second.gt => 3 })
275
- end
1285
+ let(:selection) do
1286
+ query.any_of([{ field: [ 1, 2 ] }, nil])
1287
+ end
276
1288
 
277
- it "adds the $or selector" do
278
- expect(selection.selector).to eq({
279
- "$or" => [
280
- { "first" => [ 1, 2 ] },
281
- { "second" => { "$gt" => 3 }}
282
- ]
283
- })
284
- end
1289
+ it_behaves_like 'returns a cloned query'
285
1290
 
286
- it "returns a cloned query" do
287
- expect(selection).to_not equal(query)
1291
+ it "adds the $or selector ignoring the nil element" do
1292
+ expect(selection.selector).to eq(
1293
+ "field" => [ 1, 2 ],
1294
+ )
1295
+ end
288
1296
  end
289
1297
  end
290
1298
 
291
- context "when the criterion has an aliased field" do
1299
+ context 'when query already has a condition on another field' do
292
1300
 
293
- let(:selection) do
294
- query.or({ id: 1 })
295
- end
1301
+ context 'when there is one argument' do
296
1302
 
297
- it "adds the $or selector and aliases the field" do
298
- expect(selection.selector).to eq({
299
- "$or" => [ { "_id" => 1 } ]
300
- })
1303
+ let(:selection) do
1304
+ query.where(foo: 'bar').any_of(field: [ 1, 2 ])
1305
+ end
1306
+
1307
+ it 'adds the new condition' do
1308
+ expect(selection.selector).to eq(
1309
+ 'foo' => 'bar',
1310
+ 'field' => [1, 2],
1311
+ )
1312
+ end
301
1313
  end
302
1314
 
303
- it "returns a cloned query" do
304
- expect(selection).to_not equal(query)
1315
+ context 'when there are multiple arguments' do
1316
+
1317
+ let(:selection) do
1318
+ query.where(foo: 'bar').any_of({field: [ 1, 2 ]}, {hello: 'world'})
1319
+ end
1320
+
1321
+ it 'adds the new condition' do
1322
+ expect(selection.selector).to eq(
1323
+ 'foo' => 'bar',
1324
+ '$or' => [
1325
+ {'field' => [1, 2]},
1326
+ {'hello' => 'world'},
1327
+ ],
1328
+ )
1329
+ end
305
1330
  end
306
1331
  end
307
1332
 
308
- context "when a criterion is wrapped in an array" do
1333
+ context 'when query already has an $or condition and another condition' do
309
1334
 
310
1335
  let(:selection) do
311
- query.or([{ first: [ 1, 2 ] }, { :second.gt => 3 }])
312
- end
313
-
314
- it "adds the $or selector" do
315
- expect(selection.selector).to eq({
316
- "$or" => [
317
- { "first" => [ 1, 2 ] },
318
- { "second" => { "$gt" => 3 }}
319
- ]
320
- })
1336
+ query.or(field: [ 1, 2 ]).where(foo: 'bar').any_of(test: 1)
321
1337
  end
322
1338
 
323
- it "returns a cloned query" do
324
- expect(selection).to_not equal(query)
1339
+ it 'adds the new condition' do
1340
+ expect(selection.selector).to eq(
1341
+ '$or' => [{'field' => [1, 2]}],
1342
+ 'foo' => 'bar',
1343
+ 'test' => 1,
1344
+ )
325
1345
  end
326
1346
  end
327
1347
 
328
- context "when the criterion are on the same field" do
1348
+ context 'when any_of has multiple arguments' do
329
1349
 
330
1350
  let(:selection) do
331
- query.or({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
1351
+ query.or(field: [ 1, 2 ]).where(foo: 'bar').any_of({a: 1}, {b: 2})
332
1352
  end
333
1353
 
334
- it "appends both $or expressions" do
335
- expect(selection.selector).to eq({
336
- "$or" => [
337
- { "first" => [ 1, 2 ] },
338
- { "first" => [ 3, 4 ] }
339
- ]
340
- })
1354
+ it 'adds the new condition to top level' do
1355
+ expect(selection.selector).to eq(
1356
+ '$or' => [{'field' => [1, 2]}],
1357
+ 'foo' => 'bar',
1358
+ '$and' => [{'$or' => [{'a' => 1}, {'b' => 2}]}],
1359
+ )
341
1360
  end
342
1361
 
343
- it "returns a cloned query" do
344
- expect(selection).to_not equal(query)
1362
+ context 'when query already has a top-level $and' do
1363
+ let(:selection) do
1364
+ query.or(field: [ 1, 2 ]).where('$and' => [foo: 'bar']).any_of({a: 1}, {b: 2})
1365
+ end
1366
+
1367
+ it 'adds the new condition to top level $and' do
1368
+ expect(selection.selector).to eq(
1369
+ '$or' => [{'field' => [1, 2]}],
1370
+ '$and' => [{'foo' => 'bar'}, {'$or' => [{'a' => 1}, {'b' => 2}]}],
1371
+ )
1372
+ end
345
1373
  end
346
1374
  end
347
1375
  end
348
1376
 
349
- context "when chaining the criterion" do
1377
+ context "when provided multiple criteria" do
350
1378
 
351
- context "when the criterion are for different fields" do
1379
+ context "when the criteria are for different fields" do
352
1380
 
353
1381
  let(:selection) do
354
- query.or(first: [ 1, 2 ]).or(second: [ 3, 4 ])
1382
+ query.any_of({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
355
1383
  end
356
1384
 
357
- it "adds the $or selectors" do
1385
+ it_behaves_like 'returns a cloned query'
1386
+
1387
+ it "adds the $or selector" do
358
1388
  expect(selection.selector).to eq({
359
1389
  "$or" => [
360
1390
  { "first" => [ 1, 2 ] },
@@ -362,173 +1392,295 @@ describe Mongoid::Criteria::Queryable::Selectable do
362
1392
  ]
363
1393
  })
364
1394
  end
365
-
366
- it "returns a cloned query" do
367
- expect(selection).to_not equal(query)
368
- end
369
1395
  end
370
1396
 
371
- context "when the criterion are on the same field" do
1397
+ context "when the criteria uses a Key instance" do
372
1398
 
373
1399
  let(:selection) do
374
- query.or(first: [ 1, 2 ]).or(first: [ 3, 4 ])
1400
+ query.any_of({ first: [ 1, 2 ] }, { :second.gt => 3 })
375
1401
  end
376
1402
 
377
- it "appends both $or expressions" do
1403
+ it "adds the $or selector" do
378
1404
  expect(selection.selector).to eq({
379
1405
  "$or" => [
380
1406
  { "first" => [ 1, 2 ] },
381
- { "first" => [ 3, 4 ] }
1407
+ { "second" => { "$gt" => 3 }}
382
1408
  ]
383
1409
  })
384
1410
  end
385
1411
 
386
- it "returns a cloned query" do
387
- expect(selection).to_not equal(query)
388
- end
1412
+ it_behaves_like 'returns a cloned query'
389
1413
  end
390
- end
391
- end
392
1414
 
393
- describe "#nor" do
1415
+ context 'when criteria are simple and handled via Key' do
1416
+ shared_examples_for 'adds conditions with $or' do
394
1417
 
395
- context "when provided no criterion" do
1418
+ it "adds conditions with $or" do
1419
+ expect(selection.selector).to eq({
1420
+ '$or' => [
1421
+ {'field' => 3},
1422
+ {'field' => {'$lt' => 5}},
1423
+ ],
1424
+ })
1425
+ end
396
1426
 
397
- let(:selection) do
398
- query.nor
399
- end
1427
+ it_behaves_like 'returns a cloned query'
1428
+ end
400
1429
 
401
- it "does not add any criterion" do
402
- expect(selection.selector).to eq({})
403
- end
1430
+ shared_examples_for 'combines conditions with $eq' do
404
1431
 
405
- it "returns the query" do
406
- expect(selection).to eq(query)
407
- end
1432
+ it "combines conditions with $eq" do
1433
+ expect(selection.selector).to eq({
1434
+ 'field' => {
1435
+ '$eq' => 3,
1436
+ '$lt' => 5,
1437
+ },
1438
+ })
1439
+ end
408
1440
 
409
- it "returns a cloned query" do
410
- expect(selection).to_not equal(query)
411
- end
412
- end
1441
+ it_behaves_like 'returns a cloned query'
1442
+ end
413
1443
 
414
- context "when provided nil" do
1444
+ shared_examples_for 'combines conditions with $regex' do
415
1445
 
416
- let(:selection) do
417
- query.nor(nil)
418
- end
1446
+ it "combines conditions with $regex" do
1447
+ expect(selection.selector).to eq({
1448
+ 'field' => {
1449
+ '$regex' => /t/,
1450
+ '$lt' => 5,
1451
+ },
1452
+ })
1453
+ end
419
1454
 
420
- it "does not add any criterion" do
421
- expect(selection.selector).to eq({})
422
- end
1455
+ it_behaves_like 'returns a cloned query'
1456
+ end
423
1457
 
424
- it "returns the query" do
425
- expect(selection).to eq(query)
426
- end
1458
+ context 'criteria are provided in the same hash' do
1459
+ context 'non-regexp argument' do
1460
+ let(:selection) do
1461
+ query.send(tested_method, :field => 3, :field.lt => 5)
1462
+ end
427
1463
 
428
- it "returns a cloned query" do
429
- expect(selection).to_not equal(query)
430
- end
431
- end
1464
+ it_behaves_like 'combines conditions with $eq'
1465
+ end
432
1466
 
433
- context "when provided a single criterion" do
1467
+ context 'regexp argument' do
1468
+ let(:selection) do
1469
+ query.send(tested_method, :field => /t/, :field.lt => 5)
1470
+ end
434
1471
 
435
- let(:selection) do
436
- query.nor(field: [ 1, 2 ])
437
- end
1472
+ it_behaves_like 'combines conditions with $regex'
1473
+ end
1474
+ end
438
1475
 
439
- it "adds the $nor selector" do
440
- expect(selection.selector).to eq({
441
- "$nor" => [{"field" => [ 1, 2 ] }]
442
- })
1476
+ context 'criteria are provided in separate hashes' do
1477
+ let(:selection) do
1478
+ query.send(tested_method, {:field => 3}, {:field.lt => 5})
1479
+ end
1480
+
1481
+ it_behaves_like 'adds conditions with $or'
1482
+ end
1483
+
1484
+ context 'when the criterion is wrapped in an array' do
1485
+ let(:selection) do
1486
+ query.send(tested_method, [:field => 3], [:field.lt => 5])
1487
+ end
1488
+
1489
+ it_behaves_like 'adds conditions with $or'
1490
+ end
443
1491
  end
444
1492
 
445
- it "returns a cloned query" do
446
- expect(selection).to_not equal(query)
1493
+ context 'when criteria are handled via Key and simple' do
1494
+ shared_examples_for 'adds conditions with $or' do
1495
+
1496
+ it "adds conditions with $or" do
1497
+ expect(selection.selector).to eq({
1498
+ '$or' => [
1499
+ {'field' => {'$gt' => 3}},
1500
+ {'field' => 5},
1501
+ ],
1502
+ })
1503
+ end
1504
+
1505
+ it_behaves_like 'returns a cloned query'
1506
+ end
1507
+
1508
+ shared_examples_for 'combines conditions with $eq' do
1509
+
1510
+ it "combines conditions with $eq" do
1511
+ expect(selection.selector).to eq(
1512
+ 'field' => {'$gt' => 3, '$eq' => 5},
1513
+ )
1514
+ end
1515
+
1516
+ it_behaves_like 'returns a cloned query'
1517
+ end
1518
+
1519
+ shared_examples_for 'combines conditions with $regex' do
1520
+
1521
+ it "combines conditions with $regex" do
1522
+ expect(selection.selector).to eq(
1523
+ 'field' => {'$gt' => 3, '$regex' => /t/},
1524
+ )
1525
+ end
1526
+
1527
+ it_behaves_like 'returns a cloned query'
1528
+ end
1529
+
1530
+ context 'criteria are provided in the same hash' do
1531
+ context 'non-regexp argument' do
1532
+ let(:selection) do
1533
+ query.send(tested_method, :field.gt => 3, :field => 5)
1534
+ end
1535
+
1536
+ it_behaves_like 'combines conditions with $eq'
1537
+ end
1538
+
1539
+ context 'regexp argument' do
1540
+ let(:selection) do
1541
+ query.send(tested_method, :field.gt => 3, :field => /t/)
1542
+ end
1543
+
1544
+ it_behaves_like 'combines conditions with $regex'
1545
+ end
1546
+ end
1547
+
1548
+ context 'criteria are provided in separate hashes' do
1549
+ let(:selection) do
1550
+ query.send(tested_method, {:field.gt => 3}, {:field => 5})
1551
+ end
1552
+
1553
+ it_behaves_like 'adds conditions with $or'
1554
+ end
1555
+
1556
+ context 'when the criterion is wrapped in an array' do
1557
+ let(:selection) do
1558
+ query.send(tested_method, [:field.gt => 3], [:field => 5])
1559
+ end
1560
+
1561
+ it_behaves_like 'adds conditions with $or'
1562
+ end
447
1563
  end
448
- end
449
1564
 
450
- context "when provided multiple criterion" do
1565
+ context "when a criterion has an aliased field" do
1566
+
1567
+ let(:selection) do
1568
+ query.any_of({ id: 1 })
1569
+ end
1570
+
1571
+ it "adds the $or selector and aliases the field" do
1572
+ expect(selection.selector).to eq(
1573
+ "_id" => 1,
1574
+ )
1575
+ end
1576
+
1577
+ it_behaves_like 'returns a cloned query'
1578
+ end
451
1579
 
452
- context "when the criterion are fnor different fields" do
1580
+ context "when a criterion is wrapped in an array" do
453
1581
 
454
1582
  let(:selection) do
455
- query.nor({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
1583
+ query.any_of([{ first: [ 1, 2 ] }, { :second.gt => 3 }])
456
1584
  end
457
1585
 
458
- it "adds the $nor selector" do
1586
+ it_behaves_like 'returns a cloned query'
1587
+
1588
+ it "adds the $or selector" do
459
1589
  expect(selection.selector).to eq({
460
- "$nor" => [
1590
+ "$or" => [
461
1591
  { "first" => [ 1, 2 ] },
462
- { "second" => [ 3, 4 ] }
1592
+ { "second" => { "$gt" => 3 }}
463
1593
  ]
464
1594
  })
465
1595
  end
466
-
467
- it "returns a cloned query" do
468
- expect(selection).to_not equal(query)
469
- end
470
1596
  end
471
1597
 
472
- context "when the criterion are on the same field" do
1598
+ context "when the criteria are on the same field" do
473
1599
 
474
1600
  let(:selection) do
475
- query.nor({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
1601
+ query.any_of({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
476
1602
  end
477
1603
 
478
- it "appends both $nor expressions" do
1604
+ it_behaves_like 'returns a cloned query'
1605
+
1606
+ it "appends both $or expressions" do
479
1607
  expect(selection.selector).to eq({
480
- "$nor" => [
1608
+ "$or" => [
481
1609
  { "first" => [ 1, 2 ] },
482
1610
  { "first" => [ 3, 4 ] }
483
1611
  ]
484
1612
  })
485
1613
  end
486
-
487
- it "returns a cloned query" do
488
- expect(selection).to_not equal(query)
489
- end
490
1614
  end
491
1615
  end
492
1616
 
493
- context "when chaining the criterion" do
1617
+ context "when chaining the criteria" do
494
1618
 
495
- context "when the criterion are fnor different fields" do
1619
+ context "when the criteria are for different fields" do
496
1620
 
497
1621
  let(:selection) do
498
- query.nor(first: [ 1, 2 ]).nor(second: [ 3, 4 ])
1622
+ query.any_of(first: [ 1, 2 ]).any_of(second: [ 3, 4 ])
499
1623
  end
500
1624
 
501
- it "adds the $nor selectors" do
502
- expect(selection.selector).to eq({
503
- "$nor" => [
504
- { "first" => [ 1, 2 ] },
505
- { "second" => [ 3, 4 ] }
506
- ]
507
- })
508
- end
1625
+ it_behaves_like 'returns a cloned query'
509
1626
 
510
- it "returns a cloned query" do
511
- expect(selection).to_not equal(query)
1627
+ it "adds the conditions separately" do
1628
+ expect(selection.selector).to eq(
1629
+ "first" => [ 1, 2 ],
1630
+ "second" => [ 3, 4 ],
1631
+ )
512
1632
  end
513
1633
  end
514
1634
 
515
- context "when the criterion are on the same field" do
1635
+ context "when the criteria are on the same field" do
516
1636
 
517
1637
  let(:selection) do
518
- query.nor(first: [ 1, 2 ]).nor(first: [ 3, 4 ])
1638
+ query.any_of(first: [ 1, 2 ]).any_of(first: [ 3, 4 ])
519
1639
  end
520
1640
 
521
- it "appends both $nor expressions" do
522
- expect(selection.selector).to eq({
523
- "$nor" => [
524
- { "first" => [ 1, 2 ] },
525
- { "first" => [ 3, 4 ] }
526
- ]
527
- })
1641
+ it_behaves_like 'returns a cloned query'
1642
+
1643
+ it "adds the conditions separately" do
1644
+ expect(selection.selector).to eq(
1645
+ "first" => [ 1, 2 ],
1646
+ '$and' => [{"first" => [ 3, 4 ]}],
1647
+ )
1648
+ end
1649
+ end
1650
+ end
1651
+
1652
+ context 'when using multiple criteria and symbol operators' do
1653
+ context 'when using fields that meaningfully evolve values' do
1654
+
1655
+ let(:query) do
1656
+ Dictionary.any_of({a: 1}, :published.gt => Date.new(2020, 2, 3))
1657
+ end
1658
+
1659
+ it 'generates the expected query' do
1660
+ query.selector.should == {'$or' => [
1661
+ {'a' => 1},
1662
+ # Date instance is converted to a Time instance in local time,
1663
+ # because we are querying on a Time field and dates are interpreted
1664
+ # in local time when assigning to Time fields
1665
+ {'published' => {'$gt' => Time.local(2020, 2, 3)}},
1666
+ ]}
1667
+ end
1668
+ end
1669
+
1670
+ context 'when using fields that do not meaningfully evolve values' do
1671
+
1672
+ let(:query) do
1673
+ Dictionary.any_of({a: 1}, :submitted_on.gt => Date.new(2020, 2, 3))
528
1674
  end
529
1675
 
530
- it "returns a cloned query" do
531
- expect(selection).to_not equal(query)
1676
+ it 'generates the expected query' do
1677
+ query.selector.should == {'$or' => [
1678
+ {'a' => 1},
1679
+ # Date instance is converted to a Time instance in UTC,
1680
+ # because we are querying on a Date field and dates are interpreted
1681
+ # in UTC when persisted as dates by Mongoid
1682
+ {'submitted_on' => {'$gt' => Time.utc(2020, 2, 3)}},
1683
+ ]}
532
1684
  end
533
1685
  end
534
1686
  end
@@ -561,27 +1713,45 @@ describe Mongoid::Criteria::Queryable::Selectable do
561
1713
  expect(query.negating).to be nil
562
1714
  end
563
1715
 
564
- context "when the following criteria is a query method" do
565
-
1716
+ shared_examples_for 'negates the next condition' do
566
1717
  let(:selection) do
567
- query.not.all(field: [ 1, 2 ])
1718
+ query.not.send(query_method, field: [ 1, 2 ])
568
1719
  end
569
1720
 
570
- it "negates the all selection" do
1721
+ it "negates the next condition" do
571
1722
  expect(selection.selector).to eq(
572
- { "field" => { "$not" => { "$all" => [ 1, 2 ] }}}
1723
+ { "field" => { "$not" => { operator => [ 1, 2 ] }}}
573
1724
  )
574
1725
  end
575
1726
 
576
- it "returns a cloned query" do
577
- expect(selection).to_not equal(query)
578
- end
1727
+ it_behaves_like 'returns a cloned query'
579
1728
 
580
1729
  it "removes the negation on the clone" do
581
1730
  expect(selection).to_not be_negating
582
1731
  end
583
1732
  end
584
1733
 
1734
+ context "when the next condition is #all" do
1735
+ let(:query_method) { :all }
1736
+ let(:operator) { '$all' }
1737
+
1738
+ it_behaves_like 'negates the next condition'
1739
+ end
1740
+
1741
+ context "when the next condition is #in" do
1742
+ let(:query_method) { :in }
1743
+ let(:operator) { '$in' }
1744
+
1745
+ it_behaves_like 'negates the next condition'
1746
+ end
1747
+
1748
+ context "when the next condition is #nin" do
1749
+ let(:query_method) { :nin }
1750
+ let(:operator) { '$nin' }
1751
+
1752
+ it_behaves_like 'negates the next condition'
1753
+ end
1754
+
585
1755
  context "when the following criteria is a gt method" do
586
1756
 
587
1757
  let(:selection) do
@@ -594,10 +1764,27 @@ describe Mongoid::Criteria::Queryable::Selectable do
594
1764
  )
595
1765
  end
596
1766
 
597
- it "returns a coned query" do
598
- expect(selection).to_not eq(query)
1767
+ it_behaves_like 'returns a cloned query'
1768
+
1769
+ it "removes the negation on the clone" do
1770
+ expect(selection).to_not be_negating
1771
+ end
1772
+ end
1773
+
1774
+ context "when the criteria uses Key" do
1775
+
1776
+ let(:selection) do
1777
+ query.not(:age.gt => 50)
1778
+ end
1779
+
1780
+ it "negates the gt selection" do
1781
+ expect(selection.selector).to eq(
1782
+ '$and' => ['$nor' => ['age' => {'$gt' => 50}]]
1783
+ )
599
1784
  end
600
1785
 
1786
+ it_behaves_like 'returns a cloned query'
1787
+
601
1788
  it "removes the negation on the clone" do
602
1789
  expect(selection).to_not be_negating
603
1790
  end
@@ -615,9 +1802,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
615
1802
  )
616
1803
  end
617
1804
 
618
- it "returns a cloned query" do
619
- expect(selection).to_not equal(query)
620
- end
1805
+ it_behaves_like 'returns a cloned query'
621
1806
 
622
1807
  it "removes the negation on the clone" do
623
1808
  expect(selection).to_not be_negating
@@ -636,10 +1821,27 @@ describe Mongoid::Criteria::Queryable::Selectable do
636
1821
  )
637
1822
  end
638
1823
 
639
- it "returns a cloned query" do
640
- expect(selection).to_not equal(query)
1824
+ it_behaves_like 'returns a cloned query'
1825
+
1826
+ it "removes the negation on the clone" do
1827
+ expect(selection).to_not be_negating
1828
+ end
1829
+ end
1830
+
1831
+ context 'when the following criteria uses string were form' do
1832
+
1833
+ let(:selection) do
1834
+ query.not.where('hello world')
1835
+ end
1836
+
1837
+ it "negates the selection with an operator" do
1838
+ expect(selection.selector).to eq(
1839
+ '$and' => [{'$nor' => [{'$where' => 'hello world'}]}]
1840
+ )
641
1841
  end
642
1842
 
1843
+ it_behaves_like 'returns a cloned query'
1844
+
643
1845
  it "removes the negation on the clone" do
644
1846
  expect(selection).to_not be_negating
645
1847
  end
@@ -661,9 +1863,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
661
1863
  expect(selection).to eq(query)
662
1864
  end
663
1865
 
664
- it "returns a cloned query" do
665
- expect(selection).to_not equal(query)
666
- end
1866
+ it_behaves_like 'returns a cloned query'
667
1867
  end
668
1868
 
669
1869
  context "when provided a single criterion" do
@@ -678,14 +1878,31 @@ describe Mongoid::Criteria::Queryable::Selectable do
678
1878
  })
679
1879
  end
680
1880
 
681
- it "returns a cloned query" do
682
- expect(selection).to_not equal(query)
1881
+ it_behaves_like 'returns a cloned query'
1882
+ end
1883
+
1884
+ context "when negating a field in the original selector" do
1885
+ let(:query) do
1886
+ Mongoid::Query.new("id" => "_id").where(field: 'foo')
1887
+ end
1888
+
1889
+ let(:selection) do
1890
+ query.not(field: 'bar')
683
1891
  end
1892
+
1893
+ it "combines the conditions" do
1894
+ expect(selection.selector).to eq({
1895
+ "field" => 'foo',
1896
+ '$and' => [{'$nor' => [{ "field" => 'bar' }]}],
1897
+ })
1898
+ end
1899
+
1900
+ it_behaves_like 'returns a cloned query'
684
1901
  end
685
1902
 
686
- context "when provided multiple criterion" do
1903
+ context "when provided multiple criteria" do
687
1904
 
688
- context "when the criterion are for different fields" do
1905
+ context "when the criteria are for different fields" do
689
1906
 
690
1907
  let(:selection) do
691
1908
  query.not(first: /1/, second: /2/)
@@ -698,9 +1915,23 @@ describe Mongoid::Criteria::Queryable::Selectable do
698
1915
  })
699
1916
  end
700
1917
 
701
- it "returns a cloned query" do
702
- expect(selection).to_not equal(query)
1918
+ it_behaves_like 'returns a cloned query'
1919
+ end
1920
+
1921
+ context "when the criteria are given in separate arguments" do
1922
+
1923
+ let(:selection) do
1924
+ query.not({first: /1/}, {second: /2/})
1925
+ end
1926
+
1927
+ it "adds the $not selectors" do
1928
+ expect(selection.selector).to eq({
1929
+ "first" => { "$not" => /1/ },
1930
+ "second" => { "$not" => /2/ }
1931
+ })
703
1932
  end
1933
+
1934
+ it_behaves_like 'returns a cloned query'
704
1935
  end
705
1936
  end
706
1937
 
@@ -719,9 +1950,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
719
1950
  })
720
1951
  end
721
1952
 
722
- it "returns a cloned query" do
723
- expect(selection).to_not equal(query)
724
- end
1953
+ it_behaves_like 'returns a cloned query'
725
1954
  end
726
1955
 
727
1956
  context "when the criterion are on the same field" do
@@ -730,15 +1959,14 @@ describe Mongoid::Criteria::Queryable::Selectable do
730
1959
  query.not(first: /1/).not(first: /2/)
731
1960
  end
732
1961
 
733
- it "overwrites the first $not selector" do
734
- expect(selection.selector).to eq({
735
- "first" => { "$not" => /2/ }
736
- })
1962
+ it "combines conditions" do
1963
+ expect(selection.selector).to eq(
1964
+ "first" => { "$not" => /1/ },
1965
+ '$and' => [{'$nor' => [{'first' => /2/}]}],
1966
+ )
737
1967
  end
738
1968
 
739
- it "returns a cloned query" do
740
- expect(selection).to_not equal(query)
741
- end
1969
+ it_behaves_like 'returns a cloned query'
742
1970
  end
743
1971
 
744
1972
  context "when the criterion are a double negative" do
@@ -753,10 +1981,139 @@ describe Mongoid::Criteria::Queryable::Selectable do
753
1981
  })
754
1982
  end
755
1983
 
756
- it "returns a cloned query" do
757
- expect(selection).to_not equal(query)
1984
+ it_behaves_like 'returns a cloned query'
1985
+ end
1986
+ end
1987
+
1988
+ context 'when argument is a Criteria' do
1989
+ let(:query) do
1990
+ Mongoid::Query.new.where(hello: 'world')
1991
+ end
1992
+
1993
+ let(:other) do
1994
+ Mongoid::Query.new.where(foo: 'bar')
1995
+ end
1996
+
1997
+ let(:result) { query.not(other) }
1998
+
1999
+ it 'combines' do
2000
+ expect(result.selector).to eq('hello' => 'world', 'foo' => {'$ne' => 'bar'})
2001
+ end
2002
+ end
2003
+
2004
+ context 'when argument is a simple Criteria with multiple fields' do
2005
+ let(:query) do
2006
+ Mongoid::Query.new.where(hello: 'world')
2007
+ end
2008
+
2009
+ let(:other) do
2010
+ Mongoid::Query.new.where(a: 1, b: 2)
2011
+ end
2012
+
2013
+ let(:result) { query.not(other) }
2014
+
2015
+ it 'combines fields into top level criteria' do
2016
+ expect(result.selector).to eq('hello' => 'world',
2017
+ 'a' => {'$ne' => 1}, 'b' => {'$ne' => 2})
2018
+ end
2019
+ end
2020
+
2021
+ context 'when argument is a complex Criteria' do
2022
+ let(:query) do
2023
+ Mongoid::Query.new.where(hello: 'world')
2024
+ end
2025
+
2026
+ let(:other) do
2027
+ Mongoid::Query.new.where('$nor' => [{a: 1, b: 2}])
2028
+ end
2029
+
2030
+ let(:result) { query.not(other) }
2031
+
2032
+ it 'combines with $and of $nor' do
2033
+ expect(result.selector).to eq('hello' => 'world', '$and' => [{'$nor' => [{
2034
+ '$nor' => [{'a' => 1, 'b' => 2}]}]}])
2035
+ end
2036
+ end
2037
+
2038
+ context 'when argument is a mix of Criteria and hashes' do
2039
+ let(:query) do
2040
+ Mongoid::Query.new.where(hello: 'world')
2041
+ end
2042
+
2043
+ let(:other1) do
2044
+ Mongoid::Query.new.where(foo: 'bar')
2045
+ end
2046
+
2047
+ let(:other2) do
2048
+ {bar: 42}
2049
+ end
2050
+
2051
+ let(:other3) do
2052
+ Mongoid::Query.new.where(a: 2)
2053
+ end
2054
+
2055
+ let(:result) { query.not(other1, other2, other3) }
2056
+
2057
+ it 'combines' do
2058
+ expect(result.selector).to eq('hello' => 'world',
2059
+ 'foo' => {'$ne' => 'bar'},
2060
+ 'bar' => {'$ne' => 42},
2061
+ 'a' => {'$ne' => 2},
2062
+ )
2063
+ end
2064
+ end
2065
+
2066
+ context 'when giving multiple conditions in one call on the same key with symbol operator' do
2067
+
2068
+ context 'non-regexp argument' do
2069
+ let(:selection) do
2070
+ query.not(field: 1, :field.gt => 0)
2071
+ end
2072
+
2073
+ it 'combines conditions with $eq' do
2074
+ selection.selector.should == {
2075
+ '$and' => ['$nor' => [
2076
+ 'field' => {'$eq' => 1, '$gt' => 0},
2077
+ ]]
2078
+ }
2079
+ end
2080
+ end
2081
+
2082
+ context 'regexp argument' do
2083
+ let(:selection) do
2084
+ query.not(field: /t/, :field.gt => 0)
2085
+ end
2086
+
2087
+ it 'combines conditions with $regex' do
2088
+ selection.selector.should == {
2089
+ '$and' => ['$nor' => [
2090
+ 'field' => {'$regex' => /t/, '$gt' => 0},
2091
+ ]]
2092
+ }
758
2093
  end
759
2094
  end
760
2095
  end
2096
+
2097
+ # This test confirms that MONGOID-5097 has been repaired.
2098
+ context "when using exists on a field of type Time" do
2099
+ let(:criteria) do
2100
+ Dictionary.any_of({:published.exists => true}, published: nil)
2101
+ end
2102
+
2103
+ it "doesn't raise an error" do
2104
+ expect do
2105
+ criteria
2106
+ end.to_not raise_error
2107
+ end
2108
+
2109
+ it "generates the correct selector" do
2110
+ expect(criteria.selector).to eq({
2111
+ "$or" => [ {
2112
+ "published" => { "$exists" => true }
2113
+ }, {
2114
+ "published" => nil
2115
+ } ] } )
2116
+ end
2117
+ end
761
2118
  end
762
2119
  end