mongoid 8.0.7 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +3 -3
  4. data/README.md +3 -3
  5. data/Rakefile +0 -25
  6. data/lib/config/locales/en.yml +46 -14
  7. data/lib/mongoid/association/accessors.rb +2 -2
  8. data/lib/mongoid/association/builders.rb +1 -1
  9. data/lib/mongoid/association/embedded/batchable.rb +2 -2
  10. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
  11. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -1
  12. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +3 -2
  13. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -6
  14. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +1 -1
  15. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
  16. data/lib/mongoid/association/macros.rb +0 -6
  17. data/lib/mongoid/association/nested/one.rb +40 -2
  18. data/lib/mongoid/association/proxy.rb +1 -1
  19. data/lib/mongoid/association/referenced/counter_cache.rb +2 -2
  20. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +1 -1
  21. data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -2
  22. data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -3
  23. data/lib/mongoid/association/reflections.rb +2 -2
  24. data/lib/mongoid/atomic.rb +0 -7
  25. data/lib/mongoid/attributes/dynamic.rb +1 -1
  26. data/lib/mongoid/attributes/nested.rb +2 -2
  27. data/lib/mongoid/attributes/processing.rb +5 -29
  28. data/lib/mongoid/attributes/projector.rb +1 -1
  29. data/lib/mongoid/attributes/readonly.rb +1 -1
  30. data/lib/mongoid/attributes.rb +8 -2
  31. data/lib/mongoid/changeable.rb +107 -5
  32. data/lib/mongoid/clients/storage_options.rb +2 -5
  33. data/lib/mongoid/clients/validators/storage.rb +1 -13
  34. data/lib/mongoid/collection_configurable.rb +58 -0
  35. data/lib/mongoid/composable.rb +2 -0
  36. data/lib/mongoid/config/defaults.rb +60 -0
  37. data/lib/mongoid/config/options.rb +0 -3
  38. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  39. data/lib/mongoid/config/validators.rb +1 -0
  40. data/lib/mongoid/config.rb +99 -28
  41. data/lib/mongoid/contextual/atomic.rb +1 -1
  42. data/lib/mongoid/contextual/memory.rb +233 -33
  43. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  44. data/lib/mongoid/contextual/mongo.rb +370 -133
  45. data/lib/mongoid/contextual/none.rb +162 -7
  46. data/lib/mongoid/contextual.rb +12 -0
  47. data/lib/mongoid/criteria/findable.rb +2 -2
  48. data/lib/mongoid/criteria/includable.rb +4 -3
  49. data/lib/mongoid/criteria/queryable/key.rb +1 -1
  50. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  51. data/lib/mongoid/criteria/queryable/optional.rb +8 -8
  52. data/lib/mongoid/criteria/queryable/selectable.rb +43 -12
  53. data/lib/mongoid/criteria/queryable/selector.rb +1 -1
  54. data/lib/mongoid/criteria/queryable/storable.rb +1 -1
  55. data/lib/mongoid/criteria.rb +6 -5
  56. data/lib/mongoid/deprecable.rb +1 -2
  57. data/lib/mongoid/deprecation.rb +3 -3
  58. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  59. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  60. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  61. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  62. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  63. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  64. data/lib/mongoid/errors.rb +4 -1
  65. data/lib/mongoid/extensions/hash.rb +2 -24
  66. data/lib/mongoid/extensions/object.rb +2 -2
  67. data/lib/mongoid/extensions/time.rb +2 -0
  68. data/lib/mongoid/fields/localized.rb +10 -0
  69. data/lib/mongoid/fields/standard.rb +10 -0
  70. data/lib/mongoid/fields.rb +53 -24
  71. data/lib/mongoid/findable.rb +27 -3
  72. data/lib/mongoid/interceptable.rb +10 -118
  73. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  74. data/lib/mongoid/matcher/type.rb +1 -1
  75. data/lib/mongoid/persistable/creatable.rb +1 -0
  76. data/lib/mongoid/persistable/deletable.rb +1 -1
  77. data/lib/mongoid/persistable/savable.rb +13 -1
  78. data/lib/mongoid/persistable/unsettable.rb +2 -2
  79. data/lib/mongoid/persistable/updatable.rb +51 -1
  80. data/lib/mongoid/persistable/upsertable.rb +20 -1
  81. data/lib/mongoid/persistable.rb +3 -0
  82. data/lib/mongoid/query_cache.rb +5 -1
  83. data/lib/mongoid/railties/database.rake +7 -2
  84. data/lib/mongoid/reloadable.rb +5 -3
  85. data/lib/mongoid/stateful.rb +22 -1
  86. data/lib/mongoid/tasks/database.rake +12 -0
  87. data/lib/mongoid/tasks/database.rb +20 -0
  88. data/lib/mongoid/utils.rb +22 -0
  89. data/lib/mongoid/validatable/macros.rb +5 -5
  90. data/lib/mongoid/validatable.rb +4 -1
  91. data/lib/mongoid/version.rb +1 -1
  92. data/lib/mongoid/warnings.rb +17 -1
  93. data/lib/mongoid.rb +16 -3
  94. data/spec/integration/app_spec.rb +2 -2
  95. data/spec/integration/callbacks_models.rb +37 -0
  96. data/spec/integration/callbacks_spec.rb +126 -12
  97. data/spec/integration/discriminator_key_spec.rb +4 -5
  98. data/spec/integration/i18n_fallbacks_spec.rb +3 -2
  99. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +27 -0
  100. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +20 -25
  101. data/spec/mongoid/association/embedded/embeds_many_models.rb +1 -0
  102. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  103. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -18
  104. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +5 -27
  105. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +9 -50
  106. data/spec/mongoid/association/syncable_spec.rb +1 -1
  107. data/spec/mongoid/attributes_spec.rb +3 -33
  108. data/spec/mongoid/changeable_spec.rb +299 -24
  109. data/spec/mongoid/clients_spec.rb +122 -13
  110. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  111. data/spec/mongoid/config/defaults_spec.rb +160 -0
  112. data/spec/mongoid/config_spec.rb +154 -27
  113. data/spec/mongoid/contextual/memory_spec.rb +332 -76
  114. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  115. data/spec/mongoid/contextual/mongo_spec.rb +1009 -125
  116. data/spec/mongoid/contextual/none_spec.rb +49 -2
  117. data/spec/mongoid/copyable_spec.rb +2 -10
  118. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -10
  119. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  120. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +419 -0
  121. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -1
  122. data/spec/mongoid/criteria/queryable/selector_spec.rb +3 -76
  123. data/spec/mongoid/criteria/queryable/storable_spec.rb +0 -72
  124. data/spec/mongoid/criteria_projection_spec.rb +1 -4
  125. data/spec/mongoid/criteria_spec.rb +5 -9
  126. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  127. data/spec/mongoid/extensions/hash_spec.rb +3 -3
  128. data/spec/mongoid/extensions/time_spec.rb +8 -43
  129. data/spec/mongoid/extensions/time_with_zone_spec.rb +7 -52
  130. data/spec/mongoid/fields/localized_spec.rb +46 -28
  131. data/spec/mongoid/fields_spec.rb +136 -77
  132. data/spec/mongoid/findable_spec.rb +391 -34
  133. data/spec/mongoid/indexable_spec.rb +16 -10
  134. data/spec/mongoid/interceptable_spec.rb +173 -362
  135. data/spec/mongoid/persistable/deletable_spec.rb +26 -6
  136. data/spec/mongoid/persistable/destroyable_spec.rb +26 -6
  137. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  138. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  139. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  140. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  141. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  142. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  143. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  144. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  145. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  146. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  147. data/spec/mongoid/persistable/upsertable_spec.rb +80 -6
  148. data/spec/mongoid/persistence_context_spec.rb +7 -57
  149. data/spec/mongoid/query_cache_spec.rb +56 -61
  150. data/spec/mongoid/reloadable_spec.rb +24 -28
  151. data/spec/mongoid/scopable_spec.rb +70 -0
  152. data/spec/mongoid/serializable_spec.rb +9 -30
  153. data/spec/mongoid/stateful_spec.rb +122 -8
  154. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  155. data/spec/mongoid/tasks/database_spec.rb +127 -0
  156. data/spec/mongoid/timestamps_spec.rb +9 -11
  157. data/spec/mongoid/touchable_spec.rb +277 -5
  158. data/spec/mongoid/touchable_spec_models.rb +3 -1
  159. data/spec/mongoid/traversable_spec.rb +9 -24
  160. data/spec/mongoid/validatable/uniqueness_spec.rb +2 -3
  161. data/spec/mongoid_spec.rb +36 -10
  162. data/spec/spec_helper.rb +5 -0
  163. data/spec/support/immutable_ids.rb +118 -0
  164. data/spec/support/macros.rb +47 -15
  165. data/spec/support/models/artist.rb +0 -1
  166. data/spec/support/models/band.rb +1 -0
  167. data/spec/support/models/book.rb +1 -0
  168. data/spec/support/models/building.rb +2 -0
  169. data/spec/support/models/cover.rb +10 -0
  170. data/spec/support/models/person.rb +0 -1
  171. data/spec/support/models/product.rb +1 -0
  172. data.tar.gz.sig +0 -0
  173. metadata +685 -651
  174. metadata.gz.sig +0 -0
  175. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  176. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
  177. data/spec/support/models/purse.rb +0 -9
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Errors
5
+
6
+ # This error is raised when attempting the change the value of an
7
+ # immutable attribute. For example, the _id attribute is immutable,
8
+ # and attempting to change it on a document that has already been
9
+ # persisted will result in this error.
10
+ class ImmutableAttribute < MongoidError
11
+
12
+ # Create the new error.
13
+ #
14
+ # @example Create the new error.
15
+ # ImmutableAttribute.new(:_id, "1234")
16
+ #
17
+ # @param [ Symbol | String ] name The name of the attribute.
18
+ # @param [ Object ] value The attempted set value.
19
+ def initialize(name, value)
20
+ super(
21
+ compose_message("immutable_attribute", { name: name, value: value })
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Errors
5
+
6
+ # This error is raised when a bad async query executor option is attempted
7
+ # to be set.
8
+ class InvalidQueryExecutor < MongoidError
9
+
10
+ # Create the new error.
11
+ #
12
+ # @param [ Symbol | String ] executor The attempted async query executor.
13
+ #
14
+ # @api private
15
+ def initialize(executor)
16
+ super(
17
+ compose_message(
18
+ "invalid_async_query_executor",
19
+ { executor: executor, options: [:immediate, :global_thread_pool] }
20
+ )
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Errors
5
+
6
+ # This error is raised when a bad global executor concurrency option is attempted
7
+ # to be set.
8
+ class InvalidGlobalExecutorConcurrency < MongoidError
9
+
10
+ # Create the new error.
11
+ #
12
+ # @api private
13
+ def initialize
14
+ super(
15
+ compose_message(
16
+ "invalid_global_executor_concurrency"
17
+ )
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
@@ -4,6 +4,8 @@ module Mongoid
4
4
  module Errors
5
5
 
6
6
  # Raised when calling store_in in a sub-class of Mongoid::Document
7
+ #
8
+ # @deprecated
7
9
  class InvalidStorageParent < MongoidError
8
10
 
9
11
  # Create the new error.
@@ -3,11 +3,14 @@
3
3
  require "mongoid/errors/mongoid_error"
4
4
  require "mongoid/errors/ambiguous_relationship"
5
5
  require "mongoid/errors/callback"
6
+ require "mongoid/errors/create_collection_failure"
6
7
  require "mongoid/errors/criteria_argument_required"
7
8
  require "mongoid/errors/document_not_destroyed"
8
9
  require "mongoid/errors/document_not_found"
9
10
  require "mongoid/errors/empty_config_file"
11
+ require "mongoid/errors/immutable_attribute"
10
12
  require "mongoid/errors/in_memory_collation_not_supported"
13
+ require "mongoid/errors/invalid_async_query_executor"
11
14
  require "mongoid/errors/invalid_collection"
12
15
  require "mongoid/errors/invalid_config_file"
13
16
  require "mongoid/errors/invalid_config_option"
@@ -16,6 +19,7 @@ require "mongoid/errors/invalid_field"
16
19
  require "mongoid/errors/invalid_field_option"
17
20
  require "mongoid/errors/invalid_field_type"
18
21
  require "mongoid/errors/invalid_find"
22
+ require "mongoid/errors/invalid_global_executor_concurrency"
19
23
  require "mongoid/errors/invalid_includes"
20
24
  require "mongoid/errors/invalid_index"
21
25
  require "mongoid/errors/invalid_options"
@@ -35,7 +39,6 @@ require "mongoid/errors/invalid_scope"
35
39
  require "mongoid/errors/invalid_session_use"
36
40
  require "mongoid/errors/invalid_set_polymorphic_relation"
37
41
  require "mongoid/errors/invalid_storage_options"
38
- require "mongoid/errors/invalid_storage_parent"
39
42
  require "mongoid/errors/invalid_time"
40
43
  require "mongoid/errors/inverse_not_found"
41
44
  require "mongoid/errors/mixed_relations"
@@ -38,12 +38,8 @@ module Mongoid
38
38
  consolidated = {}
39
39
  each_pair do |key, value|
40
40
  if key =~ /\$/
41
- value.keys.each do |key2|
42
- value2 = value[key2]
43
- real_key = klass.database_field_name(key2)
44
-
45
- value.delete(key2) if real_key != key2
46
- value[real_key] = value_for(key, klass, real_key, value2)
41
+ value.each_pair do |_key, _value|
42
+ value[_key] = (key == "$rename") ? _value.to_s : mongoize_for(key, klass, _key, _value)
47
43
  end
48
44
  consolidated[key] ||= {}
49
45
  consolidated[key].update(value)
@@ -185,24 +181,6 @@ module Mongoid
185
181
 
186
182
  private
187
183
 
188
- # Get the value for the provided operator, klass, key and value.
189
- #
190
- # This is necessary for special cases like $rename, $addToSet and $push.
191
- #
192
- # @param [ String ] operator The operator.
193
- # @param [ Class ] klass The model class.
194
- # @param [ String | Symbol ] key The field key.
195
- # @param [ Object ] value The original value.
196
- #
197
- # @return [ Object ] Value prepared for the provided operator.
198
- def value_for(operator, klass, key, value)
199
- case operator
200
- when "$rename" then value.to_s
201
- when "$addToSet", "$push" then value.mongoize
202
- else mongoize_for(operator, klass, operator, value)
203
- end
204
- end
205
-
206
184
  # Mongoize for the klass, key and value.
207
185
  #
208
186
  # @api private
@@ -91,7 +91,7 @@ module Mongoid
91
91
  # object.do_or_do_not(:use, "The Force")
92
92
  #
93
93
  # @param [ String | Symbol ] name The method name.
94
- # @param [ Array ] args The arguments.
94
+ # @param [ Object... ] *args The arguments.
95
95
  #
96
96
  # @return [ Object | nil ] The result of the method call or nil if the
97
97
  # method does not exist.
@@ -190,7 +190,7 @@ module Mongoid
190
190
  # object.you_must(:use, "The Force")
191
191
  #
192
192
  # @param [ String | Symbol ] name The method name.
193
- # @param [ Array ] args The arguments.
193
+ # @param [ Object... ] *args The arguments.
194
194
  #
195
195
  # @return [ Object | nil ] The result of the method call or nil if the
196
196
  # method does not exist. Nil if the object is frozen.
@@ -34,6 +34,8 @@ module Mongoid
34
34
  # ::Time.configured
35
35
  #
36
36
  # @return [ Time ] The configured time.
37
+ #
38
+ # @deprecated
37
39
  def configured
38
40
  Mongoid.use_activesupport_time_zone? ? (::Time.zone || ::Time) : ::Time
39
41
  end
@@ -31,6 +31,16 @@ module Mongoid
31
31
  true
32
32
  end
33
33
 
34
+ # Is the localized field enforcing values to be present?
35
+ #
36
+ # @example Is the localized field enforcing values to be present?
37
+ # field.localize_present?
38
+ #
39
+ # @return [ true | false ] If the field enforces present.
40
+ def localize_present?
41
+ options[:localize] == :present
42
+ end
43
+
34
44
  # Convert the provided string into a hash for the locale.
35
45
  #
36
46
  # @example Serialize the value.
@@ -97,6 +97,16 @@ module Mongoid
97
97
  false
98
98
  end
99
99
 
100
+ # Is the localized field enforcing values to be present?
101
+ #
102
+ # @example Is the localized field enforcing values to be present?
103
+ # field.localize_present?
104
+ #
105
+ # @return [ true | false ] If the field enforces present.
106
+ def localize_present?
107
+ false
108
+ end
109
+
100
110
  # Get the metadata for the field if its a foreign key.
101
111
  #
102
112
  # @example Get the metadata.
@@ -538,6 +538,8 @@ module Mongoid
538
538
  # Model.add_defaults(field)
539
539
  #
540
540
  # @param [ Field ] field The field to add for.
541
+ #
542
+ # @api private
541
543
  def add_defaults(field)
542
544
  default, name = field.default_val, field.name.to_s
543
545
  remove_defaults(name)
@@ -557,6 +559,8 @@ module Mongoid
557
559
  #
558
560
  # @param [ Symbol ] name The name of the field.
559
561
  # @param [ Hash ] options The hash of options.
562
+ #
563
+ # @api private
560
564
  def add_field(name, options = {})
561
565
  aliased = options[:as]
562
566
  aliased_fields[aliased.to_s] = name if aliased
@@ -584,6 +588,8 @@ module Mongoid
584
588
  # # => "called"
585
589
  #
586
590
  # @param [ Field ] field the field to process
591
+ #
592
+ # @api private
587
593
  def process_options(field)
588
594
  field_options = field.options
589
595
 
@@ -606,6 +612,8 @@ module Mongoid
606
612
  # @param [ Symbol ] name The name of the field.
607
613
  # @param [ Symbol ] meth The name of the accessor.
608
614
  # @param [ Hash ] options The options.
615
+ #
616
+ # @api private
609
617
  def create_accessors(name, meth, options = {})
610
618
  field = fields[name]
611
619
 
@@ -629,6 +637,8 @@ module Mongoid
629
637
  # @param [ String ] name The name of the attribute.
630
638
  # @param [ String ] meth The name of the method.
631
639
  # @param [ Field ] field The field.
640
+ #
641
+ # @api private
632
642
  def create_field_getter(name, meth, field)
633
643
  generated_methods.module_eval do
634
644
  re_define_method(meth) do
@@ -651,6 +661,8 @@ module Mongoid
651
661
  #
652
662
  # @param [ String ] name The name of the attribute.
653
663
  # @param [ String ] meth The name of the method.
664
+ #
665
+ # @api private
654
666
  def create_field_getter_before_type_cast(name, meth)
655
667
  generated_methods.module_eval do
656
668
  re_define_method("#{meth}_before_type_cast") do
@@ -671,6 +683,8 @@ module Mongoid
671
683
  # @param [ String ] name The name of the attribute.
672
684
  # @param [ String ] meth The name of the method.
673
685
  # @param [ Field ] field The field.
686
+ #
687
+ # @api private
674
688
  def create_field_setter(name, meth, field)
675
689
  generated_methods.module_eval do
676
690
  re_define_method("#{meth}=") do |value|
@@ -690,6 +704,8 @@ module Mongoid
690
704
  #
691
705
  # @param [ String ] name The name of the attribute.
692
706
  # @param [ String ] meth The name of the method.
707
+ #
708
+ # @api private
693
709
  def create_field_check(name, meth)
694
710
  generated_methods.module_eval do
695
711
  re_define_method("#{meth}?") do
@@ -706,6 +722,8 @@ module Mongoid
706
722
  #
707
723
  # @param [ String ] name The name of the attribute.
708
724
  # @param [ String ] meth The name of the method.
725
+ #
726
+ # @api private
709
727
  def create_translations_getter(name, meth)
710
728
  generated_methods.module_eval do
711
729
  re_define_method("#{meth}_translations") do
@@ -724,6 +742,8 @@ module Mongoid
724
742
  # @param [ String ] name The name of the attribute.
725
743
  # @param [ String ] meth The name of the method.
726
744
  # @param [ Field ] field The field.
745
+ #
746
+ # @api private
727
747
  def create_translations_setter(name, meth, field)
728
748
  generated_methods.module_eval do
729
749
  re_define_method("#{meth}_translations=") do |value|
@@ -743,6 +763,8 @@ module Mongoid
743
763
  # Person.generated_methods
744
764
  #
745
765
  # @return [ Module ] The module of generated methods.
766
+ #
767
+ # @api private
746
768
  def generated_methods
747
769
  @generated_methods ||= begin
748
770
  mod = Module.new
@@ -757,11 +779,21 @@ module Mongoid
757
779
  # Model.remove_defaults(name)
758
780
  #
759
781
  # @param [ String ] name The field name.
782
+ #
783
+ # @api private
760
784
  def remove_defaults(name)
761
785
  pre_processed_defaults.delete_one(name)
762
786
  post_processed_defaults.delete_one(name)
763
787
  end
764
788
 
789
+ # Create a field for the given name and options.
790
+ #
791
+ # @param [ Symbol ] name The name of the field.
792
+ # @param [ Hash ] options The hash of options.
793
+ #
794
+ # @return [ Field ] The created field.
795
+ #
796
+ # @api private
765
797
  def field_for(name, options)
766
798
  opts = options.merge(klass: self)
767
799
  opts[:type] = retrieve_and_validate_type(name, options[:type])
@@ -782,22 +814,32 @@ module Mongoid
782
814
  #
783
815
  # @api private
784
816
  def retrieve_and_validate_type(name, type)
785
- result = TYPE_MAPPINGS[type] || unmapped_type(type)
786
- raise Errors::InvalidFieldType.new(self, name, type) if !result.is_a?(Class)
787
-
788
- if unsupported_type?(result)
789
- warn_message = "Using #{result} as the field type is not supported. "
790
- if result == BSON::Decimal128
791
- warn_message += 'In BSON <= 4, the BSON::Decimal128 type will work as expected for both storing and querying, but will return a BigDecimal on query in BSON 5+. To use literal BSON::Decimal128 fields with BSON 5, set Mongoid.allow_bson5_decimal128 to true.'
792
- else
793
- warn_message += 'Saving values of this type to the database will work as expected, however, querying them will return a value of the native Ruby Integer type.'
817
+ type_mapping = TYPE_MAPPINGS[type]
818
+ result = type_mapping || unmapped_type(type)
819
+ if !result.is_a?(Class)
820
+ raise Errors::InvalidFieldType.new(self, name, type)
821
+ else
822
+ if INVALID_BSON_CLASSES.include?(result)
823
+ warn_message = "Using #{result} as the field type is not supported. "
824
+ if result == BSON::Decimal128
825
+ warn_message += "In BSON <= 4, the BSON::Decimal128 type will work as expected for both storing and querying, but will return a BigDecimal on query in BSON 5+."
826
+ else
827
+ warn_message += "Saving values of this type to the database will work as expected, however, querying them will return a value of the native Ruby Integer type."
828
+ end
829
+ Mongoid.logger.warn(warn_message)
794
830
  end
795
- Mongoid.logger.warn(warn_message)
796
831
  end
797
-
798
832
  result
799
833
  end
800
834
 
835
+ # Returns the type of the field if the type was not in the TYPE_MAPPINGS
836
+ # hash.
837
+ #
838
+ # @param [ Symbol | Class ] type The type of the field.
839
+ #
840
+ # @return [ Class ] The type of the field.
841
+ #
842
+ # @api private
801
843
  def unmapped_type(type)
802
844
  if "Boolean" == type.to_s
803
845
  Mongoid::Boolean
@@ -805,19 +847,6 @@ module Mongoid
805
847
  type || Object
806
848
  end
807
849
  end
808
-
809
- # Queries whether or not the given type is permitted as a declared field
810
- # type.
811
- #
812
- # @param [ Class ] type The type to query
813
- #
814
- # @return [ true | false ] whether or not the type is supported
815
- #
816
- # @api private
817
- def unsupported_type?(type)
818
- return !Mongoid::Config.allow_bson5_decimal128? if type == BSON::Decimal128
819
- INVALID_BSON_CLASSES.include?(type)
820
- end
821
850
  end
822
851
  end
823
852
  end
@@ -22,18 +22,24 @@ module Mongoid
22
22
  :each,
23
23
  :each_with_index,
24
24
  :extras,
25
+ :fifth,
26
+ :fifth!,
25
27
  :find_one_and_delete,
26
28
  :find_one_and_replace,
27
29
  :find_one_and_update,
28
30
  :find_or_create_by,
29
31
  :find_or_create_by!,
30
32
  :find_or_initialize_by,
33
+ :first!,
31
34
  :first_or_create,
32
35
  :first_or_create!,
33
36
  :first_or_initialize,
34
37
  :for_js,
38
+ :fourth,
39
+ :fourth!,
35
40
  :geo_near,
36
41
  :includes,
42
+ :last!,
37
43
  :map_reduce,
38
44
  :max,
39
45
  :min,
@@ -41,11 +47,19 @@ module Mongoid
41
47
  :pick,
42
48
  :pluck,
43
49
  :read,
50
+ :second,
51
+ :second!,
52
+ :second_to_last,
53
+ :second_to_last!,
44
54
  :sum,
45
55
  :take,
46
56
  :take!,
47
57
  :tally,
48
58
  :text_search,
59
+ :third,
60
+ :third!,
61
+ :third_to_last,
62
+ :third_to_last!,
49
63
  :update,
50
64
  :update_all,
51
65
 
@@ -87,9 +101,19 @@ module Mongoid
87
101
  # @example Do any documents exist for the conditions?
88
102
  # Person.exists?
89
103
  #
104
+ # @example Do any documents exist for given _id.
105
+ # Person.exists?(BSON::ObjectId(...))
106
+ #
107
+ # @example Do any documents exist for given conditions.
108
+ # Person.exists?(name: "...")
109
+ #
110
+ # @param [ Hash | Object | false ] id_or_conditions an _id to
111
+ # search for, a hash of conditions, nil or false.
112
+ #
90
113
  # @return [ true | false ] If any documents exist for the conditions.
91
- def exists?
92
- with_default_scope.exists?
114
+ # Always false if passed nil or false.
115
+ def exists?(id_or_conditions = :none)
116
+ with_default_scope.exists?(id_or_conditions)
93
117
  end
94
118
 
95
119
  # Finds a +Document+ or multiple documents by their _id values.
@@ -135,7 +159,7 @@ module Mongoid
135
159
  # @note Each argument can be an individual id, an array of ids or
136
160
  # a nested array. Each array will be flattened.
137
161
  #
138
- # @param [ Object | Array<Object> ] *args The _id value(s) to find.
162
+ # @param [ [ Object | Array<Object> ]... ] *args The id(s) to find.
139
163
  #
140
164
  # @return [ Document | Array<Document> | nil ] A document or matching documents.
141
165
  #
@@ -140,120 +140,31 @@ module Mongoid
140
140
  #
141
141
  # @api private
142
142
  def _mongoid_run_child_callbacks(kind, children: nil, &block)
143
- if Mongoid::Config.around_callbacks_for_embeds
144
- _mongoid_run_child_callbacks_with_around(kind, children: children, &block)
145
- else
146
- _mongoid_run_child_callbacks_without_around(kind, children: children, &block)
147
- end
148
- end
149
-
150
- # Execute the callbacks of given kind for embedded documents including
151
- # around callbacks.
152
- #
153
- # @note This method is prone to stack overflow errors if the document
154
- # has a large number of embedded documents. It is recommended to avoid
155
- # using around callbacks for embedded documents until a proper solution
156
- # is implemented.
157
- #
158
- # @param [ Symbol ] kind The type of callback to execute.
159
- # @param [ Array<Document> ] children Children to execute callbacks on. If
160
- # nil, callbacks will be executed on all cascadable children of
161
- # the document.
162
- #
163
- # @api private
164
- def _mongoid_run_child_callbacks_with_around(kind, children: nil, &block)
165
143
  child, *tail = (children || cascadable_children(kind))
144
+ with_children = !Mongoid::Config.prevent_multiple_calls_of_embedded_callbacks
166
145
  if child.nil?
167
146
  block&.call
168
147
  elsif tail.empty?
169
- child.run_callbacks(child_callback_type(kind, child), &block)
148
+ child.run_callbacks(child_callback_type(kind, child), with_children: with_children, &block)
170
149
  else
171
- child.run_callbacks(child_callback_type(kind, child)) do
172
- _mongoid_run_child_callbacks_with_around(kind, children: tail, &block)
173
- end
174
- end
175
- end
176
-
177
- # Execute the callbacks of given kind for embedded documents without
178
- # around callbacks.
179
- #
180
- # @param [ Symbol ] kind The type of callback to execute.
181
- # @param [ Array<Document> ] children Children to execute callbacks on. If
182
- # nil, callbacks will be executed on all cascadable children of
183
- # the document.
184
- #
185
- # @api private
186
- def _mongoid_run_child_callbacks_without_around(kind, children: nil, &block)
187
- children = (children || cascadable_children(kind))
188
- callback_list = _mongoid_run_child_before_callbacks(kind, children: children)
189
- return false if callback_list == false
190
- value = block&.call
191
- callback_list.each do |_next_sequence, env|
192
- env.value &&= value
193
- end
194
- return false if _mongoid_run_child_after_callbacks(callback_list: callback_list) == false
195
-
196
- value
197
- end
198
-
199
- # Execute the before callbacks of given kind for embedded documents.
200
- #
201
- # @param [ Symbol ] kind The type of callback to execute.
202
- # @param [ Array<Document> ] children Children to execute callbacks on.
203
- # @param [ Array<ActiveSupport::Callbacks::CallbackSequence, ActiveSupport::Callbacks::Filters::Environment> ] callback_list List of
204
- # pairs of callback sequence and environment. This list will be later used
205
- # to execute after callbacks in reverse order.
206
- #
207
- # @api private
208
- def _mongoid_run_child_before_callbacks(kind, children: [], callback_list: [])
209
- children.each do |child|
210
- chain = child.__callbacks[child_callback_type(kind, child)]
211
- env = ActiveSupport::Callbacks::Filters::Environment.new(child, false, nil)
212
- next_sequence = compile_callbacks(chain)
213
- unless next_sequence.final?
214
- Mongoid.logger.warn("Around callbacks are disabled for embedded documents. Skipping around callbacks for #{child.class.name}.")
215
- Mongoid.logger.warn("To enable around callbacks for embedded documents, set Mongoid::Config.around_callbacks_for_embeds to true.")
216
- end
217
- next_sequence.invoke_before(env)
218
- return false if env.halted
219
- env.value = !env.halted
220
- callback_list << [next_sequence, env]
221
- if (grandchildren = child.send(:cascadable_children, kind))
222
- _mongoid_run_child_before_callbacks(kind, children: grandchildren, callback_list: callback_list)
150
+ child.run_callbacks(child_callback_type(kind, child), with_children: with_children) do
151
+ _mongoid_run_child_callbacks(kind, children: tail, &block)
223
152
  end
224
153
  end
225
- callback_list
226
- end
227
-
228
- # Execute the after callbacks.
229
- #
230
- # @param [ Array<ActiveSupport::Callbacks::CallbackSequence, ActiveSupport::Callbacks::Filters::Environment> ] callback_list List of
231
- # pairs of callback sequence and environment.
232
- def _mongoid_run_child_after_callbacks(callback_list: [])
233
- callback_list.reverse_each do |next_sequence, env|
234
- next_sequence.invoke_after(env)
235
- return false if env.halted
236
- end
237
154
  end
238
155
 
239
- # Returns the stored callbacks to be executed later.
156
+ # This is used to store callbacks to be executed later. A good use case for
157
+ # this is delaying the after_find and after_initialize callbacks until the
158
+ # associations are set on the document. This can also be used to delay
159
+ # applying the defaults on a document.
240
160
  #
241
- # @return [ Array<Symbol> ] Method symbols of the stored pending callbacks.
161
+ # @return [ Array<Symbol> ] an array of symbols that represent the pending callbacks.
242
162
  #
243
163
  # @api private
244
164
  def pending_callbacks
245
165
  @pending_callbacks ||= [].to_set
246
166
  end
247
167
 
248
- # Stores callbacks to be executed later. A good use case for
249
- # this is delaying the after_find and after_initialize callbacks until the
250
- # associations are set on the document. This can also be used to delay
251
- # applying the defaults on a document.
252
- #
253
- # @param [ Array<Symbol> ] value Method symbols of the pending callbacks to store.
254
- #
255
- # @return [ Array<Symbol> ] Method symbols of the stored pending callbacks.
256
- #
257
168
  # @api private
258
169
  def pending_callbacks=(value)
259
170
  @pending_callbacks = value
@@ -388,7 +299,7 @@ module Mongoid
388
299
  end
389
300
  self.class.send :define_method, name do
390
301
  env = ActiveSupport::Callbacks::Filters::Environment.new(self, false, nil)
391
- sequence = compile_callbacks(chain)
302
+ sequence = chain.compile
392
303
  sequence.invoke_before(env)
393
304
  env.value = !env.halted
394
305
  sequence.invoke_after(env)
@@ -398,24 +309,5 @@ module Mongoid
398
309
  end
399
310
  send(name)
400
311
  end
401
-
402
- # Compile the callback chain.
403
- #
404
- # This method hides the differences between ActiveSupport implementations
405
- # before and after 7.1.
406
- #
407
- # @param [ ActiveSupport::Callbacks::CallbackChain ] chain The callback chain.
408
- # @param [ Symbol | nil ] type The type of callback chain to compile.
409
- #
410
- # @return [ ActiveSupport::Callbacks::CallbackSequence ] The compiled callback sequence.
411
- def compile_callbacks(chain, type = nil)
412
- if chain.method(:compile).arity == 0
413
- # ActiveSupport < 7.1
414
- chain.compile
415
- else
416
- # ActiveSupport >= 7.1
417
- chain.compile(type)
418
- end
419
- end
420
312
  end
421
313
  end
@@ -46,7 +46,7 @@ module Mongoid
46
46
  end
47
47
  end
48
48
 
49
- # Per https://docs.mongodb.com/ruby-driver/current/tutorials/bson-v4/#time-instances,
49
+ # Per https://www.mongodb.com/docs/ruby-driver/current/tutorials/bson-v4/#time-instances,
50
50
  # > Times in BSON (and MongoDB) can only have millisecond precision. When Ruby Time instances
51
51
  # are serialized to BSON or Extended JSON, the times are floored to the nearest millisecond.
52
52
  #
@@ -1,7 +1,7 @@
1
1
  module Mongoid
2
2
  module Matcher
3
3
 
4
- # @see https://docs.mongodb.com/manual/reference/operator/query/type/
4
+ # @see https://www.mongodb.com/docs/manual/reference/operator/query/type/
5
5
  #
6
6
  # @api private
7
7
  module Type
@@ -100,6 +100,7 @@ module Mongoid
100
100
  #
101
101
  # @return [ Document ] The document.
102
102
  def prepare_insert(options = {})
103
+ raise Errors::ReadonlyDocument.new(self.class) if readonly? && !Mongoid.legacy_readonly
103
104
  return self if performing_validations?(options) &&
104
105
  invalid?(options[:context] || :create)
105
106
  run_callbacks(:save, with_children: false) do