mongoid 7.1.0.rc0 → 7.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +6 -6
  5. data/LICENSE +1 -1
  6. data/README.md +5 -5
  7. data/Rakefile +14 -0
  8. data/lib/config/locales/en.yml +5 -5
  9. data/lib/mongoid.rb +3 -2
  10. data/lib/mongoid/association/accessors.rb +37 -2
  11. data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
  12. data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
  13. data/lib/mongoid/association/many.rb +3 -2
  14. data/lib/mongoid/association/proxy.rb +6 -4
  15. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -1
  16. data/lib/mongoid/association/referenced/belongs_to/eager.rb +38 -2
  17. data/lib/mongoid/association/referenced/eager.rb +29 -9
  18. data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -22
  19. data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -2
  20. data/lib/mongoid/atomic.rb +13 -3
  21. data/lib/mongoid/attributes.rb +28 -20
  22. data/lib/mongoid/clients/factory.rb +2 -2
  23. data/lib/mongoid/clients/options.rb +8 -8
  24. data/lib/mongoid/clients/sessions.rb +20 -4
  25. data/lib/mongoid/clients/storage_options.rb +5 -5
  26. data/lib/mongoid/config.rb +42 -12
  27. data/lib/mongoid/config/options.rb +5 -2
  28. data/lib/mongoid/contextual.rb +5 -4
  29. data/lib/mongoid/contextual/geo_near.rb +3 -2
  30. data/lib/mongoid/contextual/map_reduce.rb +3 -2
  31. data/lib/mongoid/contextual/mongo.rb +2 -1
  32. data/lib/mongoid/criteria.rb +23 -4
  33. data/lib/mongoid/criteria/modifiable.rb +2 -1
  34. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  35. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +6 -6
  36. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +12 -0
  37. data/lib/mongoid/criteria/queryable/mergeable.rb +75 -8
  38. data/lib/mongoid/criteria/queryable/pipeline.rb +3 -2
  39. data/lib/mongoid/criteria/queryable/selectable.rb +120 -13
  40. data/lib/mongoid/criteria/queryable/storable.rb +104 -99
  41. data/lib/mongoid/errors/eager_load.rb +2 -0
  42. data/lib/mongoid/errors/no_client_config.rb +2 -2
  43. data/lib/mongoid/errors/no_default_client.rb +1 -1
  44. data/lib/mongoid/extensions/hash.rb +4 -2
  45. data/lib/mongoid/extensions/regexp.rb +1 -1
  46. data/lib/mongoid/fields.rb +2 -1
  47. data/lib/mongoid/fields/standard.rb +2 -1
  48. data/lib/mongoid/fields/validators/macro.rb +4 -1
  49. data/lib/mongoid/findable.rb +5 -4
  50. data/lib/mongoid/interceptable.rb +5 -1
  51. data/lib/mongoid/matchable/regexp.rb +2 -2
  52. data/lib/mongoid/persistable/pushable.rb +11 -2
  53. data/lib/mongoid/persistence_context.rb +6 -6
  54. data/lib/mongoid/query_cache.rb +61 -18
  55. data/lib/mongoid/railties/database.rake +7 -0
  56. data/lib/mongoid/serializable.rb +10 -2
  57. data/lib/mongoid/shardable.rb +56 -4
  58. data/lib/mongoid/tasks/database.rake +10 -5
  59. data/lib/mongoid/tasks/database.rb +83 -0
  60. data/lib/mongoid/timestamps/timeless.rb +3 -1
  61. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  62. data/lib/mongoid/version.rb +1 -1
  63. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +32 -23
  64. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  65. data/spec/app/models/coding.rb +4 -0
  66. data/spec/app/models/coding/pull_request.rb +12 -0
  67. data/spec/app/models/delegating_patient.rb +16 -0
  68. data/spec/app/models/passport.rb +1 -0
  69. data/spec/app/models/phone.rb +1 -0
  70. data/spec/app/models/publication.rb +5 -0
  71. data/spec/app/models/publication/encyclopedia.rb +12 -0
  72. data/spec/app/models/publication/review.rb +14 -0
  73. data/spec/integration/app_spec.rb +254 -0
  74. data/spec/integration/associations/embedded_spec.rb +54 -0
  75. data/spec/integration/associations/has_many_spec.rb +34 -0
  76. data/spec/integration/associations/has_one_spec.rb +34 -0
  77. data/spec/integration/bson_regexp_raw_spec.rb +20 -0
  78. data/spec/integration/criteria/date_field_spec.rb +41 -0
  79. data/spec/integration/criteria/logical_spec.rb +13 -0
  80. data/spec/integration/document_spec.rb +22 -0
  81. data/spec/integration/shardable_spec.rb +149 -0
  82. data/spec/lite_spec_helper.rb +15 -4
  83. data/spec/mongoid/association/accessors_spec.rb +238 -63
  84. data/spec/mongoid/association/embedded/embeds_many_models.rb +19 -0
  85. data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
  86. data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
  87. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +193 -10
  88. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +140 -1
  89. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +146 -68
  90. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
  91. data/spec/mongoid/attributes_spec.rb +19 -7
  92. data/spec/mongoid/changeable_spec.rb +23 -0
  93. data/spec/mongoid/clients/factory_spec.rb +8 -8
  94. data/spec/mongoid/clients/options_spec.rb +11 -11
  95. data/spec/mongoid/clients/sessions_spec.rb +8 -4
  96. data/spec/mongoid/clients/transactions_spec.rb +20 -8
  97. data/spec/mongoid/clients_spec.rb +2 -2
  98. data/spec/mongoid/contextual/atomic_spec.rb +22 -11
  99. data/spec/mongoid/contextual/geo_near_spec.rb +11 -2
  100. data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
  101. data/spec/mongoid/contextual/mongo_spec.rb +76 -53
  102. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +1 -1
  103. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
  104. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
  105. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +19 -7
  106. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +28 -1
  107. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +45 -12
  108. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +1051 -392
  109. data/spec/mongoid/criteria/queryable/selectable_spec.rb +52 -0
  110. data/spec/mongoid/criteria/queryable/storable_spec.rb +80 -2
  111. data/spec/mongoid/criteria_spec.rb +36 -2
  112. data/spec/mongoid/document_fields_spec.rb +29 -0
  113. data/spec/mongoid/document_persistence_context_spec.rb +33 -0
  114. data/spec/mongoid/errors/no_client_config_spec.rb +2 -2
  115. data/spec/mongoid/errors/no_client_database_spec.rb +3 -3
  116. data/spec/mongoid/errors/no_client_hosts_spec.rb +3 -3
  117. data/spec/mongoid/fields_spec.rb +24 -1
  118. data/spec/mongoid/indexable_spec.rb +6 -4
  119. data/spec/mongoid/interceptable_spec.rb +62 -0
  120. data/spec/mongoid/interceptable_spec_models.rb +76 -0
  121. data/spec/mongoid/matchable/default_spec.rb +1 -1
  122. data/spec/mongoid/matchable/regexp_spec.rb +2 -2
  123. data/spec/mongoid/matchable_spec.rb +2 -2
  124. data/spec/mongoid/persistable/pushable_spec.rb +55 -1
  125. data/spec/mongoid/query_cache_spec.rb +77 -9
  126. data/spec/mongoid/relations/proxy_spec.rb +1 -1
  127. data/spec/mongoid/scopable_spec.rb +2 -1
  128. data/spec/mongoid/serializable_spec.rb +129 -18
  129. data/spec/mongoid/shardable_models.rb +61 -0
  130. data/spec/mongoid/shardable_spec.rb +69 -16
  131. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  132. data/spec/mongoid/tasks/database_spec.rb +1 -1
  133. data/spec/spec_helper.rb +2 -31
  134. data/spec/support/child_process_helper.rb +76 -0
  135. data/spec/support/cluster_config.rb +3 -3
  136. data/spec/support/constraints.rb +26 -10
  137. data/spec/support/expectations.rb +3 -1
  138. data/spec/support/helpers.rb +11 -0
  139. data/spec/support/lite_constraints.rb +22 -0
  140. data/spec/support/session_registry.rb +50 -0
  141. data/spec/support/spec_config.rb +12 -4
  142. metadata +518 -480
  143. metadata.gz.sig +0 -0
@@ -9,9 +9,10 @@ module Mongoid
9
9
  # This class defines the behavior for all associations that are a
10
10
  # one-to-many between documents in different collections.
11
11
  class Proxy < Association::Many
12
+ extend Forwardable
12
13
 
13
- delegate :count, to: :criteria
14
- delegate :first, :in_memory, :last, :reset, :uniq, to: :_target
14
+ def_delegator :criteria, :count
15
+ def_delegators :_target, :first, :in_memory, :last, :reset, :uniq
15
16
 
16
17
  # Appends a document or array of documents to the association. Will set
17
18
  # the parent and update the index in the process.
@@ -38,7 +38,9 @@ module Mongoid
38
38
  # @since 2.2.0
39
39
  def add_atomic_pull(document)
40
40
  document.flagged_for_destroy = true
41
- (delayed_atomic_pulls[document.association_name.to_s] ||= []).push(document)
41
+ key = document.association_name.to_s
42
+ delayed_atomic_pulls[key] ||= []
43
+ delayed_atomic_pulls[key] << document
42
44
  end
43
45
 
44
46
  # Add an atomic unset for the document.
@@ -53,7 +55,9 @@ module Mongoid
53
55
  # @since 3.0.0
54
56
  def add_atomic_unset(document)
55
57
  document.flagged_for_destroy = true
56
- (delayed_atomic_unsets[document.association_name.to_s] ||= []).push(document)
58
+ key = document.association_name.to_s
59
+ delayed_atomic_unsets[key] ||= []
60
+ delayed_atomic_unsets[key] << document
57
61
  end
58
62
 
59
63
  # Returns path of the attribute for modification
@@ -191,7 +195,13 @@ module Mongoid
191
195
  #
192
196
  # @since 2.1.0
193
197
  def atomic_paths
194
- @atomic_paths ||= _association ? _association.path(self) : Atomic::Paths::Root.new(self)
198
+ @atomic_paths ||= begin
199
+ if _association
200
+ _association.path(self)
201
+ else
202
+ Atomic::Paths::Root.new(self)
203
+ end
204
+ end
195
205
  end
196
206
 
197
207
  # Get all the attributes that need to be pulled.
@@ -159,21 +159,21 @@ module Mongoid
159
159
  #
160
160
  # @since 1.0.0
161
161
  def write_attribute(name, value)
162
- access = database_field_name(name)
163
- if attribute_writable?(access)
162
+ field_name = database_field_name(name)
163
+ if attribute_writable?(field_name)
164
164
  _assigning do
165
- validate_attribute_value(access, value)
166
- localized = fields[access].try(:localized?)
165
+ validate_attribute_value(field_name, value)
166
+ localized = fields[field_name].try(:localized?)
167
167
  attributes_before_type_cast[name.to_s] = value
168
- typed_value = typed_value_for(access, value)
169
- unless attributes[access] == typed_value || attribute_changed?(access)
170
- attribute_will_change!(access)
168
+ typed_value = typed_value_for(field_name, value)
169
+ unless attributes[field_name] == typed_value || attribute_changed?(field_name)
170
+ attribute_will_change!(field_name)
171
171
  end
172
172
  if localized
173
- attributes[access] ||= {}
174
- attributes[access].merge!(typed_value)
173
+ attributes[field_name] ||= {}
174
+ attributes[field_name].merge!(typed_value)
175
175
  else
176
- attributes[access] = typed_value
176
+ attributes[field_name] = typed_value
177
177
  end
178
178
  typed_value
179
179
  end
@@ -338,20 +338,28 @@ module Mongoid
338
338
 
339
339
  private
340
340
 
341
- # Validates an attribute value. This provides validation checking if
342
- # the value is valid for given a field.
343
- # For now, only Hash and Array fields are validated.
341
+ # Validates an attribute value as being assignable to the specified field.
344
342
  #
345
- # @param [ String, Symbol ] access The name of the attribute to validate.
346
- # @param [ Object ] value The to be validated.
343
+ # For now, only Hash and Array fields are validated, and the value is
344
+ # being checked to be of an appropriate type (i.e. either Hash or Array,
345
+ # respectively, or nil).
346
+ #
347
+ # This method takes the name of the field as stored in the document
348
+ # in the database, not (necessarily) the Ruby method name used to read/write
349
+ # the said field.
350
+ #
351
+ # @param [ String, Symbol ] field_name The name of the field.
352
+ # @param [ Object ] value The value to be validated.
347
353
  #
348
354
  # @since 3.0.10
349
- def validate_attribute_value(access, value)
350
- return unless fields[access] && value
355
+ def validate_attribute_value(field_name, value)
356
+ return if value.nil?
357
+ field = fields[field_name]
358
+ return unless field
351
359
  validatable_types = [ Hash, Array ]
352
- if validatable_types.include? fields[access].type
353
- unless value.is_a? fields[access].type
354
- raise Mongoid::Errors::InvalidValue.new(fields[access].type, value.class)
360
+ if validatable_types.include?(field.type)
361
+ unless value.is_a?(field.type)
362
+ raise Mongoid::Errors::InvalidValue.new(field.type, value.class)
355
363
  end
356
364
  end
357
365
  end
@@ -12,9 +12,9 @@ module Mongoid
12
12
  # raised.
13
13
  #
14
14
  # @example Create the client.
15
- # Factory.create(:secondary)
15
+ # Factory.create(:analytics)
16
16
  #
17
- # @param [ String, Symbol ] name The named client configuration.
17
+ # @param [ String | Symbol ] name The named client configuration.
18
18
  #
19
19
  # @raise [ Errors::NoClientConfig ] If no config could be found.
20
20
  #
@@ -9,16 +9,16 @@ module Mongoid
9
9
  # Change the persistence context for this object during the block.
10
10
  #
11
11
  # @example Save the current document to a different collection.
12
- # model.with(collection: "secondary") do |m|
12
+ # model.with(collection: "bands") do |m|
13
13
  # m.save
14
14
  # end
15
15
  #
16
16
  # @param [ Hash, Mongoid::PersistenceContext ] options_or_context
17
17
  # The storage options or a persistence context.
18
18
  #
19
- # @option options [ String, Symbol ] :collection The collection name.
20
- # @option options [ String, Symbol ] :database The database name.
21
- # @option options [ String, Symbol ] :client The client name.
19
+ # @option options [ String | Symbol ] :collection The collection name.
20
+ # @option options [ String | Symbol ] :database The database name.
21
+ # @option options [ String | Symbol ] :client The client name.
22
22
  #
23
23
  # @since 6.0.0
24
24
  def with(options_or_context, &block)
@@ -83,15 +83,15 @@ module Mongoid
83
83
  # Change the persistence context for this class during the block.
84
84
  #
85
85
  # @example Save the current document to a different collection.
86
- # Model.with(collection: "secondary") do |m|
86
+ # Model.with(collection: "bands") do |m|
87
87
  # m.create
88
88
  # end
89
89
  #
90
90
  # @param [ Hash ] options The storage options.
91
91
  #
92
- # @option options [ String, Symbol ] :collection The collection name.
93
- # @option options [ String, Symbol ] :database The database name.
94
- # @option options [ String, Symbol ] :client The client name.
92
+ # @option options [ String | Symbol ] :collection The collection name.
93
+ # @option options [ String | Symbol ] :database The database name.
94
+ # @option options [ String | Symbol ] :client The client name.
95
95
  #
96
96
  # @since 6.0.0
97
97
  def with(options, &block)
@@ -41,12 +41,20 @@ module Mongoid
41
41
  #
42
42
  # @since 6.4.0
43
43
  def with_session(options = {})
44
- raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting) if Threaded.get_session
44
+ if Threaded.get_session
45
+ raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting)
46
+ end
45
47
  session = persistence_context.client.start_session(options)
46
48
  Threaded.set_session(session)
47
49
  yield(session)
48
50
  rescue Mongo::Error::InvalidSession => ex
49
- if ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
51
+ if
52
+ # Driver 2.13.0+
53
+ defined?(Mongo::Error::SessionsNotSupported) &&
54
+ Mongo::Error::SessionsNotSupported === ex ||
55
+ # Legacy drivers
56
+ ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
57
+ then
50
58
  raise Mongoid::Errors::InvalidSessionUse.new(:sessions_not_supported)
51
59
  end
52
60
  raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_use)
@@ -92,12 +100,20 @@ module Mongoid
92
100
  #
93
101
  # @since 6.4.0
94
102
  def with_session(options = {})
95
- raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting) if Threaded.get_session
103
+ if Threaded.get_session
104
+ raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting)
105
+ end
96
106
  session = persistence_context.client.start_session(options)
97
107
  Threaded.set_session(session)
98
108
  yield(session)
99
109
  rescue Mongo::Error::InvalidSession => ex
100
- if ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
110
+ if
111
+ # Driver 2.13.0+
112
+ defined?(Mongo::Error::SessionsNotSupported) &&
113
+ Mongo::Error::SessionsNotSupported === ex ||
114
+ # Legacy drivers
115
+ ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
116
+ then
101
117
  raise Mongoid::Errors::InvalidSessionUse.new(:sessions_not_supported)
102
118
  end
103
119
  raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_use)
@@ -32,20 +32,20 @@ module Mongoid
32
32
  # @example Store this model by default in a different client.
33
33
  # class Band
34
34
  # include Mongoid::Document
35
- # store_in client: "secondary"
35
+ # store_in client: "analytics"
36
36
  # end
37
37
  #
38
38
  # @example Store this model with a combination of options.
39
39
  # class Band
40
40
  # include Mongoid::Document
41
- # store_in collection: "artists", database: "secondary"
41
+ # store_in collection: "artists", database: "music"
42
42
  # end
43
43
  #
44
44
  # @param [ Hash ] options The storage options.
45
45
  #
46
- # @option options [ String, Symbol ] :collection The collection name.
47
- # @option options [ String, Symbol ] :database The database name.
48
- # @option options [ String, Symbol ] :client The client name.
46
+ # @option options [ String | Symbol ] :collection The collection name.
47
+ # @option options [ String | Symbol ] :database The database name.
48
+ # @option options [ String | Symbol ] :client The client name.
49
49
  #
50
50
  # @return [ Class ] The model class.
51
51
  #
@@ -10,22 +10,39 @@ module Mongoid
10
10
  # This module defines all the configuration options for Mongoid, including
11
11
  # the database connections.
12
12
  module Config
13
- extend self
13
+ extend Forwardable
14
14
  extend Options
15
+ extend self
15
16
 
16
- delegate :logger=, to: ::Mongoid
17
- delegate :logger, to: ::Mongoid
17
+ def_delegators ::Mongoid, :logger, :logger=
18
18
 
19
19
  LOCK = Mutex.new
20
20
 
21
+ # Application name that is printed to the mongodb logs upon establishing
22
+ # a connection in server versions >= 3.4. Note that the name cannot
23
+ # exceed 128 bytes. It is also used as the database name if the
24
+ # database name is not explicitly defined.
25
+ option :app_name, default: nil
26
+
27
+ # Create indexes in background by default.
28
+ option :background_indexing, default: false
29
+
30
+ # Mark belongs_to associations as required by default, so that saving a
31
+ # model with a missing belongs_to association will trigger a validation
32
+ # error.
33
+ option :belongs_to_required_by_default, default: true
34
+
35
+ # Raise an exception when a field is redefined.
36
+ option :duplicate_fields_exception, default: false
37
+
38
+ # Include the root model name in json serialization.
21
39
  option :include_root_in_json, default: false
40
+
41
+ # # Include the _type field in serialization.
22
42
  option :include_type_for_serialization, default: false
23
- option :preload_models, default: false
24
- option :raise_not_found_error, default: true
25
- option :scope_overwrite_exception, default: false
26
- option :duplicate_fields_exception, default: false
27
- option :use_activesupport_time_zone, default: true
28
- option :use_utc, default: false
43
+
44
+ # Whether to join nested persistence contexts for atomic operations
45
+ # to parent contexts by default.
29
46
  option :join_contexts, default: false
30
47
 
31
48
  # The log level.
@@ -38,9 +55,22 @@ module Mongoid
38
55
  # configuration file is the log level given by this option honored.
39
56
  option :log_level, default: :info
40
57
 
41
- option :belongs_to_required_by_default, default: true
42
- option :app_name, default: nil
43
- option :background_indexing, default: false
58
+ # Preload all models in development, needed when models use inheritance.
59
+ option :preload_models, default: false
60
+
61
+ # Raise an error when performing a #find and the document is not found.
62
+ option :raise_not_found_error, default: true
63
+
64
+ # Raise an error when defining a scope with the same name as an
65
+ # existing method.
66
+ option :scope_overwrite_exception, default: false
67
+
68
+ # Use ActiveSupport's time zone in time operations instead of the
69
+ # Ruby default time zone.
70
+ option :use_activesupport_time_zone, default: true
71
+
72
+ # Return stored times as UTC.
73
+ option :use_utc, default: false
44
74
 
45
75
  # Has Mongoid been configured? This is checking that at least a valid
46
76
  # client config exists.
@@ -34,8 +34,11 @@ module Mongoid
34
34
  defaults[name] = settings[name] = options[:default]
35
35
 
36
36
  class_eval do
37
- define_method(name) do
38
- settings[name]
37
+ # log_level accessor is defined specially below
38
+ unless name.to_sym == :log_level
39
+ define_method(name) do
40
+ settings[name]
41
+ end
39
42
  end
40
43
 
41
44
  define_method("#{name}=") do |value|
@@ -8,21 +8,22 @@ require "mongoid/contextual/none"
8
8
 
9
9
  module Mongoid
10
10
  module Contextual
11
+ extend Forwardable
11
12
 
12
13
  # The aggregate operations provided in the aggregate module get delegated
13
14
  # through to the context from the criteria.
14
- delegate(*Aggregable::Mongo.public_instance_methods(false), to: :context)
15
+ def_delegators :context, *Aggregable::Mongo.public_instance_methods(false)
15
16
 
16
17
  # The atomic operations provided in the atomic context get delegated
17
18
  # through to the context from the criteria.
18
- delegate(*Atomic.public_instance_methods(false), to: :context)
19
+ def_delegators :context, *Atomic.public_instance_methods(false)
19
20
 
20
21
  # The methods in the contexts themselves should all get delegated to,
21
22
  # including destructive, modification, and optional methods.
22
- delegate(*(Mongo.public_instance_methods(false) - [ :skip, :limit ]), to: :context)
23
+ def_delegators :context, *(Mongo.public_instance_methods(false) - [ :skip, :limit ])
23
24
 
24
25
  # This gets blank and empty included.
25
- delegate(*Queryable.public_instance_methods(false), to: :context)
26
+ def_delegators :context, *Queryable.public_instance_methods(false)
26
27
 
27
28
  # Get the context in which criteria queries should execute. This is either
28
29
  # in memory (for embedded documents) or mongo (for root level documents.)
@@ -4,11 +4,12 @@
4
4
  module Mongoid
5
5
  module Contextual
6
6
  class GeoNear
7
+ extend Forwardable
7
8
  include Enumerable
8
9
  include Command
9
10
 
10
- delegate :[], to: :results
11
- delegate :==, :empty?, to: :entries
11
+ def_delegator :results, :[]
12
+ def_delegators :entries, :==, :empty?
12
13
 
13
14
  # Get the average distance for all documents from the point in the
14
15
  # command.
@@ -4,11 +4,12 @@
4
4
  module Mongoid
5
5
  module Contextual
6
6
  class MapReduce
7
+ extend Forwardable
7
8
  include Enumerable
8
9
  include Command
9
10
 
10
- delegate :[], to: :results
11
- delegate :==, :empty?, to: :entries
11
+ def_delegators :results, :[]
12
+ def_delegators :entries, :==, :empty?
12
13
 
13
14
  # Get all the counts returned by the map/reduce.
14
15
  #
@@ -11,6 +11,7 @@ require "mongoid/association/eager_loadable"
11
11
  module Mongoid
12
12
  module Contextual
13
13
  class Mongo
14
+ extend Forwardable
14
15
  include Enumerable
15
16
  include Aggregable::Mongo
16
17
  include Atomic
@@ -349,7 +350,7 @@ module Mongoid
349
350
  apply_options
350
351
  end
351
352
 
352
- delegate(:database_field_name, to: :@klass)
353
+ def_delegator :@klass, :database_field_name
353
354
 
354
355
  # Get the last document in the database for the criteria's selector.
355
356
  #
@@ -400,9 +400,22 @@ module Mongoid
400
400
  # @return [ Criteria ] The cloned selectable.
401
401
  #
402
402
  # @since 1.0.0
403
- def where(expression)
404
- if expression.is_a?(::String) && embedded?
405
- raise Errors::UnsupportedJavascript.new(klass, expression)
403
+ def where(*args)
404
+ # Historically this method required exactly one argument.
405
+ # As of https://jira.mongodb.org/browse/MONGOID-4804 it also accepts
406
+ # zero arguments.
407
+ # The underlying where implemetation that super invokes supports
408
+ # any number of arguments, but we don't presently allow mutiple
409
+ # arguments through this method. This API can be reconsidered in the
410
+ # future.
411
+ if args.length > 1
412
+ raise ArgumentError, "Criteria#where requires zero or one arguments (given #{args.length})"
413
+ end
414
+ if args.length == 1
415
+ expression = args.first
416
+ if expression.is_a?(::String) && embedded?
417
+ raise Errors::UnsupportedJavascript.new(klass, expression)
418
+ end
406
419
  end
407
420
  super
408
421
  end
@@ -437,7 +450,13 @@ module Mongoid
437
450
  #
438
451
  # @since 3.1.0
439
452
  def for_js(javascript, scope = {})
440
- js_query(BSON::CodeWithScope.new(javascript, scope))
453
+ code = if scope.empty?
454
+ # CodeWithScope is not supported for $where as of MongoDB 4.4
455
+ BSON::Code.new(javascript)
456
+ else
457
+ BSON::CodeWithScope.new(javascript, scope)
458
+ end
459
+ js_query(code)
441
460
  end
442
461
 
443
462
  private