mongoid 7.0.12 → 7.3.3

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