mongoid_rails4 4.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 (659) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3213 -0
  3. data/LICENSE +20 -0
  4. data/README.md +62 -0
  5. data/Rakefile +35 -0
  6. data/lib/config/locales/en.yml +448 -0
  7. data/lib/mongoid.rb +104 -0
  8. data/lib/mongoid/atomic.rb +384 -0
  9. data/lib/mongoid/atomic/modifiers.rb +317 -0
  10. data/lib/mongoid/atomic/paths.rb +3 -0
  11. data/lib/mongoid/atomic/paths/embedded.rb +28 -0
  12. data/lib/mongoid/atomic/paths/embedded/many.rb +44 -0
  13. data/lib/mongoid/atomic/paths/embedded/one.rb +43 -0
  14. data/lib/mongoid/atomic/paths/root.rb +39 -0
  15. data/lib/mongoid/attributes.rb +284 -0
  16. data/lib/mongoid/attributes/dynamic.rb +154 -0
  17. data/lib/mongoid/attributes/nested.rb +82 -0
  18. data/lib/mongoid/attributes/processing.rb +147 -0
  19. data/lib/mongoid/attributes/readonly.rb +56 -0
  20. data/lib/mongoid/changeable.rb +379 -0
  21. data/lib/mongoid/composable.rb +104 -0
  22. data/lib/mongoid/config.rb +263 -0
  23. data/lib/mongoid/config/environment.rb +44 -0
  24. data/lib/mongoid/config/options.rb +74 -0
  25. data/lib/mongoid/config/validators.rb +3 -0
  26. data/lib/mongoid/config/validators/option.rb +25 -0
  27. data/lib/mongoid/config/validators/session.rb +140 -0
  28. data/lib/mongoid/contextual.rb +54 -0
  29. data/lib/mongoid/contextual/aggregable/memory.rb +109 -0
  30. data/lib/mongoid/contextual/aggregable/mongo.rb +147 -0
  31. data/lib/mongoid/contextual/atomic.rb +180 -0
  32. data/lib/mongoid/contextual/command.rb +61 -0
  33. data/lib/mongoid/contextual/eager.rb +158 -0
  34. data/lib/mongoid/contextual/find_and_modify.rb +69 -0
  35. data/lib/mongoid/contextual/geo_near.rb +238 -0
  36. data/lib/mongoid/contextual/map_reduce.rb +324 -0
  37. data/lib/mongoid/contextual/memory.rb +440 -0
  38. data/lib/mongoid/contextual/mongo.rb +676 -0
  39. data/lib/mongoid/contextual/queryable.rb +25 -0
  40. data/lib/mongoid/contextual/text_search.rb +180 -0
  41. data/lib/mongoid/copyable.rb +67 -0
  42. data/lib/mongoid/criteria.rb +562 -0
  43. data/lib/mongoid/criteria/findable.rb +179 -0
  44. data/lib/mongoid/criteria/inspectable.rb +25 -0
  45. data/lib/mongoid/criteria/marshalable.rb +50 -0
  46. data/lib/mongoid/criteria/modifiable.rb +189 -0
  47. data/lib/mongoid/criteria/scopable.rb +158 -0
  48. data/lib/mongoid/document.rb +361 -0
  49. data/lib/mongoid/equality.rb +66 -0
  50. data/lib/mongoid/errors.rb +40 -0
  51. data/lib/mongoid/errors/ambiguous_relationship.rb +51 -0
  52. data/lib/mongoid/errors/callback.rb +25 -0
  53. data/lib/mongoid/errors/delete_restriction.rb +29 -0
  54. data/lib/mongoid/errors/document_not_found.rb +111 -0
  55. data/lib/mongoid/errors/eager_load.rb +22 -0
  56. data/lib/mongoid/errors/invalid_collection.rb +18 -0
  57. data/lib/mongoid/errors/invalid_config_option.rb +27 -0
  58. data/lib/mongoid/errors/invalid_field.rb +64 -0
  59. data/lib/mongoid/errors/invalid_field_option.rb +35 -0
  60. data/lib/mongoid/errors/invalid_find.rb +19 -0
  61. data/lib/mongoid/errors/invalid_includes.rb +32 -0
  62. data/lib/mongoid/errors/invalid_index.rb +28 -0
  63. data/lib/mongoid/errors/invalid_options.rb +28 -0
  64. data/lib/mongoid/errors/invalid_path.rb +21 -0
  65. data/lib/mongoid/errors/invalid_scope.rb +24 -0
  66. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +38 -0
  67. data/lib/mongoid/errors/invalid_storage_options.rb +27 -0
  68. data/lib/mongoid/errors/invalid_time.rb +22 -0
  69. data/lib/mongoid/errors/inverse_not_found.rb +29 -0
  70. data/lib/mongoid/errors/mixed_relations.rb +32 -0
  71. data/lib/mongoid/errors/mixed_session_configuration.rb +28 -0
  72. data/lib/mongoid/errors/mongoid_error.rb +92 -0
  73. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +28 -0
  74. data/lib/mongoid/errors/no_default_session.rb +23 -0
  75. data/lib/mongoid/errors/no_environment.rb +19 -0
  76. data/lib/mongoid/errors/no_map_reduce_output.rb +24 -0
  77. data/lib/mongoid/errors/no_metadata.rb +21 -0
  78. data/lib/mongoid/errors/no_parent.rb +24 -0
  79. data/lib/mongoid/errors/no_session_config.rb +22 -0
  80. data/lib/mongoid/errors/no_session_database.rb +27 -0
  81. data/lib/mongoid/errors/no_session_hosts.rb +27 -0
  82. data/lib/mongoid/errors/no_sessions_config.rb +20 -0
  83. data/lib/mongoid/errors/readonly_attribute.rb +25 -0
  84. data/lib/mongoid/errors/scope_overwrite.rb +21 -0
  85. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +20 -0
  86. data/lib/mongoid/errors/unknown_attribute.rb +25 -0
  87. data/lib/mongoid/errors/unsaved_document.rb +19 -0
  88. data/lib/mongoid/errors/unsupported_javascript.rb +27 -0
  89. data/lib/mongoid/errors/validations.rb +29 -0
  90. data/lib/mongoid/evolvable.rb +19 -0
  91. data/lib/mongoid/extensions.rb +35 -0
  92. data/lib/mongoid/extensions/array.rb +180 -0
  93. data/lib/mongoid/extensions/big_decimal.rb +69 -0
  94. data/lib/mongoid/extensions/boolean.rb +21 -0
  95. data/lib/mongoid/extensions/date.rb +77 -0
  96. data/lib/mongoid/extensions/date_time.rb +73 -0
  97. data/lib/mongoid/extensions/false_class.rb +38 -0
  98. data/lib/mongoid/extensions/float.rb +56 -0
  99. data/lib/mongoid/extensions/hash.rb +209 -0
  100. data/lib/mongoid/extensions/integer.rb +67 -0
  101. data/lib/mongoid/extensions/module.rb +28 -0
  102. data/lib/mongoid/extensions/nil_class.rb +33 -0
  103. data/lib/mongoid/extensions/object.rb +274 -0
  104. data/lib/mongoid/extensions/object_id.rb +54 -0
  105. data/lib/mongoid/extensions/range.rb +79 -0
  106. data/lib/mongoid/extensions/regexp.rb +27 -0
  107. data/lib/mongoid/extensions/set.rb +55 -0
  108. data/lib/mongoid/extensions/string.rb +199 -0
  109. data/lib/mongoid/extensions/symbol.rb +54 -0
  110. data/lib/mongoid/extensions/time.rb +88 -0
  111. data/lib/mongoid/extensions/time_with_zone.rb +56 -0
  112. data/lib/mongoid/extensions/true_class.rb +38 -0
  113. data/lib/mongoid/factory.rb +46 -0
  114. data/lib/mongoid/fields.rb +542 -0
  115. data/lib/mongoid/fields/foreign_key.rb +174 -0
  116. data/lib/mongoid/fields/localized.rb +73 -0
  117. data/lib/mongoid/fields/standard.rb +273 -0
  118. data/lib/mongoid/fields/validators.rb +2 -0
  119. data/lib/mongoid/fields/validators/macro.rb +92 -0
  120. data/lib/mongoid/findable.rb +133 -0
  121. data/lib/mongoid/identity_map.rb +163 -0
  122. data/lib/mongoid/indexable.rb +147 -0
  123. data/lib/mongoid/indexable/specification.rb +115 -0
  124. data/lib/mongoid/indexable/validators/options.rb +103 -0
  125. data/lib/mongoid/inspectable.rb +59 -0
  126. data/lib/mongoid/interceptable.rb +265 -0
  127. data/lib/mongoid/loggable.rb +69 -0
  128. data/lib/mongoid/matchable.rb +152 -0
  129. data/lib/mongoid/matchable/all.rb +27 -0
  130. data/lib/mongoid/matchable/and.rb +30 -0
  131. data/lib/mongoid/matchable/default.rb +72 -0
  132. data/lib/mongoid/matchable/exists.rb +23 -0
  133. data/lib/mongoid/matchable/gt.rb +21 -0
  134. data/lib/mongoid/matchable/gte.rb +21 -0
  135. data/lib/mongoid/matchable/in.rb +24 -0
  136. data/lib/mongoid/matchable/lt.rb +21 -0
  137. data/lib/mongoid/matchable/lte.rb +21 -0
  138. data/lib/mongoid/matchable/ne.rb +21 -0
  139. data/lib/mongoid/matchable/nin.rb +21 -0
  140. data/lib/mongoid/matchable/or.rb +33 -0
  141. data/lib/mongoid/matchable/size.rb +21 -0
  142. data/lib/mongoid/persistable.rb +207 -0
  143. data/lib/mongoid/persistable/creatable.rb +189 -0
  144. data/lib/mongoid/persistable/deletable.rb +149 -0
  145. data/lib/mongoid/persistable/destroyable.rb +55 -0
  146. data/lib/mongoid/persistable/incrementable.rb +36 -0
  147. data/lib/mongoid/persistable/logical.rb +38 -0
  148. data/lib/mongoid/persistable/poppable.rb +39 -0
  149. data/lib/mongoid/persistable/pullable.rb +55 -0
  150. data/lib/mongoid/persistable/pushable.rb +62 -0
  151. data/lib/mongoid/persistable/renamable.rb +35 -0
  152. data/lib/mongoid/persistable/savable.rb +52 -0
  153. data/lib/mongoid/persistable/settable.rb +33 -0
  154. data/lib/mongoid/persistable/unsettable.rb +36 -0
  155. data/lib/mongoid/persistable/updatable.rb +151 -0
  156. data/lib/mongoid/persistable/upsertable.rb +55 -0
  157. data/lib/mongoid/positional.rb +71 -0
  158. data/lib/mongoid/railtie.rb +156 -0
  159. data/lib/mongoid/railties/database.rake +97 -0
  160. data/lib/mongoid/railties/document.rb +12 -0
  161. data/lib/mongoid/relations.rb +162 -0
  162. data/lib/mongoid/relations/accessors.rb +299 -0
  163. data/lib/mongoid/relations/auto_save.rb +106 -0
  164. data/lib/mongoid/relations/binding.rb +218 -0
  165. data/lib/mongoid/relations/bindings.rb +9 -0
  166. data/lib/mongoid/relations/bindings/embedded/in.rb +63 -0
  167. data/lib/mongoid/relations/bindings/embedded/many.rb +50 -0
  168. data/lib/mongoid/relations/bindings/embedded/one.rb +55 -0
  169. data/lib/mongoid/relations/bindings/referenced/in.rb +65 -0
  170. data/lib/mongoid/relations/bindings/referenced/many.rb +42 -0
  171. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +67 -0
  172. data/lib/mongoid/relations/bindings/referenced/one.rb +44 -0
  173. data/lib/mongoid/relations/builder.rb +57 -0
  174. data/lib/mongoid/relations/builders.rb +104 -0
  175. data/lib/mongoid/relations/builders/embedded/in.rb +29 -0
  176. data/lib/mongoid/relations/builders/embedded/many.rb +36 -0
  177. data/lib/mongoid/relations/builders/embedded/one.rb +30 -0
  178. data/lib/mongoid/relations/builders/nested_attributes/many.rb +174 -0
  179. data/lib/mongoid/relations/builders/nested_attributes/one.rb +126 -0
  180. data/lib/mongoid/relations/builders/referenced/in.rb +26 -0
  181. data/lib/mongoid/relations/builders/referenced/many.rb +27 -0
  182. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +40 -0
  183. data/lib/mongoid/relations/builders/referenced/one.rb +26 -0
  184. data/lib/mongoid/relations/cascading.rb +56 -0
  185. data/lib/mongoid/relations/cascading/delete.rb +44 -0
  186. data/lib/mongoid/relations/cascading/destroy.rb +43 -0
  187. data/lib/mongoid/relations/cascading/nullify.rb +35 -0
  188. data/lib/mongoid/relations/cascading/restrict.rb +39 -0
  189. data/lib/mongoid/relations/constraint.rb +49 -0
  190. data/lib/mongoid/relations/conversions.rb +34 -0
  191. data/lib/mongoid/relations/counter_cache.rb +105 -0
  192. data/lib/mongoid/relations/cyclic.rb +107 -0
  193. data/lib/mongoid/relations/embedded/batchable.rb +355 -0
  194. data/lib/mongoid/relations/embedded/in.rb +231 -0
  195. data/lib/mongoid/relations/embedded/many.rb +639 -0
  196. data/lib/mongoid/relations/embedded/one.rb +223 -0
  197. data/lib/mongoid/relations/macros.rb +356 -0
  198. data/lib/mongoid/relations/many.rb +208 -0
  199. data/lib/mongoid/relations/marshalable.rb +32 -0
  200. data/lib/mongoid/relations/metadata.rb +1174 -0
  201. data/lib/mongoid/relations/nested_builder.rb +74 -0
  202. data/lib/mongoid/relations/one.rb +48 -0
  203. data/lib/mongoid/relations/options.rb +48 -0
  204. data/lib/mongoid/relations/polymorphic.rb +39 -0
  205. data/lib/mongoid/relations/proxy.rb +270 -0
  206. data/lib/mongoid/relations/referenced/in.rb +297 -0
  207. data/lib/mongoid/relations/referenced/many.rb +787 -0
  208. data/lib/mongoid/relations/referenced/many_to_many.rb +486 -0
  209. data/lib/mongoid/relations/referenced/one.rb +290 -0
  210. data/lib/mongoid/relations/reflections.rb +62 -0
  211. data/lib/mongoid/relations/synchronization.rb +169 -0
  212. data/lib/mongoid/relations/targets.rb +2 -0
  213. data/lib/mongoid/relations/targets/enumerable.rb +473 -0
  214. data/lib/mongoid/relations/touchable.rb +94 -0
  215. data/lib/mongoid/reloadable.rb +95 -0
  216. data/lib/mongoid/scopable.rb +379 -0
  217. data/lib/mongoid/selectable.rb +59 -0
  218. data/lib/mongoid/serializable.rb +170 -0
  219. data/lib/mongoid/sessions.rb +330 -0
  220. data/lib/mongoid/sessions/factory.rb +129 -0
  221. data/lib/mongoid/sessions/mongo_uri.rb +93 -0
  222. data/lib/mongoid/sessions/options.rb +141 -0
  223. data/lib/mongoid/sessions/validators.rb +2 -0
  224. data/lib/mongoid/sessions/validators/storage.rb +49 -0
  225. data/lib/mongoid/shardable.rb +65 -0
  226. data/lib/mongoid/state.rb +97 -0
  227. data/lib/mongoid/threaded.rb +383 -0
  228. data/lib/mongoid/threaded/lifecycle.rb +164 -0
  229. data/lib/mongoid/timestamps.rb +15 -0
  230. data/lib/mongoid/timestamps/created.rb +30 -0
  231. data/lib/mongoid/timestamps/created/short.rb +19 -0
  232. data/lib/mongoid/timestamps/short.rb +10 -0
  233. data/lib/mongoid/timestamps/updated.rb +39 -0
  234. data/lib/mongoid/timestamps/updated/short.rb +19 -0
  235. data/lib/mongoid/traversable.rb +192 -0
  236. data/lib/mongoid/unit_of_work.rb +61 -0
  237. data/lib/mongoid/validatable.rb +180 -0
  238. data/lib/mongoid/validatable/associated.rb +48 -0
  239. data/lib/mongoid/validatable/format.rb +20 -0
  240. data/lib/mongoid/validatable/length.rb +20 -0
  241. data/lib/mongoid/validatable/localizable.rb +30 -0
  242. data/lib/mongoid/validatable/macros.rb +94 -0
  243. data/lib/mongoid/validatable/presence.rb +86 -0
  244. data/lib/mongoid/validatable/queryable.rb +30 -0
  245. data/lib/mongoid/validatable/uniqueness.rb +330 -0
  246. data/lib/mongoid/version.rb +4 -0
  247. data/lib/rack/mongoid.rb +2 -0
  248. data/lib/rack/mongoid/middleware/identity_map.rb +39 -0
  249. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  250. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +76 -0
  251. data/lib/rails/generators/mongoid/model/model_generator.rb +25 -0
  252. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +19 -0
  253. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  254. data/lib/rails/generators/mongoid/observer/templates/observer.rb.tt +4 -0
  255. data/lib/rails/generators/mongoid_generator.rb +65 -0
  256. data/lib/rails/mongoid.rb +180 -0
  257. data/lib/support/ruby_version.rb +26 -0
  258. data/spec/app/models/account.rb +28 -0
  259. data/spec/app/models/acolyte.rb +17 -0
  260. data/spec/app/models/actor.rb +18 -0
  261. data/spec/app/models/actress.rb +2 -0
  262. data/spec/app/models/address.rb +77 -0
  263. data/spec/app/models/address_component.rb +5 -0
  264. data/spec/app/models/address_number.rb +6 -0
  265. data/spec/app/models/agency.rb +5 -0
  266. data/spec/app/models/agent.rb +12 -0
  267. data/spec/app/models/album.rb +14 -0
  268. data/spec/app/models/alert.rb +5 -0
  269. data/spec/app/models/animal.rb +25 -0
  270. data/spec/app/models/answer.rb +4 -0
  271. data/spec/app/models/appointment.rb +7 -0
  272. data/spec/app/models/article.rb +10 -0
  273. data/spec/app/models/artist.rb +66 -0
  274. data/spec/app/models/artwork.rb +4 -0
  275. data/spec/app/models/audio.rb +5 -0
  276. data/spec/app/models/augmentation.rb +11 -0
  277. data/spec/app/models/author.rb +4 -0
  278. data/spec/app/models/band.rb +26 -0
  279. data/spec/app/models/bar.rb +10 -0
  280. data/spec/app/models/basic.rb +6 -0
  281. data/spec/app/models/bed.rb +1 -0
  282. data/spec/app/models/big_palette.rb +2 -0
  283. data/spec/app/models/birthday.rb +13 -0
  284. data/spec/app/models/book.rb +13 -0
  285. data/spec/app/models/breed.rb +4 -0
  286. data/spec/app/models/browser.rb +6 -0
  287. data/spec/app/models/building.rb +5 -0
  288. data/spec/app/models/building_address.rb +5 -0
  289. data/spec/app/models/bus.rb +7 -0
  290. data/spec/app/models/business.rb +5 -0
  291. data/spec/app/models/callback_recorder.rb +25 -0
  292. data/spec/app/models/callback_test.rb +9 -0
  293. data/spec/app/models/canvas.rb +25 -0
  294. data/spec/app/models/car.rb +1 -0
  295. data/spec/app/models/cat.rb +8 -0
  296. data/spec/app/models/category.rb +8 -0
  297. data/spec/app/models/child.rb +4 -0
  298. data/spec/app/models/child_doc.rb +22 -0
  299. data/spec/app/models/church.rb +4 -0
  300. data/spec/app/models/circle.rb +3 -0
  301. data/spec/app/models/circuit.rb +4 -0
  302. data/spec/app/models/circus.rb +7 -0
  303. data/spec/app/models/code.rb +5 -0
  304. data/spec/app/models/comment.rb +16 -0
  305. data/spec/app/models/contractor.rb +5 -0
  306. data/spec/app/models/cookie.rb +6 -0
  307. data/spec/app/models/country_code.rb +8 -0
  308. data/spec/app/models/definition.rb +7 -0
  309. data/spec/app/models/description.rb +11 -0
  310. data/spec/app/models/dictionary.rb +10 -0
  311. data/spec/app/models/division.rb +10 -0
  312. data/spec/app/models/doctor.rb +12 -0
  313. data/spec/app/models/dog.rb +7 -0
  314. data/spec/app/models/dokument.rb +5 -0
  315. data/spec/app/models/dragon.rb +4 -0
  316. data/spec/app/models/driver.rb +7 -0
  317. data/spec/app/models/drug.rb +6 -0
  318. data/spec/app/models/dungeon.rb +4 -0
  319. data/spec/app/models/email.rb +6 -0
  320. data/spec/app/models/employer.rb +5 -0
  321. data/spec/app/models/entry.rb +6 -0
  322. data/spec/app/models/eraser.rb +1 -0
  323. data/spec/app/models/event.rb +22 -0
  324. data/spec/app/models/exhibition.rb +4 -0
  325. data/spec/app/models/exhibitor.rb +5 -0
  326. data/spec/app/models/eye.rb +9 -0
  327. data/spec/app/models/eye_bowl.rb +9 -0
  328. data/spec/app/models/face.rb +8 -0
  329. data/spec/app/models/favorite.rb +6 -0
  330. data/spec/app/models/filesystem.rb +5 -0
  331. data/spec/app/models/fire_hydrant.rb +6 -0
  332. data/spec/app/models/firefox.rb +4 -0
  333. data/spec/app/models/fish.rb +7 -0
  334. data/spec/app/models/folder.rb +7 -0
  335. data/spec/app/models/folder_item.rb +9 -0
  336. data/spec/app/models/fruits.rb +28 -0
  337. data/spec/app/models/game.rb +19 -0
  338. data/spec/app/models/ghost.rb +7 -0
  339. data/spec/app/models/home.rb +4 -0
  340. data/spec/app/models/house.rb +6 -0
  341. data/spec/app/models/html_writer.rb +3 -0
  342. data/spec/app/models/image.rb +22 -0
  343. data/spec/app/models/implant.rb +16 -0
  344. data/spec/app/models/item.rb +8 -0
  345. data/spec/app/models/jar.rb +7 -0
  346. data/spec/app/models/label.rb +40 -0
  347. data/spec/app/models/language.rb +5 -0
  348. data/spec/app/models/lat_lng.rb +15 -0
  349. data/spec/app/models/league.rb +11 -0
  350. data/spec/app/models/learner.rb +2 -0
  351. data/spec/app/models/line_item.rb +6 -0
  352. data/spec/app/models/location.rb +8 -0
  353. data/spec/app/models/login.rb +8 -0
  354. data/spec/app/models/manufacturer.rb +7 -0
  355. data/spec/app/models/meat.rb +4 -0
  356. data/spec/app/models/membership.rb +4 -0
  357. data/spec/app/models/mixed_drink.rb +4 -0
  358. data/spec/app/models/movie.rb +13 -0
  359. data/spec/app/models/my_hash.rb +2 -0
  360. data/spec/app/models/name.rb +23 -0
  361. data/spec/app/models/node.rb +5 -0
  362. data/spec/app/models/note.rb +12 -0
  363. data/spec/app/models/ordered_post.rb +6 -0
  364. data/spec/app/models/ordered_preference.rb +6 -0
  365. data/spec/app/models/oscar.rb +15 -0
  366. data/spec/app/models/override.rb +16 -0
  367. data/spec/app/models/ownable.rb +6 -0
  368. data/spec/app/models/owner.rb +6 -0
  369. data/spec/app/models/pack.rb +3 -0
  370. data/spec/app/models/page.rb +5 -0
  371. data/spec/app/models/page_question.rb +4 -0
  372. data/spec/app/models/palette.rb +7 -0
  373. data/spec/app/models/parent.rb +5 -0
  374. data/spec/app/models/parent_doc.rb +6 -0
  375. data/spec/app/models/passport.rb +5 -0
  376. data/spec/app/models/patient.rb +9 -0
  377. data/spec/app/models/pdf_writer.rb +3 -0
  378. data/spec/app/models/pencil.rb +1 -0
  379. data/spec/app/models/person.rb +205 -0
  380. data/spec/app/models/pet.rb +23 -0
  381. data/spec/app/models/pet_owner.rb +6 -0
  382. data/spec/app/models/phone.rb +11 -0
  383. data/spec/app/models/pizza.rb +7 -0
  384. data/spec/app/models/player.rb +35 -0
  385. data/spec/app/models/post.rb +44 -0
  386. data/spec/app/models/powerup.rb +11 -0
  387. data/spec/app/models/preference.rb +9 -0
  388. data/spec/app/models/princess.rb +8 -0
  389. data/spec/app/models/product.rb +15 -0
  390. data/spec/app/models/profile.rb +5 -0
  391. data/spec/app/models/pronunciation.rb +5 -0
  392. data/spec/app/models/purchase.rb +4 -0
  393. data/spec/app/models/question.rb +8 -0
  394. data/spec/app/models/quiz.rb +7 -0
  395. data/spec/app/models/rating.rb +8 -0
  396. data/spec/app/models/record.rb +46 -0
  397. data/spec/app/models/registry.rb +4 -0
  398. data/spec/app/models/role.rb +7 -0
  399. data/spec/app/models/root_category.rb +4 -0
  400. data/spec/app/models/sandwich.rb +4 -0
  401. data/spec/app/models/scheduler.rb +7 -0
  402. data/spec/app/models/seo.rb +7 -0
  403. data/spec/app/models/series.rb +4 -0
  404. data/spec/app/models/server.rb +13 -0
  405. data/spec/app/models/service.rb +22 -0
  406. data/spec/app/models/shape.rb +12 -0
  407. data/spec/app/models/shelf.rb +5 -0
  408. data/spec/app/models/shipping_container.rb +5 -0
  409. data/spec/app/models/shipping_pack.rb +3 -0
  410. data/spec/app/models/shop.rb +6 -0
  411. data/spec/app/models/short_agent.rb +4 -0
  412. data/spec/app/models/short_quiz.rb +5 -0
  413. data/spec/app/models/slave.rb +6 -0
  414. data/spec/app/models/song.rb +8 -0
  415. data/spec/app/models/sound.rb +5 -0
  416. data/spec/app/models/square.rb +4 -0
  417. data/spec/app/models/strategy.rb +3 -0
  418. data/spec/app/models/sub_item.rb +3 -0
  419. data/spec/app/models/subscription.rb +4 -0
  420. data/spec/app/models/survey.rb +5 -0
  421. data/spec/app/models/symptom.rb +6 -0
  422. data/spec/app/models/tag.rb +8 -0
  423. data/spec/app/models/target.rb +5 -0
  424. data/spec/app/models/template.rb +5 -0
  425. data/spec/app/models/thing.rb +9 -0
  426. data/spec/app/models/title.rb +3 -0
  427. data/spec/app/models/tool.rb +8 -0
  428. data/spec/app/models/topping.rb +5 -0
  429. data/spec/app/models/track.rb +38 -0
  430. data/spec/app/models/translation.rb +5 -0
  431. data/spec/app/models/tree.rb +9 -0
  432. data/spec/app/models/truck.rb +3 -0
  433. data/spec/app/models/user.rb +21 -0
  434. data/spec/app/models/user_account.rb +10 -0
  435. data/spec/app/models/validation_callback.rb +10 -0
  436. data/spec/app/models/vehicle.rb +11 -0
  437. data/spec/app/models/version.rb +5 -0
  438. data/spec/app/models/vet_visit.rb +5 -0
  439. data/spec/app/models/video.rb +13 -0
  440. data/spec/app/models/weapon.rb +11 -0
  441. data/spec/app/models/wiki_page.rb +14 -0
  442. data/spec/app/models/word.rb +15 -0
  443. data/spec/app/models/word_origin.rb +11 -0
  444. data/spec/app/models/writer.rb +11 -0
  445. data/spec/config/mongoid.yml +38 -0
  446. data/spec/mongoid/atomic/modifiers_spec.rb +456 -0
  447. data/spec/mongoid/atomic/paths/embedded/many_spec.rb +118 -0
  448. data/spec/mongoid/atomic/paths/embedded/one_spec.rb +110 -0
  449. data/spec/mongoid/atomic/paths/root_spec.rb +48 -0
  450. data/spec/mongoid/atomic/paths_spec.rb +270 -0
  451. data/spec/mongoid/atomic_spec.rb +365 -0
  452. data/spec/mongoid/attributes/nested_spec.rb +4832 -0
  453. data/spec/mongoid/attributes/readonly_spec.rb +169 -0
  454. data/spec/mongoid/attributes_spec.rb +1412 -0
  455. data/spec/mongoid/changeable_spec.rb +1507 -0
  456. data/spec/mongoid/composable_spec.rb +24 -0
  457. data/spec/mongoid/config/environment_spec.rb +83 -0
  458. data/spec/mongoid/config/options_spec.rb +56 -0
  459. data/spec/mongoid/config_spec.rb +318 -0
  460. data/spec/mongoid/contextual/aggregable/memory_spec.rb +293 -0
  461. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +455 -0
  462. data/spec/mongoid/contextual/atomic_spec.rb +529 -0
  463. data/spec/mongoid/contextual/find_and_modify_spec.rb +220 -0
  464. data/spec/mongoid/contextual/geo_near_spec.rb +405 -0
  465. data/spec/mongoid/contextual/map_reduce_spec.rb +464 -0
  466. data/spec/mongoid/contextual/memory_spec.rb +1236 -0
  467. data/spec/mongoid/contextual/mongo_spec.rb +1843 -0
  468. data/spec/mongoid/contextual/text_search_spec.rb +207 -0
  469. data/spec/mongoid/copyable_spec.rb +393 -0
  470. data/spec/mongoid/criteria/findable_spec.rb +1189 -0
  471. data/spec/mongoid/criteria/inspectable_spec.rb +27 -0
  472. data/spec/mongoid/criteria/marshalable_spec.rb +28 -0
  473. data/spec/mongoid/criteria/modifiable_spec.rb +1063 -0
  474. data/spec/mongoid/criteria/scopable_spec.rb +391 -0
  475. data/spec/mongoid/criteria_spec.rb +3821 -0
  476. data/spec/mongoid/document_spec.rb +1205 -0
  477. data/spec/mongoid/equality_spec.rb +241 -0
  478. data/spec/mongoid/errors/ambiguous_relationship_spec.rb +29 -0
  479. data/spec/mongoid/errors/callback_spec.rb +29 -0
  480. data/spec/mongoid/errors/delete_restriction_spec.rb +29 -0
  481. data/spec/mongoid/errors/document_not_found_spec.rb +104 -0
  482. data/spec/mongoid/errors/eager_load_spec.rb +29 -0
  483. data/spec/mongoid/errors/invalid_collection_spec.rb +36 -0
  484. data/spec/mongoid/errors/invalid_config_option_spec.rb +29 -0
  485. data/spec/mongoid/errors/invalid_field_option_spec.rb +29 -0
  486. data/spec/mongoid/errors/invalid_field_spec.rb +37 -0
  487. data/spec/mongoid/errors/invalid_find_spec.rb +29 -0
  488. data/spec/mongoid/errors/invalid_includes_spec.rb +40 -0
  489. data/spec/mongoid/errors/invalid_index_spec.rb +29 -0
  490. data/spec/mongoid/errors/invalid_options_spec.rb +29 -0
  491. data/spec/mongoid/errors/invalid_path_spec.rb +23 -0
  492. data/spec/mongoid/errors/invalid_scope_spec.rb +29 -0
  493. data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +17 -0
  494. data/spec/mongoid/errors/invalid_storage_options_spec.rb +29 -0
  495. data/spec/mongoid/errors/invalid_time_spec.rb +29 -0
  496. data/spec/mongoid/errors/inverse_not_found_spec.rb +29 -0
  497. data/spec/mongoid/errors/mixed_relations_spec.rb +29 -0
  498. data/spec/mongoid/errors/mixed_session_configuration_spec.rb +29 -0
  499. data/spec/mongoid/errors/mongoid_error_spec.rb +48 -0
  500. data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +29 -0
  501. data/spec/mongoid/errors/no_environment_spec.rb +29 -0
  502. data/spec/mongoid/errors/no_map_reduce_output_spec.rb +29 -0
  503. data/spec/mongoid/errors/no_metadata_spec.rb +23 -0
  504. data/spec/mongoid/errors/no_parent_spec.rb +29 -0
  505. data/spec/mongoid/errors/no_session_config_spec.rb +29 -0
  506. data/spec/mongoid/errors/no_session_database_spec.rb +29 -0
  507. data/spec/mongoid/errors/no_session_hosts_spec.rb +29 -0
  508. data/spec/mongoid/errors/no_sessions_config_spec.rb +29 -0
  509. data/spec/mongoid/errors/readonly_attribute_spec.rb +29 -0
  510. data/spec/mongoid/errors/scope_overwrite_spec.rb +29 -0
  511. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +29 -0
  512. data/spec/mongoid/errors/unknown_attribute_spec.rb +29 -0
  513. data/spec/mongoid/errors/unsaved_document_spec.rb +37 -0
  514. data/spec/mongoid/errors/unsupported_javascript_spec.rb +29 -0
  515. data/spec/mongoid/errors/validations_spec.rb +45 -0
  516. data/spec/mongoid/extensions/array_spec.rb +638 -0
  517. data/spec/mongoid/extensions/big_decimal_spec.rb +104 -0
  518. data/spec/mongoid/extensions/binary_spec.rb +60 -0
  519. data/spec/mongoid/extensions/boolean_spec.rb +135 -0
  520. data/spec/mongoid/extensions/date_spec.rb +235 -0
  521. data/spec/mongoid/extensions/date_time_spec.rb +155 -0
  522. data/spec/mongoid/extensions/false_class_spec.rb +42 -0
  523. data/spec/mongoid/extensions/float_spec.rb +133 -0
  524. data/spec/mongoid/extensions/hash_spec.rb +333 -0
  525. data/spec/mongoid/extensions/integer_spec.rb +136 -0
  526. data/spec/mongoid/extensions/module_spec.rb +42 -0
  527. data/spec/mongoid/extensions/nil_class_spec.rb +11 -0
  528. data/spec/mongoid/extensions/object_id_spec.rb +946 -0
  529. data/spec/mongoid/extensions/object_spec.rb +292 -0
  530. data/spec/mongoid/extensions/range_spec.rb +105 -0
  531. data/spec/mongoid/extensions/regexp_spec.rb +47 -0
  532. data/spec/mongoid/extensions/set_spec.rb +33 -0
  533. data/spec/mongoid/extensions/string_spec.rb +357 -0
  534. data/spec/mongoid/extensions/symbol_spec.rb +76 -0
  535. data/spec/mongoid/extensions/time_spec.rb +467 -0
  536. data/spec/mongoid/extensions/time_with_zone_spec.rb +405 -0
  537. data/spec/mongoid/extensions/true_class_spec.rb +42 -0
  538. data/spec/mongoid/extensions_spec.rb +15 -0
  539. data/spec/mongoid/factory_spec.rb +185 -0
  540. data/spec/mongoid/fields/foreign_key_spec.rb +694 -0
  541. data/spec/mongoid/fields/internal/foreign_keys/array_spec.rb +184 -0
  542. data/spec/mongoid/fields/internal/foreign_keys/object_spec.rb +201 -0
  543. data/spec/mongoid/fields/localized_spec.rb +386 -0
  544. data/spec/mongoid/fields/standard_spec.rb +166 -0
  545. data/spec/mongoid/fields_spec.rb +1229 -0
  546. data/spec/mongoid/findable_spec.rb +342 -0
  547. data/spec/mongoid/identity_map_spec.rb +564 -0
  548. data/spec/mongoid/indexable/specification_spec.rb +87 -0
  549. data/spec/mongoid/indexable_spec.rb +504 -0
  550. data/spec/mongoid/inspectable_spec.rb +49 -0
  551. data/spec/mongoid/interceptable_spec.rb +1564 -0
  552. data/spec/mongoid/loggable_spec.rb +21 -0
  553. data/spec/mongoid/matchable/all_spec.rb +31 -0
  554. data/spec/mongoid/matchable/and_spec.rb +162 -0
  555. data/spec/mongoid/matchable/default_spec.rb +130 -0
  556. data/spec/mongoid/matchable/exists_spec.rb +57 -0
  557. data/spec/mongoid/matchable/gt_spec.rb +75 -0
  558. data/spec/mongoid/matchable/gte_spec.rb +74 -0
  559. data/spec/mongoid/matchable/in_spec.rb +25 -0
  560. data/spec/mongoid/matchable/lt_spec.rb +74 -0
  561. data/spec/mongoid/matchable/lte_spec.rb +74 -0
  562. data/spec/mongoid/matchable/ne_spec.rb +25 -0
  563. data/spec/mongoid/matchable/nin_spec.rb +25 -0
  564. data/spec/mongoid/matchable/or_spec.rb +106 -0
  565. data/spec/mongoid/matchable/size_spec.rb +25 -0
  566. data/spec/mongoid/matchable_spec.rb +532 -0
  567. data/spec/mongoid/persistable/creatable_spec.rb +512 -0
  568. data/spec/mongoid/persistable/deletable_spec.rb +205 -0
  569. data/spec/mongoid/persistable/destroyable_spec.rb +148 -0
  570. data/spec/mongoid/persistable/incrementable_spec.rb +173 -0
  571. data/spec/mongoid/persistable/logical_spec.rb +143 -0
  572. data/spec/mongoid/persistable/poppable_spec.rb +115 -0
  573. data/spec/mongoid/persistable/pullable_spec.rb +228 -0
  574. data/spec/mongoid/persistable/pushable_spec.rb +258 -0
  575. data/spec/mongoid/persistable/renamable_spec.rb +135 -0
  576. data/spec/mongoid/persistable/savable_spec.rb +432 -0
  577. data/spec/mongoid/persistable/settable_spec.rb +139 -0
  578. data/spec/mongoid/persistable/unsettable_spec.rb +155 -0
  579. data/spec/mongoid/persistable/updatable_spec.rb +522 -0
  580. data/spec/mongoid/persistable/upsertable_spec.rb +106 -0
  581. data/spec/mongoid/persistable_spec.rb +206 -0
  582. data/spec/mongoid/positional_spec.rb +227 -0
  583. data/spec/mongoid/railties/document_spec.rb +24 -0
  584. data/spec/mongoid/relations/accessors_spec.rb +736 -0
  585. data/spec/mongoid/relations/auto_save_spec.rb +261 -0
  586. data/spec/mongoid/relations/bindings/embedded/in_spec.rb +171 -0
  587. data/spec/mongoid/relations/bindings/embedded/many_spec.rb +54 -0
  588. data/spec/mongoid/relations/bindings/embedded/one_spec.rb +77 -0
  589. data/spec/mongoid/relations/bindings/referenced/in_spec.rb +241 -0
  590. data/spec/mongoid/relations/bindings/referenced/many_spec.rb +153 -0
  591. data/spec/mongoid/relations/bindings/referenced/many_to_many_spec.rb +178 -0
  592. data/spec/mongoid/relations/bindings/referenced/one_spec.rb +131 -0
  593. data/spec/mongoid/relations/builders/embedded/in_spec.rb +34 -0
  594. data/spec/mongoid/relations/builders/embedded/many_spec.rb +132 -0
  595. data/spec/mongoid/relations/builders/embedded/one_spec.rb +99 -0
  596. data/spec/mongoid/relations/builders/nested_attributes/many_spec.rb +234 -0
  597. data/spec/mongoid/relations/builders/nested_attributes/one_spec.rb +250 -0
  598. data/spec/mongoid/relations/builders/referenced/in_spec.rb +241 -0
  599. data/spec/mongoid/relations/builders/referenced/many_spec.rb +137 -0
  600. data/spec/mongoid/relations/builders/referenced/many_to_many_spec.rb +178 -0
  601. data/spec/mongoid/relations/builders/referenced/one_spec.rb +124 -0
  602. data/spec/mongoid/relations/builders_spec.rb +226 -0
  603. data/spec/mongoid/relations/cascading/delete_spec.rb +101 -0
  604. data/spec/mongoid/relations/cascading/destroy_spec.rb +47 -0
  605. data/spec/mongoid/relations/cascading/nullify_spec.rb +32 -0
  606. data/spec/mongoid/relations/cascading/restrict_spec.rb +68 -0
  607. data/spec/mongoid/relations/cascading_spec.rb +355 -0
  608. data/spec/mongoid/relations/constraint_spec.rb +74 -0
  609. data/spec/mongoid/relations/conversions_spec.rb +126 -0
  610. data/spec/mongoid/relations/counter_cache_spec.rb +205 -0
  611. data/spec/mongoid/relations/cyclic_spec.rb +156 -0
  612. data/spec/mongoid/relations/embedded/dirty_spec.rb +65 -0
  613. data/spec/mongoid/relations/embedded/in_spec.rb +579 -0
  614. data/spec/mongoid/relations/embedded/many_spec.rb +3781 -0
  615. data/spec/mongoid/relations/embedded/one_spec.rb +1014 -0
  616. data/spec/mongoid/relations/macros_spec.rb +613 -0
  617. data/spec/mongoid/relations/metadata_spec.rb +1917 -0
  618. data/spec/mongoid/relations/options_spec.rb +35 -0
  619. data/spec/mongoid/relations/polymorphic_spec.rb +128 -0
  620. data/spec/mongoid/relations/proxy_spec.rb +48 -0
  621. data/spec/mongoid/relations/referenced/in_spec.rb +1435 -0
  622. data/spec/mongoid/relations/referenced/many_spec.rb +3546 -0
  623. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +3556 -0
  624. data/spec/mongoid/relations/referenced/one_spec.rb +1289 -0
  625. data/spec/mongoid/relations/reflections_spec.rb +101 -0
  626. data/spec/mongoid/relations/synchronization_spec.rb +449 -0
  627. data/spec/mongoid/relations/targets/enumerable_spec.rb +1710 -0
  628. data/spec/mongoid/relations/touchable_spec.rb +296 -0
  629. data/spec/mongoid/relations_spec.rb +188 -0
  630. data/spec/mongoid/reloadable_spec.rb +305 -0
  631. data/spec/mongoid/scopable_spec.rb +926 -0
  632. data/spec/mongoid/selectable_spec.rb +134 -0
  633. data/spec/mongoid/serializable_spec.rb +862 -0
  634. data/spec/mongoid/sessions/factory_spec.rb +312 -0
  635. data/spec/mongoid/sessions/mongo_uri_spec.rb +103 -0
  636. data/spec/mongoid/sessions/options_spec.rb +71 -0
  637. data/spec/mongoid/sessions_spec.rb +1078 -0
  638. data/spec/mongoid/shardable_spec.rb +61 -0
  639. data/spec/mongoid/state_spec.rb +102 -0
  640. data/spec/mongoid/threaded_spec.rb +258 -0
  641. data/spec/mongoid/timestamps/created/short_spec.rb +51 -0
  642. data/spec/mongoid/timestamps/created_spec.rb +44 -0
  643. data/spec/mongoid/timestamps/updated/short_spec.rb +90 -0
  644. data/spec/mongoid/timestamps/updated_spec.rb +86 -0
  645. data/spec/mongoid/timestamps_spec.rb +112 -0
  646. data/spec/mongoid/traversable_spec.rb +244 -0
  647. data/spec/mongoid/unit_of_work_spec.rb +196 -0
  648. data/spec/mongoid/validatable/associated_spec.rb +183 -0
  649. data/spec/mongoid/validatable/format_spec.rb +83 -0
  650. data/spec/mongoid/validatable/length_spec.rb +119 -0
  651. data/spec/mongoid/validatable/numericality_spec.rb +30 -0
  652. data/spec/mongoid/validatable/presence_spec.rb +511 -0
  653. data/spec/mongoid/validatable/uniqueness_spec.rb +2305 -0
  654. data/spec/mongoid/validatable_spec.rb +309 -0
  655. data/spec/mongoid_spec.rb +74 -0
  656. data/spec/rack/mongoid/middleware/identity_map_spec.rb +72 -0
  657. data/spec/rails/mongoid_spec.rb +462 -0
  658. data/spec/spec_helper.rb +103 -0
  659. metadata +1159 -0
@@ -0,0 +1,440 @@
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
+ include Eager
10
+ include Queryable
11
+ include Positional
12
+
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 :documents, :path, :root, :selector
18
+
19
+ # Check if the context is equal to the other object.
20
+ #
21
+ # @example Check equality.
22
+ # context == []
23
+ #
24
+ # @param [ Array ] other The other array.
25
+ #
26
+ # @return [ true, false ] If the objects are equal.
27
+ #
28
+ # @since 3.0.0
29
+ def ==(other)
30
+ return false unless other.respond_to?(:entries)
31
+ entries == other.entries
32
+ end
33
+
34
+ # Delete all documents in the database that match the selector.
35
+ #
36
+ # @example Delete all the documents.
37
+ # context.delete
38
+ #
39
+ # @return [ nil ] Nil.
40
+ #
41
+ # @since 3.0.0
42
+ def delete
43
+ deleted = count
44
+ removed = map do |doc|
45
+ prepare_remove(doc)
46
+ doc.as_document
47
+ end
48
+ unless removed.empty?
49
+ collection.find(selector).update(
50
+ positionally(selector, "$pullAll" => { path => removed })
51
+ )
52
+ end
53
+ deleted
54
+ end
55
+ alias :delete_all :delete
56
+
57
+ # Destroy all documents in the database that match the selector.
58
+ #
59
+ # @example Destroy all the documents.
60
+ # context.destroy
61
+ #
62
+ # @return [ nil ] Nil.
63
+ #
64
+ # @since 3.0.0
65
+ def destroy
66
+ deleted = count
67
+ each do |doc|
68
+ documents.delete_one(doc)
69
+ doc.destroy
70
+ end
71
+ deleted
72
+ end
73
+ alias :destroy_all :destroy
74
+
75
+ # Get the distinct values in the db for the provided field.
76
+ #
77
+ # @example Get the distinct values.
78
+ # context.distinct(:name)
79
+ #
80
+ # @param [ String, Symbol ] field The name of the field.
81
+ #
82
+ # @return [ Array<Object> ] The distinct values for the field.
83
+ #
84
+ # @since 3.0.0
85
+ def distinct(field)
86
+ documents.map{ |doc| doc.send(field) }.uniq
87
+ end
88
+
89
+ # Iterate over the context. If provided a block, yield to a Mongoid
90
+ # document for each, otherwise return an enum.
91
+ #
92
+ # @example Iterate over the context.
93
+ # context.each do |doc|
94
+ # puts doc.name
95
+ # end
96
+ #
97
+ # @return [ Enumerator ] The enumerator.
98
+ #
99
+ # @since 3.0.0
100
+ def each
101
+ if block_given?
102
+ documents_for_iteration.each do |doc|
103
+ yield(doc)
104
+ end
105
+ # eager_loadable? ? docs : self
106
+ else
107
+ to_enum
108
+ end
109
+ end
110
+
111
+ # Do any documents exist for the context.
112
+ #
113
+ # @example Do any documents exist for the context.
114
+ # context.exists?
115
+ #
116
+ # @return [ true, false ] If the count is more than zero.
117
+ #
118
+ # @since 3.0.0
119
+ def exists?
120
+ count > 0
121
+ end
122
+
123
+ # Get the first document in the database for the criteria's selector.
124
+ #
125
+ # @example Get the first document.
126
+ # context.first
127
+ #
128
+ # @return [ Document ] The first document.
129
+ #
130
+ # @since 3.0.0
131
+ def first
132
+ doc = documents.first
133
+ eager_load_one(doc) if eager_loadable?(doc)
134
+ doc
135
+ end
136
+ alias :one :first
137
+
138
+ # Create the new in memory context.
139
+ #
140
+ # @example Create the new context.
141
+ # Memory.new(criteria)
142
+ #
143
+ # @param [ Criteria ] The criteria.
144
+ #
145
+ # @since 3.0.0
146
+ def initialize(criteria)
147
+ @criteria, @klass = criteria, criteria.klass
148
+ @documents = criteria.documents.select do |doc|
149
+ @root ||= doc._root
150
+ @collection ||= root.collection
151
+ doc.matches?(criteria.selector)
152
+ end
153
+ apply_sorting
154
+ apply_options
155
+ end
156
+
157
+ # Get the last document in the database for the criteria's selector.
158
+ #
159
+ # @example Get the last document.
160
+ # context.last
161
+ #
162
+ # @return [ Document ] The last document.
163
+ #
164
+ # @since 3.0.0
165
+ def last
166
+ doc = documents.last
167
+ eager_load_one(doc) if eager_loadable?(doc)
168
+ doc
169
+ end
170
+
171
+ # Get the length of matching documents in the context.
172
+ #
173
+ # @example Get the length of matching documents.
174
+ # context.length
175
+ #
176
+ # @return [ Integer ] The matching length.
177
+ #
178
+ # @since 3.0.0
179
+ def length
180
+ documents.length
181
+ end
182
+ alias :size :length
183
+
184
+ # Limits the number of documents that are returned.
185
+ #
186
+ # @example Limit the documents.
187
+ # context.limit(20)
188
+ #
189
+ # @param [ Integer ] value The number of documents to return.
190
+ #
191
+ # @return [ Mongo ] The context.
192
+ #
193
+ # @since 3.0.0
194
+ def limit(value)
195
+ self.limiting = value
196
+ self
197
+ end
198
+
199
+ # Skips the provided number of documents.
200
+ #
201
+ # @example Skip the documents.
202
+ # context.skip(20)
203
+ #
204
+ # @param [ Integer ] value The number of documents to skip.
205
+ #
206
+ # @return [ Mongo ] The context.
207
+ #
208
+ # @since 3.0.0
209
+ def skip(value)
210
+ self.skipping = value
211
+ self
212
+ end
213
+
214
+ # Sorts the documents by the provided spec.
215
+ #
216
+ # @example Sort the documents.
217
+ # context.sort(name: -1, title: 1)
218
+ #
219
+ # @param [ Hash ] values The sorting values as field/direction(1/-1)
220
+ # pairs.
221
+ #
222
+ # @return [ Mongo ] The context.
223
+ #
224
+ # @since 3.0.0
225
+ def sort(values)
226
+ in_place_sort(values) and self
227
+ end
228
+
229
+ # Update the first matching document atomically.
230
+ #
231
+ # @example Update the matching document.
232
+ # context.update(name: "Smiths")
233
+ #
234
+ # @param [ Hash ] attributes The new attributes for the document.
235
+ #
236
+ # @return [ nil, false ] False if no attributes were provided.
237
+ #
238
+ # @since 3.0.0
239
+ def update(attributes = nil)
240
+ update_documents(attributes, [ first ])
241
+ end
242
+
243
+ # Update all the matching documents atomically.
244
+ #
245
+ # @example Update all the matching documents.
246
+ # context.update_all(name: "Smiths")
247
+ #
248
+ # @param [ Hash ] attributes The new attributes for each document.
249
+ #
250
+ # @return [ nil, false ] False if no attributes were provided.
251
+ #
252
+ # @since 3.0.0
253
+ def update_all(attributes = nil)
254
+ update_documents(attributes, entries)
255
+ end
256
+
257
+ private
258
+
259
+ # Get the documents the context should iterate. This follows 3 rules:
260
+ #
261
+ # @api private
262
+ #
263
+ # @example Get the documents for iteration.
264
+ # context.documents_for_iteration
265
+ #
266
+ # @return [ Array<Document> ] The docs to iterate.
267
+ #
268
+ # @since 3.1.0
269
+ def documents_for_iteration
270
+ docs = documents[skipping || 0, limiting || documents.length] || []
271
+ if eager_loadable?
272
+ eager_load(docs)
273
+ end
274
+ docs
275
+ end
276
+
277
+ # Update the provided documents with the attributes.
278
+ #
279
+ # @api private
280
+ #
281
+ # @example Update the documents.
282
+ # context.update_documents({}, doc)
283
+ #
284
+ # @param [ Hash ] attributes The attributes.
285
+ # @param [ Array<Document> ] docs The docs to update.
286
+ #
287
+ # @since 3.0.4
288
+ def update_documents(attributes, docs)
289
+ return false if !attributes || docs.empty?
290
+ updates = { "$set" => {}}
291
+ docs.each do |doc|
292
+ @selector ||= root.atomic_selector
293
+ doc.write_attributes(attributes)
294
+ updates["$set"].merge!(doc.atomic_updates["$set"] || {})
295
+ doc.move_changes
296
+ end
297
+ collection.find(selector).update(updates)
298
+ end
299
+
300
+ # Get the limiting value.
301
+ #
302
+ # @api private
303
+ #
304
+ # @example Get the limiting value.
305
+ #
306
+ # @return [ Integer ] The limit.
307
+ #
308
+ # @since 3.0.0
309
+ def limiting
310
+ defined?(@limiting) ? @limiting : nil
311
+ end
312
+
313
+ # Set the limiting value.
314
+ #
315
+ # @api private
316
+ #
317
+ # @example Set the limiting value.
318
+ #
319
+ # @param [ Integer ] value The limit.
320
+ #
321
+ # @return [ Integer ] The limit.
322
+ #
323
+ # @since 3.0.0
324
+ def limiting=(value)
325
+ @limiting = value
326
+ end
327
+
328
+ # Get the skiping value.
329
+ #
330
+ # @api private
331
+ #
332
+ # @example Get the skiping value.
333
+ #
334
+ # @return [ Integer ] The skip.
335
+ #
336
+ # @since 3.0.0
337
+ def skipping
338
+ defined?(@skipping) ? @skipping : nil
339
+ end
340
+
341
+ # Set the skiping value.
342
+ #
343
+ # @api private
344
+ #
345
+ # @example Set the skiping value.
346
+ #
347
+ # @param [ Integer ] value The skip.
348
+ #
349
+ # @return [ Integer ] The skip.
350
+ #
351
+ # @since 3.0.0
352
+ def skipping=(value)
353
+ @skipping = value
354
+ end
355
+
356
+ # Apply criteria options.
357
+ #
358
+ # @api private
359
+ #
360
+ # @example Apply criteria options.
361
+ # context.apply_options
362
+ #
363
+ # @return [ Memory ] self.
364
+ #
365
+ # @since 3.0.0
366
+ def apply_options
367
+ skip(criteria.options[:skip]).limit(criteria.options[:limit])
368
+ end
369
+
370
+ # Map the sort symbols to the correct MongoDB values.
371
+ #
372
+ # @example Apply the sorting params.
373
+ # context.apply_sorting
374
+ #
375
+ # @since 3.0.0
376
+ def apply_sorting
377
+ if spec = criteria.options[:sort]
378
+ in_place_sort(spec)
379
+ end
380
+ end
381
+
382
+ # Compare two values, checking for nil.
383
+ #
384
+ # @api private
385
+ #
386
+ # @example Compare the two objects.
387
+ # context.compare(a, b)
388
+ #
389
+ # @param [ Object ] a The first object.
390
+ # @param [ Object ] b The first object.
391
+ #
392
+ # @return [ Integer ] The comparison value.
393
+ #
394
+ # @since 3.0.0
395
+ def compare(a, b)
396
+ case
397
+ when a.nil? then b.nil? ? 0 : 1
398
+ when b.nil? then -1
399
+ else a <=> b
400
+ end
401
+ end
402
+
403
+ # Sort the documents in place.
404
+ #
405
+ # @example Sort the documents.
406
+ # context.in_place_sort(name: 1)
407
+ #
408
+ # @param [ Hash ] values The field/direction sorting pairs.
409
+ #
410
+ # @since 3.0.0
411
+ def in_place_sort(values)
412
+ values.keys.reverse.each do |field|
413
+ documents.sort! do |a, b|
414
+ a_value, b_value = a[field], b[field]
415
+ value = compare(a_value.__sortable__, b_value.__sortable__)
416
+ values[field] < 0 ? value * -1 : value
417
+ end
418
+ end
419
+ end
420
+
421
+ # Prepare the document for batch removal.
422
+ #
423
+ # @api private
424
+ #
425
+ # @example Prepare for removal.
426
+ # context.prepare_remove(doc)
427
+ #
428
+ # @param [ Document ] doc The document.
429
+ #
430
+ # @since 3.0.0
431
+ def prepare_remove(doc)
432
+ @selector ||= root.atomic_selector
433
+ @path ||= doc.atomic_path
434
+ documents.delete_one(doc)
435
+ doc._parent.remove_child(doc)
436
+ doc.destroyed = true
437
+ end
438
+ end
439
+ end
440
+ end
@@ -0,0 +1,676 @@
1
+ # encoding: utf-8
2
+ require "mongoid/contextual/atomic"
3
+ require "mongoid/contextual/aggregable/mongo"
4
+ require "mongoid/contextual/command"
5
+ require "mongoid/contextual/eager"
6
+ require "mongoid/contextual/find_and_modify"
7
+ require "mongoid/contextual/geo_near"
8
+ require "mongoid/contextual/map_reduce"
9
+ require "mongoid/contextual/text_search"
10
+
11
+ module Mongoid
12
+ module Contextual
13
+ class Mongo
14
+ include Enumerable
15
+ include Aggregable::Mongo
16
+ include Atomic
17
+ include Eager
18
+ include Queryable
19
+
20
+ # @attribute [r] query The Moped query.
21
+ attr_reader :query
22
+
23
+ # Is the context cached?
24
+ #
25
+ # @example Is the context cached?
26
+ # context.cached?
27
+ #
28
+ # @return [ true, false ] If the context is cached.
29
+ #
30
+ # @since 3.0.0
31
+ def cached?
32
+ !!@cache
33
+ end
34
+
35
+ # Get the number of documents matching the query.
36
+ #
37
+ # @example Get the number of matching documents.
38
+ # context.count
39
+ #
40
+ # @example Get the count of documents matching the provided.
41
+ # context.count(document)
42
+ #
43
+ # @example Get the count for where the provided block is true.
44
+ # context.count do |doc|
45
+ # doc.likes > 1
46
+ # end
47
+ #
48
+ # @param [ Document ] document A document to match or true if wanting
49
+ # skip and limit to be factored into the count.
50
+ #
51
+ # @return [ Integer ] The number of matches.
52
+ #
53
+ # @since 3.0.0
54
+ def count(document = false, &block)
55
+ return super(&block) if block_given?
56
+ if document.is_a?(Document)
57
+ return collection.find(criteria.and(_id: document.id).selector).count
58
+ end
59
+ return query.count(document) if document
60
+ try_cache(:count) { query.count }
61
+ end
62
+
63
+ # Delete all documents in the database that match the selector.
64
+ #
65
+ # @example Delete all the documents.
66
+ # context.delete
67
+ #
68
+ # @return [ nil ] Nil.
69
+ #
70
+ # @since 3.0.0
71
+ def delete
72
+ self.count.tap do
73
+ query.remove_all
74
+ end
75
+ end
76
+ alias :delete_all :delete
77
+
78
+ # Destroy all documents in the database that match the selector.
79
+ #
80
+ # @example Destroy all the documents.
81
+ # context.destroy
82
+ #
83
+ # @return [ nil ] Nil.
84
+ #
85
+ # @since 3.0.0
86
+ def destroy
87
+ destroyed = self.count
88
+ each do |doc|
89
+ doc.destroy
90
+ end
91
+ destroyed
92
+ end
93
+ alias :destroy_all :destroy
94
+
95
+ # Get the distinct values in the db for the provided field.
96
+ #
97
+ # @example Get the distinct values.
98
+ # context.distinct(:name)
99
+ #
100
+ # @param [ String, Symbol ] field The name of the field.
101
+ #
102
+ # @return [ Array<Object> ] The distinct values for the field.
103
+ #
104
+ # @since 3.0.0
105
+ def distinct(field)
106
+ query.distinct(klass.database_field_name(field))
107
+ end
108
+
109
+ # Iterate over the context. If provided a block, yield to a Mongoid
110
+ # document for each, otherwise return an enum.
111
+ #
112
+ # @example Iterate over the context.
113
+ # context.each do |doc|
114
+ # puts doc.name
115
+ # end
116
+ #
117
+ # @return [ Enumerator ] The enumerator.
118
+ #
119
+ # @since 3.0.0
120
+ def each(&block)
121
+ if block_given?
122
+ selecting do
123
+ documents_for_iteration.each do |doc|
124
+ yield_document(doc, &block)
125
+ end
126
+ @cache_loaded = true
127
+ eager_loadable? ? docs : self
128
+ end
129
+ else
130
+ to_enum
131
+ end
132
+ end
133
+
134
+ # Do any documents exist for the context.
135
+ #
136
+ # @example Do any documents exist for the context.
137
+ # context.exists?
138
+ #
139
+ # @note We don't use count here since Mongo does not use counted
140
+ # b-tree indexes, unless a count is already cached then that is
141
+ # used to determine the value.
142
+ #
143
+ # @return [ true, false ] If the count is more than zero.
144
+ #
145
+ # @since 3.0.0
146
+ def exists?
147
+ return !documents.empty? if cached? && cache_loaded?
148
+ return @count > 0 if instance_variable_defined?(:@count)
149
+
150
+ try_cache(:exists) do
151
+ !!(query.dup.select(_id: 1).limit(1).first)
152
+ end
153
+ end
154
+
155
+ # Run an explain on the criteria.
156
+ #
157
+ # @example Explain the criteria.
158
+ # Band.where(name: "Depeche Mode").explain
159
+ #
160
+ # @return [ Hash ] The explain result.
161
+ #
162
+ # @since 3.0.0
163
+ def explain
164
+ query.explain
165
+ end
166
+
167
+ # Execute the find and modify command, used for MongoDB's
168
+ # $findAndModify.
169
+ #
170
+ # @example Execute the command.
171
+ # context.find_and_modify({ "$inc" => { likes: 1 }}, new: true)
172
+ #
173
+ # @param [ Hash ] update The updates.
174
+ # @param [ Hash ] options The command options.
175
+ #
176
+ # @option options [ true, false ] :new Return the updated document.
177
+ # @option options [ true, false ] :remove Delete the first document.
178
+ # @option options [ true, false ] :upsert Create the document if it doesn't exist.
179
+ #
180
+ # @return [ Document ] The result of the command.
181
+ #
182
+ # @since 3.0.0
183
+ def find_and_modify(update, options = {})
184
+ if doc = FindAndModify.new(collection, criteria, update, options).result
185
+ Factory.from_db(klass, doc)
186
+ end
187
+ end
188
+
189
+ # Get the first document in the database for the criteria's selector.
190
+ #
191
+ # @example Get the first document.
192
+ # context.first
193
+ #
194
+ # @return [ Document ] The first document.
195
+ #
196
+ # @since 3.0.0
197
+ def first
198
+ return documents.first if cached? && cache_loaded?
199
+ try_cache(:first) do
200
+ with_sorting do
201
+ with_eager_loading(query.first)
202
+ end
203
+ end
204
+ end
205
+ alias :one :first
206
+
207
+ # Execute a $geoNear command against the database.
208
+ #
209
+ # @example Find documents close to 10, 10.
210
+ # context.geo_near([ 10, 10 ])
211
+ #
212
+ # @example Find with spherical distance.
213
+ # context.geo_near([ 10, 10 ]).spherical
214
+ #
215
+ # @example Find with a max distance.
216
+ # context.geo_near([ 10, 10 ]).max_distance(0.5)
217
+ #
218
+ # @example Provide a distance multiplier.
219
+ # context.geo_near([ 10, 10 ]).distance_multiplier(1133)
220
+ #
221
+ # @param [ Array<Float> ] coordinates The coordinates.
222
+ #
223
+ # @return [ GeoNear ] The GeoNear command.
224
+ #
225
+ # @since 3.1.0
226
+ def geo_near(coordinates)
227
+ GeoNear.new(collection, criteria, coordinates)
228
+ end
229
+
230
+ # Invoke the block for each element of Contextual. Create a new array
231
+ # containing the values returned by the block.
232
+ #
233
+ # If the symbol field name is passed instead of the block, additional
234
+ # optimizations would be used.
235
+ #
236
+ # @example Map by some field.
237
+ # context.map(:field1)
238
+ #
239
+ # @exmaple Map with block.
240
+ # context.map(&:field1)
241
+ #
242
+ # @param [ Symbol ] field The field name.
243
+ #
244
+ # @return [ Array ] The result of mapping.
245
+ def map(field = nil, &block)
246
+ if block_given?
247
+ super(&block)
248
+ else
249
+ field = field.to_sym
250
+ criteria.only(field).map(&field.to_proc)
251
+ end
252
+ end
253
+
254
+ # Create the new Mongo context. This delegates operations to the
255
+ # underlying driver - in Mongoid's case Moped.
256
+ #
257
+ # @example Create the new context.
258
+ # Mongo.new(criteria)
259
+ #
260
+ # @param [ Criteria ] criteria The criteria.
261
+ #
262
+ # @since 3.0.0
263
+ def initialize(criteria)
264
+ @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
265
+ @collection = @klass.with(criteria.persistence_options || {}).collection
266
+ criteria.send(:merge_type_selection)
267
+ @query = collection.find(criteria.selector)
268
+ apply_options
269
+ end
270
+
271
+ delegate(:database_field_name, to: :@klass)
272
+
273
+ # Get the last document in the database for the criteria's selector.
274
+ #
275
+ # @example Get the last document.
276
+ # context.last
277
+ #
278
+ # @return [ Document ] The last document.
279
+ #
280
+ # @since 3.0.0
281
+ def last
282
+ try_cache(:last) do
283
+ with_inverse_sorting do
284
+ with_eager_loading(query.first)
285
+ end
286
+ end
287
+ end
288
+
289
+ # Get's the number of documents matching the query selector.
290
+ #
291
+ # @example Get the length.
292
+ # context.length
293
+ #
294
+ # @return [ Integer ] The number of documents.
295
+ #
296
+ # @since 3.0.0
297
+ def length
298
+ @length ||= self.count
299
+ end
300
+ alias :size :length
301
+
302
+ # Limits the number of documents that are returned from the database.
303
+ #
304
+ # @example Limit the documents.
305
+ # context.limit(20)
306
+ #
307
+ # @param [ Integer ] value The number of documents to return.
308
+ #
309
+ # @return [ Mongo ] The context.
310
+ #
311
+ # @since 3.0.0
312
+ def limit(value)
313
+ query.limit(value) and self
314
+ end
315
+
316
+ # Initiate a map/reduce operation from the context.
317
+ #
318
+ # @example Initiate a map/reduce.
319
+ # context.map_reduce(map, reduce)
320
+ #
321
+ # @param [ String ] map The map js function.
322
+ # @param [ String ] reduce The reduce js function.
323
+ #
324
+ # @return [ MapReduce ] The map/reduce lazy wrapper.
325
+ #
326
+ # @since 3.0.0
327
+ def map_reduce(map, reduce)
328
+ MapReduce.new(collection, criteria, map, reduce)
329
+ end
330
+
331
+ # Pluck the single field values from the database. Will return duplicates
332
+ # if they exist and only works for top level fields.
333
+ #
334
+ # @example Pluck a field.
335
+ # context.pluck(:_id)
336
+ #
337
+ # @note This method will return the raw db values - it performs no custom
338
+ # serialization.
339
+ #
340
+ # @param [ String, Symbol, Array ] field Fields to pluck.
341
+ #
342
+ # @return [ Array<Object, Array> ] The plucked values.
343
+ #
344
+ # @since 3.1.0
345
+ def pluck(*fields)
346
+ normalized_select = fields.inject({}) do |hash, f|
347
+ hash[klass.database_field_name(f)] = 1
348
+ hash
349
+ end
350
+
351
+ query.dup.select(normalized_select).map do |doc|
352
+ if normalized_select.size == 1
353
+ doc[normalized_select.keys.first]
354
+ else
355
+ normalized_select.keys.map { |n| doc[n] }.compact
356
+ end
357
+ end.compact
358
+ end
359
+
360
+ # Skips the provided number of documents.
361
+ #
362
+ # @example Skip the documents.
363
+ # context.skip(20)
364
+ #
365
+ # @param [ Integer ] value The number of documents to skip.
366
+ #
367
+ # @return [ Mongo ] The context.
368
+ #
369
+ # @since 3.0.0
370
+ def skip(value)
371
+ query.skip(value) and self
372
+ end
373
+
374
+ # Sorts the documents by the provided spec.
375
+ #
376
+ # @example Sort the documents.
377
+ # context.sort(name: -1, title: 1)
378
+ #
379
+ # @param [ Hash ] values The sorting values as field/direction(1/-1)
380
+ # pairs.
381
+ #
382
+ # @return [ Mongo ] The context.
383
+ #
384
+ # @since 3.0.0
385
+ def sort(values = nil, &block)
386
+ if block_given?
387
+ super(&block)
388
+ else
389
+ # update the criteria
390
+ @criteria = criteria.order_by(values)
391
+ apply_option(:sort)
392
+ self
393
+ end
394
+ end
395
+
396
+ # Execute a text command against the database.
397
+ #
398
+ # @example Find documents with the text "phase"
399
+ # context.text_search("phase")
400
+ #
401
+ # @param [ String ] query The text search query.
402
+ #
403
+ # @return [ TextSearch ] The TextSearch command.
404
+ #
405
+ # @since 4.0.0
406
+ def text_search(query)
407
+ TextSearch.new(collection, criteria, query)
408
+ end
409
+
410
+ # Update the first matching document atomically.
411
+ #
412
+ # @example Update the first matching document.
413
+ # context.update({ "$set" => { name: "Smiths" }})
414
+ #
415
+ # @param [ Hash ] attributes The new attributes for the document.
416
+ #
417
+ # @return [ nil, false ] False if no attributes were provided.
418
+ #
419
+ # @since 3.0.0
420
+ def update(attributes = nil)
421
+ update_documents(attributes)
422
+ end
423
+
424
+ # Update all the matching documents atomically.
425
+ #
426
+ # @example Update all the matching documents.
427
+ # context.update({ "$set" => { name: "Smiths" }})
428
+ #
429
+ # @param [ Hash ] attributes The new attributes for each document.
430
+ #
431
+ # @return [ nil, false ] False if no attributes were provided.
432
+ #
433
+ # @since 3.0.0
434
+ def update_all(attributes = nil)
435
+ update_documents(attributes, :update_all)
436
+ end
437
+
438
+ private
439
+
440
+ # yield the block given or return the cached value
441
+ #
442
+ # @param [ String, Symbol ] key The instance variable name
443
+ #
444
+ # @return the result of the block
445
+ #
446
+ # @since 3.1.4
447
+ def try_cache(key, &block)
448
+ unless cached?
449
+ yield
450
+ else
451
+ unless ret = instance_variable_get("@#{key}")
452
+ instance_variable_set("@#{key}", ret = yield)
453
+ end
454
+ ret
455
+ end
456
+ end
457
+
458
+ # Update the documents for the provided method.
459
+ #
460
+ # @api private
461
+ #
462
+ # @example Update the documents.
463
+ # context.update_documents(attrs)
464
+ #
465
+ # @param [ Hash ] attributes The updates.
466
+ # @param [ Symbol ] method The method to use.
467
+ #
468
+ # @return [ true, false ] If the update succeeded.
469
+ #
470
+ # @since 3.0.4
471
+ def update_documents(attributes, method = :update)
472
+ return false unless attributes
473
+ attributes = Hash[attributes.map { |k, v| [klass.database_field_name(k.to_s), v] }]
474
+ query.send(method, attributes.__consolidate__(klass))
475
+ end
476
+
477
+ # Apply the field limitations.
478
+ #
479
+ # @api private
480
+ #
481
+ # @example Apply the field limitations.
482
+ # context.apply_fields
483
+ #
484
+ # @since 3.0.0
485
+ def apply_fields
486
+ if spec = criteria.options[:fields]
487
+ query.select(spec)
488
+ end
489
+ end
490
+
491
+ # Apply the options.
492
+ #
493
+ # @api private
494
+ #
495
+ # @example Apply all options.
496
+ # context.apply_options
497
+ #
498
+ # @since 3.1.0
499
+ def apply_options
500
+ apply_fields
501
+ [ :hint, :limit, :skip, :sort, :batch_size, :max_scan ].each do |name|
502
+ apply_option(name)
503
+ end
504
+ if criteria.options[:timeout] == false
505
+ query.no_timeout
506
+ end
507
+ end
508
+
509
+ # Apply an option.
510
+ #
511
+ # @api private
512
+ #
513
+ # @example Apply the skip option.
514
+ # context.apply_option(:skip)
515
+ #
516
+ # @since 3.1.0
517
+ def apply_option(name)
518
+ if spec = criteria.options[name]
519
+ query.send(name, spec)
520
+ end
521
+ end
522
+
523
+ # Apply an ascending id sort for use with #first queries, only if no
524
+ # other sorting is provided.
525
+ #
526
+ # @api private
527
+ #
528
+ # @example Apply the id sorting params to the given block
529
+ # context.with_sorting
530
+ #
531
+ # @since 3.0.0
532
+ def with_sorting
533
+ begin
534
+ unless criteria.options.has_key?(:sort)
535
+ query.sort(_id: 1)
536
+ end
537
+ yield
538
+ ensure
539
+ apply_option(:sort)
540
+ end
541
+ end
542
+
543
+ # Map the inverse sort symbols to the correct MongoDB values.
544
+ #
545
+ # @api private
546
+ #
547
+ # @example Apply the inverse sorting params to the given block
548
+ # context.with_inverse_sorting
549
+ #
550
+ # @since 3.0.0
551
+ def with_inverse_sorting
552
+ begin
553
+ if spec = criteria.options[:sort]
554
+ query.sort(Hash[spec.map{|k, v| [k, -1*v]}])
555
+ else
556
+ query.sort(_id: -1)
557
+ end
558
+ yield
559
+ ensure
560
+ apply_option(:sort)
561
+ end
562
+ end
563
+
564
+ # Is the cache able to be added to?
565
+ #
566
+ # @api private
567
+ #
568
+ # @example Is the context cacheable?
569
+ # context.cacheable?
570
+ #
571
+ # @return [ true, false ] If caching, and the cache isn't loaded.
572
+ #
573
+ # @since 3.0.0
574
+ def cacheable?
575
+ cached? && !cache_loaded?
576
+ end
577
+
578
+ # Is the cache fully loaded? Will be true if caching after one full
579
+ # iteration.
580
+ #
581
+ # @api private
582
+ #
583
+ # @example Is the cache loaded?
584
+ # context.cache_loaded?
585
+ #
586
+ # @return [ true, false ] If the cache is loaded.
587
+ #
588
+ # @since 3.0.0
589
+ def cache_loaded?
590
+ !!@cache_loaded
591
+ end
592
+
593
+ # Get the documents for cached queries.
594
+ #
595
+ # @api private
596
+ #
597
+ # @example Get the cached documents.
598
+ # context.documents
599
+ #
600
+ # @return [ Array<Document> ] The documents.
601
+ #
602
+ # @since 3.0.0
603
+ def documents
604
+ @documents ||= []
605
+ end
606
+
607
+ # Get the documents the context should iterate. This follows 3 rules:
608
+ #
609
+ # 1. If the query is cached, and we already have documents loaded, use
610
+ # them.
611
+ # 2. If we are eager loading, then eager load the documents and use
612
+ # those.
613
+ # 3. Use the query.
614
+ #
615
+ # @api private
616
+ #
617
+ # @example Get the documents for iteration.
618
+ # context.documents_for_iteration
619
+ #
620
+ # @return [ Array<Document>, Moped::Query ] The docs to iterate.
621
+ #
622
+ # @since 3.0.0
623
+ def documents_for_iteration
624
+ if cached? && !documents.empty?
625
+ documents
626
+ elsif eager_loadable?
627
+ docs = query.map{ |doc| Factory.from_db(klass, doc) }
628
+ eager_load(docs)
629
+ docs
630
+ else
631
+ query
632
+ end
633
+ end
634
+
635
+ # If we are limiting results, we need to set the field limitations on a
636
+ # thread local to avoid overriding the default values.
637
+ #
638
+ # @example Execute with selection.
639
+ # context.selecting do
640
+ # collection.find
641
+ # end
642
+ #
643
+ # @return [ Object ] The yielded value.
644
+ #
645
+ # @since 2.4.4
646
+ def selecting
647
+ begin
648
+ fields = criteria.options[:fields]
649
+ Threaded.set_selection(criteria.object_id, fields) unless fields.blank?
650
+ yield
651
+ ensure
652
+ Threaded.delete_selection(criteria.object_id)
653
+ end
654
+ end
655
+
656
+ # Yield to the document.
657
+ #
658
+ # @api private
659
+ #
660
+ # @example Yield the document.
661
+ # context.yield_document(doc) do |doc|
662
+ # ...
663
+ # end
664
+ #
665
+ # @param [ Document ] document The document to yield to.
666
+ #
667
+ # @since 3.0.0
668
+ def yield_document(document, &block)
669
+ doc = document.respond_to?(:_id) ?
670
+ document : Factory.from_db(klass, document, criteria.object_id)
671
+ yield(doc)
672
+ documents.push(doc) if cacheable?
673
+ end
674
+ end
675
+ end
676
+ end