mongoid 7.0.5 → 7.0.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d4a5f733ce016f190a456b5801a1e3a1efbe89a30d99a20cd4c73e5696e7004
4
- data.tar.gz: a40c8e747c7eeff97d8259bd6b11d35bf25de5434674c24f1c5ebe71ed5d6f3e
3
+ metadata.gz: ef857ba0b8faece9cb5bb46f2d1cb6e50fa1e2b52e6870c22cec4c5a3e73b98d
4
+ data.tar.gz: 030fbeeabf03434eb695eef129dd7abc1304419b550937ae225c2edd33824570
5
5
  SHA512:
6
- metadata.gz: 121ace21edf0fec13546294a101b4bb383eed7d7b7ead0d6bd3624ccfad5601a70a9e4b0363e710e687ba237835ea4a61da8d17ebab00a2537751a7fcbf5410f
7
- data.tar.gz: d39854dd3981a7c517e6ba00c0d85feb1e9bb6e928dabf233f603bf35f8299706c0981ed3cb9ba3c121e2af58ae42bc0e0e876a3a45f0264ac344d48469e9401
6
+ metadata.gz: 5e05da048526dece6963bfc5d33bb8e2db2ae3e26d37c9aa39949b9f69d16a93e33780bc7ce9244b23df11eb70e77d86cd95dfcd4426f864f3eb3429c0883033
7
+ data.tar.gz: dbb8f110097c0184d6de55630aac584722944d345723cca7ecaf76719548798970e992ba051beeb9b3ed801a49b4a2b1397a04717597620ab0183967091b368a
Binary file
data.tar.gz.sig CHANGED
Binary file
data/LICENSE CHANGED
@@ -1,4 +1,5 @@
1
1
  Copyright (c) 2009-2016 Durran Jordan
2
+ Copyright (c) 2015-2020 MongoDB, Inc.
2
3
 
3
4
  Permission is hereby granted, free of charge, to any person obtaining
4
5
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -31,7 +31,8 @@ Please see the [MongoDB website](http://docs.mongodb.org/ecosystem/tutorial/ruby
31
31
  License
32
32
  -------
33
33
 
34
- Copyright (c) 2009-2017 Durran Jordan
34
+ Copyright (c) 2009-2016 Durran Jordan
35
+ Copyright (c) 2015-2020 MongoDB, Inc.
35
36
 
36
37
  Permission is hereby granted, free of charge, to any person obtaining
37
38
  a copy of this software and associated documentation files (the
@@ -13,6 +13,7 @@ require "active_support/time_with_zone"
13
13
  require "active_model"
14
14
 
15
15
  require "mongo"
16
+ require 'mongo/active_support'
16
17
 
17
18
  require "mongoid/version"
18
19
  require "mongoid/config"
@@ -157,21 +157,21 @@ module Mongoid
157
157
  #
158
158
  # @since 1.0.0
159
159
  def write_attribute(name, value)
160
- access = database_field_name(name)
161
- if attribute_writable?(access)
160
+ field_name = database_field_name(name)
161
+ if attribute_writable?(field_name)
162
162
  _assigning do
163
- validate_attribute_value(access, value)
164
- localized = fields[access].try(:localized?)
163
+ validate_attribute_value(field_name, value)
164
+ localized = fields[field_name].try(:localized?)
165
165
  attributes_before_type_cast[name.to_s] = value
166
- typed_value = typed_value_for(access, value)
167
- unless attributes[access] == typed_value || attribute_changed?(access)
168
- attribute_will_change!(access)
166
+ typed_value = typed_value_for(field_name, value)
167
+ unless attributes[field_name] == typed_value || attribute_changed?(field_name)
168
+ attribute_will_change!(field_name)
169
169
  end
170
170
  if localized
171
- attributes[access] ||= {}
172
- attributes[access].merge!(typed_value)
171
+ attributes[field_name] ||= {}
172
+ attributes[field_name].merge!(typed_value)
173
173
  else
174
- attributes[access] = typed_value
174
+ attributes[field_name] = typed_value
175
175
  end
176
176
  typed_value
177
177
  end
@@ -337,20 +337,28 @@ module Mongoid
337
337
 
338
338
  private
339
339
 
340
- # Validates an attribute value. This provides validation checking if
341
- # the value is valid for given a field.
342
- # For now, only Hash and Array fields are validated.
340
+ # Validates an attribute value as being assignable to the specified field.
343
341
  #
344
- # @param [ String, Symbol ] access The name of the attribute to validate.
345
- # @param [ Object ] value The to be validated.
342
+ # For now, only Hash and Array fields are validated, and the value is
343
+ # being checked to be of an appropriate type (i.e. either Hash or Array,
344
+ # respectively, or nil).
345
+ #
346
+ # This method takes the name of the field as stored in the document
347
+ # in the database, not (necessarily) the Ruby method name used to read/write
348
+ # the said field.
349
+ #
350
+ # @param [ String, Symbol ] field_name The name of the field.
351
+ # @param [ Object ] value The value to be validated.
346
352
  #
347
353
  # @since 3.0.10
348
- def validate_attribute_value(access, value)
349
- return unless fields[access] && value
354
+ def validate_attribute_value(field_name, value)
355
+ return if value.nil?
356
+ field = fields[field_name]
357
+ return unless field
350
358
  validatable_types = [ Hash, Array ]
351
- if validatable_types.include? fields[access].type
352
- unless value.is_a? fields[access].type
353
- raise Mongoid::Errors::InvalidValue.new(fields[access].type, value.class)
359
+ if validatable_types.include?(field.type)
360
+ unless value.is_a?(field.type)
361
+ raise Mongoid::Errors::InvalidValue.new(field.type, value.class)
354
362
  end
355
363
  end
356
364
  end
@@ -38,12 +38,13 @@ module Mongoid
38
38
  # @since 4.0.0
39
39
  def define_dynamic_reader(name)
40
40
  return unless name.valid_method_name?
41
- class_eval <<-READER, __FILE__, __LINE__ + 1
42
- def #{name}
43
- attribute_will_change!(#{name.inspect})
44
- read_raw_attribute(#{name.inspect})
41
+
42
+ class_eval do
43
+ define_method(name) do
44
+ attribute_will_change!(name)
45
+ read_raw_attribute(name)
45
46
  end
46
- READER
47
+ end
47
48
  end
48
49
 
49
50
  # Define a reader method for a dynamic attribute before type cast.
@@ -57,12 +58,12 @@ module Mongoid
57
58
  #
58
59
  # @since 4.0.0
59
60
  def define_dynamic_before_type_cast_reader(name)
60
- class_eval <<-READER, __FILE__, __LINE__ + 1
61
- def #{name}_before_type_cast
62
- attribute_will_change!(#{name.inspect})
63
- read_attribute_before_type_cast(#{name.inspect})
61
+ class_eval do
62
+ define_method("#{name}_before_type_cast") do
63
+ attribute_will_change!(name)
64
+ read_attribute_before_type_cast(name)
64
65
  end
65
- READER
66
+ end
66
67
  end
67
68
 
68
69
  # Define a writer method for a dynamic attribute.
@@ -78,11 +79,11 @@ module Mongoid
78
79
  def define_dynamic_writer(name)
79
80
  return unless name.valid_method_name?
80
81
 
81
- class_eval <<-WRITER, __FILE__, __LINE__ + 1
82
- def #{name}=(value)
83
- write_attribute(#{name.inspect}, value)
82
+ class_eval do
83
+ define_method("#{name}=") do |value|
84
+ write_attribute(name, value)
84
85
  end
85
- WRITER
86
+ end
86
87
  end
87
88
 
88
89
  # If the attribute is dynamic, add a field for it with a type of object
@@ -6,35 +6,48 @@ module Mongoid
6
6
  module Environment
7
7
  extend self
8
8
 
9
- # Get the name of the environment that we are running under. This first
10
- # looks for Rails, then Sinatra, then a RACK_ENV environment variable,
11
- # and if none of those are found raises an error.
9
+ # Get the name of the environment that Mongoid is running under.
10
+ #
11
+ # Uses the following sources in order:
12
+ # - If +::Rails+ is defined, +Rails.env+.
13
+ # - If +::Sinatra+ is defined, +Sinatra::Base.environment+.
14
+ # - +RACK_ENV+
15
+ # - +MONGOID_ENV*
12
16
  #
13
17
  # @example Get the env name.
14
18
  # Environment.env_name
15
19
  #
16
- # @raise [ Errors::NoEnvironment ] If no environment was set.
20
+ # @raise [ Errors::NoEnvironment ] If environment name cannot be
21
+ # determined because none of the sources was set.
17
22
  #
18
23
  # @return [ String ] The name of the current environment.
19
24
  #
20
25
  # @since 2.3.0
26
+ # @api public
21
27
  def env_name
22
- return Rails.env if defined?(Rails) && Rails.respond_to?(:env)
23
- return Sinatra::Base.environment.to_s if defined?(Sinatra)
24
- ENV["RACK_ENV"] || ENV["MONGOID_ENV"] || raise(Errors::NoEnvironment.new)
28
+ if defined?(::Rails)
29
+ return ::Rails.env
30
+ end
31
+ if defined?(::Sinatra)
32
+ return ::Sinatra::Base.environment.to_s
33
+ end
34
+ ENV["RACK_ENV"] || ENV["MONGOID_ENV"] or raise Errors::NoEnvironment
25
35
  end
26
36
 
27
37
  # Load the yaml from the provided path and return the settings for the
28
- # current environment.
38
+ # specified environment, or for the current Mongoid environment.
29
39
  #
30
40
  # @example Load the yaml.
31
41
  # Environment.load_yaml("/work/mongoid.yml")
32
42
  #
33
43
  # @param [ String ] path The location of the file.
44
+ # @param [ String | Symbol ] environment Optional environment name to
45
+ # override the current Mongoid environment.
34
46
  #
35
47
  # @return [ Hash ] The settings.
36
48
  #
37
49
  # @since 2.3.0
50
+ # @api private
38
51
  def load_yaml(path, environment = nil)
39
52
  env = environment ? environment.to_s : env_name
40
53
  YAML.load(ERB.new(File.new(path).read).result)[env]
@@ -45,7 +45,7 @@ module Mongoid
45
45
  use(:__union__)
46
46
  end
47
47
 
48
- # Reset the stratgies to nil, used after cloning.
48
+ # Clear the current strategy and negating flag, used after cloning.
49
49
  #
50
50
  # @example Reset the strategies.
51
51
  # mergeable.reset_strategies!
@@ -54,7 +54,8 @@ module Mongoid
54
54
  #
55
55
  # @since 1.0.0
56
56
  def reset_strategies!
57
- self.strategy, self.negating = nil, nil
57
+ self.strategy = nil
58
+ self.negating = nil
58
59
  end
59
60
 
60
61
  private
@@ -167,7 +168,7 @@ module Mongoid
167
168
  # @example Add the criterion.
168
169
  # mergeable.__override__([ 1, 2 ], "$in")
169
170
  #
170
- # @param [ Hash ] criterion The criteria.
171
+ # @param [ Hash | Criteria ] criterion The criteria.
171
172
  # @param [ String ] operator The MongoDB operator.
172
173
  #
173
174
  # @return [ Mergeable ] The new mergeable.
@@ -225,7 +226,7 @@ module Mongoid
225
226
  # @api private
226
227
  #
227
228
  # @example Add criterion with a strategy.
228
- # mergeable.with_strategy(:__union__, [ 1, 2, 3 ], "$in")
229
+ # mergeable.with_strategy(:__union__, {field_name: [ 1, 2, 3 ]}, "$in")
229
230
  #
230
231
  # @param [ Symbol ] strategy The name of the strategy method.
231
232
  # @param [ Object ] criterion The criterion to add.
@@ -434,7 +434,7 @@ module Mongoid
434
434
  # @since 1.0.0
435
435
  def not(*criterion)
436
436
  if criterion.empty?
437
- tap { |query| query.negating = true }
437
+ dup.tap { |query| query.negating = true }
438
438
  else
439
439
  __override__(criterion.first, "$not")
440
440
  end
@@ -630,8 +630,6 @@ module Mongoid
630
630
  # Take the provided criterion and store it as a selection in the query
631
631
  # selector.
632
632
  #
633
- # @api private
634
- #
635
633
  # @example Store the selection.
636
634
  # selectable.selection({ field: "value" })
637
635
  #
@@ -640,6 +638,7 @@ module Mongoid
640
638
  # @return [ Selectable ] The cloned selectable.
641
639
  #
642
640
  # @since 1.0.0
641
+ # @api private
643
642
  def selection(criterion = nil)
644
643
  clone.tap do |query|
645
644
  if criterion
@@ -2,6 +2,7 @@
2
2
  require "mongoid/matchable/default"
3
3
  require "mongoid/matchable/all"
4
4
  require "mongoid/matchable/and"
5
+ require "mongoid/matchable/elem_match"
5
6
  require "mongoid/matchable/eq"
6
7
  require "mongoid/matchable/exists"
7
8
  require "mongoid/matchable/gt"
@@ -11,15 +12,14 @@ require "mongoid/matchable/lt"
11
12
  require "mongoid/matchable/lte"
12
13
  require "mongoid/matchable/ne"
13
14
  require "mongoid/matchable/nin"
14
- require "mongoid/matchable/or"
15
15
  require "mongoid/matchable/nor"
16
- require "mongoid/matchable/size"
17
- require "mongoid/matchable/elem_match"
16
+ require "mongoid/matchable/or"
18
17
  require "mongoid/matchable/regexp"
18
+ require "mongoid/matchable/size"
19
19
 
20
20
  module Mongoid
21
21
 
22
- # This module contains all the behavior for ruby implementations of MongoDB
22
+ # This module contains all the behavior for Ruby implementations of MongoDB
23
23
  # selectors.
24
24
  #
25
25
  # @since 4.0.0
@@ -31,8 +31,8 @@ module Mongoid
31
31
  # @since 1.0.0
32
32
  MATCHERS = {
33
33
  "$all" => All,
34
- "$elemMatch" => ElemMatch,
35
34
  "$and" => And,
35
+ "$elemMatch" => ElemMatch,
36
36
  "$eq" => Eq,
37
37
  "$exists" => Exists,
38
38
  "$gt" => Gt,
@@ -42,8 +42,8 @@ module Mongoid
42
42
  "$lte" => Lte,
43
43
  "$ne" => Ne,
44
44
  "$nin" => Nin,
45
- "$or" => Or,
46
45
  "$nor" => Nor,
46
+ "$or" => Or,
47
47
  "$size" => Size,
48
48
  }.with_indifferent_access.freeze
49
49
 
@@ -64,13 +64,13 @@ module Mongoid
64
64
  value.each do |item|
65
65
  if item[0].to_s == "$not".freeze
66
66
  item = item[1]
67
- return false if matcher(self, key, item)._matches?(item)
67
+ return false if matcher(key, item)._matches?(item)
68
68
  else
69
- return false unless matcher(self, key, Hash[*item])._matches?(Hash[*item])
69
+ return false unless matcher(key, Hash[*item])._matches?(Hash[*item])
70
70
  end
71
71
  end
72
72
  else
73
- return false unless matcher(self, key, value)._matches?(value)
73
+ return false unless matcher(key, value)._matches?(value)
74
74
  end
75
75
  end
76
76
  true
@@ -81,20 +81,18 @@ module Mongoid
81
81
  # Get the matcher for the supplied key and value. Will determine the class
82
82
  # name from the key.
83
83
  #
84
- # @api private
85
- #
86
84
  # @example Get the matcher.
87
85
  # document.matcher(:title, { "$in" => [ "test" ] })
88
86
  #
89
- # @param [ Document ] document The document to check.
90
87
  # @param [ Symbol, String ] key The field name.
91
88
  # @param [ Object, Hash ] value The value or selector.
92
89
  #
93
90
  # @return [ Matcher ] The matcher.
94
91
  #
95
92
  # @since 2.0.0.rc.7
96
- def matcher(document, key, value)
97
- Matchable.matcher(document, key, value)
93
+ # @api private
94
+ def matcher(key, value)
95
+ Matchable.matcher(self, key, value)
98
96
  end
99
97
 
100
98
  class << self
@@ -105,7 +103,7 @@ module Mongoid
105
103
  # @api private
106
104
  #
107
105
  # @example Get the matcher.
108
- # document.matcher(:title, { "$in" => [ "test" ] })
106
+ # Matchable.matcher(document, :title, { "$in" => [ "test" ] })
109
107
  #
110
108
  # @param [ Document ] document The document to check.
111
109
  # @param [ Symbol, String ] key The field name.
@@ -149,6 +147,7 @@ module Mongoid
149
147
  # @return [ Object ] The value of the attribute.
150
148
  #
151
149
  # @since 2.2.1
150
+ # @api private
152
151
  def extract_attribute(document, key)
153
152
  if (key_string = key.to_s) =~ /.+\..+/
154
153
  key_string.split('.').inject(document.send(:as_attributes)) do |_attribs, _key|
@@ -10,11 +10,12 @@ module Mongoid
10
10
  # @example Do the values match?
11
11
  # matcher._matches?({ :key => 10 })
12
12
  #
13
- # @param [ Hash ] value The values to check.
13
+ # @param [ Hash ] condition The condition to evaluate. This must be
14
+ # a one-element hash like {'$gt' => 1}.
14
15
  #
15
16
  # @return [ true, false ] If the values match.
16
- def _matches?(value)
17
- first = first(value)
17
+ def _matches?(condition)
18
+ first = condition_value(condition)
18
19
  return false if first.is_a?(Array) && first.empty?
19
20
 
20
21
  attribute_array = Array.wrap(@attribute)
@@ -20,52 +20,99 @@ module Mongoid
20
20
  @attribute, @document = attribute, document
21
21
  end
22
22
 
23
- # Return true if the attribute and value are equal, or if it is an array
24
- # if the value is included.
23
+ # Checks whether the attribute matches the value, using the default
24
+ # MongoDB matching logic (i.e., when no operator is specified in the
25
+ # criteria).
25
26
  #
26
- # @example Does this value match?
27
- # default._matches?("value")
27
+ # If attribute and value are both of basic types like string or number,
28
+ # this method returns true if and only if the attribute equals the value.
28
29
  #
29
- # @param [ Object ] value The value to check if it matches.
30
+ # Value can also be of a type like Regexp or Range which defines
31
+ # more complex matching/inclusion behavior via the === operator.
32
+ # If so, and attribute is still of a basic type like string or number,
33
+ # this method returns true if and only if the value's === operator
34
+ # returns true for the attribute. For example, this method returns true
35
+ # if attribute is a string and value is a Regexp and attribute matches
36
+ # the value, of if attribute is a number and value is a Range and
37
+ # the value includes the attribute.
30
38
  #
31
- # @return [ true, false ] True if matches, false if not.
39
+ # If attribute is an array and value is not an array, the checks just
40
+ # described (i.e. the === operator invocation) are performed on each item
41
+ # of the attribute array. If any of the items in the attribute match
42
+ # the value according to the value type's === operator, this method
43
+ # returns true.
44
+ #
45
+ # If attribute and value are both arrays, this method returns true if and
46
+ # only if the arrays are equal (including the order of the elements).
47
+ #
48
+ # @param [ Object ] value The value to check.
49
+ #
50
+ # @return [ true, false ] True if attribute matches the value, false if not.
32
51
  #
33
52
  # @since 1.0.0
34
53
  def _matches?(value)
35
- attribute.is_a?(Array) && !value.is_a?(Array) ? attribute.any? { |_attribute| value === _attribute } : value === attribute
54
+ if attribute.is_a?(Array) && !value.is_a?(Array)
55
+ attribute.any? { |_attribute| value === _attribute }
56
+ else
57
+ value === attribute
58
+ end
36
59
  end
37
60
 
38
61
  protected
39
62
 
40
- # Convenience method for getting the first value in a hash.
63
+ # Given a condition, which is a one-element hash consisting of an
64
+ # operator and a value like {'$gt' => 1}, return the value.
41
65
  #
42
- # @example Get the first value.
43
- # matcher.first(:test => "value")
66
+ # @example Get the condition value.
67
+ # matcher.condition_value({'$gt' => 1})
68
+ # # => 1
44
69
  #
45
- # @param [ Hash ] hash The has to pull from.
70
+ # @param [ Hash ] condition The condition.
46
71
  #
47
- # @return [ Object ] The first value.
72
+ # @return [ Object ] The value of the condition.
48
73
  #
49
74
  # @since 1.0.0
50
- def first(hash)
51
- hash.values.first
75
+ def condition_value(condition)
76
+ unless condition.is_a?(Hash)
77
+ raise ArgumentError, 'Condition must be a hash'
78
+ end
79
+
80
+ unless condition.length == 1
81
+ raise ArgumentError, 'Condition must have one element'
82
+ end
83
+
84
+ condition.values.first
52
85
  end
53
86
 
54
- # If object exists then compare the two, otherwise return false
87
+ # Determines whether the attribute value stored in this matcher
88
+ # satisfies the provided condition using the provided operator.
89
+ #
90
+ # For example, given an instance of Gt matcher with the @attribute of
91
+ # 2, the matcher is set up to answer whether the attribute is
92
+ # greater than some input value. This input value is provided in
93
+ # the condition, which could be {"$gt" => 1}, and the operator is
94
+ # provided (somewhat in a duplicate fashion) in the operator argument,
95
+ # in this case :>.
55
96
  #
56
- # @example Determine if we can compare.
57
- # matcher.determine("test", "$in")
97
+ # @example
98
+ # matcher = Matchable::Gt.new(2)
99
+ # matcher.determine({'$gt' => 1}, :>)
100
+ # # => true
58
101
  #
59
- # @param [ Object ] value The value to compare with.
60
- # @param [ Symbol, String ] operator The comparison operation.
102
+ # @param [ Hash ] condition The condition to evaluate. This must be
103
+ # a one-element hash; the key is ignored, and the value is passed
104
+ # as the argument to the operator.
105
+ # @param [ Symbol, String ] operator The comparison operator or method.
106
+ # The operator is invoked on the attribute stored in the matcher
107
+ # instance.
61
108
  #
62
- # @return [ true, false ] The comparison or false.
109
+ # @return [ true, false ] Result of condition evaluation.
63
110
  #
64
111
  # @since 1.0.0
65
- def determine(value, operator)
66
- attribute.__array__.any? {|attr|
67
- attr ? attr.send(operator, first(value)) : false
68
- }
112
+ def determine(condition, operator)
113
+ attribute.__array__.any? do |attr|
114
+ attr && attr.send(operator, condition_value(condition))
115
+ end
69
116
  end
70
117
  end
71
118
  end