mongoid 2.8.1 → 3.0.0.rc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (351) hide show
  1. data/CHANGELOG.md +802 -58
  2. data/LICENSE +1 -1
  3. data/README.md +10 -11
  4. data/Rakefile +2 -8
  5. data/lib/config/locales/en.yml +441 -51
  6. data/lib/mongoid.rb +24 -39
  7. data/lib/mongoid/atomic.rb +16 -33
  8. data/lib/mongoid/atomic/modifiers.rb +2 -2
  9. data/lib/mongoid/atomic/paths/embedded.rb +4 -5
  10. data/lib/mongoid/atomic/paths/embedded/many.rb +6 -6
  11. data/lib/mongoid/atomic/paths/embedded/one.rb +5 -5
  12. data/lib/mongoid/atomic/paths/root.rb +4 -5
  13. data/lib/mongoid/attributes.rb +95 -32
  14. data/lib/mongoid/attributes/processing.rb +14 -10
  15. data/lib/mongoid/attributes/readonly.rb +56 -0
  16. data/lib/mongoid/callbacks.rb +90 -27
  17. data/lib/mongoid/collections/retry.rb +2 -3
  18. data/lib/mongoid/components.rb +11 -23
  19. data/lib/mongoid/config.rb +87 -233
  20. data/lib/mongoid/config/environment.rb +5 -6
  21. data/lib/mongoid/config/inflections.rb +6 -0
  22. data/lib/mongoid/config/options.rb +1 -1
  23. data/lib/mongoid/config/validators.rb +3 -0
  24. data/lib/mongoid/config/validators/option.rb +25 -0
  25. data/lib/mongoid/config/validators/session.rb +140 -0
  26. data/lib/mongoid/contextual.rb +50 -0
  27. data/lib/mongoid/contextual/aggregable/memory.rb +98 -0
  28. data/lib/mongoid/contextual/aggregable/mongo.rb +181 -0
  29. data/lib/mongoid/contextual/atomic.rb +179 -0
  30. data/lib/mongoid/contextual/command.rb +43 -0
  31. data/lib/mongoid/contextual/find_and_modify.rb +66 -0
  32. data/lib/mongoid/contextual/map_reduce.rb +273 -0
  33. data/lib/mongoid/contextual/memory.rb +383 -0
  34. data/lib/mongoid/contextual/mongo.rb +543 -0
  35. data/lib/mongoid/copyable.rb +3 -34
  36. data/lib/mongoid/criteria.rb +436 -250
  37. data/lib/mongoid/criterion/inspection.rb +14 -8
  38. data/lib/mongoid/criterion/scoping.rb +114 -44
  39. data/lib/mongoid/dirty.rb +152 -67
  40. data/lib/mongoid/document.rb +69 -50
  41. data/lib/mongoid/errors.rb +22 -1
  42. data/lib/mongoid/errors/ambiguous_relationship.rb +51 -0
  43. data/lib/mongoid/errors/callback.rb +5 -6
  44. data/lib/mongoid/errors/delete_restriction.rb +29 -0
  45. data/lib/mongoid/errors/document_not_found.rb +98 -17
  46. data/lib/mongoid/errors/eager_load.rb +3 -6
  47. data/lib/mongoid/errors/invalid_collection.rb +3 -3
  48. data/lib/mongoid/errors/invalid_config_option.rb +27 -0
  49. data/lib/mongoid/errors/invalid_database.rb +3 -3
  50. data/lib/mongoid/errors/invalid_field.rb +54 -8
  51. data/lib/mongoid/errors/invalid_field_option.rb +35 -0
  52. data/lib/mongoid/errors/invalid_find.rb +3 -3
  53. data/lib/mongoid/errors/invalid_index.rb +28 -0
  54. data/lib/mongoid/errors/invalid_options.rb +4 -4
  55. data/lib/mongoid/errors/invalid_scope.rb +24 -0
  56. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +38 -0
  57. data/lib/mongoid/errors/invalid_storage_options.rb +27 -0
  58. data/lib/mongoid/errors/invalid_time.rb +3 -6
  59. data/lib/mongoid/errors/inverse_not_found.rb +29 -0
  60. data/lib/mongoid/errors/mixed_relations.rb +4 -9
  61. data/lib/mongoid/errors/mixed_session_configuration.rb +28 -0
  62. data/lib/mongoid/errors/mongoid_error.rb +54 -3
  63. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +28 -0
  64. data/lib/mongoid/errors/no_default_session.rb +23 -0
  65. data/lib/mongoid/errors/no_environment.rb +3 -3
  66. data/lib/mongoid/errors/no_map_reduce_output.rb +24 -0
  67. data/lib/mongoid/errors/no_parent.rb +24 -0
  68. data/lib/mongoid/errors/no_session_config.rb +22 -0
  69. data/lib/mongoid/errors/no_session_database.rb +27 -0
  70. data/lib/mongoid/errors/no_session_hosts.rb +27 -0
  71. data/lib/mongoid/errors/no_sessions_config.rb +20 -0
  72. data/lib/mongoid/errors/readonly_attribute.rb +25 -0
  73. data/lib/mongoid/errors/scope_overwrite.rb +4 -4
  74. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +4 -4
  75. data/lib/mongoid/errors/unknown_attribute.rb +25 -0
  76. data/lib/mongoid/errors/unsaved_document.rb +4 -8
  77. data/lib/mongoid/errors/unsupported_javascript.rb +27 -0
  78. data/lib/mongoid/errors/unsupported_version.rb +4 -4
  79. data/lib/mongoid/errors/validations.rb +7 -6
  80. data/lib/mongoid/errors/versioning_not_on_root.rb +23 -0
  81. data/lib/mongoid/extensions.rb +28 -76
  82. data/lib/mongoid/extensions/array.rb +127 -0
  83. data/lib/mongoid/extensions/big_decimal.rb +42 -0
  84. data/lib/mongoid/extensions/boolean.rb +24 -0
  85. data/lib/mongoid/extensions/date.rb +70 -0
  86. data/lib/mongoid/extensions/date_time.rb +68 -0
  87. data/lib/mongoid/extensions/false_class.rb +26 -0
  88. data/lib/mongoid/extensions/float.rb +44 -0
  89. data/lib/mongoid/extensions/hash.rb +91 -0
  90. data/lib/mongoid/extensions/integer.rb +54 -0
  91. data/lib/mongoid/extensions/module.rb +28 -0
  92. data/lib/mongoid/extensions/nil_class.rb +21 -0
  93. data/lib/mongoid/extensions/object.rb +188 -0
  94. data/lib/mongoid/extensions/object_id.rb +53 -0
  95. data/lib/mongoid/extensions/range.rb +55 -0
  96. data/lib/mongoid/extensions/regexp.rb +27 -0
  97. data/lib/mongoid/extensions/set.rb +55 -0
  98. data/lib/mongoid/extensions/string.rb +155 -0
  99. data/lib/mongoid/extensions/symbol.rb +54 -0
  100. data/lib/mongoid/extensions/time.rb +78 -0
  101. data/lib/mongoid/extensions/time_with_zone.rb +55 -0
  102. data/lib/mongoid/extensions/true_class.rb +26 -0
  103. data/lib/mongoid/factory.rb +1 -1
  104. data/lib/mongoid/fields.rb +129 -194
  105. data/lib/mongoid/fields/foreign_key.rb +134 -0
  106. data/lib/mongoid/fields/localized.rb +73 -0
  107. data/lib/mongoid/fields/standard.rb +268 -0
  108. data/lib/mongoid/fields/validators.rb +2 -0
  109. data/lib/mongoid/fields/validators/macro.rb +83 -0
  110. data/lib/mongoid/finders.rb +42 -43
  111. data/lib/mongoid/hierarchy.rb +25 -14
  112. data/lib/mongoid/identity_map.rb +31 -19
  113. data/lib/mongoid/indexes.rb +66 -15
  114. data/lib/mongoid/indexes/validators/options.rb +80 -0
  115. data/lib/mongoid/inspection.rb +1 -1
  116. data/lib/mongoid/javascript.rb +1 -1
  117. data/lib/mongoid/json.rb +2 -2
  118. data/lib/mongoid/loggable.rb +69 -0
  119. data/lib/mongoid/matchers.rb +1 -1
  120. data/lib/mongoid/matchers/all.rb +7 -8
  121. data/lib/mongoid/matchers/and.rb +3 -3
  122. data/lib/mongoid/matchers/default.rb +6 -4
  123. data/lib/mongoid/matchers/exists.rb +2 -2
  124. data/lib/mongoid/matchers/gt.rb +2 -2
  125. data/lib/mongoid/matchers/gte.rb +2 -2
  126. data/lib/mongoid/matchers/in.rb +3 -7
  127. data/lib/mongoid/matchers/lt.rb +2 -2
  128. data/lib/mongoid/matchers/lte.rb +2 -2
  129. data/lib/mongoid/matchers/ne.rb +2 -2
  130. data/lib/mongoid/matchers/nin.rb +2 -2
  131. data/lib/mongoid/matchers/or.rb +2 -2
  132. data/lib/mongoid/matchers/size.rb +2 -2
  133. data/lib/mongoid/matchers/strategies.rb +3 -3
  134. data/lib/mongoid/multi_parameter_attributes.rb +8 -10
  135. data/lib/mongoid/nested_attributes.rb +17 -9
  136. data/lib/mongoid/observer.rb +1 -2
  137. data/lib/mongoid/paranoia.rb +13 -18
  138. data/lib/mongoid/persistence.rb +43 -39
  139. data/lib/mongoid/persistence/atomic.rb +2 -2
  140. data/lib/mongoid/persistence/atomic/add_to_set.rb +5 -9
  141. data/lib/mongoid/persistence/atomic/bit.rb +5 -7
  142. data/lib/mongoid/persistence/atomic/inc.rb +5 -7
  143. data/lib/mongoid/persistence/atomic/operation.rb +45 -6
  144. data/lib/mongoid/persistence/atomic/pop.rb +5 -7
  145. data/lib/mongoid/persistence/atomic/pull.rb +5 -7
  146. data/lib/mongoid/persistence/atomic/pull_all.rb +5 -7
  147. data/lib/mongoid/persistence/atomic/push.rb +4 -10
  148. data/lib/mongoid/persistence/atomic/push_all.rb +4 -10
  149. data/lib/mongoid/persistence/atomic/rename.rb +6 -7
  150. data/lib/mongoid/persistence/atomic/sets.rb +5 -7
  151. data/lib/mongoid/persistence/atomic/unset.rb +4 -5
  152. data/lib/mongoid/persistence/deletion.rb +2 -2
  153. data/lib/mongoid/persistence/insertion.rb +10 -16
  154. data/lib/mongoid/persistence/modification.rb +5 -9
  155. data/lib/mongoid/persistence/operations.rb +6 -19
  156. data/lib/mongoid/persistence/operations/embedded/insert.rb +7 -6
  157. data/lib/mongoid/persistence/operations/embedded/remove.rb +5 -5
  158. data/lib/mongoid/persistence/operations/insert.rb +4 -4
  159. data/lib/mongoid/persistence/operations/remove.rb +4 -4
  160. data/lib/mongoid/persistence/operations/update.rb +5 -5
  161. data/lib/mongoid/railtie.rb +26 -11
  162. data/lib/mongoid/railties/database.rake +22 -108
  163. data/lib/mongoid/relations.rb +4 -6
  164. data/lib/mongoid/relations/accessors.rb +119 -19
  165. data/lib/mongoid/relations/auto_save.rb +59 -5
  166. data/lib/mongoid/relations/binding.rb +211 -2
  167. data/lib/mongoid/relations/bindings/embedded/in.rb +16 -22
  168. data/lib/mongoid/relations/bindings/embedded/many.rb +9 -50
  169. data/lib/mongoid/relations/bindings/embedded/one.rb +10 -16
  170. data/lib/mongoid/relations/bindings/referenced/in.rb +31 -57
  171. data/lib/mongoid/relations/bindings/referenced/many.rb +8 -20
  172. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +15 -19
  173. data/lib/mongoid/relations/bindings/referenced/one.rb +10 -24
  174. data/lib/mongoid/relations/builder.rb +3 -3
  175. data/lib/mongoid/relations/builders.rb +19 -16
  176. data/lib/mongoid/relations/builders/embedded/in.rb +5 -5
  177. data/lib/mongoid/relations/builders/embedded/many.rb +12 -12
  178. data/lib/mongoid/relations/builders/embedded/one.rb +6 -6
  179. data/lib/mongoid/relations/builders/nested_attributes/many.rb +8 -8
  180. data/lib/mongoid/relations/builders/nested_attributes/one.rb +4 -4
  181. data/lib/mongoid/relations/builders/referenced/in.rb +4 -4
  182. data/lib/mongoid/relations/builders/referenced/many.rb +5 -5
  183. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +7 -5
  184. data/lib/mongoid/relations/builders/referenced/one.rb +5 -5
  185. data/lib/mongoid/relations/cascading.rb +6 -4
  186. data/lib/mongoid/relations/cascading/delete.rb +3 -5
  187. data/lib/mongoid/relations/cascading/destroy.rb +3 -3
  188. data/lib/mongoid/relations/cascading/nullify.rb +3 -3
  189. data/lib/mongoid/relations/cascading/restrict.rb +37 -0
  190. data/lib/mongoid/relations/constraint.rb +4 -3
  191. data/lib/mongoid/relations/conversions.rb +5 -6
  192. data/lib/mongoid/relations/cyclic.rb +7 -7
  193. data/lib/mongoid/relations/embedded/batchable.rb +346 -0
  194. data/lib/mongoid/relations/embedded/in.rb +23 -12
  195. data/lib/mongoid/relations/embedded/many.rb +99 -161
  196. data/lib/mongoid/relations/embedded/one.rb +25 -14
  197. data/lib/mongoid/relations/macros.rb +105 -61
  198. data/lib/mongoid/relations/many.rb +93 -14
  199. data/lib/mongoid/relations/metadata.rb +200 -45
  200. data/lib/mongoid/relations/nested_builder.rb +3 -5
  201. data/lib/mongoid/relations/one.rb +2 -2
  202. data/lib/mongoid/relations/options.rb +2 -2
  203. data/lib/mongoid/relations/polymorphic.rb +9 -9
  204. data/lib/mongoid/relations/proxy.rb +60 -31
  205. data/lib/mongoid/relations/referenced/in.rb +40 -15
  206. data/lib/mongoid/relations/referenced/many.rb +117 -132
  207. data/lib/mongoid/relations/referenced/many_to_many.rb +101 -46
  208. data/lib/mongoid/relations/referenced/one.rb +34 -13
  209. data/lib/mongoid/relations/reflections.rb +3 -3
  210. data/lib/mongoid/relations/synchronization.rb +19 -23
  211. data/lib/mongoid/relations/targets/enumerable.rb +86 -57
  212. data/lib/mongoid/reloading.rb +12 -14
  213. data/lib/mongoid/scoping.rb +329 -0
  214. data/lib/mongoid/serialization.rb +8 -27
  215. data/lib/mongoid/sessions.rb +359 -0
  216. data/lib/mongoid/sessions/factory.rb +106 -0
  217. data/lib/mongoid/sessions/mongo_uri.rb +93 -0
  218. data/lib/mongoid/sessions/validators.rb +2 -0
  219. data/lib/mongoid/sessions/validators/storage.rb +49 -0
  220. data/lib/mongoid/sharding.rb +6 -6
  221. data/lib/mongoid/state.rb +6 -7
  222. data/lib/mongoid/threaded.rb +167 -59
  223. data/lib/mongoid/threaded/lifecycle.rb +21 -22
  224. data/lib/mongoid/threaded/sessions.rb +0 -0
  225. data/lib/mongoid/timestamps.rb +1 -1
  226. data/lib/mongoid/timestamps/created.rb +8 -4
  227. data/lib/mongoid/timestamps/timeless.rb +6 -4
  228. data/lib/mongoid/timestamps/updated.rb +3 -3
  229. data/lib/mongoid/unit_of_work.rb +61 -0
  230. data/lib/mongoid/validations.rb +27 -19
  231. data/lib/mongoid/validations/associated.rb +2 -2
  232. data/lib/mongoid/validations/format.rb +2 -2
  233. data/lib/mongoid/validations/presence.rb +31 -5
  234. data/lib/mongoid/validations/uniqueness.rb +9 -12
  235. data/lib/mongoid/version.rb +2 -2
  236. data/lib/mongoid/versioning.rb +25 -26
  237. data/lib/rack/mongoid/middleware/identity_map.rb +3 -3
  238. data/lib/rails/generators/mongoid/config/config_generator.rb +1 -1
  239. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +59 -19
  240. data/lib/rails/generators/mongoid/model/model_generator.rb +7 -7
  241. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +2 -2
  242. data/lib/rails/generators/mongoid/observer/observer_generator.rb +4 -4
  243. data/lib/rails/generators/mongoid_generator.rb +5 -5
  244. data/lib/rails/mongoid.rb +69 -25
  245. metadata +110 -137
  246. checksums.yaml +0 -7
  247. data/lib/config/locales/bg.yml +0 -61
  248. data/lib/config/locales/de.yml +0 -61
  249. data/lib/config/locales/en-GB.yml +0 -64
  250. data/lib/config/locales/es.yml +0 -59
  251. data/lib/config/locales/fr.yml +0 -62
  252. data/lib/config/locales/hi.yml +0 -53
  253. data/lib/config/locales/hu.yml +0 -64
  254. data/lib/config/locales/id.yml +0 -62
  255. data/lib/config/locales/it.yml +0 -59
  256. data/lib/config/locales/ja.yml +0 -57
  257. data/lib/config/locales/kr.yml +0 -54
  258. data/lib/config/locales/nl.yml +0 -61
  259. data/lib/config/locales/pl.yml +0 -59
  260. data/lib/config/locales/pt-BR.yml +0 -60
  261. data/lib/config/locales/pt.yml +0 -60
  262. data/lib/config/locales/ro.yml +0 -66
  263. data/lib/config/locales/ru.yml +0 -61
  264. data/lib/config/locales/sv.yml +0 -60
  265. data/lib/config/locales/vi.yml +0 -62
  266. data/lib/config/locales/zh-CN.yml +0 -53
  267. data/lib/mongoid/collection.rb +0 -157
  268. data/lib/mongoid/collections.rb +0 -120
  269. data/lib/mongoid/collections/master.rb +0 -45
  270. data/lib/mongoid/collections/operations.rb +0 -44
  271. data/lib/mongoid/config/database.rb +0 -181
  272. data/lib/mongoid/config/replset_database.rb +0 -80
  273. data/lib/mongoid/contexts.rb +0 -25
  274. data/lib/mongoid/contexts/enumerable.rb +0 -313
  275. data/lib/mongoid/contexts/enumerable/sort.rb +0 -43
  276. data/lib/mongoid/contexts/mongo.rb +0 -487
  277. data/lib/mongoid/criterion/builder.rb +0 -34
  278. data/lib/mongoid/criterion/complex.rb +0 -84
  279. data/lib/mongoid/criterion/creational.rb +0 -34
  280. data/lib/mongoid/criterion/exclusion.rb +0 -110
  281. data/lib/mongoid/criterion/inclusion.rb +0 -290
  282. data/lib/mongoid/criterion/optional.rb +0 -259
  283. data/lib/mongoid/criterion/selector.rb +0 -177
  284. data/lib/mongoid/cursor.rb +0 -88
  285. data/lib/mongoid/default_scope.rb +0 -36
  286. data/lib/mongoid/errors/invalid_type.rb +0 -25
  287. data/lib/mongoid/extensions/array/deep_copy.rb +0 -25
  288. data/lib/mongoid/extensions/array/deletion.rb +0 -29
  289. data/lib/mongoid/extensions/false_class/equality.rb +0 -26
  290. data/lib/mongoid/extensions/hash/criteria_helpers.rb +0 -47
  291. data/lib/mongoid/extensions/hash/deep_copy.rb +0 -25
  292. data/lib/mongoid/extensions/hash/scoping.rb +0 -25
  293. data/lib/mongoid/extensions/integer/checks.rb +0 -23
  294. data/lib/mongoid/extensions/nil/collectionization.rb +0 -23
  295. data/lib/mongoid/extensions/object/checks.rb +0 -29
  296. data/lib/mongoid/extensions/object/deep_copy.rb +0 -21
  297. data/lib/mongoid/extensions/object/reflections.rb +0 -48
  298. data/lib/mongoid/extensions/object/substitutable.rb +0 -15
  299. data/lib/mongoid/extensions/object/yoda.rb +0 -44
  300. data/lib/mongoid/extensions/object_id/conversions.rb +0 -60
  301. data/lib/mongoid/extensions/proc/scoping.rb +0 -25
  302. data/lib/mongoid/extensions/string/checks.rb +0 -36
  303. data/lib/mongoid/extensions/string/conversions.rb +0 -22
  304. data/lib/mongoid/extensions/string/inflections.rb +0 -118
  305. data/lib/mongoid/extensions/symbol/checks.rb +0 -23
  306. data/lib/mongoid/extensions/symbol/inflections.rb +0 -67
  307. data/lib/mongoid/extensions/true_class/equality.rb +0 -26
  308. data/lib/mongoid/extras.rb +0 -31
  309. data/lib/mongoid/fields/internal/array.rb +0 -77
  310. data/lib/mongoid/fields/internal/big_decimal.rb +0 -63
  311. data/lib/mongoid/fields/internal/bignum.rb +0 -10
  312. data/lib/mongoid/fields/internal/binary.rb +0 -11
  313. data/lib/mongoid/fields/internal/boolean.rb +0 -58
  314. data/lib/mongoid/fields/internal/date.rb +0 -51
  315. data/lib/mongoid/fields/internal/date_time.rb +0 -28
  316. data/lib/mongoid/fields/internal/false_class.rb +0 -10
  317. data/lib/mongoid/fields/internal/fixnum.rb +0 -10
  318. data/lib/mongoid/fields/internal/float.rb +0 -47
  319. data/lib/mongoid/fields/internal/foreign_keys/array.rb +0 -88
  320. data/lib/mongoid/fields/internal/foreign_keys/object.rb +0 -56
  321. data/lib/mongoid/fields/internal/hash.rb +0 -11
  322. data/lib/mongoid/fields/internal/integer.rb +0 -59
  323. data/lib/mongoid/fields/internal/localized.rb +0 -62
  324. data/lib/mongoid/fields/internal/nil_class.rb +0 -53
  325. data/lib/mongoid/fields/internal/object.rb +0 -11
  326. data/lib/mongoid/fields/internal/object_id.rb +0 -46
  327. data/lib/mongoid/fields/internal/range.rb +0 -61
  328. data/lib/mongoid/fields/internal/set.rb +0 -57
  329. data/lib/mongoid/fields/internal/string.rb +0 -42
  330. data/lib/mongoid/fields/internal/symbol.rb +0 -43
  331. data/lib/mongoid/fields/internal/time.rb +0 -23
  332. data/lib/mongoid/fields/internal/time_with_zone.rb +0 -23
  333. data/lib/mongoid/fields/internal/timekeeping.rb +0 -122
  334. data/lib/mongoid/fields/internal/true_class.rb +0 -10
  335. data/lib/mongoid/fields/mappings.rb +0 -42
  336. data/lib/mongoid/fields/serializable.rb +0 -270
  337. data/lib/mongoid/identity.rb +0 -92
  338. data/lib/mongoid/keys.rb +0 -144
  339. data/lib/mongoid/logger.rb +0 -45
  340. data/lib/mongoid/multi_database.rb +0 -36
  341. data/lib/mongoid/named_scope.rb +0 -166
  342. data/lib/mongoid/relations/embedded/atomic.rb +0 -89
  343. data/lib/mongoid/relations/embedded/atomic/operation.rb +0 -63
  344. data/lib/mongoid/relations/embedded/atomic/pull.rb +0 -65
  345. data/lib/mongoid/relations/embedded/atomic/push_all.rb +0 -59
  346. data/lib/mongoid/relations/embedded/atomic/set.rb +0 -61
  347. data/lib/mongoid/relations/embedded/atomic/unset.rb +0 -41
  348. data/lib/mongoid/relations/referenced/batch.rb +0 -73
  349. data/lib/mongoid/relations/referenced/batch/insert.rb +0 -57
  350. data/lib/mongoid/safety.rb +0 -105
  351. data/lib/mongoid/scope.rb +0 -31
@@ -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