mongoid 7.6.0 → 8.0.1

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 (313) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data/README.md +3 -3
  4. data/Rakefile +21 -85
  5. data/lib/config/locales/en.yml +46 -30
  6. data/lib/mongoid/association/accessors.rb +32 -3
  7. data/lib/mongoid/association/bindable.rb +48 -0
  8. data/lib/mongoid/association/builders.rb +4 -2
  9. data/lib/mongoid/association/eager_loadable.rb +29 -7
  10. data/lib/mongoid/association/embedded/batchable.rb +28 -5
  11. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  12. data/lib/mongoid/association/embedded/embedded_in.rb +2 -1
  13. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  14. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +1 -1
  15. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +40 -18
  16. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +18 -4
  17. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +21 -2
  18. data/lib/mongoid/association/macros.rb +2 -1
  19. data/lib/mongoid/association/many.rb +5 -0
  20. data/lib/mongoid/association/nested/many.rb +2 -1
  21. data/lib/mongoid/association/proxy.rb +12 -0
  22. data/lib/mongoid/association/referenced/auto_save.rb +3 -2
  23. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  24. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  25. data/lib/mongoid/association/referenced/belongs_to.rb +1 -1
  26. data/lib/mongoid/association/referenced/counter_cache.rb +8 -8
  27. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +64 -11
  28. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +4 -1
  29. data/lib/mongoid/association/referenced/has_many/enumerable.rb +10 -18
  30. data/lib/mongoid/association/referenced/has_many/proxy.rb +12 -9
  31. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  32. data/lib/mongoid/association/referenced/has_one/proxy.rb +8 -11
  33. data/lib/mongoid/association/referenced/syncable.rb +2 -2
  34. data/lib/mongoid/association/relatable.rb +38 -4
  35. data/lib/mongoid/attributes/processing.rb +9 -2
  36. data/lib/mongoid/attributes.rb +30 -27
  37. data/lib/mongoid/cacheable.rb +2 -2
  38. data/lib/mongoid/changeable.rb +37 -2
  39. data/lib/mongoid/clients/options.rb +4 -0
  40. data/lib/mongoid/clients/sessions.rb +2 -14
  41. data/lib/mongoid/config.rb +15 -11
  42. data/lib/mongoid/contextual/aggregable/memory.rb +23 -15
  43. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  44. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  45. data/lib/mongoid/contextual/memory.rb +55 -28
  46. data/lib/mongoid/contextual/mongo.rb +173 -287
  47. data/lib/mongoid/contextual/none.rb +33 -15
  48. data/lib/mongoid/copyable.rb +32 -8
  49. data/lib/mongoid/criteria/includable.rb +24 -20
  50. data/lib/mongoid/criteria/marshalable.rb +10 -2
  51. data/lib/mongoid/criteria/queryable/extensions/array.rb +2 -15
  52. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  53. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  54. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  55. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  56. data/lib/mongoid/criteria/queryable/extensions/hash.rb +0 -16
  57. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  58. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  59. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  60. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +1 -1
  61. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +3 -1
  62. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  63. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  64. data/lib/mongoid/criteria/queryable/optional.rb +3 -9
  65. data/lib/mongoid/criteria/queryable/options.rb +1 -1
  66. data/lib/mongoid/criteria/queryable/selectable.rb +2 -24
  67. data/lib/mongoid/criteria/queryable/selector.rb +90 -5
  68. data/lib/mongoid/criteria/queryable/smash.rb +39 -6
  69. data/lib/mongoid/criteria/queryable/storable.rb +1 -1
  70. data/lib/mongoid/criteria/queryable.rb +11 -6
  71. data/lib/mongoid/criteria.rb +1 -28
  72. data/lib/mongoid/deprecable.rb +36 -0
  73. data/lib/mongoid/deprecation.rb +25 -0
  74. data/lib/mongoid/document.rb +88 -33
  75. data/lib/mongoid/equality.rb +4 -4
  76. data/lib/mongoid/errors/document_not_found.rb +6 -2
  77. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  78. data/lib/mongoid/errors/invalid_field.rb +5 -1
  79. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  80. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  81. data/lib/mongoid/errors.rb +2 -2
  82. data/lib/mongoid/extensions/array.rb +8 -6
  83. data/lib/mongoid/extensions/big_decimal.rb +29 -10
  84. data/lib/mongoid/extensions/binary.rb +42 -0
  85. data/lib/mongoid/extensions/boolean.rb +8 -2
  86. data/lib/mongoid/extensions/date.rb +26 -20
  87. data/lib/mongoid/extensions/date_time.rb +1 -1
  88. data/lib/mongoid/extensions/float.rb +4 -5
  89. data/lib/mongoid/extensions/hash.rb +12 -5
  90. data/lib/mongoid/extensions/integer.rb +4 -5
  91. data/lib/mongoid/extensions/object.rb +2 -0
  92. data/lib/mongoid/extensions/range.rb +41 -10
  93. data/lib/mongoid/extensions/regexp.rb +11 -4
  94. data/lib/mongoid/extensions/set.rb +11 -4
  95. data/lib/mongoid/extensions/string.rb +2 -13
  96. data/lib/mongoid/extensions/symbol.rb +3 -14
  97. data/lib/mongoid/extensions/time.rb +27 -16
  98. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  99. data/lib/mongoid/extensions.rb +1 -0
  100. data/lib/mongoid/factory.rb +42 -7
  101. data/lib/mongoid/fields/foreign_key.rb +7 -0
  102. data/lib/mongoid/fields/validators/macro.rb +3 -9
  103. data/lib/mongoid/fields.rb +49 -7
  104. data/lib/mongoid/findable.rb +21 -16
  105. data/lib/mongoid/indexable/specification.rb +1 -1
  106. data/lib/mongoid/indexable/validators/options.rb +4 -1
  107. data/lib/mongoid/interceptable.rb +69 -9
  108. data/lib/mongoid/persistable/creatable.rb +14 -5
  109. data/lib/mongoid/persistable/updatable.rb +12 -5
  110. data/lib/mongoid/persistence_context.rb +8 -42
  111. data/lib/mongoid/query_cache.rb +6 -258
  112. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  113. data/lib/mongoid/reloadable.rb +7 -3
  114. data/lib/mongoid/scopable.rb +9 -11
  115. data/lib/mongoid/selectable.rb +1 -2
  116. data/lib/mongoid/shardable.rb +11 -35
  117. data/lib/mongoid/stateful.rb +27 -1
  118. data/lib/mongoid/timestamps/created.rb +1 -1
  119. data/lib/mongoid/timestamps/updated.rb +1 -1
  120. data/lib/mongoid/touchable.rb +2 -3
  121. data/lib/mongoid/traversable.rb +1 -0
  122. data/lib/mongoid/validatable/uniqueness.rb +2 -1
  123. data/lib/mongoid/version.rb +1 -5
  124. data/lib/mongoid/warnings.rb +3 -4
  125. data/lib/mongoid.rb +1 -0
  126. data/spec/config/mongoid.yml +16 -0
  127. data/spec/integration/app_spec.rb +8 -12
  128. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  129. data/spec/integration/associations/embedded_spec.rb +15 -0
  130. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  131. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  132. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  133. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  134. data/spec/integration/associations/has_one_spec.rb +97 -1
  135. data/spec/integration/associations/scope_option_spec.rb +1 -1
  136. data/spec/integration/callbacks_models.rb +95 -1
  137. data/spec/integration/callbacks_spec.rb +226 -4
  138. data/spec/integration/criteria/range_spec.rb +95 -1
  139. data/spec/integration/discriminator_key_spec.rb +115 -76
  140. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  141. data/spec/integration/i18n_fallbacks_spec.rb +1 -15
  142. data/spec/integration/matcher_examples_spec.rb +20 -13
  143. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  144. data/spec/integration/matcher_operator_spec.rb +3 -5
  145. data/spec/integration/persistence/range_field_spec.rb +350 -0
  146. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  147. data/spec/mongoid/association/depending_spec.rb +9 -9
  148. data/spec/mongoid/association/eager_spec.rb +2 -1
  149. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  150. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  151. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  152. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  153. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +198 -8
  154. data/spec/mongoid/association/embedded/embeds_many_models.rb +36 -0
  155. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  156. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  157. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  158. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  159. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  160. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  161. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  162. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  163. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  164. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  165. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +38 -5
  166. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  167. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  168. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  169. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
  170. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +62 -13
  171. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  172. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  173. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  174. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  175. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  176. data/spec/mongoid/association/syncable_spec.rb +14 -0
  177. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  178. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  179. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  180. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  181. data/spec/mongoid/attributes_spec.rb +480 -27
  182. data/spec/mongoid/cacheable_spec.rb +3 -3
  183. data/spec/mongoid/changeable_spec.rb +130 -13
  184. data/spec/mongoid/clients/factory_spec.rb +23 -30
  185. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  186. data/spec/mongoid/clients_spec.rb +2 -2
  187. data/spec/mongoid/config_spec.rb +52 -15
  188. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  189. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  190. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  191. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  192. data/spec/mongoid/contextual/memory_spec.rb +521 -14
  193. data/spec/mongoid/contextual/mongo_spec.rb +566 -426
  194. data/spec/mongoid/contextual/none_spec.rb +11 -19
  195. data/spec/mongoid/copyable_spec.rb +451 -2
  196. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  197. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  198. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  199. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  200. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  201. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  202. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +1 -2
  203. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  204. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  205. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +1 -2
  206. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  207. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  208. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  209. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  210. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  211. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  212. data/spec/mongoid/criteria/queryable/selectable_spec.rb +77 -85
  213. data/spec/mongoid/criteria/queryable/selector_spec.rb +16 -77
  214. data/spec/mongoid/criteria/queryable/storable_spec.rb +0 -72
  215. data/spec/mongoid/criteria_spec.rb +469 -1201
  216. data/spec/mongoid/document_fields_spec.rb +173 -24
  217. data/spec/mongoid/document_spec.rb +32 -41
  218. data/spec/mongoid/equality_spec.rb +12 -12
  219. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  220. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  221. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  222. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  223. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  224. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  225. data/spec/mongoid/extensions/array_spec.rb +16 -2
  226. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  227. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  228. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  229. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  230. data/spec/mongoid/extensions/date_spec.rb +71 -1
  231. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  232. data/spec/mongoid/extensions/float_spec.rb +48 -76
  233. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  234. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  235. data/spec/mongoid/extensions/range_spec.rb +255 -54
  236. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  237. data/spec/mongoid/extensions/set_spec.rb +106 -0
  238. data/spec/mongoid/extensions/string_spec.rb +53 -25
  239. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  240. data/spec/mongoid/extensions/time_spec.rb +634 -66
  241. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  242. data/spec/mongoid/factory_spec.rb +61 -1
  243. data/spec/mongoid/fields_spec.rb +321 -50
  244. data/spec/mongoid/findable_spec.rb +64 -29
  245. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  246. data/spec/mongoid/indexable_spec.rb +16 -19
  247. data/spec/mongoid/interceptable_spec.rb +584 -5
  248. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  249. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  250. data/spec/mongoid/mongoizable_spec.rb +285 -0
  251. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  252. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  253. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  254. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  255. data/spec/mongoid/persistence_context_spec.rb +24 -0
  256. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  257. data/spec/mongoid/query_cache_spec.rb +1 -156
  258. data/spec/mongoid/reloadable_spec.rb +35 -2
  259. data/spec/mongoid/scopable_spec.rb +36 -34
  260. data/spec/mongoid/serializable_spec.rb +14 -7
  261. data/spec/mongoid/shardable_models.rb +0 -14
  262. data/spec/mongoid/shardable_spec.rb +61 -153
  263. data/spec/mongoid/stateful_spec.rb +28 -0
  264. data/spec/mongoid/timestamps_spec.rb +390 -0
  265. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  266. data/spec/mongoid/touchable_spec.rb +116 -0
  267. data/spec/mongoid/touchable_spec_models.rb +12 -8
  268. data/spec/mongoid/traversable_spec.rb +4 -11
  269. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  270. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  271. data/spec/mongoid/warnings_spec.rb +35 -0
  272. data/spec/mongoid_spec.rb +1 -7
  273. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  274. data/spec/rails/mongoid_spec.rb +4 -16
  275. data/spec/shared/lib/mrss/docker_runner.rb +1 -8
  276. data/spec/shared/lib/mrss/event_subscriber.rb +5 -15
  277. data/spec/shared/lib/mrss/lite_constraints.rb +2 -10
  278. data/spec/shared/lib/mrss/server_version_registry.rb +24 -17
  279. data/spec/shared/lib/mrss/spec_organizer.rb +3 -32
  280. data/spec/shared/lib/mrss/utils.rb +6 -28
  281. data/spec/shared/share/Dockerfile.erb +107 -33
  282. data/spec/shared/shlib/distro.sh +0 -10
  283. data/spec/shared/shlib/server.sh +33 -64
  284. data/spec/shared/shlib/set_env.sh +71 -12
  285. data/spec/support/constraints.rb +24 -0
  286. data/spec/support/expectations.rb +17 -20
  287. data/spec/support/macros.rb +30 -0
  288. data/spec/support/models/augmentation.rb +12 -0
  289. data/spec/support/models/band.rb +3 -0
  290. data/spec/support/models/catalog.rb +24 -0
  291. data/spec/support/models/circus.rb +3 -0
  292. data/spec/support/models/fanatic.rb +8 -0
  293. data/spec/support/models/implant.rb +9 -0
  294. data/spec/support/models/label.rb +2 -0
  295. data/spec/support/models/passport.rb +9 -0
  296. data/spec/support/models/person.rb +1 -0
  297. data/spec/support/models/player.rb +2 -0
  298. data/spec/support/models/powerup.rb +12 -0
  299. data/spec/support/models/registry.rb +1 -0
  300. data/spec/support/models/school.rb +14 -0
  301. data/spec/support/models/shield.rb +18 -0
  302. data/spec/support/models/student.rb +14 -0
  303. data/spec/support/models/weapon.rb +12 -0
  304. data.tar.gz.sig +0 -0
  305. metadata +695 -641
  306. metadata.gz.sig +0 -0
  307. data/lib/mongoid/errors/eager_load.rb +0 -23
  308. data/lib/mongoid/errors/invalid_value.rb +0 -17
  309. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
  310. data/spec/shared/CANDIDATE.md +0 -28
  311. data/spec/shared/lib/mrss/release/candidate.rb +0 -281
  312. data/spec/shared/lib/mrss/release/product_data.rb +0 -144
  313. data/spec/shared/lib/tasks/candidate.rake +0 -64
@@ -17,6 +17,8 @@ module Mongoid
17
17
  include Association::EagerLoadable
18
18
  include Queryable
19
19
 
20
+ Mongoid.deprecate(self, :geo_near)
21
+
20
22
  # Options constant.
21
23
  OPTIONS = [ :hint,
22
24
  :limit,
@@ -35,17 +37,6 @@ module Mongoid
35
37
  # @attribute [r] view The Mongo collection view.
36
38
  attr_reader :view
37
39
 
38
- # Is the context cached?
39
- #
40
- # @example Is the context cached?
41
- # context.cached?
42
- #
43
- # @return [ true, false ] If the context is cached.
44
- def cached?
45
- Mongoid::Warnings.warn_criteria_cache_deprecated
46
- !!@cache
47
- end
48
-
49
40
  # Get the number of documents matching the query.
50
41
  #
51
42
  # @example Get the number of matching documents.
@@ -65,14 +56,7 @@ module Mongoid
65
56
  # @return [ Integer ] The number of matches.
66
57
  def count(options = {}, &block)
67
58
  return super(&block) if block_given?
68
-
69
- try_cache(:count) do
70
- if valid_for_count_documents?
71
- view.count_documents(options)
72
- else
73
- view.count(options)
74
- end
75
- end
59
+ view.count_documents(options)
76
60
  end
77
61
 
78
62
  # Get the estimated number of documents matching the query.
@@ -91,7 +75,7 @@ module Mongoid
91
75
  unless self.criteria.selector.empty?
92
76
  raise Mongoid::Errors::InvalidEstimatedCountCriteria.new(self.klass)
93
77
  end
94
- try_cache(:estimated_count) { view.estimated_document_count(options) }
78
+ view.estimated_document_count(options)
95
79
  end
96
80
 
97
81
  # Delete all documents in the database that match the selector.
@@ -159,7 +143,6 @@ module Mongoid
159
143
  documents_for_iteration.each do |doc|
160
144
  yield_document(doc, &block)
161
145
  end
162
- @cache_loaded = true
163
146
  self
164
147
  else
165
148
  to_enum
@@ -172,17 +155,11 @@ module Mongoid
172
155
  # context.exists?
173
156
  #
174
157
  # @note We don't use count here since Mongo does not use counted
175
- # b-tree indexes, unless a count is already cached then that is
176
- # used to determine the value.
158
+ # b-tree indexes.
177
159
  #
178
160
  # @return [ true, false ] If the count is more than zero.
179
161
  def exists?
180
- return !documents.empty? if cached? && cache_loaded?
181
- return @count > 0 if instance_variable_defined?(:@count)
182
-
183
- try_cache(:exists) do
184
- !!(view.projection(_id: 1).limit(1).first)
185
- end
162
+ !!(view.projection(_id: 1).limit(1).first)
186
163
  end
187
164
 
188
165
  # Run an explain on the criteria.
@@ -256,32 +233,16 @@ module Mongoid
256
233
  # @note Automatically adding a sort on _id when no other sort is
257
234
  # defined on the criteria has the potential to cause bad performance issues.
258
235
  # If you experience unexpected poor performance when using #first or #last
259
- # and have no sort defined on the criteria, use the option { id_sort: :none }.
260
- # Be aware that #first/#last won't guarantee order in this case.
261
- #
262
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
263
- # return, or a hash of options.
236
+ # and have no sort defined on the criteria, use #take instead.
237
+ # Be aware that #take won't guarantee order.
264
238
  #
265
- # @option limit_or_opts [ :none ] :id_sort This option is deprecated.
266
- # Don't apply a sort on _id if no other sort is defined on the criteria.
239
+ # @param [ Integer ] limit The number of documents to return.
267
240
  #
268
241
  # @return [ Document ] The first document.
269
- def first(limit_or_opts = nil)
270
- limit, opts = extract_limit_and_opts(limit_or_opts)
271
- if cached? && cache_loaded?
272
- return limit ? documents.first(limit) : documents.first
273
- end
274
- try_numbered_cache(:first, limit) do
275
- if opts.key?(:id_sort)
276
- Mongoid::Warnings.warn_id_sort_deprecated
277
- end
278
- sorted_view = view
279
- if sort = view.sort || ({ _id: 1 } unless opts[:id_sort] == :none)
280
- sorted_view = view.sort(sort)
281
- end
282
- if raw_docs = sorted_view.limit(limit || 1).to_a
283
- process_raw_docs(raw_docs, limit)
284
- end
242
+ def first(limit = nil)
243
+ sort = view.sort || { _id: 1 }
244
+ if raw_docs = view.sort(sort).limit(limit || 1).to_a
245
+ process_raw_docs(raw_docs, limit)
285
246
  end
286
247
  end
287
248
  alias :one :first
@@ -290,7 +251,6 @@ module Mongoid
290
251
  #
291
252
  # @api private
292
253
  def find_first
293
- return documents.first if cached? && cache_loaded?
294
254
  if raw_doc = view.first
295
255
  doc = Factory.from_db(klass, raw_doc, criteria)
296
256
  eager_load([doc]).first
@@ -320,33 +280,6 @@ module Mongoid
320
280
  GeoNear.new(collection, criteria, coordinates)
321
281
  end
322
282
 
323
- # Invoke the block for each element of Contextual. Create a new array
324
- # containing the values returned by the block.
325
- #
326
- # If the symbol field name is passed instead of the block, additional
327
- # optimizations would be used.
328
- #
329
- # @example Map by some field.
330
- # context.map(:field1)
331
- #
332
- # @example Map with block.
333
- # context.map(&:field1)
334
- #
335
- # @param [ Symbol ] field The field name.
336
- #
337
- # @return [ Array ] The result of mapping.
338
- def map(field = nil, &block)
339
- if !field.nil?
340
- Mongoid::Warnings.warn_map_field_deprecated
341
- end
342
-
343
- if block_given?
344
- super(&block)
345
- else
346
- criteria.pluck(field)
347
- end
348
- end
349
-
350
283
  # Create the new Mongo context. This delegates operations to the
351
284
  # underlying driver.
352
285
  #
@@ -355,7 +288,7 @@ module Mongoid
355
288
  #
356
289
  # @param [ Criteria ] criteria The criteria.
357
290
  def initialize(criteria)
358
- @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
291
+ @criteria, @klass = criteria, criteria.klass
359
292
  @collection = @klass.collection
360
293
  criteria.send(:merge_type_selection)
361
294
  @view = collection.find(criteria.selector, session: _session)
@@ -372,39 +305,26 @@ module Mongoid
372
305
  # @note Automatically adding a sort on _id when no other sort is
373
306
  # defined on the criteria has the potential to cause bad performance issues.
374
307
  # If you experience unexpected poor performance when using #first or #last
375
- # and have no sort defined on the criteria, use the option { id_sort: :none }.
376
- # Be aware that #first/#last won't guarantee order in this case.
377
- #
378
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
379
- # return, or a hash of options.
308
+ # and have no sort defined on the criteria, use #take instead.
309
+ # Be aware that #take won't guarantee order.
380
310
  #
381
- # @option limit_or_opts [ :none ] :id_sort This option is deprecated.
382
- # Don't apply a sort on _id if no other sort is defined on the criteria.
311
+ # @param [ Integer ] limit The number of documents to return.
383
312
  #
384
313
  # @return [ Document ] The last document.
385
- def last(limit_or_opts = nil)
386
- limit, opts = extract_limit_and_opts(limit_or_opts)
387
- if cached? && cache_loaded?
388
- return limit ? documents.last(limit) : documents.last
389
- end
390
- res = try_numbered_cache(:last, limit) do
391
- with_inverse_sorting(opts) do
392
- if raw_docs = view.limit(limit || 1).to_a
393
- process_raw_docs(raw_docs, limit)
394
- end
395
- end
396
- end
397
- res.is_a?(Array) ? res.reverse : res
314
+ def last(limit = nil)
315
+ raw_docs = view.sort(inverse_sorting).limit(limit || 1).to_a.reverse
316
+ process_raw_docs(raw_docs, limit)
398
317
  end
399
318
 
400
- # Get's the number of documents matching the query selector.
319
+ # Returns the number of documents in the database matching
320
+ # the query selector.
401
321
  #
402
322
  # @example Get the length.
403
323
  # context.length
404
324
  #
405
325
  # @return [ Integer ] The number of documents.
406
326
  def length
407
- @length ||= self.count
327
+ self.count
408
328
  end
409
329
  alias :size :length
410
330
 
@@ -477,9 +397,6 @@ module Mongoid
477
397
  # @example Pluck a field.
478
398
  # context.pluck(:_id)
479
399
  #
480
- # @note This method will return the raw db values - it performs no custom
481
- # serialization.
482
- #
483
400
  # @param [ String, Symbol, Array ] fields Fields to pluck.
484
401
  #
485
402
  # @return [ Array<Object, Array> ] The plucked values.
@@ -512,6 +429,87 @@ module Mongoid
512
429
  end
513
430
  end
514
431
 
432
+ # Pick the single field values from the database.
433
+ #
434
+ # @example Pick a field.
435
+ # context.pick(:_id)
436
+ #
437
+ # @param [ String, Symbol, Array ] fields Fields to pick.
438
+ #
439
+ # @return [ Object, Array<Object> ] The picked values.
440
+ def pick(*fields)
441
+ limit(1).pluck(*fields).first
442
+ end
443
+
444
+ # Get a hash of counts for the values of a single field. For example,
445
+ # if the following documents were in the database:
446
+ #
447
+ # { _id: 1, age: 21 }
448
+ # { _id: 2, age: 21 }
449
+ # { _id: 3, age: 22 }
450
+ #
451
+ # Model.tally("age")
452
+ #
453
+ # would yield the following result:
454
+ #
455
+ # { 21 => 2, 22 => 1 }
456
+ #
457
+ # When tallying a field inside an array or embeds_many association:
458
+ #
459
+ # { _id: 1, array: [ { x: 1 }, { x: 2 } ] }
460
+ # { _id: 2, array: [ { x: 1 }, { x: 2 } ] }
461
+ # { _id: 3, array: [ { x: 1 }, { x: 3 } ] }
462
+ #
463
+ # Model.tally("array.x")
464
+ #
465
+ # The keys of the resulting hash are arrays:
466
+ #
467
+ # { [ 1, 2 ] => 2, [ 1, 3 ] => 1 }
468
+ #
469
+ # Note that if tallying an element in an array of hashes, and the key
470
+ # doesn't exist in some of the hashes, tally will not include those
471
+ # nil keys in the resulting hash:
472
+ #
473
+ # { _id: 1, array: [ { x: 1 }, { x: 2 }, { y: 3 } ] }
474
+ #
475
+ # Model.tally("array.x")
476
+ # # => { [ 1, 2 ] => 1 }
477
+ #
478
+ # @param [ String | Symbol ] field The field name.
479
+ #
480
+ # @return [ Hash ] The hash of counts.
481
+ def tally(field)
482
+ name = klass.cleanse_localized_field_names(field)
483
+
484
+ fld = klass.traverse_association_tree(name)
485
+ pipeline = [ { "$group" => { _id: "$#{name}", counts: { "$sum": 1 } } } ]
486
+ pipeline.unshift("$match" => view.filter) unless view.filter.blank?
487
+
488
+ collection.aggregate(pipeline).reduce({}) do |tallies, doc|
489
+ is_translation = "#{name}_translations" == field.to_s
490
+ val = doc["_id"]
491
+
492
+ key = if val.is_a?(Array)
493
+ val.map do |v|
494
+ demongoize_with_field(fld, v, is_translation)
495
+ end
496
+ else
497
+ demongoize_with_field(fld, val, is_translation)
498
+ end
499
+
500
+ # The only time where a key will already exist in the tallies hash
501
+ # is when the values are stored differently in the database, but
502
+ # demongoize to the same value. A good example of when this happens
503
+ # is when using localized fields. While the server query won't group
504
+ # together hashes that have other values in different languages, the
505
+ # demongoized value is just the translation in the current locale,
506
+ # which can be the same across multiple of those unequal hashes.
507
+ tallies[key] ||= 0
508
+ tallies[key] += doc["counts"]
509
+ tallies
510
+ end
511
+ end
512
+
515
513
  # Skips the provided number of documents.
516
514
  #
517
515
  # @example Skip the documents.
@@ -578,64 +576,6 @@ module Mongoid
578
576
 
579
577
  private
580
578
 
581
- # yield the block given or return the cached value
582
- #
583
- # @param [ String, Symbol ] key The instance variable name
584
- #
585
- # @return the result of the block
586
- def try_cache(key, &block)
587
- unless cached?
588
- yield
589
- else
590
- unless ret = instance_variable_get("@#{key}")
591
- instance_variable_set("@#{key}", ret = yield)
592
- end
593
- ret
594
- end
595
- end
596
-
597
- # yield the block given or return the cached value
598
- #
599
- # @param [ String, Symbol ] key The instance variable name
600
- # @param [ Integer | nil ] n The number of documents requested or nil
601
- # if none is requested.
602
- #
603
- # @return [ Object ] The result of the block.
604
- def try_numbered_cache(key, n, &block)
605
- unless cached?
606
- yield if block_given?
607
- else
608
- len = n || 1
609
- ret = instance_variable_get("@#{key}")
610
- if !ret || ret.length < len
611
- instance_variable_set("@#{key}", ret = Array.wrap(yield))
612
- elsif !n
613
- ret.is_a?(Array) ? ret.first : ret
614
- elsif ret.length > len
615
- ret.first(n)
616
- else
617
- ret
618
- end
619
- end
620
- end
621
-
622
- # Extract the limit and opts from the given argument, so that code
623
- # can operate without having to worry about the current type and
624
- # state of the argument.
625
- #
626
- # @param [ nil | Integer | Hash ] limit_or_opts The value to pull the
627
- # limit and option hash from.
628
- #
629
- # @return [ Array<nil | Integer, Hash> ] A 2-array of the limit and the
630
- # option hash.
631
- def extract_limit_and_opts(limit_or_opts)
632
- case limit_or_opts
633
- when nil, Integer then [ limit_or_opts, {} ]
634
- when Hash then [ nil, limit_or_opts ]
635
- else raise ArgumentError, "expected nil, Integer, or Hash"
636
- end
637
- end
638
-
639
579
  # Update the documents for the provided method.
640
580
  #
641
581
  # @api private
@@ -696,57 +636,9 @@ module Mongoid
696
636
  # Map the inverse sort symbols to the correct MongoDB values.
697
637
  #
698
638
  # @api private
699
- #
700
- # @example Apply the inverse sorting params to the given block
701
- # context.with_inverse_sorting
702
- def with_inverse_sorting(opts = {})
703
- Mongoid::Warnings.warn_id_sort_deprecated if opts.key?(:id_sort)
704
-
705
- begin
706
- if sort = criteria.options[:sort] || ( { _id: 1 } unless opts[:id_sort] == :none )
707
- @view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
708
- end
709
- yield
710
- ensure
711
- apply_option(:sort)
712
- end
713
- end
714
-
715
- # Is the cache able to be added to?
716
- #
717
- # @api private
718
- #
719
- # @example Is the context cacheable?
720
- # context.cacheable?
721
- #
722
- # @return [ true, false ] If caching, and the cache isn't loaded.
723
- def cacheable?
724
- cached? && !cache_loaded?
725
- end
726
-
727
- # Is the cache fully loaded? Will be true if caching after one full
728
- # iteration.
729
- #
730
- # @api private
731
- #
732
- # @example Is the cache loaded?
733
- # context.cache_loaded?
734
- #
735
- # @return [ true, false ] If the cache is loaded.
736
- def cache_loaded?
737
- !!@cache_loaded
738
- end
739
-
740
- # Get the documents for cached queries.
741
- #
742
- # @api private
743
- #
744
- # @example Get the cached documents.
745
- # context.documents
746
- #
747
- # @return [ Array<Document> ] The documents.
748
- def documents
749
- @documents ||= []
639
+ def inverse_sorting
640
+ sort = view.sort || { _id: 1 }
641
+ Hash[sort.map{|k, v| [k, -1*v]}]
750
642
  end
751
643
 
752
644
  # Get the documents the context should iterate. This follows 3 rules:
@@ -764,7 +656,6 @@ module Mongoid
764
656
  #
765
657
  # @return [ Array<Document>, Mongo::Collection::View ] The docs to iterate.
766
658
  def documents_for_iteration
767
- return documents if cached? && !documents.empty?
768
659
  return view unless eager_loadable?
769
660
  docs = view.map{ |doc| Factory.from_db(klass, doc, criteria) }
770
661
  eager_load(docs)
@@ -784,7 +675,6 @@ module Mongoid
784
675
  doc = document.respond_to?(:_id) ?
785
676
  document : Factory.from_db(klass, document, criteria)
786
677
  yield(doc)
787
- documents.push(doc) if cacheable?
788
678
  end
789
679
 
790
680
  private
@@ -797,6 +687,26 @@ module Mongoid
797
687
  collection.write_concern.nil? || collection.write_concern.acknowledged?
798
688
  end
799
689
 
690
+ # Fetch the element from the given hash and demongoize it using the
691
+ # given field. If the obj is an array, map over it and call this method
692
+ # on all of its elements.
693
+ #
694
+ # @param [ Hash | Array<Hash> ] obj The hash or array of hashes to fetch from.
695
+ # @param [ String ] meth The key to fetch from the hash.
696
+ # @param [ Field ] field The field to use for demongoization.
697
+ #
698
+ # @return [ Object ] The demongoized value.
699
+ #
700
+ # @api private
701
+ def fetch_and_demongoize(obj, meth, field)
702
+ if obj.is_a?(Array)
703
+ obj.map { |doc| fetch_and_demongoize(doc, meth, field) }
704
+ else
705
+ res = obj.try(:fetch, meth, nil)
706
+ field ? field.demongoize(res) : res.class.demongoize(res)
707
+ end
708
+ end
709
+
800
710
  # Extracts the value for the given field name from the given attribute
801
711
  # hash.
802
712
  #
@@ -805,24 +715,18 @@ module Mongoid
805
715
  #
806
716
  # @param [ Object ] The value for the given field name
807
717
  def extract_value(attrs, field_name)
808
- def fetch_and_demongoize(d, meth, klass)
809
- res = d.try(:fetch, meth, nil)
810
- if field = klass.fields[meth]
811
- field.demongoize(res)
812
- else
813
- res.class.demongoize(res)
814
- end
815
- end
718
+ i = 1
719
+ num_meths = field_name.count('.') + 1
720
+ curr = attrs.dup
816
721
 
817
- k = klass
818
- meths = field_name.split('.')
819
- meths.each_with_index.inject(attrs) do |curr, (meth, i)|
722
+ klass.traverse_association_tree(field_name) do |meth, obj, is_field|
723
+ field = obj if is_field
820
724
  is_translation = false
821
- if !k.fields.key?(meth) && !k.relations.key?(meth)
822
- if tr = meth.match(/(.*)_translations\z/)&.captures&.first
823
- is_translation = true
824
- meth = tr
825
- end
725
+ # If no association or field was found, check if the meth is an
726
+ # _translations field.
727
+ if obj.nil? & tr = meth.match(/(.*)_translations\z/)&.captures&.first
728
+ is_translation = true
729
+ meth = tr
826
730
  end
827
731
 
828
732
  # 1. If curr is an array fetch from all elements in the array.
@@ -835,31 +739,24 @@ module Mongoid
835
739
  # 3. If the meth is an _translations field, do not demongoize the
836
740
  # value so the full hash is returned.
837
741
  # 4. Otherwise, fetch and demongoize the value for the key meth.
838
- if curr.is_a? Array
839
- res = curr.map { |x| fetch_and_demongoize(x, meth, k) }
742
+ curr = if curr.is_a? Array
743
+ res = fetch_and_demongoize(curr, meth, field)
840
744
  res.empty? ? nil : res
841
- elsif !is_translation && k.fields[meth]&.localized?
842
- if i < meths.length-1
745
+ elsif !is_translation && field&.localized?
746
+ if i < num_meths
843
747
  curr.try(:fetch, meth, nil)
844
748
  else
845
- fetch_and_demongoize(curr, meth, k)
749
+ fetch_and_demongoize(curr, meth, field)
846
750
  end
847
751
  elsif is_translation
848
752
  curr.try(:fetch, meth, nil)
849
753
  else
850
- fetch_and_demongoize(curr, meth, k)
851
- end.tap do
852
- if as = k.try(:aliased_associations)
853
- if a = as.fetch(meth, nil)
854
- meth = a
855
- end
856
- end
857
-
858
- if relation = k.relations[meth]
859
- k = relation.klass
860
- end
754
+ fetch_and_demongoize(curr, meth, field)
861
755
  end
756
+
757
+ i += 1
862
758
  end
759
+ curr
863
760
  end
864
761
 
865
762
  # Recursively demongoize the given value. This method recursively traverses
@@ -872,29 +769,36 @@ module Mongoid
872
769
  #
873
770
  # @return [ Object ] The demongoized value.
874
771
  def recursive_demongoize(field_name, value, is_translation)
875
- k = klass
876
- field_name.split('.').each do |meth|
877
- if as = k.try(:aliased_associations)
878
- if a = as.fetch(meth, nil)
879
- meth = a.to_s
880
- end
881
- end
772
+ field = klass.traverse_association_tree(field_name)
773
+ demongoize_with_field(field, value, is_translation)
774
+ end
882
775
 
883
- if relation = k.relations[meth]
884
- k = relation.klass
885
- elsif field = k.fields[meth]
886
- # If it's a localized field that's not a hash, don't demongoize
887
- # again, we already have the translation. If it's an _translation
888
- # field, don't demongoize, we want the full hash not just a
889
- # specific translation.
890
- if field.localized? && (!value.is_a?(Hash) || is_translation)
891
- return value.class.demongoize(value)
892
- else
893
- return field.demongoize(value)
894
- end
776
+ # Demongoize the value for the given field. If the field is nil or the
777
+ # field is a translations field, the value is demongoized using its class.
778
+ #
779
+ # @param [ Field ] field The field to use to demongoize.
780
+ # @param [ Object ] value The value to demongoize.
781
+ # @param [ Boolean ] is_translation The field we are retrieving is an
782
+ # _translations field.
783
+ #
784
+ # @return [ Object ] The demongoized value.
785
+ #
786
+ # @api private
787
+ def demongoize_with_field(field, value, is_translation)
788
+ if field
789
+ # If it's a localized field that's not a hash, don't demongoize
790
+ # again, we already have the translation. If it's an _translations
791
+ # field, don't demongoize, we want the full hash not just a
792
+ # specific translation.
793
+ # If it is a hash, and it's not a translations field, we need to
794
+ # demongoize to get the correct translation.
795
+ if field.localized? && (!value.is_a?(Hash) || is_translation)
796
+ value.class.demongoize(value)
895
797
  else
896
- return value.class.demongoize(value)
798
+ field.demongoize(value)
897
799
  end
800
+ else
801
+ value.class.demongoize(value)
898
802
  end
899
803
  end
900
804
 
@@ -909,24 +813,6 @@ module Mongoid
909
813
  docs = eager_load(docs)
910
814
  limit ? docs : docs.first
911
815
  end
912
-
913
- # Queries whether the current context is valid for use with
914
- # the #count_documents? predicate. A context is valid if it
915
- # does not include a `$where` operator.
916
- #
917
- # @return [ true | false ] whether or not the current context
918
- # excludes a `$where` operator.
919
- def valid_for_count_documents?(hash = view.filter)
920
- # Note that `view.filter` is a BSON::Document, and all keys in a
921
- # BSON::Document are strings; we don't need to worry about symbol
922
- # representations of `$where`.
923
- hash.keys.each do |key|
924
- return false if key == '$where'
925
- return false if hash[key].is_a?(Hash) && !valid_for_count_documents?(hash[key])
926
- end
927
-
928
- true
929
- end
930
816
  end
931
817
  end
932
818
  end