mongoid 2.8.1 → 3.0.0.rc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (351) hide show
  1. data/CHANGELOG.md +802 -58
  2. data/LICENSE +1 -1
  3. data/README.md +10 -11
  4. data/Rakefile +2 -8
  5. data/lib/config/locales/en.yml +441 -51
  6. data/lib/mongoid.rb +24 -39
  7. data/lib/mongoid/atomic.rb +16 -33
  8. data/lib/mongoid/atomic/modifiers.rb +2 -2
  9. data/lib/mongoid/atomic/paths/embedded.rb +4 -5
  10. data/lib/mongoid/atomic/paths/embedded/many.rb +6 -6
  11. data/lib/mongoid/atomic/paths/embedded/one.rb +5 -5
  12. data/lib/mongoid/atomic/paths/root.rb +4 -5
  13. data/lib/mongoid/attributes.rb +95 -32
  14. data/lib/mongoid/attributes/processing.rb +14 -10
  15. data/lib/mongoid/attributes/readonly.rb +56 -0
  16. data/lib/mongoid/callbacks.rb +90 -27
  17. data/lib/mongoid/collections/retry.rb +2 -3
  18. data/lib/mongoid/components.rb +11 -23
  19. data/lib/mongoid/config.rb +87 -233
  20. data/lib/mongoid/config/environment.rb +5 -6
  21. data/lib/mongoid/config/inflections.rb +6 -0
  22. data/lib/mongoid/config/options.rb +1 -1
  23. data/lib/mongoid/config/validators.rb +3 -0
  24. data/lib/mongoid/config/validators/option.rb +25 -0
  25. data/lib/mongoid/config/validators/session.rb +140 -0
  26. data/lib/mongoid/contextual.rb +50 -0
  27. data/lib/mongoid/contextual/aggregable/memory.rb +98 -0
  28. data/lib/mongoid/contextual/aggregable/mongo.rb +181 -0
  29. data/lib/mongoid/contextual/atomic.rb +179 -0
  30. data/lib/mongoid/contextual/command.rb +43 -0
  31. data/lib/mongoid/contextual/find_and_modify.rb +66 -0
  32. data/lib/mongoid/contextual/map_reduce.rb +273 -0
  33. data/lib/mongoid/contextual/memory.rb +383 -0
  34. data/lib/mongoid/contextual/mongo.rb +543 -0
  35. data/lib/mongoid/copyable.rb +3 -34
  36. data/lib/mongoid/criteria.rb +436 -250
  37. data/lib/mongoid/criterion/inspection.rb +14 -8
  38. data/lib/mongoid/criterion/scoping.rb +114 -44
  39. data/lib/mongoid/dirty.rb +152 -67
  40. data/lib/mongoid/document.rb +69 -50
  41. data/lib/mongoid/errors.rb +22 -1
  42. data/lib/mongoid/errors/ambiguous_relationship.rb +51 -0
  43. data/lib/mongoid/errors/callback.rb +5 -6
  44. data/lib/mongoid/errors/delete_restriction.rb +29 -0
  45. data/lib/mongoid/errors/document_not_found.rb +98 -17
  46. data/lib/mongoid/errors/eager_load.rb +3 -6
  47. data/lib/mongoid/errors/invalid_collection.rb +3 -3
  48. data/lib/mongoid/errors/invalid_config_option.rb +27 -0
  49. data/lib/mongoid/errors/invalid_database.rb +3 -3
  50. data/lib/mongoid/errors/invalid_field.rb +54 -8
  51. data/lib/mongoid/errors/invalid_field_option.rb +35 -0
  52. data/lib/mongoid/errors/invalid_find.rb +3 -3
  53. data/lib/mongoid/errors/invalid_index.rb +28 -0
  54. data/lib/mongoid/errors/invalid_options.rb +4 -4
  55. data/lib/mongoid/errors/invalid_scope.rb +24 -0
  56. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +38 -0
  57. data/lib/mongoid/errors/invalid_storage_options.rb +27 -0
  58. data/lib/mongoid/errors/invalid_time.rb +3 -6
  59. data/lib/mongoid/errors/inverse_not_found.rb +29 -0
  60. data/lib/mongoid/errors/mixed_relations.rb +4 -9
  61. data/lib/mongoid/errors/mixed_session_configuration.rb +28 -0
  62. data/lib/mongoid/errors/mongoid_error.rb +54 -3
  63. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +28 -0
  64. data/lib/mongoid/errors/no_default_session.rb +23 -0
  65. data/lib/mongoid/errors/no_environment.rb +3 -3
  66. data/lib/mongoid/errors/no_map_reduce_output.rb +24 -0
  67. data/lib/mongoid/errors/no_parent.rb +24 -0
  68. data/lib/mongoid/errors/no_session_config.rb +22 -0
  69. data/lib/mongoid/errors/no_session_database.rb +27 -0
  70. data/lib/mongoid/errors/no_session_hosts.rb +27 -0
  71. data/lib/mongoid/errors/no_sessions_config.rb +20 -0
  72. data/lib/mongoid/errors/readonly_attribute.rb +25 -0
  73. data/lib/mongoid/errors/scope_overwrite.rb +4 -4
  74. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +4 -4
  75. data/lib/mongoid/errors/unknown_attribute.rb +25 -0
  76. data/lib/mongoid/errors/unsaved_document.rb +4 -8
  77. data/lib/mongoid/errors/unsupported_javascript.rb +27 -0
  78. data/lib/mongoid/errors/unsupported_version.rb +4 -4
  79. data/lib/mongoid/errors/validations.rb +7 -6
  80. data/lib/mongoid/errors/versioning_not_on_root.rb +23 -0
  81. data/lib/mongoid/extensions.rb +28 -76
  82. data/lib/mongoid/extensions/array.rb +127 -0
  83. data/lib/mongoid/extensions/big_decimal.rb +42 -0
  84. data/lib/mongoid/extensions/boolean.rb +24 -0
  85. data/lib/mongoid/extensions/date.rb +70 -0
  86. data/lib/mongoid/extensions/date_time.rb +68 -0
  87. data/lib/mongoid/extensions/false_class.rb +26 -0
  88. data/lib/mongoid/extensions/float.rb +44 -0
  89. data/lib/mongoid/extensions/hash.rb +91 -0
  90. data/lib/mongoid/extensions/integer.rb +54 -0
  91. data/lib/mongoid/extensions/module.rb +28 -0
  92. data/lib/mongoid/extensions/nil_class.rb +21 -0
  93. data/lib/mongoid/extensions/object.rb +188 -0
  94. data/lib/mongoid/extensions/object_id.rb +53 -0
  95. data/lib/mongoid/extensions/range.rb +55 -0
  96. data/lib/mongoid/extensions/regexp.rb +27 -0
  97. data/lib/mongoid/extensions/set.rb +55 -0
  98. data/lib/mongoid/extensions/string.rb +155 -0
  99. data/lib/mongoid/extensions/symbol.rb +54 -0
  100. data/lib/mongoid/extensions/time.rb +78 -0
  101. data/lib/mongoid/extensions/time_with_zone.rb +55 -0
  102. data/lib/mongoid/extensions/true_class.rb +26 -0
  103. data/lib/mongoid/factory.rb +1 -1
  104. data/lib/mongoid/fields.rb +129 -194
  105. data/lib/mongoid/fields/foreign_key.rb +134 -0
  106. data/lib/mongoid/fields/localized.rb +73 -0
  107. data/lib/mongoid/fields/standard.rb +268 -0
  108. data/lib/mongoid/fields/validators.rb +2 -0
  109. data/lib/mongoid/fields/validators/macro.rb +83 -0
  110. data/lib/mongoid/finders.rb +42 -43
  111. data/lib/mongoid/hierarchy.rb +25 -14
  112. data/lib/mongoid/identity_map.rb +31 -19
  113. data/lib/mongoid/indexes.rb +66 -15
  114. data/lib/mongoid/indexes/validators/options.rb +80 -0
  115. data/lib/mongoid/inspection.rb +1 -1
  116. data/lib/mongoid/javascript.rb +1 -1
  117. data/lib/mongoid/json.rb +2 -2
  118. data/lib/mongoid/loggable.rb +69 -0
  119. data/lib/mongoid/matchers.rb +1 -1
  120. data/lib/mongoid/matchers/all.rb +7 -8
  121. data/lib/mongoid/matchers/and.rb +3 -3
  122. data/lib/mongoid/matchers/default.rb +6 -4
  123. data/lib/mongoid/matchers/exists.rb +2 -2
  124. data/lib/mongoid/matchers/gt.rb +2 -2
  125. data/lib/mongoid/matchers/gte.rb +2 -2
  126. data/lib/mongoid/matchers/in.rb +3 -7
  127. data/lib/mongoid/matchers/lt.rb +2 -2
  128. data/lib/mongoid/matchers/lte.rb +2 -2
  129. data/lib/mongoid/matchers/ne.rb +2 -2
  130. data/lib/mongoid/matchers/nin.rb +2 -2
  131. data/lib/mongoid/matchers/or.rb +2 -2
  132. data/lib/mongoid/matchers/size.rb +2 -2
  133. data/lib/mongoid/matchers/strategies.rb +3 -3
  134. data/lib/mongoid/multi_parameter_attributes.rb +8 -10
  135. data/lib/mongoid/nested_attributes.rb +17 -9
  136. data/lib/mongoid/observer.rb +1 -2
  137. data/lib/mongoid/paranoia.rb +13 -18
  138. data/lib/mongoid/persistence.rb +43 -39
  139. data/lib/mongoid/persistence/atomic.rb +2 -2
  140. data/lib/mongoid/persistence/atomic/add_to_set.rb +5 -9
  141. data/lib/mongoid/persistence/atomic/bit.rb +5 -7
  142. data/lib/mongoid/persistence/atomic/inc.rb +5 -7
  143. data/lib/mongoid/persistence/atomic/operation.rb +45 -6
  144. data/lib/mongoid/persistence/atomic/pop.rb +5 -7
  145. data/lib/mongoid/persistence/atomic/pull.rb +5 -7
  146. data/lib/mongoid/persistence/atomic/pull_all.rb +5 -7
  147. data/lib/mongoid/persistence/atomic/push.rb +4 -10
  148. data/lib/mongoid/persistence/atomic/push_all.rb +4 -10
  149. data/lib/mongoid/persistence/atomic/rename.rb +6 -7
  150. data/lib/mongoid/persistence/atomic/sets.rb +5 -7
  151. data/lib/mongoid/persistence/atomic/unset.rb +4 -5
  152. data/lib/mongoid/persistence/deletion.rb +2 -2
  153. data/lib/mongoid/persistence/insertion.rb +10 -16
  154. data/lib/mongoid/persistence/modification.rb +5 -9
  155. data/lib/mongoid/persistence/operations.rb +6 -19
  156. data/lib/mongoid/persistence/operations/embedded/insert.rb +7 -6
  157. data/lib/mongoid/persistence/operations/embedded/remove.rb +5 -5
  158. data/lib/mongoid/persistence/operations/insert.rb +4 -4
  159. data/lib/mongoid/persistence/operations/remove.rb +4 -4
  160. data/lib/mongoid/persistence/operations/update.rb +5 -5
  161. data/lib/mongoid/railtie.rb +26 -11
  162. data/lib/mongoid/railties/database.rake +22 -108
  163. data/lib/mongoid/relations.rb +4 -6
  164. data/lib/mongoid/relations/accessors.rb +119 -19
  165. data/lib/mongoid/relations/auto_save.rb +59 -5
  166. data/lib/mongoid/relations/binding.rb +211 -2
  167. data/lib/mongoid/relations/bindings/embedded/in.rb +16 -22
  168. data/lib/mongoid/relations/bindings/embedded/many.rb +9 -50
  169. data/lib/mongoid/relations/bindings/embedded/one.rb +10 -16
  170. data/lib/mongoid/relations/bindings/referenced/in.rb +31 -57
  171. data/lib/mongoid/relations/bindings/referenced/many.rb +8 -20
  172. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +15 -19
  173. data/lib/mongoid/relations/bindings/referenced/one.rb +10 -24
  174. data/lib/mongoid/relations/builder.rb +3 -3
  175. data/lib/mongoid/relations/builders.rb +19 -16
  176. data/lib/mongoid/relations/builders/embedded/in.rb +5 -5
  177. data/lib/mongoid/relations/builders/embedded/many.rb +12 -12
  178. data/lib/mongoid/relations/builders/embedded/one.rb +6 -6
  179. data/lib/mongoid/relations/builders/nested_attributes/many.rb +8 -8
  180. data/lib/mongoid/relations/builders/nested_attributes/one.rb +4 -4
  181. data/lib/mongoid/relations/builders/referenced/in.rb +4 -4
  182. data/lib/mongoid/relations/builders/referenced/many.rb +5 -5
  183. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +7 -5
  184. data/lib/mongoid/relations/builders/referenced/one.rb +5 -5
  185. data/lib/mongoid/relations/cascading.rb +6 -4
  186. data/lib/mongoid/relations/cascading/delete.rb +3 -5
  187. data/lib/mongoid/relations/cascading/destroy.rb +3 -3
  188. data/lib/mongoid/relations/cascading/nullify.rb +3 -3
  189. data/lib/mongoid/relations/cascading/restrict.rb +37 -0
  190. data/lib/mongoid/relations/constraint.rb +4 -3
  191. data/lib/mongoid/relations/conversions.rb +5 -6
  192. data/lib/mongoid/relations/cyclic.rb +7 -7
  193. data/lib/mongoid/relations/embedded/batchable.rb +346 -0
  194. data/lib/mongoid/relations/embedded/in.rb +23 -12
  195. data/lib/mongoid/relations/embedded/many.rb +99 -161
  196. data/lib/mongoid/relations/embedded/one.rb +25 -14
  197. data/lib/mongoid/relations/macros.rb +105 -61
  198. data/lib/mongoid/relations/many.rb +93 -14
  199. data/lib/mongoid/relations/metadata.rb +200 -45
  200. data/lib/mongoid/relations/nested_builder.rb +3 -5
  201. data/lib/mongoid/relations/one.rb +2 -2
  202. data/lib/mongoid/relations/options.rb +2 -2
  203. data/lib/mongoid/relations/polymorphic.rb +9 -9
  204. data/lib/mongoid/relations/proxy.rb +60 -31
  205. data/lib/mongoid/relations/referenced/in.rb +40 -15
  206. data/lib/mongoid/relations/referenced/many.rb +117 -132
  207. data/lib/mongoid/relations/referenced/many_to_many.rb +101 -46
  208. data/lib/mongoid/relations/referenced/one.rb +34 -13
  209. data/lib/mongoid/relations/reflections.rb +3 -3
  210. data/lib/mongoid/relations/synchronization.rb +19 -23
  211. data/lib/mongoid/relations/targets/enumerable.rb +86 -57
  212. data/lib/mongoid/reloading.rb +12 -14
  213. data/lib/mongoid/scoping.rb +329 -0
  214. data/lib/mongoid/serialization.rb +8 -27
  215. data/lib/mongoid/sessions.rb +359 -0
  216. data/lib/mongoid/sessions/factory.rb +106 -0
  217. data/lib/mongoid/sessions/mongo_uri.rb +93 -0
  218. data/lib/mongoid/sessions/validators.rb +2 -0
  219. data/lib/mongoid/sessions/validators/storage.rb +49 -0
  220. data/lib/mongoid/sharding.rb +6 -6
  221. data/lib/mongoid/state.rb +6 -7
  222. data/lib/mongoid/threaded.rb +167 -59
  223. data/lib/mongoid/threaded/lifecycle.rb +21 -22
  224. data/lib/mongoid/threaded/sessions.rb +0 -0
  225. data/lib/mongoid/timestamps.rb +1 -1
  226. data/lib/mongoid/timestamps/created.rb +8 -4
  227. data/lib/mongoid/timestamps/timeless.rb +6 -4
  228. data/lib/mongoid/timestamps/updated.rb +3 -3
  229. data/lib/mongoid/unit_of_work.rb +61 -0
  230. data/lib/mongoid/validations.rb +27 -19
  231. data/lib/mongoid/validations/associated.rb +2 -2
  232. data/lib/mongoid/validations/format.rb +2 -2
  233. data/lib/mongoid/validations/presence.rb +31 -5
  234. data/lib/mongoid/validations/uniqueness.rb +9 -12
  235. data/lib/mongoid/version.rb +2 -2
  236. data/lib/mongoid/versioning.rb +25 -26
  237. data/lib/rack/mongoid/middleware/identity_map.rb +3 -3
  238. data/lib/rails/generators/mongoid/config/config_generator.rb +1 -1
  239. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +59 -19
  240. data/lib/rails/generators/mongoid/model/model_generator.rb +7 -7
  241. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +2 -2
  242. data/lib/rails/generators/mongoid/observer/observer_generator.rb +4 -4
  243. data/lib/rails/generators/mongoid_generator.rb +5 -5
  244. data/lib/rails/mongoid.rb +69 -25
  245. metadata +110 -137
  246. checksums.yaml +0 -7
  247. data/lib/config/locales/bg.yml +0 -61
  248. data/lib/config/locales/de.yml +0 -61
  249. data/lib/config/locales/en-GB.yml +0 -64
  250. data/lib/config/locales/es.yml +0 -59
  251. data/lib/config/locales/fr.yml +0 -62
  252. data/lib/config/locales/hi.yml +0 -53
  253. data/lib/config/locales/hu.yml +0 -64
  254. data/lib/config/locales/id.yml +0 -62
  255. data/lib/config/locales/it.yml +0 -59
  256. data/lib/config/locales/ja.yml +0 -57
  257. data/lib/config/locales/kr.yml +0 -54
  258. data/lib/config/locales/nl.yml +0 -61
  259. data/lib/config/locales/pl.yml +0 -59
  260. data/lib/config/locales/pt-BR.yml +0 -60
  261. data/lib/config/locales/pt.yml +0 -60
  262. data/lib/config/locales/ro.yml +0 -66
  263. data/lib/config/locales/ru.yml +0 -61
  264. data/lib/config/locales/sv.yml +0 -60
  265. data/lib/config/locales/vi.yml +0 -62
  266. data/lib/config/locales/zh-CN.yml +0 -53
  267. data/lib/mongoid/collection.rb +0 -157
  268. data/lib/mongoid/collections.rb +0 -120
  269. data/lib/mongoid/collections/master.rb +0 -45
  270. data/lib/mongoid/collections/operations.rb +0 -44
  271. data/lib/mongoid/config/database.rb +0 -181
  272. data/lib/mongoid/config/replset_database.rb +0 -80
  273. data/lib/mongoid/contexts.rb +0 -25
  274. data/lib/mongoid/contexts/enumerable.rb +0 -313
  275. data/lib/mongoid/contexts/enumerable/sort.rb +0 -43
  276. data/lib/mongoid/contexts/mongo.rb +0 -487
  277. data/lib/mongoid/criterion/builder.rb +0 -34
  278. data/lib/mongoid/criterion/complex.rb +0 -84
  279. data/lib/mongoid/criterion/creational.rb +0 -34
  280. data/lib/mongoid/criterion/exclusion.rb +0 -110
  281. data/lib/mongoid/criterion/inclusion.rb +0 -290
  282. data/lib/mongoid/criterion/optional.rb +0 -259
  283. data/lib/mongoid/criterion/selector.rb +0 -177
  284. data/lib/mongoid/cursor.rb +0 -88
  285. data/lib/mongoid/default_scope.rb +0 -36
  286. data/lib/mongoid/errors/invalid_type.rb +0 -25
  287. data/lib/mongoid/extensions/array/deep_copy.rb +0 -25
  288. data/lib/mongoid/extensions/array/deletion.rb +0 -29
  289. data/lib/mongoid/extensions/false_class/equality.rb +0 -26
  290. data/lib/mongoid/extensions/hash/criteria_helpers.rb +0 -47
  291. data/lib/mongoid/extensions/hash/deep_copy.rb +0 -25
  292. data/lib/mongoid/extensions/hash/scoping.rb +0 -25
  293. data/lib/mongoid/extensions/integer/checks.rb +0 -23
  294. data/lib/mongoid/extensions/nil/collectionization.rb +0 -23
  295. data/lib/mongoid/extensions/object/checks.rb +0 -29
  296. data/lib/mongoid/extensions/object/deep_copy.rb +0 -21
  297. data/lib/mongoid/extensions/object/reflections.rb +0 -48
  298. data/lib/mongoid/extensions/object/substitutable.rb +0 -15
  299. data/lib/mongoid/extensions/object/yoda.rb +0 -44
  300. data/lib/mongoid/extensions/object_id/conversions.rb +0 -60
  301. data/lib/mongoid/extensions/proc/scoping.rb +0 -25
  302. data/lib/mongoid/extensions/string/checks.rb +0 -36
  303. data/lib/mongoid/extensions/string/conversions.rb +0 -22
  304. data/lib/mongoid/extensions/string/inflections.rb +0 -118
  305. data/lib/mongoid/extensions/symbol/checks.rb +0 -23
  306. data/lib/mongoid/extensions/symbol/inflections.rb +0 -67
  307. data/lib/mongoid/extensions/true_class/equality.rb +0 -26
  308. data/lib/mongoid/extras.rb +0 -31
  309. data/lib/mongoid/fields/internal/array.rb +0 -77
  310. data/lib/mongoid/fields/internal/big_decimal.rb +0 -63
  311. data/lib/mongoid/fields/internal/bignum.rb +0 -10
  312. data/lib/mongoid/fields/internal/binary.rb +0 -11
  313. data/lib/mongoid/fields/internal/boolean.rb +0 -58
  314. data/lib/mongoid/fields/internal/date.rb +0 -51
  315. data/lib/mongoid/fields/internal/date_time.rb +0 -28
  316. data/lib/mongoid/fields/internal/false_class.rb +0 -10
  317. data/lib/mongoid/fields/internal/fixnum.rb +0 -10
  318. data/lib/mongoid/fields/internal/float.rb +0 -47
  319. data/lib/mongoid/fields/internal/foreign_keys/array.rb +0 -88
  320. data/lib/mongoid/fields/internal/foreign_keys/object.rb +0 -56
  321. data/lib/mongoid/fields/internal/hash.rb +0 -11
  322. data/lib/mongoid/fields/internal/integer.rb +0 -59
  323. data/lib/mongoid/fields/internal/localized.rb +0 -62
  324. data/lib/mongoid/fields/internal/nil_class.rb +0 -53
  325. data/lib/mongoid/fields/internal/object.rb +0 -11
  326. data/lib/mongoid/fields/internal/object_id.rb +0 -46
  327. data/lib/mongoid/fields/internal/range.rb +0 -61
  328. data/lib/mongoid/fields/internal/set.rb +0 -57
  329. data/lib/mongoid/fields/internal/string.rb +0 -42
  330. data/lib/mongoid/fields/internal/symbol.rb +0 -43
  331. data/lib/mongoid/fields/internal/time.rb +0 -23
  332. data/lib/mongoid/fields/internal/time_with_zone.rb +0 -23
  333. data/lib/mongoid/fields/internal/timekeeping.rb +0 -122
  334. data/lib/mongoid/fields/internal/true_class.rb +0 -10
  335. data/lib/mongoid/fields/mappings.rb +0 -42
  336. data/lib/mongoid/fields/serializable.rb +0 -270
  337. data/lib/mongoid/identity.rb +0 -92
  338. data/lib/mongoid/keys.rb +0 -144
  339. data/lib/mongoid/logger.rb +0 -45
  340. data/lib/mongoid/multi_database.rb +0 -36
  341. data/lib/mongoid/named_scope.rb +0 -166
  342. data/lib/mongoid/relations/embedded/atomic.rb +0 -89
  343. data/lib/mongoid/relations/embedded/atomic/operation.rb +0 -63
  344. data/lib/mongoid/relations/embedded/atomic/pull.rb +0 -65
  345. data/lib/mongoid/relations/embedded/atomic/push_all.rb +0 -59
  346. data/lib/mongoid/relations/embedded/atomic/set.rb +0 -61
  347. data/lib/mongoid/relations/embedded/atomic/unset.rb +0 -41
  348. data/lib/mongoid/relations/referenced/batch.rb +0 -73
  349. data/lib/mongoid/relations/referenced/batch/insert.rb +0 -57
  350. data/lib/mongoid/safety.rb +0 -105
  351. data/lib/mongoid/scope.rb +0 -31
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- module Mongoid #:nodoc:
2
+ module Mongoid
3
3
 
4
4
  # This module contains the behaviour of Mongoid's clone/dup of documents.
5
5
  module Copyable
@@ -23,44 +23,13 @@ module Mongoid #:nodoc:
23
23
  # @example Clone the document.
24
24
  # document.clone
25
25
  #
26
- # @param [ Document ] other The document getting cloned.
27
- #
28
- # @return [ Document ] The new document.
29
- def initialize_copy(other)
30
- __copy__(other)
31
- end
32
-
33
- # Clone or dup the current +Document+. This will return all attributes with
34
- # the exception of the document's id and versions, and will reset all the
35
- # instance variables.
36
- #
37
- # This clone also includes embedded documents.
38
- #
39
26
  # @example Dup the document.
40
27
  # document.dup
41
28
  #
42
29
  # @param [ Document ] other The document getting cloned.
43
30
  #
44
31
  # @return [ Document ] The new document.
45
- def initialize_dup(other)
46
- __copy__(other)
47
- end
48
-
49
- private
50
-
51
- # Handle the copy of the object.
52
- #
53
- # @api private
54
- #
55
- # @example Copy the object.
56
- # document.__copy__(other)
57
- #
58
- # @param [ Document ] other The other document.
59
- #
60
- # @return [ Document ] self.
61
- #
62
- # @since 3.0.0
63
- def __copy__(other)
32
+ def initialize_copy(other)
64
33
  other.as_document
65
34
  instance_variables.each { |name| remove_instance_variable(name) }
66
35
  COPYABLES.each do |name|
@@ -72,7 +41,7 @@ module Mongoid #:nodoc:
72
41
  attributes["version"] = 1
73
42
  end
74
43
  @new_record = true
75
- identify
44
+ apply_defaults
76
45
  end
77
46
  end
78
47
  end
@@ -1,15 +1,8 @@
1
1
  # encoding: utf-8
2
- require "mongoid/criterion/builder"
3
- require "mongoid/criterion/creational"
4
- require "mongoid/criterion/complex"
5
- require "mongoid/criterion/exclusion"
6
- require "mongoid/criterion/inclusion"
7
2
  require "mongoid/criterion/inspection"
8
- require "mongoid/criterion/optional"
9
3
  require "mongoid/criterion/scoping"
10
- require "mongoid/criterion/selector"
11
4
 
12
- module Mongoid #:nodoc:
5
+ module Mongoid
13
6
 
14
7
  # The +Criteria+ class is the core object needed in Mongoid to retrieve
15
8
  # objects from the database. It is a DSL that essentially sets up the
@@ -17,78 +10,14 @@ module Mongoid #:nodoc:
17
10
  # in the Ruby driver. Each method on the +Criteria+ returns self to they
18
11
  # can be chained in order to create a readable criterion to be executed
19
12
  # against the database.
20
- #
21
- # @example Create and execute a criteria.
22
- # criteria = Criteria.new
23
- # criteria.only(:field).where(:field => "value").skip(20).limit(20)
24
- # criteria.execute
25
13
  class Criteria
26
14
  include Enumerable
27
- include Criterion::Builder
28
- include Criterion::Creational
29
- include Criterion::Exclusion
30
- include Criterion::Inclusion
15
+ include Contextual
16
+ include Origin::Queryable
31
17
  include Criterion::Inspection
32
- include Criterion::Optional
33
18
  include Criterion::Scoping
34
19
 
35
- attr_accessor \
36
- :documents,
37
- :embedded,
38
- :ids,
39
- :klass,
40
- :options,
41
- :selector,
42
- :field_list
43
-
44
- delegate \
45
- :add_to_set,
46
- :aggregate,
47
- :avg,
48
- :blank?,
49
- :count,
50
- :size,
51
- :length,
52
- :delete,
53
- :delete_all,
54
- :destroy,
55
- :destroy_all,
56
- :distinct,
57
- :empty?,
58
- :execute,
59
- :first,
60
- :group,
61
- :last,
62
- :max,
63
- :min,
64
- :one,
65
- :pull,
66
- :shift,
67
- :sum,
68
- :update,
69
- :update_all, :to => :context
70
-
71
- # Concatinate the criteria with another enumerable. If the other is a
72
- # +Criteria+ then it needs to get the collection from it.
73
- #
74
- # @example Concat 2 criteria.
75
- # criteria + criteria
76
- #
77
- # @param [ Criteria ] other The other criteria.
78
- def +(other)
79
- entries + comparable(other)
80
- end
81
-
82
- # Returns the difference between the criteria and another enumerable. If
83
- # the other is a +Criteria+ then it needs to get the collection from it.
84
- #
85
- # @example Get the difference of 2 criteria.
86
- # criteria - criteria
87
- #
88
- # @param [ Criteria ] other The other criteria.
89
- def -(other)
90
- entries - comparable(other)
91
- end
20
+ attr_accessor :embedded, :klass
92
21
 
93
22
  # Returns true if the supplied +Enumerable+ or +Criteria+ is equal to the results
94
23
  # of this +Criteria+ or the criteria itself.
@@ -98,51 +27,147 @@ module Mongoid #:nodoc:
98
27
  # @param [ Object ] other The other +Enumerable+ or +Criteria+ to compare to.
99
28
  #
100
29
  # @return [ true, false ] If the objects are equal.
30
+ #
31
+ # @since 1.0.0
101
32
  def ==(other)
102
33
  case other
103
- when Criteria
104
- self.selector == other.selector && self.options == other.options
105
- when Enumerable
106
- return (execute.entries == other)
107
- else
108
- return false
34
+ when Criteria then super
35
+ when Enumerable then entries == other
36
+ else false
109
37
  end
110
38
  end
111
39
 
112
- # Get the collection associated with the criteria.
40
+ # Needed to properly get a criteria back as json
113
41
  #
114
- # @example Get the collection.
115
- # criteria.collection
42
+ # @example Get the criteria as json.
43
+ # Person.where(:title => "Sir").as_json
116
44
  #
117
- # @return [ Collection ] The collection.
45
+ # @param [ Hash ] options Options to pass through to the serializer.
118
46
  #
119
- # @since 2.2.0
120
- def collection
121
- klass.collection
47
+ # @return [ String ] The JSON string.
48
+ def as_json(options = nil)
49
+ entries.as_json(options)
50
+ end
51
+
52
+ # Build a document given the selector and return it.
53
+ # Complex criteria, such as $in and $or operations will get ignored.
54
+ #
55
+ # @example build the document.
56
+ # Person.where(:title => "Sir").build
57
+ #
58
+ # @example Build with selectors getting ignored.
59
+ # Person.where(:age.gt => 5).build
60
+ #
61
+ # @return [ Document ] A non-persisted document.
62
+ #
63
+ # @since 2.0.0
64
+ def build(attrs = {})
65
+ create_document(:new, attrs)
66
+ end
67
+
68
+ # Tells the criteria that the cursor that gets returned needs to be
69
+ # cached. This is so multiple iterations don't hit the database multiple
70
+ # times, however this is not advisable when working with large data sets
71
+ # as the entire results will get stored in memory.
72
+ #
73
+ # @example Flag the criteria as cached.
74
+ # criteria.cache
75
+ #
76
+ # @return [ Criteria ] The cloned criteria.
77
+ def cache
78
+ crit = clone
79
+ crit.options.merge!(cache: true)
80
+ crit
81
+ end
82
+
83
+ # Will return true if the cache option has been set.
84
+ #
85
+ # @example Is the criteria cached?
86
+ # criteria.cached?
87
+ #
88
+ # @return [ true, false ] If the criteria is flagged as cached.
89
+ def cached?
90
+ options[:cache] == true
91
+ end
92
+
93
+ # Create a document in the database given the selector and return it.
94
+ # Complex criteria, such as $in and $or operations will get ignored.
95
+ #
96
+ # @example Create the document.
97
+ # Person.where(:title => "Sir").create
98
+ #
99
+ # @example Create with selectors getting ignored.
100
+ # Person.where(:age.gt => 5).create
101
+ #
102
+ # @return [ Document ] A newly created document.
103
+ #
104
+ # @since 2.0.0.rc.1
105
+ def create(attrs = {})
106
+ create_document(:create, attrs)
122
107
  end
123
108
 
124
- # Return or create the context in which this criteria should be executed.
109
+ # Create a document in the database given the selector and return it.
110
+ # Complex criteria, such as $in and $or operations will get ignored.
111
+ # If validation fails, an error will be raised.
112
+ #
113
+ # @example Create the document.
114
+ # Person.where(:title => "Sir").create
115
+ #
116
+ # @example Create with selectors getting ignored.
117
+ # Person.where(:age.gt => 5).create
125
118
  #
126
- # This will return an Enumerable context if the class is embedded,
127
- # otherwise it will return a Mongo context for root classes.
119
+ # @raise [ Errors::Validations ] on a validation error.
128
120
  #
129
- # @example Get the appropriate context.
130
- # criteria.context
121
+ # @return [ Document ] A newly created document.
131
122
  #
132
- # @return [ Mongo, Enumerable ] The appropriate context.
133
- def context
134
- @context ||= Contexts.context_for(self, embedded)
123
+ # @since 3.0.0
124
+ def create!(attrs = {})
125
+ create_document(:create!, attrs)
135
126
  end
136
127
 
137
- # Iterate over each +Document+ in the results. This can take an optional
138
- # block to pass to each argument in the results.
128
+ # Get the documents from the embedded criteria.
139
129
  #
140
- # @example Iterate over the criteria results.
141
- # criteria.each { |doc| p doc }
130
+ # @example Get the documents.
131
+ # criteria.documents
142
132
  #
143
- # @return [ Criteria ] The criteria itself.
144
- def each(&block)
145
- tap { context.iterate(&block) }
133
+ # @return [ Array<Document> ] The documents.
134
+ #
135
+ # @since 3.0.0
136
+ def documents
137
+ @documents ||= []
138
+ end
139
+
140
+ # Set the embedded documents on the criteria.
141
+ #
142
+ # @example Set the documents.
143
+ #
144
+ # @param [ Array<Document> ] docs The embedded documents.
145
+ #
146
+ # @return [ Array<Document> ] The embedded documents.
147
+ #
148
+ # @since 3.0.0
149
+ def documents=(docs)
150
+ @documents = docs
151
+ end
152
+
153
+ # Execute the criteria or raise an error if no documents found.
154
+ #
155
+ # @example Execute or raise
156
+ # criteria.execute_or_raise(id)
157
+ #
158
+ # @param [ Object ] args The arguments passed.
159
+ #
160
+ # @raise [ Errors::DocumentNotFound ] If nothing returned.
161
+ #
162
+ # @return [ Document, Array<Document> ] The document(s).
163
+ #
164
+ # @since 2.0.0
165
+ def execute_or_raise(ids, multi)
166
+ result = multiple_from_map_or_db(ids)
167
+ if (result.size < ids.size) && Mongoid.raise_not_found_error
168
+ raise Errors::DocumentNotFound.new(klass, ids, ids - result.map(&:_id))
169
+ end
170
+ multi ? result : result.first
146
171
  end
147
172
 
148
173
  # Return true if the criteria has some Document or not.
@@ -151,6 +176,8 @@ module Mongoid #:nodoc:
151
176
  # criteria.exists?
152
177
  #
153
178
  # @return [ true, false ] If documents match.
179
+ #
180
+ # @since 1.0.0
154
181
  def exists?
155
182
  context.count > 0
156
183
  end
@@ -165,7 +192,83 @@ module Mongoid #:nodoc:
165
192
  #
166
193
  # @since 2.3.0
167
194
  def extract_id
168
- selector[:_id]
195
+ selector.extract_id
196
+ end
197
+
198
+ # Adds a criterion to the +Criteria+ that specifies additional options
199
+ # to be passed to the Ruby driver, in the exact format for the driver.
200
+ #
201
+ # @example Add extra params to the criteria.
202
+ # criteria.extras(:limit => 20, :skip => 40)
203
+ #
204
+ # @param [ Hash ] extras The extra driver options.
205
+ #
206
+ # @return [ Criteria ] The cloned criteria.
207
+ #
208
+ # @since 2.0.0
209
+ def extras(extras)
210
+ crit = clone
211
+ crit.options.merge!(extras)
212
+ crit
213
+ end
214
+
215
+ # Get the list of included fields.
216
+ #
217
+ # @example Get the field list.
218
+ # criteria.field_list
219
+ #
220
+ # @return [ Array<String> ] The fields.
221
+ #
222
+ # @since 2.0.0
223
+ def field_list
224
+ if options[:fields]
225
+ options[:fields].keys.reject!{ |key| key == "_type" }
226
+ else
227
+ []
228
+ end
229
+ end
230
+
231
+ # Find the matchind document(s) in the criteria for the provided ids.
232
+ #
233
+ # @example Find by an id.
234
+ # criteria.find(BSON::ObjectId.new)
235
+ #
236
+ # @example Find by multiple ids.
237
+ # criteria.find([ BSON::ObjectId.new, BSON::ObjectId.new ])
238
+ #
239
+ # @param [ Array<BSON::ObjectId> ] args The ids to search for.
240
+ #
241
+ # @return [ Array<Document>, Document ] The matching document(s).
242
+ #
243
+ # @since 1.0.0
244
+ def find(*args)
245
+ multi = args.first.is_a?(::Array) || args.first.is_a?(::Range) || args.size > 1
246
+ ids = *args.flat_map do |arg|
247
+ arg.is_a?(::Range) ? arg.to_a : arg
248
+ end
249
+ raise_invalid if ids.any?(&:nil?)
250
+ for_ids(ids).execute_or_raise(ids, multi)
251
+ end
252
+
253
+ # Adds a criterion to the +Criteria+ that specifies an id that must be matched.
254
+ #
255
+ # @example Add a single id criteria.
256
+ # criteria.for_ids([ 1 ])
257
+ #
258
+ # @example Add multiple id criteria.
259
+ # criteria.for_ids([ 1, 2 ])
260
+ #
261
+ # @param [ Array ] ids The array of ids.
262
+ #
263
+ # @return [ Criteria ] The cloned criteria.
264
+ def for_ids(ids)
265
+ field = klass.fields["_id"]
266
+ method = extract_id ? :all_of : :where
267
+ if ids.size > 1
268
+ send(method, { _id: { "$in" => ids.map{ |id| field.mongoize(id) }}})
269
+ else
270
+ send(method, { _id: field.mongoize(ids.first) })
271
+ end
169
272
  end
170
273
 
171
274
  # When freezing a criteria we need to initialize the context first
@@ -182,31 +285,108 @@ module Mongoid #:nodoc:
182
285
  context and inclusions and super
183
286
  end
184
287
 
185
- # Merges the supplied argument hash into a single criteria
288
+ # Get the document from the identity map, and if not found hit the
289
+ # database.
186
290
  #
187
- # @example Fuse the criteria and the object.
188
- # criteria.fuse(:where => { :field => "value"}, :limit => 20)
291
+ # @example Get the document from the map or criteria.
292
+ # criteria.from_map_or_db
189
293
  #
190
- # @param [ Hash ] criteria_conditions Criteria keys and values.
294
+ # @return [ Document ] The found document.
191
295
  #
192
- # @return [ Criteria ] self.
193
- def fuse(criteria_conditions = {})
194
- criteria_conditions.inject(self) do |criteria, (key, value)|
195
- criteria.send(key, value)
296
+ # @since 2.2.1
297
+ def from_map_or_db
298
+ doc = IdentityMap.get(klass, extract_id || selector)
299
+ doc && doc.matches?(selector) ? doc : first
300
+ end
301
+
302
+ # Get the documents from the identity map, and if not found hit the
303
+ # database.
304
+ #
305
+ # @example Get the documents from the map or criteria.
306
+ # criteria.multiple_from_map_or_db(ids)
307
+ #
308
+ # @param [ ids ] The searched ids.
309
+ #
310
+ # @return [ Array<Document> ] The found documents.
311
+ def multiple_from_map_or_db(ids)
312
+ return entries if klass.embedded?
313
+ result = []
314
+ ids.reject! do |id|
315
+ doc = IdentityMap.get(klass, id)
316
+ doc && doc.matches?(selector) ? result.push(doc) : false
317
+ end
318
+ ids.empty? ? result : result + any_in(id: ids).entries
319
+ end
320
+
321
+ # Initialize the new criteria.
322
+ #
323
+ # @example Init the new criteria.
324
+ # Criteria.new(Band)
325
+ #
326
+ # @param [ Class ] klass The model class.
327
+ #
328
+ # @since 1.0.0
329
+ def initialize(klass)
330
+ @klass = klass
331
+ super(klass.aliased_fields, klass.fields)
332
+ end
333
+
334
+ # Eager loads all the provided relations. Will load all the documents
335
+ # into the identity map who's ids match based on the extra query for the
336
+ # ids.
337
+ #
338
+ # @note This will only work if Mongoid's identity map is enabled. To do
339
+ # so set identity_map_enabled: true in your mongoid.yml
340
+ #
341
+ # @note This will work for embedded relations that reference another
342
+ # collection via belongs_to as well.
343
+ #
344
+ # @note Eager loading brings all the documents into memory, so there is a
345
+ # sweet spot on the performance gains. Internal benchmarks show that
346
+ # eager loading becomes slower around 100k documents, but this will
347
+ # naturally depend on the specific application.
348
+ #
349
+ # @example Eager load the provided relations.
350
+ # Person.includes(:posts, :game)
351
+ #
352
+ # @param [ Array<Symbol> ] relations The names of the relations to eager
353
+ # load.
354
+ #
355
+ # @return [ Criteria ] The cloned criteria.
356
+ #
357
+ # @since 2.2.0
358
+ def includes(*relations)
359
+ relations.each do |name|
360
+ metadata = klass.reflect_on_association(name)
361
+ inclusions.push(metadata) unless inclusions.include?(metadata)
196
362
  end
363
+ clone
197
364
  end
198
365
 
199
- # Create the new +Criteria+ object. This will initialize the selector
200
- # and options hashes, as well as the type of criteria.
366
+ # Get a list of criteria that are to be executed for eager loading.
367
+ #
368
+ # @example Get the eager loading inclusions.
369
+ # Person.includes(:game).inclusions
201
370
  #
202
- # @example Instantiate a new criteria.
203
- # Criteria.new(Model, true)
371
+ # @return [ Array<Metadata> ] The inclusions.
204
372
  #
205
- # @param [ Class ] klass The model the criteria is for.
206
- # @param [ true, false ] embedded Is the criteria for embedded docs.
207
- def initialize(klass, embedded = false)
208
- @selector = Criterion::Selector.new(klass)
209
- @options, @klass, @documents, @embedded = {}, klass, [], embedded
373
+ # @since 2.2.0
374
+ def inclusions
375
+ @inclusions ||= []
376
+ end
377
+
378
+ # Set the inclusions for the criteria.
379
+ #
380
+ # @example Set the inclusions.
381
+ # criteria.inclusions = [ meta ]
382
+ #
383
+ # @param [ Array<Metadata> ] The inclusions.
384
+ #
385
+ # @return [ Array<Metadata> ] The new inclusions.
386
+ #
387
+ # @since 3.0.0
388
+ def inclusions=(value)
389
+ @inclusions = value
210
390
  end
211
391
 
212
392
  # Merges another object with this +Criteria+ and returns a new criteria.
@@ -214,27 +394,51 @@ module Mongoid #:nodoc:
214
394
  # combine multiple scopes together, where a chained scope situation
215
395
  # may be desired.
216
396
  #
217
- # @example Merge the criteria with a conditions hash.
218
- # criteria.merge({ :conditions => { :title => "Sir" } })
219
- #
220
397
  # @example Merge the criteria with another criteria.
221
398
  # criteri.merge(other_criteria)
222
399
  #
223
- # @param [ Criteria, Hash ] other The other criterion to merge with.
400
+ # @param [ Criteria ] other The other criterion to merge with.
224
401
  #
225
402
  # @return [ Criteria ] A cloned self.
226
403
  def merge(other)
227
- clone.tap do |crit|
228
- if other.is_a?(Criteria)
229
- crit.selector.update(other.selector)
230
- crit.options.update(other.options)
231
- crit.documents = other.documents
232
- else
233
- duped = other.dup
234
- crit.selector.update(duped.delete(:conditions) || {})
235
- crit.options.update(duped)
236
- end
237
- end
404
+ crit = clone
405
+ crit.merge!(other)
406
+ crit
407
+ end
408
+
409
+ # Merge the other criteria into this one.
410
+ #
411
+ # @example Merge another criteria into this criteria.
412
+ # criteria.merge(Person.where(name: "bob"))
413
+ #
414
+ # @param [ Criteria ] other The criteria to merge in.
415
+ #
416
+ # @return [ Criteria ] The merged criteria.
417
+ #
418
+ # @since 3.0.0
419
+ def merge!(other)
420
+ criteria = other.to_criteria
421
+ selector.update(criteria.selector)
422
+ options.update(criteria.options)
423
+ self.documents = criteria.documents.dup if criteria.documents.any?
424
+ self.scoping_options = criteria.scoping_options
425
+ self.inclusions = (inclusions + criteria.inclusions.dup).uniq
426
+ self
427
+ end
428
+
429
+ # Overriden to include _type in the fields.
430
+ #
431
+ # @example Limit the fields returned from the database.
432
+ # Band.only(:name)
433
+ #
434
+ # @param [ Array<Symbol> ] args The names of the fields.
435
+ #
436
+ # @return [ Criteria ] The cloned criteria.
437
+ #
438
+ # @since 1.0.0
439
+ def only(*args)
440
+ return clone if args.empty?
441
+ super(*(args + [:_type]))
238
442
  end
239
443
 
240
444
  # Returns true if criteria responds to the given method.
@@ -247,118 +451,107 @@ module Mongoid #:nodoc:
247
451
  #
248
452
  # @return [ true, false ] If the criteria responds to the method.
249
453
  def respond_to?(name, include_private = false)
250
- return false if [ :safely, :unsafely ].include?(name)
251
- # don't include klass private methods because method_missing won't call them
252
- super || @klass.respond_to?(name) || entries.respond_to?(name, include_private)
454
+ super || klass.respond_to?(name) || entries.respond_to?(name, include_private)
253
455
  end
254
456
 
255
- # Returns the selector and options as a +Hash+ that would be passed to a
256
- # scope for use with named scopes.
257
- #
258
- # @example Get the criteria as a scoped hash.
259
- # criteria.as_conditions
260
- #
261
- # @return [ Hash ] The criteria as a scoped hash.
262
- def as_conditions
263
- scope_options = @options.dup
264
- sorting = scope_options.delete(:sort)
265
- scope_options[:order_by] = sorting if sorting
266
- scope_options[:includes] = inclusions.map(&:name) if inclusions.any?
267
- { :where => @selector }.merge(scope_options)
268
- end
269
457
  alias :to_ary :to_a
270
458
 
271
- # Needed to properly get a criteria back as json
459
+ # Convenience for objects that want to be merged into a criteria.
272
460
  #
273
- # @example Get the criteria as json.
274
- # Person.where(:title => "Sir").as_json
461
+ # @example Convert to a criteria.
462
+ # criteria.to_criteria
275
463
  #
276
- # @param [ Hash ] options Options to pass through to the serializer.
464
+ # @return [ Criteria ] self.
277
465
  #
278
- # @return [ String ] The JSON string.
279
- def as_json(options = nil)
280
- entries.as_json(options)
466
+ # @since 3.0.0
467
+ def to_criteria
468
+ self
281
469
  end
282
470
 
283
- # Search for documents based on a variety of args.
284
- #
285
- # @example Find by an id.
286
- # criteria.search(BSON::ObjectId.new)
471
+ # Convert the criteria to a proc.
287
472
  #
288
- # @example Find by multiple ids.
289
- # criteria.search([ BSON::ObjectId.new, BSON::ObjectId.new ])
290
- #
291
- # @example Conditionally find all matching documents.
292
- # criteria.search(:all, :conditions => { :title => "Sir" })
473
+ # @example Convert the criteria to a proc.
474
+ # criteria.to_proc
293
475
  #
294
- # @example Conditionally find the first document.
295
- # criteria.search(:first, :conditions => { :title => "Sir" })
476
+ # @return [ Proc ] The wrapped criteria.
296
477
  #
297
- # @example Conditionally find the last document.
298
- # criteria.search(:last, :conditions => { :title => "Sir" })
478
+ # @since 3.0.0
479
+ def to_proc
480
+ ->{ self }
481
+ end
482
+
483
+ # Adds a criterion to the +Criteria+ that specifies a type or an Array of
484
+ # types that must be matched.
299
485
  #
300
- # @param [ Symbol, BSON::ObjectId, Array<BSON::ObjectId> ] arg The
301
- # argument to search with.
302
- # @param [ Hash ] options The options to search with.
486
+ # @example Match only specific models.
487
+ # criteria.type('Browser')
488
+ # criteria.type(['Firefox', 'Browser'])
303
489
  #
304
- # @return [ Array<Symbol, Criteria> ] The type and criteria.
490
+ # @param [ Array<String> ] types The types to match against.
305
491
  #
306
- # @since 2.0.0
307
- def search(*args)
308
- raise_invalid if args[0].nil?
309
- type = args[0]
310
- params = args[1] || {}
311
- return [ :ids, for_ids(type) ] unless type.is_a?(Symbol)
312
- conditions = params.delete(:conditions) || {}
313
- if conditions.include?(:id)
314
- conditions[:_id] = conditions[:id]
315
- conditions.delete(:id)
316
- end
317
- return [ type, where(conditions).extras(params) ]
492
+ # @return [ Criteria ] The cloned criteria.
493
+ def type(types)
494
+ types = [types] unless types.is_a?(Array)
495
+ any_in(_type: types)
318
496
  end
319
497
 
320
- # Convenience method of raising an invalid options error.
498
+ # This is the general entry point for most MongoDB queries. This either
499
+ # creates a standard field: value selection, and expanded selection with
500
+ # the use of hash methods, or a $where selection if a string is provided.
321
501
  #
322
- # @example Raise the error.
323
- # criteria.raise_invalid
502
+ # @example Add a standard selection.
503
+ # criteria.where(name: "syd")
324
504
  #
325
- # @raise [ Errors::InvalidOptions ] The error.
505
+ # @example Add a javascript selection.
506
+ # criteria.where("this.name == 'syd'")
326
507
  #
327
- # @since 2.0.0
328
- def raise_invalid
329
- raise Errors::InvalidFind.new
330
- end
331
-
332
- protected
333
-
334
- # Return the entries of the other criteria or the object. Used for
335
- # comparing criteria or an enumerable.
508
+ # @param [ String, Hash ] criterion The javascript or standard selection.
336
509
  #
337
- # @example Get the comparable version.
338
- # criteria.comparable(other)
510
+ # @raise [ UnsupportedJavascript ] If provided a string and the criteria
511
+ # is embedded.
339
512
  #
340
- # @param [ Criteria ] other Another criteria.
513
+ # @return [ Criteria ] The cloned selectable.
341
514
  #
342
- # @return [ Array ] The array to compare with.
343
- def comparable(other)
344
- other.is_a?(Criteria) ? other.entries : other
515
+ # @since 1.0.0
516
+ def where(expression)
517
+ if expression.is_a?(::String) && embedded?
518
+ raise Errors::UnsupportedJavascript.new(klass, expression)
519
+ end
520
+ super
345
521
  end
346
522
 
347
- # Get the raw driver collection from the criteria.
523
+ private
524
+
525
+ # Create a document given the provided method and attributes from the
526
+ # existing selector.
348
527
  #
349
- # @example Get the raw driver collection.
350
- # criteria.driver
528
+ # @api private
351
529
  #
352
- # @return [ Mongo::Collection ] The driver collection.
530
+ # @example Create a new document.
531
+ # criteria.create_document(:new, {})
353
532
  #
354
- # @since 2.2.0
355
- def driver
356
- collection.driver
533
+ # @param [ Symbol ] method Either :new or :create.
534
+ # @param [ Hash ] attrs Additional attributes to use.
535
+ #
536
+ # @return [ Document ] The new or saved document.
537
+ #
538
+ # @since 3.0.0
539
+ def create_document(method, attrs = {})
540
+ klass.__send__(method,
541
+ selector.reduce(attrs) do |hash, (key, value)|
542
+ unless key.to_s =~ /\$/ || value.is_a?(Hash)
543
+ hash[key] = value
544
+ end
545
+ hash
546
+ end
547
+ )
357
548
  end
358
549
 
359
550
  # Clone or dup the current +Criteria+. This will return a new criteria with
360
551
  # the selector, options, klass, embedded options, etc intact.
361
552
  #
553
+ # @api private
554
+ #
362
555
  # @example Clone a criteria.
363
556
  # criteria.clone
364
557
  #
@@ -368,56 +561,49 @@ module Mongoid #:nodoc:
368
561
  # @param [ Criteria ] other The criteria getting cloned.
369
562
  #
370
563
  # @return [ nil ] nil.
564
+ #
565
+ # @since 1.0.0
371
566
  def initialize_copy(other)
372
567
  @selector = other.selector.dup
373
568
  @options = other.options.dup
374
- @includes = other.inclusions.dup
569
+ @inclusions = other.inclusions.dup
570
+ @scoping_options = other.scoping_options
571
+ @documents = other.documents.dup
375
572
  @context = nil
376
573
  end
377
574
 
378
575
  # Used for chaining +Criteria+ scopes together in the for of class methods
379
576
  # on the +Document+ the criteria is for.
577
+ #
578
+ # @example Handle method missing.
579
+ # criteria.method_missing(:name)
580
+ #
581
+ # @param [ Symbol ] name The method name.
582
+ # @param [ Array ] args The arguments.
583
+ #
584
+ # @return [ Object ] The result of the method call.
585
+ #
586
+ # @since 1.0.0
380
587
  def method_missing(name, *args, &block)
381
- super if [ :safely, :unsafely ].include?(name)
382
- if @klass.respond_to?(name)
383
- @klass.send(:with_scope, self) do
384
- @klass.send(name, *args, &block)
588
+ if klass.respond_to?(name)
589
+ klass.send(:with_scope, self) do
590
+ klass.send(name, *args, &block)
385
591
  end
386
592
  else
387
593
  return entries.send(name, *args)
388
594
  end
389
595
  end
390
596
 
391
- # Update the selector setting the operator on the value for each key in the
392
- # supplied attributes +Hash+.
393
- #
394
- # @example Update the selector.
395
- # criteria.update_selector({ :field => "value" }, "$in")
396
- #
397
- # @param [ Hash, Array ] attributes The values to convert and apply.
398
- # @param [ String ] operator The MongoDB operator.
399
- # @param [ Symbol ] combine The operator to use when combining sets.
400
- def update_selector(attributes, operator, combine = :+)
401
- clone.tap do |crit|
402
- converted = BSON::ObjectId.convert(klass, attributes || {})
403
- converted.each_pair do |key, value|
404
- existing = crit.selector[key]
405
- unless existing
406
- crit.selector[key] = { operator => value }
407
- else
408
- if existing.respond_to?(:merge)
409
- if existing.has_key?(operator)
410
- new_value = existing.values.first.send(combine, value)
411
- crit.selector[key] = { operator => new_value }
412
- else
413
- crit.selector[key][operator] = value
414
- end
415
- else
416
- crit.selector[key] = { operator => value }
417
- end
418
- end
419
- end
420
- end
597
+ # Convenience method of raising an invalid options error.
598
+ #
599
+ # @example Raise the error.
600
+ # criteria.raise_invalid
601
+ #
602
+ # @raise [ Errors::InvalidOptions ] The error.
603
+ #
604
+ # @since 2.0.0
605
+ def raise_invalid
606
+ raise Errors::InvalidFind.new
421
607
  end
422
608
  end
423
609
  end