mongoid 2.8.1 → 3.0.0.rc

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 (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