mongoid 7.5.4 → 8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (298) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +3 -3
  4. data/Rakefile +0 -25
  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 -262
  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 -1
  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 -14
  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 -416
  194. data/spec/mongoid/contextual/none_spec.rb +11 -19
  195. data/spec/mongoid/copyable_spec.rb +451 -1
  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/date_spec.rb +11 -0
  203. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  204. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  205. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  206. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  207. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  208. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  209. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  210. data/spec/mongoid/criteria/queryable/selectable_spec.rb +77 -85
  211. data/spec/mongoid/criteria/queryable/selector_spec.rb +16 -77
  212. data/spec/mongoid/criteria/queryable/storable_spec.rb +0 -72
  213. data/spec/mongoid/criteria_spec.rb +469 -1201
  214. data/spec/mongoid/document_fields_spec.rb +173 -24
  215. data/spec/mongoid/document_spec.rb +32 -41
  216. data/spec/mongoid/equality_spec.rb +12 -12
  217. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  218. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  219. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  220. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  221. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  222. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  223. data/spec/mongoid/extensions/array_spec.rb +16 -2
  224. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  225. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  226. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  227. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  228. data/spec/mongoid/extensions/date_spec.rb +71 -1
  229. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  230. data/spec/mongoid/extensions/float_spec.rb +48 -76
  231. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  232. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  233. data/spec/mongoid/extensions/range_spec.rb +255 -54
  234. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  235. data/spec/mongoid/extensions/set_spec.rb +106 -0
  236. data/spec/mongoid/extensions/string_spec.rb +53 -25
  237. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  238. data/spec/mongoid/extensions/time_spec.rb +634 -66
  239. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  240. data/spec/mongoid/factory_spec.rb +61 -1
  241. data/spec/mongoid/fields_spec.rb +321 -50
  242. data/spec/mongoid/findable_spec.rb +64 -29
  243. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  244. data/spec/mongoid/indexable_spec.rb +16 -19
  245. data/spec/mongoid/interceptable_spec.rb +584 -5
  246. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  247. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  248. data/spec/mongoid/mongoizable_spec.rb +285 -0
  249. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  250. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  251. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  252. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  253. data/spec/mongoid/persistence_context_spec.rb +24 -0
  254. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  255. data/spec/mongoid/query_cache_spec.rb +0 -154
  256. data/spec/mongoid/reloadable_spec.rb +35 -2
  257. data/spec/mongoid/scopable_spec.rb +36 -34
  258. data/spec/mongoid/shardable_models.rb +0 -14
  259. data/spec/mongoid/shardable_spec.rb +61 -153
  260. data/spec/mongoid/stateful_spec.rb +28 -0
  261. data/spec/mongoid/timestamps_spec.rb +390 -0
  262. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  263. data/spec/mongoid/touchable_spec.rb +116 -0
  264. data/spec/mongoid/touchable_spec_models.rb +12 -8
  265. data/spec/mongoid/traversable_spec.rb +4 -11
  266. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  267. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  268. data/spec/mongoid/warnings_spec.rb +35 -0
  269. data/spec/mongoid_spec.rb +1 -7
  270. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  271. data/spec/rails/mongoid_spec.rb +4 -16
  272. data/spec/shared/lib/mrss/event_subscriber.rb +5 -15
  273. data/spec/shared/lib/mrss/lite_constraints.rb +0 -8
  274. data/spec/shared/shlib/server.sh +5 -5
  275. data/spec/support/constraints.rb +24 -0
  276. data/spec/support/macros.rb +30 -0
  277. data/spec/support/models/augmentation.rb +12 -0
  278. data/spec/support/models/band.rb +3 -0
  279. data/spec/support/models/catalog.rb +24 -0
  280. data/spec/support/models/circus.rb +3 -0
  281. data/spec/support/models/fanatic.rb +8 -0
  282. data/spec/support/models/implant.rb +9 -0
  283. data/spec/support/models/label.rb +2 -0
  284. data/spec/support/models/passport.rb +9 -0
  285. data/spec/support/models/person.rb +1 -0
  286. data/spec/support/models/player.rb +2 -0
  287. data/spec/support/models/powerup.rb +12 -0
  288. data/spec/support/models/registry.rb +1 -0
  289. data/spec/support/models/school.rb +14 -0
  290. data/spec/support/models/shield.rb +18 -0
  291. data/spec/support/models/student.rb +14 -0
  292. data/spec/support/models/weapon.rb +12 -0
  293. data.tar.gz.sig +0 -0
  294. metadata +689 -657
  295. metadata.gz.sig +0 -0
  296. data/lib/mongoid/errors/eager_load.rb +0 -23
  297. data/lib/mongoid/errors/invalid_value.rb +0 -17
  298. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
@@ -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,7 +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
- try_cache(:count) { view.count_documents(options) }
59
+ view.count_documents(options)
69
60
  end
70
61
 
71
62
  # Get the estimated number of documents matching the query.
@@ -84,7 +75,7 @@ module Mongoid
84
75
  unless self.criteria.selector.empty?
85
76
  raise Mongoid::Errors::InvalidEstimatedCountCriteria.new(self.klass)
86
77
  end
87
- try_cache(:estimated_count) { view.estimated_document_count(options) }
78
+ view.estimated_document_count(options)
88
79
  end
89
80
 
90
81
  # Delete all documents in the database that match the selector.
@@ -152,7 +143,6 @@ module Mongoid
152
143
  documents_for_iteration.each do |doc|
153
144
  yield_document(doc, &block)
154
145
  end
155
- @cache_loaded = true
156
146
  self
157
147
  else
158
148
  to_enum
@@ -165,17 +155,11 @@ module Mongoid
165
155
  # context.exists?
166
156
  #
167
157
  # @note We don't use count here since Mongo does not use counted
168
- # b-tree indexes, unless a count is already cached then that is
169
- # used to determine the value.
158
+ # b-tree indexes.
170
159
  #
171
160
  # @return [ true, false ] If the count is more than zero.
172
161
  def exists?
173
- return !documents.empty? if cached? && cache_loaded?
174
- return @count > 0 if instance_variable_defined?(:@count)
175
-
176
- try_cache(:exists) do
177
- !!(view.projection(_id: 1).limit(1).first)
178
- end
162
+ !!(view.projection(_id: 1).limit(1).first)
179
163
  end
180
164
 
181
165
  # Run an explain on the criteria.
@@ -249,32 +233,16 @@ module Mongoid
249
233
  # @note Automatically adding a sort on _id when no other sort is
250
234
  # defined on the criteria has the potential to cause bad performance issues.
251
235
  # If you experience unexpected poor performance when using #first or #last
252
- # and have no sort defined on the criteria, use the option { id_sort: :none }.
253
- # Be aware that #first/#last won't guarantee order in this case.
236
+ # and have no sort defined on the criteria, use #take instead.
237
+ # Be aware that #take won't guarantee order.
254
238
  #
255
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
256
- # return, or a hash of options.
257
- #
258
- # @option limit_or_opts [ :none ] :id_sort This option is deprecated.
259
- # 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.
260
240
  #
261
241
  # @return [ Document ] The first document.
262
- def first(limit_or_opts = nil)
263
- limit, opts = extract_limit_and_opts(limit_or_opts)
264
- if cached? && cache_loaded?
265
- return limit ? documents.first(limit) : documents.first
266
- end
267
- try_numbered_cache(:first, limit) do
268
- if opts.key?(:id_sort)
269
- Mongoid::Warnings.warn_id_sort_deprecated
270
- end
271
- sorted_view = view
272
- if sort = view.sort || ({ _id: 1 } unless opts[:id_sort] == :none)
273
- sorted_view = view.sort(sort)
274
- end
275
- if raw_docs = sorted_view.limit(limit || 1).to_a
276
- process_raw_docs(raw_docs, limit)
277
- 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)
278
246
  end
279
247
  end
280
248
  alias :one :first
@@ -283,7 +251,6 @@ module Mongoid
283
251
  #
284
252
  # @api private
285
253
  def find_first
286
- return documents.first if cached? && cache_loaded?
287
254
  if raw_doc = view.first
288
255
  doc = Factory.from_db(klass, raw_doc, criteria)
289
256
  eager_load([doc]).first
@@ -313,33 +280,6 @@ module Mongoid
313
280
  GeoNear.new(collection, criteria, coordinates)
314
281
  end
315
282
 
316
- # Invoke the block for each element of Contextual. Create a new array
317
- # containing the values returned by the block.
318
- #
319
- # If the symbol field name is passed instead of the block, additional
320
- # optimizations would be used.
321
- #
322
- # @example Map by some field.
323
- # context.map(:field1)
324
- #
325
- # @example Map with block.
326
- # context.map(&:field1)
327
- #
328
- # @param [ Symbol ] field The field name.
329
- #
330
- # @return [ Array ] The result of mapping.
331
- def map(field = nil, &block)
332
- if !field.nil?
333
- Mongoid::Warnings.warn_map_field_deprecated
334
- end
335
-
336
- if block_given?
337
- super(&block)
338
- else
339
- criteria.pluck(field)
340
- end
341
- end
342
-
343
283
  # Create the new Mongo context. This delegates operations to the
344
284
  # underlying driver.
345
285
  #
@@ -348,7 +288,7 @@ module Mongoid
348
288
  #
349
289
  # @param [ Criteria ] criteria The criteria.
350
290
  def initialize(criteria)
351
- @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
291
+ @criteria, @klass = criteria, criteria.klass
352
292
  @collection = @klass.collection
353
293
  criteria.send(:merge_type_selection)
354
294
  @view = collection.find(criteria.selector, session: _session)
@@ -365,39 +305,26 @@ module Mongoid
365
305
  # @note Automatically adding a sort on _id when no other sort is
366
306
  # defined on the criteria has the potential to cause bad performance issues.
367
307
  # If you experience unexpected poor performance when using #first or #last
368
- # and have no sort defined on the criteria, use the option { id_sort: :none }.
369
- # Be aware that #first/#last won't guarantee order in this case.
370
- #
371
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
372
- # 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.
373
310
  #
374
- # @option limit_or_opts [ :none ] :id_sort This option is deprecated.
375
- # 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.
376
312
  #
377
313
  # @return [ Document ] The last document.
378
- def last(limit_or_opts = nil)
379
- limit, opts = extract_limit_and_opts(limit_or_opts)
380
- if cached? && cache_loaded?
381
- return limit ? documents.last(limit) : documents.last
382
- end
383
- res = try_numbered_cache(:last, limit) do
384
- with_inverse_sorting(opts) do
385
- if raw_docs = view.limit(limit || 1).to_a
386
- process_raw_docs(raw_docs, limit)
387
- end
388
- end
389
- end
390
- 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)
391
317
  end
392
318
 
393
- # Get's the number of documents matching the query selector.
319
+ # Returns the number of documents in the database matching
320
+ # the query selector.
394
321
  #
395
322
  # @example Get the length.
396
323
  # context.length
397
324
  #
398
325
  # @return [ Integer ] The number of documents.
399
326
  def length
400
- @length ||= self.count
327
+ self.count
401
328
  end
402
329
  alias :size :length
403
330
 
@@ -470,9 +397,6 @@ module Mongoid
470
397
  # @example Pluck a field.
471
398
  # context.pluck(:_id)
472
399
  #
473
- # @note This method will return the raw db values - it performs no custom
474
- # serialization.
475
- #
476
400
  # @param [ String, Symbol, Array ] fields Fields to pluck.
477
401
  #
478
402
  # @return [ Array<Object, Array> ] The plucked values.
@@ -505,6 +429,87 @@ module Mongoid
505
429
  end
506
430
  end
507
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
+
508
513
  # Skips the provided number of documents.
509
514
  #
510
515
  # @example Skip the documents.
@@ -571,64 +576,6 @@ module Mongoid
571
576
 
572
577
  private
573
578
 
574
- # yield the block given or return the cached value
575
- #
576
- # @param [ String, Symbol ] key The instance variable name
577
- #
578
- # @return the result of the block
579
- def try_cache(key, &block)
580
- unless cached?
581
- yield
582
- else
583
- unless ret = instance_variable_get("@#{key}")
584
- instance_variable_set("@#{key}", ret = yield)
585
- end
586
- ret
587
- end
588
- end
589
-
590
- # yield the block given or return the cached value
591
- #
592
- # @param [ String, Symbol ] key The instance variable name
593
- # @param [ Integer | nil ] n The number of documents requested or nil
594
- # if none is requested.
595
- #
596
- # @return [ Object ] The result of the block.
597
- def try_numbered_cache(key, n, &block)
598
- unless cached?
599
- yield if block_given?
600
- else
601
- len = n || 1
602
- ret = instance_variable_get("@#{key}")
603
- if !ret || ret.length < len
604
- instance_variable_set("@#{key}", ret = Array.wrap(yield))
605
- elsif !n
606
- ret.is_a?(Array) ? ret.first : ret
607
- elsif ret.length > len
608
- ret.first(n)
609
- else
610
- ret
611
- end
612
- end
613
- end
614
-
615
- # Extract the limit and opts from the given argument, so that code
616
- # can operate without having to worry about the current type and
617
- # state of the argument.
618
- #
619
- # @param [ nil | Integer | Hash ] limit_or_opts The value to pull the
620
- # limit and option hash from.
621
- #
622
- # @return [ Array<nil | Integer, Hash> ] A 2-array of the limit and the
623
- # option hash.
624
- def extract_limit_and_opts(limit_or_opts)
625
- case limit_or_opts
626
- when nil, Integer then [ limit_or_opts, {} ]
627
- when Hash then [ nil, limit_or_opts ]
628
- else raise ArgumentError, "expected nil, Integer, or Hash"
629
- end
630
- end
631
-
632
579
  # Update the documents for the provided method.
633
580
  #
634
581
  # @api private
@@ -689,57 +636,9 @@ module Mongoid
689
636
  # Map the inverse sort symbols to the correct MongoDB values.
690
637
  #
691
638
  # @api private
692
- #
693
- # @example Apply the inverse sorting params to the given block
694
- # context.with_inverse_sorting
695
- def with_inverse_sorting(opts = {})
696
- Mongoid::Warnings.warn_id_sort_deprecated if opts.key?(:id_sort)
697
-
698
- begin
699
- if sort = criteria.options[:sort] || ( { _id: 1 } unless opts[:id_sort] == :none )
700
- @view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
701
- end
702
- yield
703
- ensure
704
- apply_option(:sort)
705
- end
706
- end
707
-
708
- # Is the cache able to be added to?
709
- #
710
- # @api private
711
- #
712
- # @example Is the context cacheable?
713
- # context.cacheable?
714
- #
715
- # @return [ true, false ] If caching, and the cache isn't loaded.
716
- def cacheable?
717
- cached? && !cache_loaded?
718
- end
719
-
720
- # Is the cache fully loaded? Will be true if caching after one full
721
- # iteration.
722
- #
723
- # @api private
724
- #
725
- # @example Is the cache loaded?
726
- # context.cache_loaded?
727
- #
728
- # @return [ true, false ] If the cache is loaded.
729
- def cache_loaded?
730
- !!@cache_loaded
731
- end
732
-
733
- # Get the documents for cached queries.
734
- #
735
- # @api private
736
- #
737
- # @example Get the cached documents.
738
- # context.documents
739
- #
740
- # @return [ Array<Document> ] The documents.
741
- def documents
742
- @documents ||= []
639
+ def inverse_sorting
640
+ sort = view.sort || { _id: 1 }
641
+ Hash[sort.map{|k, v| [k, -1*v]}]
743
642
  end
744
643
 
745
644
  # Get the documents the context should iterate. This follows 3 rules:
@@ -757,7 +656,6 @@ module Mongoid
757
656
  #
758
657
  # @return [ Array<Document>, Mongo::Collection::View ] The docs to iterate.
759
658
  def documents_for_iteration
760
- return documents if cached? && !documents.empty?
761
659
  return view unless eager_loadable?
762
660
  docs = view.map{ |doc| Factory.from_db(klass, doc, criteria) }
763
661
  eager_load(docs)
@@ -777,7 +675,6 @@ module Mongoid
777
675
  doc = document.respond_to?(:_id) ?
778
676
  document : Factory.from_db(klass, document, criteria)
779
677
  yield(doc)
780
- documents.push(doc) if cacheable?
781
678
  end
782
679
 
783
680
  private
@@ -790,6 +687,26 @@ module Mongoid
790
687
  collection.write_concern.nil? || collection.write_concern.acknowledged?
791
688
  end
792
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
+
793
710
  # Extracts the value for the given field name from the given attribute
794
711
  # hash.
795
712
  #
@@ -798,24 +715,18 @@ module Mongoid
798
715
  #
799
716
  # @param [ Object ] The value for the given field name
800
717
  def extract_value(attrs, field_name)
801
- def fetch_and_demongoize(d, meth, klass)
802
- res = d.try(:fetch, meth, nil)
803
- if field = klass.fields[meth]
804
- field.demongoize(res)
805
- else
806
- res.class.demongoize(res)
807
- end
808
- end
718
+ i = 1
719
+ num_meths = field_name.count('.') + 1
720
+ curr = attrs.dup
809
721
 
810
- k = klass
811
- meths = field_name.split('.')
812
- 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
813
724
  is_translation = false
814
- if !k.fields.key?(meth) && !k.relations.key?(meth)
815
- if tr = meth.match(/(.*)_translations\z/)&.captures&.first
816
- is_translation = true
817
- meth = tr
818
- 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
819
730
  end
820
731
 
821
732
  # 1. If curr is an array fetch from all elements in the array.
@@ -828,31 +739,24 @@ module Mongoid
828
739
  # 3. If the meth is an _translations field, do not demongoize the
829
740
  # value so the full hash is returned.
830
741
  # 4. Otherwise, fetch and demongoize the value for the key meth.
831
- if curr.is_a? Array
832
- 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)
833
744
  res.empty? ? nil : res
834
- elsif !is_translation && k.fields[meth]&.localized?
835
- if i < meths.length-1
745
+ elsif !is_translation && field&.localized?
746
+ if i < num_meths
836
747
  curr.try(:fetch, meth, nil)
837
748
  else
838
- fetch_and_demongoize(curr, meth, k)
749
+ fetch_and_demongoize(curr, meth, field)
839
750
  end
840
751
  elsif is_translation
841
752
  curr.try(:fetch, meth, nil)
842
753
  else
843
- fetch_and_demongoize(curr, meth, k)
844
- end.tap do
845
- if as = k.try(:aliased_associations)
846
- if a = as.fetch(meth, nil)
847
- meth = a
848
- end
849
- end
850
-
851
- if relation = k.relations[meth]
852
- k = relation.klass
853
- end
754
+ fetch_and_demongoize(curr, meth, field)
854
755
  end
756
+
757
+ i += 1
855
758
  end
759
+ curr
856
760
  end
857
761
 
858
762
  # Recursively demongoize the given value. This method recursively traverses
@@ -865,29 +769,36 @@ module Mongoid
865
769
  #
866
770
  # @return [ Object ] The demongoized value.
867
771
  def recursive_demongoize(field_name, value, is_translation)
868
- k = klass
869
- field_name.split('.').each do |meth|
870
- if as = k.try(:aliased_associations)
871
- if a = as.fetch(meth, nil)
872
- meth = a.to_s
873
- end
874
- end
772
+ field = klass.traverse_association_tree(field_name)
773
+ demongoize_with_field(field, value, is_translation)
774
+ end
875
775
 
876
- if relation = k.relations[meth]
877
- k = relation.klass
878
- elsif field = k.fields[meth]
879
- # If it's a localized field that's not a hash, don't demongoize
880
- # again, we already have the translation. If it's an _translation
881
- # field, don't demongoize, we want the full hash not just a
882
- # specific translation.
883
- if field.localized? && (!value.is_a?(Hash) || is_translation)
884
- return value.class.demongoize(value)
885
- else
886
- return field.demongoize(value)
887
- 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)
888
797
  else
889
- return value.class.demongoize(value)
798
+ field.demongoize(value)
890
799
  end
800
+ else
801
+ value.class.demongoize(value)
891
802
  end
892
803
  end
893
804
 
@@ -50,7 +50,7 @@ module Mongoid
50
50
  # @example Get the distinct values in null context.
51
51
  # context.distinct(:name)
52
52
  #
53
- # @param [ String, Symbol ] _field The name of the field.
53
+ # @param [ String | Symbol ] _field The name of the field.
54
54
  #
55
55
  # @return [ Array ] An empty Array.
56
56
  def distinct(_field)
@@ -88,13 +88,37 @@ module Mongoid
88
88
  # @example Get the values for null context.
89
89
  # context.pluck(:name)
90
90
  #
91
- # @param [ String, Symbol, Array ] args Field or fields to pluck.
91
+ # @param [ String | Symbol ] *_fields Field or fields to pluck.
92
92
  #
93
93
  # @return [ Array ] An empty Array.
94
- def pluck(*args)
94
+ def pluck(*_fields)
95
95
  []
96
96
  end
97
97
 
98
+ # Pick the field values in null context.
99
+ #
100
+ # @example Get the value for null context.
101
+ # context.pick(:name)
102
+ #
103
+ # @param [ String | Symbol ] *_fields Field or fields to pick.
104
+ #
105
+ # @return [ nil ] Always reeturn nil.
106
+ def pick(*_fields)
107
+ nil
108
+ end
109
+
110
+ # Tally the field values in null context.
111
+ #
112
+ # @example Get the values for null context.
113
+ # context.tally(:name)
114
+ #
115
+ # @param [ String | Symbol ] _field Field to tally.
116
+ #
117
+ # @return [ Hash ] An empty Hash.
118
+ def tally(_field)
119
+ {}
120
+ end
121
+
98
122
  # Create the new null context.
99
123
  #
100
124
  # @example Create the new context.
@@ -110,14 +134,11 @@ module Mongoid
110
134
  # @example Get the first document in null context.
111
135
  # context.first
112
136
  #
113
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
114
- # return, or a hash of options.
137
+ # @param [ Integer ] limit The number of documents to return.
115
138
  #
116
139
  # @return [ nil ] Always nil.
117
- def first(limit_or_opts = nil)
118
- if !limit_or_opts.nil? && !limit_or_opts.is_a?(Hash)
119
- []
120
- end
140
+ def first(limit = nil)
141
+ [] unless limit.nil?
121
142
  end
122
143
 
123
144
  # Always returns nil.
@@ -125,14 +146,11 @@ module Mongoid
125
146
  # @example Get the last document in null context.
126
147
  # context.last
127
148
  #
128
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
129
- # return, or a hash of options.
149
+ # @param [ Integer ] limit The number of documents to return.
130
150
  #
131
151
  # @return [ nil ] Always nil.
132
- def last(limit_or_opts = nil)
133
- if !limit_or_opts.nil? && !limit_or_opts.is_a?(Hash)
134
- []
135
- end
152
+ def last(limit = nil)
153
+ [] unless limit.nil?
136
154
  end
137
155
 
138
156
  # Returns nil or empty array.