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