mongoid 2.4.10 → 3.0.0

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