mongoid 6.4.4 → 7.1.7

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