mongoid 7.0.5 → 7.0.6

Sign up to get free protection for your applications and to get access to all the features.
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