mongoid 5.4.1 → 6.0.0.beta

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 (264) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/config/locales/en.yml +23 -16
  5. data/lib/mongoid.rb +4 -9
  6. data/lib/mongoid/atomic.rb +1 -1
  7. data/lib/mongoid/atomic/modifiers.rb +8 -12
  8. data/lib/mongoid/attributes.rb +9 -11
  9. data/lib/mongoid/attributes/dynamic.rb +5 -6
  10. data/lib/mongoid/attributes/nested.rb +1 -1
  11. data/lib/mongoid/attributes/processing.rb +4 -0
  12. data/lib/mongoid/attributes/readonly.rb +22 -0
  13. data/lib/mongoid/cacheable.rb +36 -0
  14. data/lib/mongoid/changeable.rb +37 -1
  15. data/lib/mongoid/clients.rb +0 -63
  16. data/lib/mongoid/clients/factory.rb +0 -2
  17. data/lib/mongoid/clients/options.rb +54 -249
  18. data/lib/mongoid/clients/storage_options.rb +1 -69
  19. data/lib/mongoid/composable.rb +26 -2
  20. data/lib/mongoid/config.rb +1 -1
  21. data/lib/mongoid/config/options.rb +1 -1
  22. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -0
  23. data/lib/mongoid/contextual/atomic.rb +6 -9
  24. data/lib/mongoid/contextual/geo_near.rb +2 -3
  25. data/lib/mongoid/contextual/map_reduce.rb +97 -24
  26. data/lib/mongoid/contextual/memory.rb +7 -4
  27. data/lib/mongoid/contextual/mongo.rb +63 -54
  28. data/lib/mongoid/contextual/none.rb +2 -2
  29. data/lib/mongoid/copyable.rb +19 -19
  30. data/lib/mongoid/criteria.rb +5 -4
  31. data/lib/mongoid/criteria/findable.rb +2 -3
  32. data/lib/mongoid/criteria/includable.rb +63 -16
  33. data/lib/mongoid/criteria/marshalable.rb +2 -2
  34. data/lib/mongoid/criteria/modifiable.rb +17 -1
  35. data/lib/mongoid/criteria/options.rb +25 -0
  36. data/lib/mongoid/criteria/queryable.rb +86 -0
  37. data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
  38. data/lib/mongoid/criteria/queryable/extensions.rb +28 -0
  39. data/lib/mongoid/criteria/queryable/extensions/array.rb +185 -0
  40. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +37 -0
  41. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +34 -0
  42. data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
  43. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +53 -0
  44. data/lib/mongoid/criteria/queryable/extensions/hash.rb +200 -0
  45. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +86 -0
  46. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +90 -0
  47. data/lib/mongoid/criteria/queryable/extensions/object.rb +206 -0
  48. data/lib/mongoid/criteria/queryable/extensions/range.rb +70 -0
  49. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +45 -0
  50. data/lib/mongoid/criteria/queryable/extensions/set.rb +34 -0
  51. data/lib/mongoid/criteria/queryable/extensions/string.rb +137 -0
  52. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +79 -0
  53. data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
  54. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +54 -0
  55. data/lib/mongoid/criteria/queryable/forwardable.rb +65 -0
  56. data/lib/mongoid/criteria/queryable/key.rb +103 -0
  57. data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
  58. data/lib/mongoid/criteria/queryable/mergeable.rb +271 -0
  59. data/lib/mongoid/criteria/queryable/optional.rb +411 -0
  60. data/lib/mongoid/criteria/queryable/options.rb +136 -0
  61. data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
  62. data/lib/mongoid/criteria/queryable/selectable.rb +662 -0
  63. data/lib/mongoid/criteria/queryable/selector.rb +196 -0
  64. data/lib/mongoid/criteria/queryable/smash.rb +103 -0
  65. data/lib/mongoid/document.rb +9 -23
  66. data/lib/mongoid/errors.rb +2 -1
  67. data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
  68. data/lib/mongoid/errors/delete_restriction.rb +2 -2
  69. data/lib/mongoid/errors/invalid_field.rb +2 -2
  70. data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
  71. data/lib/mongoid/errors/invalid_relation.rb +66 -0
  72. data/lib/mongoid/errors/inverse_not_found.rb +1 -1
  73. data/lib/mongoid/errors/mongoid_error.rb +1 -1
  74. data/lib/mongoid/evolvable.rb +1 -1
  75. data/lib/mongoid/extensions.rb +0 -5
  76. data/lib/mongoid/extensions/big_decimal.rb +17 -8
  77. data/lib/mongoid/extensions/date.rb +4 -1
  78. data/lib/mongoid/extensions/hash.rb +2 -3
  79. data/lib/mongoid/extensions/object.rb +2 -2
  80. data/lib/mongoid/extensions/string.rb +4 -3
  81. data/lib/mongoid/extensions/time.rb +5 -2
  82. data/lib/mongoid/factory.rb +1 -0
  83. data/lib/mongoid/fields/foreign_key.rb +2 -2
  84. data/lib/mongoid/fields/localized.rb +3 -8
  85. data/lib/mongoid/fields/validators/macro.rb +18 -0
  86. data/lib/mongoid/findable.rb +3 -3
  87. data/lib/mongoid/indexable.rb +17 -16
  88. data/lib/mongoid/indexable/specification.rb +1 -1
  89. data/lib/mongoid/indexable/validators/options.rb +1 -2
  90. data/lib/mongoid/interceptable.rb +6 -17
  91. data/lib/mongoid/loggable.rb +1 -1
  92. data/lib/mongoid/matchable.rb +3 -10
  93. data/lib/mongoid/matchable/gt.rb +2 -0
  94. data/lib/mongoid/matchable/gte.rb +2 -0
  95. data/lib/mongoid/matchable/lt.rb +2 -0
  96. data/lib/mongoid/matchable/lte.rb +2 -0
  97. data/lib/mongoid/persistable.rb +6 -5
  98. data/lib/mongoid/persistable/creatable.rb +2 -0
  99. data/lib/mongoid/persistable/deletable.rb +7 -3
  100. data/lib/mongoid/persistable/settable.rb +3 -16
  101. data/lib/mongoid/persistable/updatable.rb +10 -12
  102. data/lib/mongoid/persistence_context.rb +216 -0
  103. data/lib/mongoid/query_cache.rb +5 -30
  104. data/lib/mongoid/relations/accessors.rb +6 -2
  105. data/lib/mongoid/relations/auto_save.rb +12 -4
  106. data/lib/mongoid/relations/bindings/embedded/in.rb +4 -0
  107. data/lib/mongoid/relations/bindings/embedded/many.rb +8 -1
  108. data/lib/mongoid/relations/bindings/embedded/one.rb +10 -0
  109. data/lib/mongoid/relations/bindings/referenced/many.rb +4 -0
  110. data/lib/mongoid/relations/builders.rb +2 -2
  111. data/lib/mongoid/relations/builders/embedded/one.rb +1 -1
  112. data/lib/mongoid/relations/builders/nested_attributes/many.rb +1 -1
  113. data/lib/mongoid/relations/conversions.rb +1 -1
  114. data/lib/mongoid/relations/counter_cache.rb +28 -18
  115. data/lib/mongoid/relations/eager.rb +19 -7
  116. data/lib/mongoid/relations/eager/base.rb +5 -5
  117. data/lib/mongoid/relations/embedded/batchable.rb +9 -33
  118. data/lib/mongoid/relations/embedded/in.rb +16 -2
  119. data/lib/mongoid/relations/embedded/many.rb +23 -8
  120. data/lib/mongoid/relations/embedded/one.rb +17 -2
  121. data/lib/mongoid/relations/macros.rb +9 -2
  122. data/lib/mongoid/relations/metadata.rb +3 -3
  123. data/lib/mongoid/relations/nested_builder.rb +1 -1
  124. data/lib/mongoid/relations/options.rb +2 -2
  125. data/lib/mongoid/relations/proxy.rb +2 -33
  126. data/lib/mongoid/relations/referenced/in.rb +23 -11
  127. data/lib/mongoid/relations/referenced/many.rb +24 -16
  128. data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
  129. data/lib/mongoid/relations/referenced/one.rb +17 -1
  130. data/lib/mongoid/relations/reflections.rb +3 -5
  131. data/lib/mongoid/relations/touchable.rb +1 -1
  132. data/lib/mongoid/reloadable.rb +1 -1
  133. data/lib/mongoid/scopable.rb +3 -3
  134. data/lib/mongoid/serializable.rb +2 -3
  135. data/lib/mongoid/tasks/database.rb +1 -2
  136. data/lib/mongoid/threaded.rb +4 -4
  137. data/lib/mongoid/traversable.rb +1 -1
  138. data/lib/mongoid/validatable.rb +1 -1
  139. data/lib/mongoid/validatable/macros.rb +2 -4
  140. data/lib/mongoid/validatable/uniqueness.rb +1 -2
  141. data/lib/mongoid/version.rb +1 -1
  142. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -7
  143. data/spec/app/models/album.rb +5 -1
  144. data/spec/app/models/artist.rb +21 -0
  145. data/spec/app/models/band.rb +0 -1
  146. data/spec/app/models/church.rb +0 -2
  147. data/spec/app/models/ordered_post.rb +5 -0
  148. data/spec/app/models/oscar.rb +1 -2
  149. data/spec/app/models/person.rb +3 -1
  150. data/spec/app/models/post.rb +0 -1
  151. data/spec/app/models/princess.rb +2 -0
  152. data/spec/app/models/record.rb +1 -0
  153. data/spec/app/models/thing.rb +1 -1
  154. data/spec/config/mongoid.yml +1 -5
  155. data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
  156. data/spec/mongoid/atomic_spec.rb +17 -17
  157. data/spec/mongoid/attributes/nested_spec.rb +14 -14
  158. data/spec/mongoid/attributes/readonly_spec.rb +87 -44
  159. data/spec/mongoid/attributes_spec.rb +63 -0
  160. data/spec/mongoid/cacheable_spec.rb +112 -0
  161. data/spec/mongoid/changeable_spec.rb +58 -0
  162. data/spec/mongoid/clients/factory_spec.rb +3 -11
  163. data/spec/mongoid/clients/options_spec.rb +378 -96
  164. data/spec/mongoid/clients_spec.rb +207 -170
  165. data/spec/mongoid/composable_spec.rb +7 -0
  166. data/spec/mongoid/config_spec.rb +41 -21
  167. data/spec/mongoid/contextual/atomic_spec.rb +77 -343
  168. data/spec/mongoid/contextual/map_reduce_spec.rb +119 -111
  169. data/spec/mongoid/contextual/memory_spec.rb +56 -316
  170. data/spec/mongoid/contextual/mongo_spec.rb +104 -378
  171. data/spec/mongoid/copyable_spec.rb +8 -15
  172. data/spec/mongoid/criteria/modifiable_spec.rb +239 -7
  173. data/spec/mongoid/criteria/options_spec.rb +29 -0
  174. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
  175. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
  176. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
  177. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
  178. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
  179. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
  180. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
  181. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
  182. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
  183. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
  184. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
  185. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
  186. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
  187. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
  188. data/spec/mongoid/{extensions/origin/regexp_raw_spec.rb → criteria/queryable/extensions/regexp_spec.rb} +21 -20
  189. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
  190. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
  191. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
  192. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
  193. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
  194. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
  195. data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
  196. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
  197. data/spec/mongoid/criteria/queryable/optional_spec.rb +1786 -0
  198. data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
  199. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
  200. data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
  201. data/spec/mongoid/criteria/queryable/selectable_spec.rb +4159 -0
  202. data/spec/mongoid/criteria/queryable/selector_spec.rb +778 -0
  203. data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
  204. data/spec/mongoid/criteria_spec.rb +45 -63
  205. data/spec/mongoid/document_spec.rb +21 -88
  206. data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
  207. data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
  208. data/spec/mongoid/extensions/big_decimal_spec.rb +320 -18
  209. data/spec/mongoid/extensions/date_spec.rb +2 -6
  210. data/spec/mongoid/extensions/date_time_spec.rb +2 -6
  211. data/spec/mongoid/extensions/float_spec.rb +8 -1
  212. data/spec/mongoid/extensions/integer_spec.rb +8 -1
  213. data/spec/mongoid/extensions/object_spec.rb +11 -0
  214. data/spec/mongoid/extensions/string_spec.rb +21 -0
  215. data/spec/mongoid/extensions/time_spec.rb +4 -8
  216. data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
  217. data/spec/mongoid/fields/localized_spec.rb +0 -91
  218. data/spec/mongoid/findable_spec.rb +46 -1
  219. data/spec/mongoid/indexable_spec.rb +6 -46
  220. data/spec/mongoid/interceptable_spec.rb +49 -10
  221. data/spec/mongoid/matchable/gt_spec.rb +11 -0
  222. data/spec/mongoid/matchable/gte_spec.rb +10 -0
  223. data/spec/mongoid/matchable/lt_spec.rb +11 -0
  224. data/spec/mongoid/matchable/lte_spec.rb +11 -0
  225. data/spec/mongoid/matchable_spec.rb +1 -51
  226. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  227. data/spec/mongoid/persistable/deletable_spec.rb +1 -1
  228. data/spec/mongoid/persistable/destroyable_spec.rb +6 -2
  229. data/spec/mongoid/persistable/savable_spec.rb +30 -30
  230. data/spec/mongoid/persistable/settable_spec.rb +0 -185
  231. data/spec/mongoid/persistable/updatable_spec.rb +166 -5
  232. data/spec/mongoid/persistence_context_spec.rb +654 -0
  233. data/spec/mongoid/positional_spec.rb +10 -10
  234. data/spec/mongoid/query_cache_spec.rb +89 -65
  235. data/spec/mongoid/relations/accessors_spec.rb +1 -1
  236. data/spec/mongoid/relations/auto_save_spec.rb +39 -6
  237. data/spec/mongoid/relations/builders_spec.rb +37 -10
  238. data/spec/mongoid/relations/counter_cache_spec.rb +64 -15
  239. data/spec/mongoid/relations/cyclic_spec.rb +0 -22
  240. data/spec/mongoid/relations/embedded/many_spec.rb +9 -41
  241. data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
  242. data/spec/mongoid/relations/macros_spec.rb +395 -7
  243. data/spec/mongoid/relations/proxy_spec.rb +3 -1
  244. data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
  245. data/spec/mongoid/relations/referenced/many_spec.rb +6 -29
  246. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +6 -29
  247. data/spec/mongoid/relations/reflections_spec.rb +9 -9
  248. data/spec/mongoid/reloadable_spec.rb +51 -0
  249. data/spec/mongoid/scopable_spec.rb +0 -12
  250. data/spec/mongoid/serializable_spec.rb +0 -50
  251. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  252. data/spec/mongoid/validatable/uniqueness_spec.rb +16 -9
  253. data/spec/mongoid/validatable_spec.rb +16 -0
  254. data/spec/spec_helper.rb +10 -10
  255. metadata +536 -479
  256. metadata.gz.sig +0 -0
  257. data/lib/mongoid/clients/thread_options.rb +0 -19
  258. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +0 -20
  259. data/lib/mongoid/extensions/decimal128.rb +0 -39
  260. data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
  261. data/lib/mongoid/matchable/regexp.rb +0 -27
  262. data/spec/app/models/post_genre.rb +0 -6
  263. data/spec/mongoid/extensions/decimal128_spec.rb +0 -44
  264. data/spec/mongoid/matchable/regexp_spec.rb +0 -59
@@ -12,6 +12,7 @@ require "mongoid/scopable"
12
12
  require "mongoid/serializable"
13
13
  require "mongoid/shardable"
14
14
  require "mongoid/stateful"
15
+ require "mongoid/cacheable"
15
16
  require "mongoid/traversable"
16
17
  require "mongoid/validatable"
17
18
 
@@ -32,7 +33,6 @@ module Mongoid
32
33
  include ActiveModel::Model
33
34
  include ActiveModel::ForbiddenAttributesProtection
34
35
  include ActiveModel::Serializers::JSON
35
- include ActiveModel::Serializers::Xml
36
36
  include Atomic
37
37
  include Changeable
38
38
  include Clients
@@ -50,6 +50,7 @@ module Mongoid
50
50
  include Serializable
51
51
  include Shardable
52
52
  include Stateful
53
+ include Cacheable
53
54
  include Threaded::Lifecycle
54
55
  include Traversable
55
56
  include Validatable
@@ -76,6 +77,7 @@ module Mongoid
76
77
  Clients,
77
78
  Shardable,
78
79
  Stateful,
80
+ Cacheable,
79
81
  Threaded::Lifecycle,
80
82
  Traversable,
81
83
  Validatable,
@@ -84,6 +86,28 @@ module Mongoid
84
86
  ActiveModel::Validations
85
87
  ]
86
88
 
89
+ # These are methods names defined in included blocks that may conflict
90
+ # with user-defined relation or field names.
91
+ # They won't be in the list of Module.instance_methods on which the
92
+ # #prohibited_methods code below is dependent so we must track them
93
+ # separately.
94
+ #
95
+ # @return [ Array<Symbol> ] A list of reserved method names.
96
+ #
97
+ # @since 6.0.0
98
+ RESERVED_METHOD_NAMES = [ :fields,
99
+ :aliased_fields,
100
+ :localized_fields,
101
+ :index_specifications,
102
+ :shard_key_fields,
103
+ :nested_attributes,
104
+ :readonly_attributes,
105
+ :storage_options,
106
+ :cascades,
107
+ :cyclic,
108
+ :cache_timestamp_format
109
+ ]
110
+
87
111
  class << self
88
112
 
89
113
  # Get a list of methods that would be a bad idea to define as field names
@@ -98,7 +122,7 @@ module Mongoid
98
122
  def prohibited_methods
99
123
  @prohibited_methods ||= MODULES.flat_map do |mod|
100
124
  mod.instance_methods.map(&:to_sym)
101
- end
125
+ end + RESERVED_METHOD_NAMES
102
126
  end
103
127
  end
104
128
  end
@@ -25,7 +25,7 @@ module Mongoid
25
25
  option :use_activesupport_time_zone, default: true
26
26
  option :use_utc, default: false
27
27
  option :log_level, default: :info
28
- option :app_name, default: nil
28
+ option :belongs_to_required_by_default, default: true
29
29
 
30
30
  # Has Mongoid been configured? This is checking that at least a valid
31
31
  # client config exists.
@@ -31,7 +31,7 @@ module Mongoid
31
31
  def option(name, options = {})
32
32
  defaults[name] = settings[name] = options[:default]
33
33
 
34
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
34
+ class_eval <<-RUBY
35
35
  def #{name}
36
36
  settings[#{name.inspect}]
37
37
  end
@@ -124,6 +124,7 @@ module Mongoid
124
124
  def pipeline(field)
125
125
  db_field = "$#{database_field_name(field)}"
126
126
  pipeline = []
127
+ pipeline << { "$match" => criteria.selector }
127
128
  pipeline << { "$match" => criteria.exists(field => true).selector }
128
129
  pipeline << { "$sort" => criteria.options[:sort] } if criteria.options[:sort]
129
130
  pipeline << { "$skip" => criteria.options[:skip] } if criteria.options[:skip]
@@ -106,21 +106,18 @@ module Mongoid
106
106
  view.update_many("$push" => collect_operations(pushes))
107
107
  end
108
108
 
109
- # Perform an atomic $push/$each operation on the matching documents.
109
+ # Perform an atomic $pushAll operation on the matching documents.
110
110
  #
111
111
  # @example Push the values to the matching docs.
112
- # context.push_each(members: [ "Alan", "Fletch" ])
112
+ # context.push(members: [ "Alan", "Fletch" ])
113
113
  #
114
114
  # @param [ Hash ] pushes The operations.
115
115
  #
116
116
  # @return [ nil ] Nil.
117
117
  #
118
- # @since 5.4.0
119
- def push_each(pushes)
120
- push_each_updates = collect_operations(pushes).each.inject({}) do |ops, (field, elements)|
121
- ops.merge!(field => { '$each' => elements })
122
- end
123
- view.update_many("$push" => push_each_updates)
118
+ # @since 3.0.0
119
+ def push_all(pushes)
120
+ view.update_many("$pushAll" => collect_operations(pushes))
124
121
  end
125
122
 
126
123
  # Perform an atomic $rename of fields on the matching documents.
@@ -160,7 +157,7 @@ module Mongoid
160
157
  # @example Unset the field on the matches.
161
158
  # context.unset(:name)
162
159
  #
163
- # @param [ String, Symbol, Array ] args The name of the fields.
160
+ # @param [ String, Symbol, Array ] fields The name of the fields.
164
161
  #
165
162
  # @return [ nil ] Nil.
166
163
  #
@@ -63,10 +63,9 @@ module Mongoid
63
63
  # @example Initialize the new map/reduce.
64
64
  # MapReduce.new(criteria, map, reduce)
65
65
  #
66
- # @param [ Mongo::Collection ] collection The collection to run the
67
- # operation on.
68
66
  # @param [ Criteria ] criteria The Mongoid criteria.
69
- # @param [ String ] near
67
+ # @param [ String ] map The map js function.
68
+ # @param [ String ] reduce The reduce js function.
70
69
  #
71
70
  # @since 3.0.0
72
71
  def initialize(collection, criteria, near)
@@ -32,13 +32,12 @@ module Mongoid
32
32
  #
33
33
  # @since 3.0.0
34
34
  def each
35
- validate_out!
36
35
  if block_given?
37
- @map_reduce.each do |doc|
36
+ documents.each do |doc|
38
37
  yield doc
39
38
  end
40
39
  else
41
- @map_reduce.to_enum
40
+ to_enum
42
41
  end
43
42
  end
44
43
 
@@ -65,7 +64,7 @@ module Mongoid
65
64
  #
66
65
  # @since 3.0.0
67
66
  def finalize(function)
68
- @map_reduce = @map_reduce.finalize(function)
67
+ command[:finalize] = function
69
68
  self
70
69
  end
71
70
 
@@ -80,9 +79,10 @@ module Mongoid
80
79
  #
81
80
  # @since 3.0.0
82
81
  def initialize(collection, criteria, map, reduce)
83
- @collection = collection
84
- @criteria = criteria
85
- @map_reduce = @criteria.view.map_reduce(map, reduce)
82
+ @collection, @criteria = collection, criteria
83
+ command[:mapreduce] = collection.name.to_s
84
+ command[:map], command[:reduce] = map, reduce
85
+ apply_criteria_options
86
86
  end
87
87
 
88
88
  # Get the number of documents that were input into the map/reduce.
@@ -106,12 +106,11 @@ module Mongoid
106
106
  #
107
107
  # @since 3.0.0
108
108
  def js_mode
109
- @map_reduce = @map_reduce.js_mode(true)
109
+ command[:jsMode] = true
110
110
  self
111
111
  end
112
112
 
113
113
  # Specifies where the map/reduce output is to be stored.
114
- # Please see MongoDB documentation for supported map reduce options.
115
114
  #
116
115
  # @example Store output in memory.
117
116
  # map_reduce.out(inline: 1)
@@ -125,9 +124,6 @@ module Mongoid
125
124
  # @example Store output in a collection, reducing existing documents.
126
125
  # map_reduce.out(reduce: "collection_name")
127
126
  #
128
- # @example Return results from map reduce.
129
- # map_reduce.out(inline: 1)
130
- #
131
127
  # @param [ Hash ] location The place to store the results.
132
128
  #
133
129
  # @return [ MapReduce ] The map/reduce object.
@@ -138,7 +134,7 @@ module Mongoid
138
134
  normalized.update_values do |value|
139
135
  value.is_a?(::Symbol) ? value.to_s : value
140
136
  end
141
- @map_reduce = @map_reduce.out(normalized)
137
+ command[:out] = normalized
142
138
  self
143
139
  end
144
140
 
@@ -163,12 +159,8 @@ module Mongoid
163
159
  #
164
160
  # @since 3.0.0
165
161
  def raw
166
- validate_out!
167
- cmd = command
168
- opts = { read: cmd.delete(:read).options } if cmd[:read]
169
- @map_reduce.database.command(cmd, opts || {}).first
162
+ results
170
163
  end
171
- alias :results :raw
172
164
 
173
165
  # Execute the map/reduce, returning the raw output.
174
166
  # Useful when you don't care about map/reduce's ouptut.
@@ -204,7 +196,7 @@ module Mongoid
204
196
  #
205
197
  # @since 3.0.0
206
198
  def scope(object)
207
- @map_reduce = @map_reduce.scope(object)
199
+ command[:scope] = object
208
200
  self
209
201
  end
210
202
 
@@ -240,14 +232,95 @@ module Mongoid
240
232
  }
241
233
  end
242
234
 
243
- def command
244
- @map_reduce.send(:map_reduce_spec)[:selector]
235
+ private
236
+
237
+ # Apply criteria specific options - query, sort, limit.
238
+ #
239
+ # @api private
240
+ #
241
+ # @example Apply the criteria options
242
+ # map_reduce.apply_criteria_options
243
+ #
244
+ # @return [ nil ] Nothing.
245
+ #
246
+ # @since 3.0.0
247
+ def apply_criteria_options
248
+ command[:query] = criteria.selector
249
+ if sort = criteria.options[:sort]
250
+ command[:sort] = sort
251
+ end
252
+ if limit = criteria.options[:limit]
253
+ command[:limit] = limit
254
+ end
245
255
  end
246
256
 
247
- private
257
+ # Get the result documents from the map/reduce. If the output was inline
258
+ # then we grab them from the results key. If the output was a temp
259
+ # collection then we need to execute a find on that collection.
260
+ #
261
+ # @api private
262
+ #
263
+ # @example Get the documents.
264
+ # map_reduce.documents
265
+ #
266
+ # @return [ Array, Cursor ] The documents.
267
+ #
268
+ # @since 3.0.0
269
+ def documents
270
+ return results["results"] if results.has_key?("results")
271
+ view = client[output_collection].find
272
+ view.no_cursor_timeout if criteria.options[:timeout] == false
273
+ view
274
+ end
248
275
 
249
- def validate_out!
250
- raise Errors::NoMapReduceOutput.new({}) unless @map_reduce.out
276
+ # Get the collection that the map/reduce results were stored in.
277
+ #
278
+ # @api private
279
+ #
280
+ # @example Get the output collection.
281
+ # map_reduce.output_collection
282
+ #
283
+ # @return [ Symbol, String ] The output collection.
284
+ #
285
+ # @since 3.0.0
286
+ def output_collection
287
+ command[:out].values.first
288
+ end
289
+
290
+ # Execute the map/reduce command and get the results.
291
+ #
292
+ # @api private
293
+ #
294
+ # @example Get the results.
295
+ # map_reduce.results
296
+ #
297
+ # @return [ Hash ] The results of the command.
298
+ #
299
+ # @since 3.0.0
300
+ def results
301
+ raise Errors::NoMapReduceOutput.new(command) unless command[:out]
302
+ @results ||= __client__.command(command).first
303
+ end
304
+
305
+ # Get the client with the proper consistency.
306
+ #
307
+ # @api private
308
+ #
309
+ # @note We can use eventual if the output is set to inline.
310
+ #
311
+ # @example Get the client.
312
+ # map_reduce.__client__
313
+ #
314
+ # @return [ Mongo::Client ] The client with consistency set.
315
+ #
316
+ # @since 3.0.15
317
+ def __client__
318
+ if command[:out][:inline] != 1
319
+ # @todo: close
320
+ client.with(read: { mode: :primary })
321
+ else
322
+ client
323
+ end
251
324
  end
252
325
  end
253
326
  end
@@ -130,7 +130,9 @@ module Mongoid
130
130
  #
131
131
  # @since 3.0.0
132
132
  def first
133
- eager_load([documents.first]).first
133
+ doc = documents.first
134
+ eager_load_one(doc)
135
+ doc
134
136
  end
135
137
  alias :one :first
136
138
  alias :find_first :first
@@ -140,7 +142,7 @@ module Mongoid
140
142
  # @example Create the new context.
141
143
  # Memory.new(criteria)
142
144
  #
143
- # @param [ Criteria ] criteria The criteria.
145
+ # @param [ Criteria ] The criteria.
144
146
  #
145
147
  # @since 3.0.0
146
148
  def initialize(criteria)
@@ -163,7 +165,9 @@ module Mongoid
163
165
  #
164
166
  # @since 3.0.0
165
167
  def last
166
- eager_load([documents.last]).first
168
+ doc = documents.last
169
+ eager_load_one(doc)
170
+ doc
167
171
  end
168
172
 
169
173
  # Get the length of matching documents in the context.
@@ -373,7 +377,6 @@ module Mongoid
373
377
  #
374
378
  # @since 3.0.0
375
379
  def apply_options
376
- raise Errors::InMemoryCollationNotSupported.new if criteria.options[:collation]
377
380
  skip(criteria.options[:skip]).limit(criteria.options[:limit])
378
381
  end
379
382
 
@@ -18,18 +18,7 @@ module Mongoid
18
18
  # Options constant.
19
19
  #
20
20
  # @since 5.0.0
21
- OPTIONS = [ :hint,
22
- :limit,
23
- :skip,
24
- :sort,
25
- :batch_size,
26
- :max_scan,
27
- :snapshot,
28
- :comment,
29
- :read,
30
- :cursor_type,
31
- :collation
32
- ].freeze
21
+ OPTIONS = [ :hint, :limit, :skip, :sort, :batch_size, :max_scan, :max_time_ms, :snapshot, :comment, :read ].freeze
33
22
 
34
23
  # @attribute [r] view The Mongo collection view.
35
24
  attr_reader :view
@@ -79,7 +68,9 @@ module Mongoid
79
68
  #
80
69
  # @since 3.0.0
81
70
  def delete
82
- view.delete_many.deleted_count
71
+ self.count.tap do
72
+ view.delete_many
73
+ end
83
74
  end
84
75
  alias :delete_all :delete
85
76
 
@@ -92,10 +83,11 @@ module Mongoid
92
83
  #
93
84
  # @since 3.0.0
94
85
  def destroy
95
- each.inject(0) do |count, doc|
86
+ destroyed = self.count
87
+ each do |doc|
96
88
  doc.destroy
97
- count += 1
98
89
  end
90
+ destroyed
99
91
  end
100
92
  alias :destroy_all :destroy
101
93
 
@@ -110,7 +102,9 @@ module Mongoid
110
102
  #
111
103
  # @since 3.0.0
112
104
  def distinct(field)
113
- view.distinct(klass.database_field_name(field))
105
+ view.distinct(klass.database_field_name(field)).map do |value|
106
+ value.class.demongoize(value)
107
+ end
114
108
  end
115
109
 
116
110
  # Iterate over the context. If provided a block, yield to a Mongoid
@@ -197,7 +191,7 @@ module Mongoid
197
191
  # @example Execute the command.
198
192
  # context.find_one_and_update({ likes: 1 })
199
193
  #
200
- # @param [ Hash ] replacement The replacement.
194
+ # @param [ Hash ] update The updates.
201
195
  # @param [ Hash ] options The command options.
202
196
  #
203
197
  # @option options [ :before, :after ] :return_document Return the updated document
@@ -233,21 +227,27 @@ module Mongoid
233
227
  # @example Get the first document.
234
228
  # context.first
235
229
  #
236
- # @note Mongoid previously added an _id sort when no sort parameters were
237
- # provided explicitly by the user. This caused bad performance issues
238
- # and was not expected, so #first/#last will no longer guarantee order
239
- # if no sorting parameters are provided. For order guarantees - a sort
240
- # must be explicitly provided.
230
+ # @note Automatically adding a sort on _id when no other sort is
231
+ # defined on the criteria has the potential to cause bad performance issues.
232
+ # If you experience unexpected poor performance when using #first or #last
233
+ # and have no sort defined on the criteria, use the option { sort: :none }.
234
+ # Be aware that #first/#last won't guarantee order in this case.
235
+ #
236
+ # @param [ Hash ] opts The options for the query returning the first document.
237
+ #
238
+ # @option opts [ :none ] :id_sort Don't apply a sort on _id if no other sort
239
+ # is defined on the criteria.
241
240
  #
242
241
  # @return [ Document ] The first document.
243
242
  #
244
243
  # @since 3.0.0
245
- def first
244
+ def first(opts = {})
246
245
  return documents.first if cached? && cache_loaded?
247
246
  try_cache(:first) do
248
- if raw_doc = view.limit(-1).first
249
- doc = Factory.from_db(klass, raw_doc, criteria.options[:fields])
250
- eager_load([doc]).first
247
+ if sort = view.sort || ({ _id: 1 } unless opts[:id_sort] == :none)
248
+ with_eager_loading(view.sort(sort).limit(-1).first)
249
+ else
250
+ with_eager_loading(view.limit(-1).first)
251
251
  end
252
252
  end
253
253
  end
@@ -260,10 +260,7 @@ module Mongoid
260
260
  # @since 4.0.2
261
261
  def find_first
262
262
  return documents.first if cached? && cache_loaded?
263
- if raw_doc = view.first
264
- doc = Factory.from_db(klass, raw_doc, criteria.options[:fields])
265
- eager_load([doc]).first
266
- end
263
+ with_eager_loading(view.first)
267
264
  end
268
265
 
269
266
  # Execute a $geoNear command against the database.
@@ -298,7 +295,7 @@ module Mongoid
298
295
  # @example Map by some field.
299
296
  # context.map(:field1)
300
297
  #
301
- # @example Map with block.
298
+ # @exmaple Map with block.
302
299
  # context.map(&:field1)
303
300
  #
304
301
  # @param [ Symbol ] field The field name.
@@ -308,7 +305,8 @@ module Mongoid
308
305
  if block_given?
309
306
  super(&block)
310
307
  else
311
- criteria.pluck(field)
308
+ field = field.to_sym
309
+ criteria.only(field).map(&field.to_proc)
312
310
  end
313
311
  end
314
312
 
@@ -323,7 +321,7 @@ module Mongoid
323
321
  # @since 3.0.0
324
322
  def initialize(criteria)
325
323
  @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
326
- @collection = @klass.with(criteria.persistence_options || {}).collection
324
+ @collection = @klass.collection
327
325
  criteria.send(:merge_type_selection)
328
326
  @view = collection.find(criteria.selector)
329
327
  apply_options
@@ -336,22 +334,22 @@ module Mongoid
336
334
  # @example Get the last document.
337
335
  # context.last
338
336
  #
339
- # @note Mongoid previously added an _id sort when no sort parameters were
340
- # provided explicitly by the user. This caused bad performance issues
341
- # and was not expected, so #first/#last will no longer guarantee order
342
- # if no sorting parameters are provided. For order guarantees - a sort
343
- # must be explicitly provided.
337
+ # @note Automatically adding a sort on _id when no other sort is
338
+ # defined on the criteria has the potential to cause bad performance issues.
339
+ # If you experience unexpected poor performance when using #first or #last
340
+ # and have no sort defined on the criteria, use the option { sort: :none }.
341
+ # Be aware that #first/#last won't guarantee order in this case.
342
+ #
343
+ # @param [ Hash ] opts The options for the query returning the first document.
344
344
  #
345
- # @return [ Document ] The last document.
345
+ # @option opts [ :none ] :id_sort Don't apply a sort on _id if no other sort
346
+ # is defined on the criteria.
346
347
  #
347
348
  # @since 3.0.0
348
- def last
349
+ def last(opts = {})
349
350
  try_cache(:last) do
350
- with_inverse_sorting do
351
- if raw_doc = view.limit(-1).first
352
- doc = Factory.from_db(klass, raw_doc, criteria.options[:fields])
353
- eager_load([doc]).first
354
- end
351
+ with_inverse_sorting(opts) do
352
+ with_eager_loading(view.limit(-1).first)
355
353
  end
356
354
  end
357
355
  end
@@ -407,7 +405,7 @@ module Mongoid
407
405
  # @note This method will return the raw db values - it performs no custom
408
406
  # serialization.
409
407
  #
410
- # @param [ String, Symbol, Array ] fields Fields to pluck.
408
+ # @param [ String, Symbol, Array ] field Fields to pluck.
411
409
  #
412
410
  # @return [ Array<Object, Array> ] The plucked values.
413
411
  #
@@ -559,6 +557,12 @@ module Mongoid
559
557
  if criteria.options[:timeout] == false
560
558
  @view = view.no_cursor_timeout
561
559
  end
560
+ if criteria.options[:cursor_type]
561
+ # @todo: update to use #cursor_type method on view when driver 2.3 is released.
562
+ # See RUBY-1080
563
+ @view = view.clone
564
+ @view.options.merge!(cursor_type: criteria.options[:cursor_type])
565
+ end
562
566
  end
563
567
 
564
568
  # Apply an option.
@@ -583,10 +587,10 @@ module Mongoid
583
587
  # context.with_inverse_sorting
584
588
  #
585
589
  # @since 3.0.0
586
- def with_inverse_sorting
590
+ def with_inverse_sorting(opts = {})
587
591
  begin
588
- if spec = criteria.options[:sort]
589
- @view = view.sort(Hash[spec.map{|k, v| [k, -1*v]}])
592
+ if sort = criteria.options[:sort] || ( { _id: 1 } unless opts[:id_sort] == :none )
593
+ @view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
590
594
  end
591
595
  yield
592
596
  ensure
@@ -654,10 +658,15 @@ module Mongoid
654
658
  #
655
659
  # @since 3.0.0
656
660
  def documents_for_iteration
657
- return documents if cached? && !documents.empty?
658
- return view unless eager_loadable?
659
- docs = view.map{ |doc| Factory.from_db(klass, doc, criteria.options[:fields]) }
660
- eager_load(docs)
661
+ if cached? && !documents.empty?
662
+ documents
663
+ elsif eager_loadable?
664
+ docs = view.map{ |doc| Factory.from_db(klass, doc, criteria.options[:fields]) }
665
+ eager_load(docs)
666
+ docs
667
+ else
668
+ view
669
+ end
661
670
  end
662
671
 
663
672
  # Yield to the document.
@@ -674,7 +683,7 @@ module Mongoid
674
683
  # @since 3.0.0
675
684
  def yield_document(document, &block)
676
685
  doc = document.respond_to?(:_id) ?
677
- document : Factory.from_db(klass, document, criteria.options[:fields])
686
+ document : Factory.from_db(klass, document, criteria.options[:fields])
678
687
  yield(doc)
679
688
  documents.push(doc) if cacheable?
680
689
  end