mongoid 2.4.9 → 3.0.0.rc

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