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
@@ -0,0 +1,662 @@
1
+ # encoding: utf-8
2
+ require "mongoid/contextual/atomic"
3
+ require "mongoid/contextual/aggregable/mongo"
4
+ require "mongoid/contextual/command"
5
+ require "mongoid/contextual/find_and_modify"
6
+ require "mongoid/contextual/map_reduce"
7
+
8
+ module Mongoid
9
+ module Contextual
10
+ class Mongo
11
+ include Enumerable
12
+ include Aggregable::Mongo
13
+ include Atomic
14
+
15
+ # @attribute [r] criteria The criteria for the context.
16
+ # @attribute [r] klass The klass for the criteria.
17
+ # @attribute [r] query The Moped query.
18
+ attr_reader :criteria, :klass, :query
19
+
20
+ # @attribute [rw] eager_loaded Has the context been eager loaded?
21
+ attr_accessor :eager_loaded
22
+
23
+ # Is the enumerable of matching documents empty?
24
+ #
25
+ # @example Is the context empty?
26
+ # context.blank?
27
+ #
28
+ # @return [ true, false ] If the context is empty.
29
+ #
30
+ # @since 3.0.0
31
+ def blank?
32
+ count == 0
33
+ end
34
+ alias :empty? :blank?
35
+
36
+ # Is the context cached?
37
+ #
38
+ # @example Is the context cached?
39
+ # context.cached?
40
+ #
41
+ # @return [ true, false ] If the context is cached.
42
+ #
43
+ # @since 3.0.0
44
+ def cached?
45
+ !!@cache
46
+ end
47
+
48
+ # Get the number of documents matching the query.
49
+ #
50
+ # @example Get the number of matching documents.
51
+ # context.count
52
+ #
53
+ # @example Get the count of documents matching the provided.
54
+ # context.count(document)
55
+ #
56
+ # @example Get the count for where the provided block is true.
57
+ # context.count do |doc|
58
+ # doc.likes > 1
59
+ # end
60
+ #
61
+ # @param [ Document ] document A document ot match.
62
+ #
63
+ # @return [ Integer ] The number of matches.
64
+ #
65
+ # @since 3.0.0
66
+ def count(document = nil, &block)
67
+ return super(&block) if block_given?
68
+ return query.count unless document
69
+ klass.collection.find(criteria.and(_id: document.id).selector).count
70
+ end
71
+
72
+ # Delete all documents in the database that match the selector.
73
+ #
74
+ # @example Delete all the documents.
75
+ # context.delete
76
+ #
77
+ # @return [ nil ] Nil.
78
+ #
79
+ # @since 3.0.0
80
+ def delete
81
+ query.count.tap do
82
+ query.remove_all
83
+ end
84
+ end
85
+ alias :delete_all :delete
86
+
87
+ # Destroy all documents in the database that match the selector.
88
+ #
89
+ # @example Destroy all the documents.
90
+ # context.destroy
91
+ #
92
+ # @return [ nil ] Nil.
93
+ #
94
+ # @since 3.0.0
95
+ def destroy
96
+ destroyed = query.count
97
+ each do |doc|
98
+ doc.destroy
99
+ end
100
+ destroyed
101
+ end
102
+ alias :destroy_all :destroy
103
+
104
+ # Get the distinct values in the db for the provided field.
105
+ #
106
+ # @example Get the distinct values.
107
+ # context.distinct(:name)
108
+ #
109
+ # @param [ String, Symbol ] field The name of the field.
110
+ #
111
+ # @return [ Array<Object> ] The distinct values for the field.
112
+ #
113
+ # @since 3.0.0
114
+ def distinct(field)
115
+ query.distinct(field)
116
+ end
117
+
118
+ # Iterate over the context. If provided a block, yield to a Mongoid
119
+ # document for each, otherwise return an enum.
120
+ #
121
+ # @example Iterate over the context.
122
+ # context.each do |doc|
123
+ # puts doc.name
124
+ # end
125
+ #
126
+ # @return [ Enumerator ] The enumerator.
127
+ #
128
+ # @since 3.0.0
129
+ def each(&block)
130
+ if block_given?
131
+ reset_length
132
+ selecting do
133
+ documents_for_iteration.each do |doc|
134
+ yield_and_increment(doc, &block)
135
+ end
136
+ @cache_loaded = true
137
+ eager_loadable? ? docs : self
138
+ end
139
+ else
140
+ to_enum
141
+ end
142
+ end
143
+
144
+ # Do any documents exist for the context.
145
+ #
146
+ # @example Do any documents exist for the context.
147
+ # context.exists?
148
+ #
149
+ # @return [ true, false ] If the count is more than zero.
150
+ #
151
+ # @since 3.0.0
152
+ def exists?
153
+ count > 0
154
+ end
155
+
156
+ # Run an explain on the criteria.
157
+ #
158
+ # @example Explain the criteria.
159
+ # Band.where(name: "Depeche Mode").explain
160
+ #
161
+ # @return [ Hash ] The explain result.
162
+ #
163
+ # @since 3.0.0
164
+ def explain
165
+ query.explain
166
+ end
167
+
168
+ # Execute the find and modify command, used for MongoDB's
169
+ # $findAndModify.
170
+ #
171
+ # @example Execute the command.
172
+ # context.find_and_modify({ "$inc" => { likes: 1 }}, new: true)
173
+ #
174
+ # @param [ Hash ] update The updates.
175
+ # @param [ Hash ] options The command options.
176
+ #
177
+ # @option options [ true, false ] :new Return the updated document.
178
+ # @option options [ true, false ] :remove Delete the first document.
179
+ # @option options [ true, false ] :upsert Create the document if it doesn't exist.
180
+ #
181
+ # @return [ Document ] The result of the command.
182
+ #
183
+ # @since 3.0.0
184
+ def find_and_modify(update, options = {})
185
+ if doc = FindAndModify.new(criteria, update, options).result
186
+ Factory.from_db(klass, doc)
187
+ end
188
+ end
189
+
190
+ # Get the first document in the database for the criteria's selector.
191
+ #
192
+ # @example Get the first document.
193
+ # context.first
194
+ #
195
+ # @return [ Document ] The first document.
196
+ #
197
+ # @since 3.0.0
198
+ def first
199
+ with_eager_loading(query.first)
200
+ end
201
+ alias :one :first
202
+
203
+ # Create the new Mongo context. This delegates operations to the
204
+ # underlying driver - in Mongoid's case Moped.
205
+ #
206
+ # @example Create the new context.
207
+ # Mongo.new(criteria)
208
+ #
209
+ # @param [ Criteria ] criteria The criteria.
210
+ #
211
+ # @since 3.0.0
212
+ def initialize(criteria)
213
+ @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
214
+ add_type_selection
215
+ @query = klass.collection.find(criteria.selector)
216
+ apply_options
217
+ end
218
+
219
+ # Get the last document in the database for the criteria's selector.
220
+ #
221
+ # @example Get the last document.
222
+ # context.last
223
+ #
224
+ # @return [ Document ] The last document.
225
+ #
226
+ # @since 3.0.0
227
+ def last
228
+ apply_inverse_sorting
229
+ with_eager_loading(query.first)
230
+ end
231
+
232
+ # Get's the number of documents matching the query selector.
233
+ #
234
+ # @example Get the length.
235
+ # context.length
236
+ #
237
+ # @return [ Integer ] The number of documents.
238
+ #
239
+ # @since 3.0.0
240
+ def length
241
+ @length ||= query.count
242
+ end
243
+ alias :size :length
244
+
245
+ # Limits the number of documents that are returned from the database.
246
+ #
247
+ # @example Limit the documents.
248
+ # context.limit(20)
249
+ #
250
+ # @param [ Integer ] value The number of documents to return.
251
+ #
252
+ # @return [ Mongo ] The context.
253
+ #
254
+ # @since 3.0.0
255
+ def limit(value)
256
+ query.limit(value) and self
257
+ end
258
+
259
+ # Initiate a map/reduce operation from the context.
260
+ #
261
+ # @example Initiate a map/reduce.
262
+ # context.map_reduce(map, reduce)
263
+ #
264
+ # @param [ String ] map The map js function.
265
+ # @param [ String ] reduce The reduce js function.
266
+ #
267
+ # @return [ MapReduce ] The map/reduce lazy wrapper.
268
+ #
269
+ # @since 3.0.0
270
+ def map_reduce(map, reduce)
271
+ MapReduce.new(criteria, map, reduce)
272
+ end
273
+
274
+ # Skips the provided number of documents.
275
+ #
276
+ # @example Skip the documents.
277
+ # context.skip(20)
278
+ #
279
+ # @param [ Integer ] value The number of documents to skip.
280
+ #
281
+ # @return [ Mongo ] The context.
282
+ #
283
+ # @since 3.0.0
284
+ def skip(value)
285
+ query.skip(value) and self
286
+ end
287
+
288
+ # Sorts the documents by the provided spec.
289
+ #
290
+ # @example Sort the documents.
291
+ # context.sort(name: -1, title: 1)
292
+ #
293
+ # @param [ Hash ] values The sorting values as field/direction(1/-1)
294
+ # pairs.
295
+ #
296
+ # @return [ Mongo ] The context.
297
+ #
298
+ # @since 3.0.0
299
+ def sort(values = nil, &block)
300
+ if block_given?
301
+ super(&block)
302
+ else
303
+ query.sort(values) and self
304
+ end
305
+ end
306
+
307
+ # Update all the matching documents atomically.
308
+ #
309
+ # @example Update all the matching documents.
310
+ # context.update({ "$set" => { name: "Smiths" }})
311
+ #
312
+ # @param [ Hash ] attributes The new attributes for each document.
313
+ #
314
+ # @return [ nil, false ] False if no attributes were provided.
315
+ #
316
+ # @since 3.0.0
317
+ def update(attributes = nil)
318
+ return false unless attributes
319
+ query.update_all(attributes.__consolidate__)
320
+ end
321
+ alias :update_all :update
322
+
323
+ private
324
+
325
+ # For models where inheritance is at play we need to add the type
326
+ # selection.
327
+ #
328
+ # @example Add the type selection.
329
+ # context.add_type_selection
330
+ #
331
+ # @return [ true, false ] If type selection was added.
332
+ #
333
+ # @since 3.0.0
334
+ def add_type_selection
335
+ if klass.hereditary? && !criteria.selector.keys.include?(:_type)
336
+ criteria.selector.merge!(_type: { "$in" => klass._types })
337
+ end
338
+ end
339
+
340
+ # Apply the field limitations.
341
+ #
342
+ # @api private
343
+ #
344
+ # @example Apply the field limitations.
345
+ # context.apply_fields
346
+ #
347
+ # @since 3.0.0
348
+ def apply_fields
349
+ if spec = criteria.options[:fields]
350
+ query.select(spec)
351
+ end
352
+ end
353
+
354
+ # Apply the skip option.
355
+ #
356
+ # @api private
357
+ #
358
+ # @example Apply the skip option.
359
+ # context.apply_skip
360
+ #
361
+ # @since 3.0.0
362
+ def apply_skip
363
+ if spec = criteria.options[:skip]
364
+ query.skip(spec)
365
+ end
366
+ end
367
+
368
+ # Apply the limit option.
369
+ #
370
+ # @api private
371
+ #
372
+ # @example Apply the limit option.
373
+ # context.apply_limit
374
+ #
375
+ # @since 3.0.0
376
+ def apply_limit
377
+ if spec = criteria.options[:limit]
378
+ query.limit(spec)
379
+ end
380
+ end
381
+
382
+ # Map the sort symbols to the correct MongoDB values.
383
+ #
384
+ # @example Apply the sorting params.
385
+ # context.apply_sorting
386
+ #
387
+ # @since 3.0.0
388
+ def apply_sorting
389
+ if spec = criteria.options[:sort]
390
+ query.sort(spec)
391
+ end
392
+ end
393
+
394
+ # Apply the hint option
395
+ #
396
+ # @example Apply the hint params.
397
+ # context.apply_hint
398
+ #
399
+ # @since 3.0.0
400
+ def apply_hint
401
+ if spec = criteria.options[:hint]
402
+ query.hint(spec)
403
+ end
404
+ end
405
+
406
+ # Map the inverse sort symbols to the correct MongoDB values.
407
+ #
408
+ # @example Apply the inverse sorting params.
409
+ # context.apply_inverse_sorting
410
+ #
411
+ # @since 3.0.0
412
+ def apply_inverse_sorting
413
+ if spec = criteria.options[:sort]
414
+ query.sort(Hash[spec.map{|k, v| [k, -1*v]}])
415
+ else
416
+ query.sort({_id: -1})
417
+ end
418
+ end
419
+
420
+ # Is the cache able to be added to?
421
+ #
422
+ # @api private
423
+ #
424
+ # @example Is the context cacheable?
425
+ # context.cacheable?
426
+ #
427
+ # @return [ true, false ] If caching, and the cache isn't loaded.
428
+ #
429
+ # @since 3.0.0
430
+ def cacheable?
431
+ cached? && !cache_loaded?
432
+ end
433
+
434
+ # Is the cache fully loaded? Will be true if caching after one full
435
+ # iteration.
436
+ #
437
+ # @api private
438
+ #
439
+ # @example Is the cache loaded?
440
+ # context.cache_loaded?
441
+ #
442
+ # @return [ true, false ] If the cache is loaded.
443
+ #
444
+ # @since 3.0.0
445
+ def cache_loaded?
446
+ !!@cache_loaded
447
+ end
448
+
449
+ # Get the documents for cached queries.
450
+ #
451
+ # @api private
452
+ #
453
+ # @example Get the cached documents.
454
+ # context.documents
455
+ #
456
+ # @return [ Array<Document> ] The documents.
457
+ #
458
+ # @since 3.0.0
459
+ def documents
460
+ @documents ||= []
461
+ end
462
+
463
+ # Get the documents the context should iterate. This follows 3 rules:
464
+ #
465
+ # 1. If the query is cached, and we already have documents loaded, use
466
+ # them.
467
+ # 2. If we are eager loading, then eager load the documents and use
468
+ # those.
469
+ # 3. Use the query.
470
+ #
471
+ # @api private
472
+ #
473
+ # @example Get the documents for iteration.
474
+ # context.documents_for_iteration
475
+ #
476
+ # @return [ Array<Document>, Moped::Query ] The docs to iterate.
477
+ #
478
+ # @since 3.0.0
479
+ def documents_for_iteration
480
+ if cached? && !documents.empty?
481
+ documents
482
+ elsif eager_loadable?
483
+ docs = query.map{ |doc| Factory.from_db(klass, doc) }
484
+ eager_load(docs)
485
+ docs
486
+ else
487
+ query
488
+ end
489
+ end
490
+
491
+ # Eager load the inclusions for the provided documents.
492
+ #
493
+ # @example Eager load the inclusions.
494
+ # context.eager_load(docs)
495
+ #
496
+ # @param [ Array<Document> ] docs The docs returning from the db.
497
+ #
498
+ # @return [ true ] Always true.
499
+ #
500
+ # @since 3.0.0
501
+ def eager_load(docs)
502
+ criteria.inclusions.reject! do |metadata|
503
+ metadata.eager_load(eager_loaded_ids(docs, metadata)) if !docs.empty?
504
+ end
505
+ self.eager_loaded = true
506
+ end
507
+
508
+ # Get the ids that to be used to eager load documents.
509
+ #
510
+ # @api private
511
+ #
512
+ # @example Get the ids.
513
+ # context.eager_load(docs, metadata)
514
+ #
515
+ # @param [ Array<Document> ] docs The pre-loaded documents.
516
+ # @param [ Metadata ] metadata The relation metadata.
517
+ #
518
+ # @return [ Array<Object> ] The ids.
519
+ #
520
+ # @since 3.0.0
521
+ def eager_loaded_ids(docs, metadata)
522
+ if metadata.stores_foreign_key?
523
+ load_ids(metadata.foreign_key).flatten
524
+ else
525
+ docs.map(&:id)
526
+ end
527
+ end
528
+
529
+ # Is this context able to be eager loaded?
530
+ #
531
+ # @example Is the context eager loadable?
532
+ # context.eager_loadable?
533
+ #
534
+ # @return [ true, false ] If the context is able to be eager loaded.
535
+ #
536
+ # @since 3.0.0
537
+ def eager_loadable?
538
+ !eager_loaded && !criteria.inclusions.empty?
539
+ end
540
+
541
+ # Increment the length of the results.
542
+ #
543
+ # @api private
544
+ #
545
+ # @example Increment the length.
546
+ # context.increment_length
547
+ #
548
+ # @return [ Integer ] The new length
549
+ #
550
+ # @since 3.0.0
551
+ def increment_length
552
+ @length += 1
553
+ end
554
+
555
+ # Reset the length to zero. This happens once before iteration.
556
+ #
557
+ # @api private
558
+ #
559
+ # @example Reset the length.
560
+ # context.reset_length
561
+ #
562
+ # @return [ Integer ] zero.
563
+ #
564
+ # @since 3.0.0
565
+ def reset_length
566
+ @length = 0
567
+ end
568
+
569
+ # Loads an array of ids only for the current criteria. Used by eager
570
+ # loading to determine the documents to load.
571
+ #
572
+ # @example Load the related ids.
573
+ # criteria.load_ids("person_id")
574
+ #
575
+ # @param [ String ] key The id or foriegn key string.
576
+ #
577
+ # @return [ Array<String, Moped::BSON::ObjectId> ] The ids to load.
578
+ #
579
+ # @since 3.0.0
580
+ def load_ids(key)
581
+ query.select(key => 1).map do |doc|
582
+ doc[key]
583
+ end
584
+ end
585
+
586
+ # Apply all the optional criterion.
587
+ #
588
+ # @example Apply the options.
589
+ # context.apply_options
590
+ #
591
+ # @since 3.0.0
592
+ def apply_options
593
+ apply_fields
594
+ apply_limit
595
+ apply_skip
596
+ apply_sorting
597
+ apply_hint
598
+ end
599
+
600
+ # If we are limiting results, we need to set the field limitations on a
601
+ # thread local to avoid overriding the default values.
602
+ #
603
+ # @example Execute with selection.
604
+ # context.selecting do
605
+ # collection.find
606
+ # end
607
+ #
608
+ # @return [ Object ] The yielded value.
609
+ #
610
+ # @since 2.4.4
611
+ def selecting
612
+ begin
613
+ unless criteria.options[:fields].blank?
614
+ Threaded.selection = criteria.options[:fields]
615
+ end
616
+ yield
617
+ ensure
618
+ Threaded.selection = nil
619
+ end
620
+ end
621
+
622
+ # If the provided document exists, eager load it's dependencies or return
623
+ # nil.
624
+ #
625
+ # @example Eager load if the document is not nil.
626
+ # context.with_eager_loading(document)
627
+ #
628
+ # @param [ Hash ] document The document from the database.
629
+ #
630
+ # @return [ Document, nil ] The instantiated model document.
631
+ #
632
+ # @since 3.0.0
633
+ def with_eager_loading(document)
634
+ selecting do
635
+ return nil unless document
636
+ doc = Factory.from_db(klass, document)
637
+ eager_load([ doc ]) if eager_loadable?
638
+ doc
639
+ end
640
+ end
641
+
642
+ # Yield to the document and increment the length.
643
+ #
644
+ # @api private
645
+ #
646
+ # @example Yield and increment.
647
+ # context.yield_and_increment(doc) do |doc|
648
+ # ...
649
+ # end
650
+ #
651
+ # @param [ Document ] document The document to yield to.
652
+ #
653
+ # @since 3.0.0
654
+ def yield_and_increment(document, &block)
655
+ doc = document.respond_to?(:_id) ? document : Factory.from_db(klass, document)
656
+ yield(doc)
657
+ increment_length
658
+ documents.push(doc) if cacheable?
659
+ end
660
+ end
661
+ end
662
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+ require "mongoid/contextual/memory"
3
+ require "mongoid/contextual/mongo"
4
+
5
+ module Mongoid
6
+ module Contextual
7
+
8
+ # The aggregate operations provided in the aggregate module get delegated
9
+ # through to the context from the criteria.
10
+ delegate(*Aggregable::Mongo.public_instance_methods(false), to: :context)
11
+
12
+ # The atomic operations provided in the atomic context get delegated
13
+ # through to the context from the criteria.
14
+ delegate(*Atomic.public_instance_methods(false), to: :context)
15
+
16
+ # The methods in the contexts themselves should all get delegated to,
17
+ # including destructive, modification, and optional methods.
18
+ delegate(*(Mongo.public_instance_methods(false) - [ :skip, :limit ]), to: :context)
19
+
20
+ # Get the context in which criteria queries should execute. This is either
21
+ # in memory (for embedded documents) or mongo (for root level documents.)
22
+ #
23
+ # @example Get the context.
24
+ # criteria.context
25
+ #
26
+ # @return [ Memory, Mongo ] The context.
27
+ #
28
+ # @since 3.0.0
29
+ def context
30
+ @context ||= create_context
31
+ end
32
+
33
+ private
34
+
35
+ # Create the context for the queries to execute. Will be memory for
36
+ # embedded documents and mongo for root documents.
37
+ #
38
+ # @api private
39
+ #
40
+ # @example Create the context.
41
+ # contextual.create_context
42
+ #
43
+ # @return [ Mongo, Memory ] The context.
44
+ #
45
+ # @since 3.0.0
46
+ def create_context
47
+ embedded ? Memory.new(self) : Mongo.new(self)
48
+ end
49
+ end
50
+ end