mongoid 8.1.3 → 8.1.11
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 +4 -4
- data/Rakefile +43 -45
- data/lib/mongoid/association/accessors.rb +5 -1
- data/lib/mongoid/association/eager_loadable.rb +3 -0
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +18 -3
- data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +21 -4
- data/lib/mongoid/association/referenced/has_many/proxy.rb +11 -2
- data/lib/mongoid/atomic.rb +9 -7
- data/lib/mongoid/attributes/readonly.rb +8 -3
- data/lib/mongoid/contextual/mongo.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -1
- data/lib/mongoid/criteria/queryable/selectable.rb +1 -1
- data/lib/mongoid/document.rb +8 -1
- data/lib/mongoid/equality.rb +1 -0
- data/lib/mongoid/extensions/hash.rb +4 -4
- data/lib/mongoid/fields.rb +13 -8
- data/lib/mongoid/interceptable.rb +6 -7
- data/lib/mongoid/matcher.rb +15 -1
- data/lib/mongoid/serializable.rb +7 -7
- data/lib/mongoid/timestamps/created.rb +8 -1
- data/lib/mongoid/touchable.rb +1 -1
- data/lib/mongoid/traversable.rb +36 -1
- data/lib/mongoid/validatable/associated.rb +98 -17
- data/lib/mongoid/validatable/macros.rb +15 -0
- data/lib/mongoid/validatable/numericality.rb +19 -0
- data/lib/mongoid/validatable.rb +9 -0
- data/lib/mongoid/version.rb +5 -1
- data/spec/integration/app_spec.rb +24 -5
- data/spec/integration/associations/embeds_one_spec.rb +25 -5
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +40 -0
- data/spec/mongoid/association/eager_spec.rb +24 -2
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +35 -0
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +4 -0
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +4 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +28 -37
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +42 -0
- data/spec/mongoid/attributes/readonly_spec.rb +19 -0
- data/spec/mongoid/attributes_spec.rb +16 -0
- data/spec/mongoid/contextual/mongo_spec.rb +78 -3
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +29 -0
- data/spec/mongoid/document_spec.rb +27 -0
- data/spec/mongoid/equality_spec.rb +6 -0
- data/spec/mongoid/fields_spec.rb +3 -3
- data/spec/mongoid/interceptable_spec.rb +80 -0
- data/spec/mongoid/interceptable_spec_models.rb +47 -111
- data/spec/mongoid/serializable_spec.rb +16 -9
- data/spec/mongoid/timestamps/created_spec.rb +23 -0
- data/spec/mongoid/validatable/associated_spec.rb +27 -34
- data/spec/mongoid/validatable/numericality_spec.rb +16 -0
- data/spec/shared/lib/mrss/docker_runner.rb +1 -2
- data/spec/shared/lib/mrss/release/candidate.rb +281 -0
- data/spec/shared/lib/mrss/release/product_data.rb +144 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +1 -1
- data/spec/shared/lib/tasks/candidate.rake +64 -0
- data/spec/shared/share/Dockerfile.erb +15 -85
- data/spec/shared/shlib/distro.sh +10 -0
- data/spec/shared/shlib/server.sh +33 -26
- data/spec/shared/shlib/set_env.sh +9 -68
- data/spec/support/expectations.rb +20 -17
- data/spec/support/models/band.rb +1 -0
- data/spec/support/models/lat_lng.rb +6 -0
- data/spec/support/models/name.rb +10 -0
- metadata +15 -38
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 21db50efa946dce1a9e43718d0e15d37c0e4373c9d693123d21cfe13b8afb3bf
|
|
4
|
+
data.tar.gz: 7d01ee5d5a8eb3c81a92c3055e94bf8bb90a8a911258401459b5e447c45a220c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f1e10a0cb03863509acb1d150460e4f7c475092b45bb65f7619ecd8f0384d4ed6e92416565a07e6e900af26fbf26b32c4cd2c9418c4dfbe1f858da451a3e9378
|
|
7
|
+
data.tar.gz: e2e75603f8ba8f3debead96161f81350ced4696aac125ba0b17f48a94a42cc48e867651deb1b6a60c3d57f48fa237f26ac61775f3c2be3750f62fc2b66d27661
|
data/Rakefile
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "bundler"
|
|
4
|
-
require "bundler/gem_tasks"
|
|
5
4
|
Bundler.setup
|
|
6
5
|
|
|
7
6
|
ROOT = File.expand_path(File.join(File.dirname(__FILE__)))
|
|
@@ -10,34 +9,53 @@ $: << File.join(ROOT, 'spec/shared/lib')
|
|
|
10
9
|
|
|
11
10
|
require "rake"
|
|
12
11
|
require "rspec/core/rake_task"
|
|
13
|
-
require 'mrss/spec_organizer'
|
|
14
|
-
require 'rubygems/package'
|
|
15
|
-
require 'rubygems/security/policies'
|
|
16
|
-
|
|
17
|
-
def signed_gem?(path_to_gem)
|
|
18
|
-
Gem::Package.new(path_to_gem, Gem::Security::HighSecurity).verify
|
|
19
|
-
true
|
|
20
|
-
rescue Gem::Security::Exception => e
|
|
21
|
-
false
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
|
25
|
-
require "mongoid/version"
|
|
26
12
|
|
|
27
|
-
|
|
28
|
-
|
|
13
|
+
if File.exist?('./spec/shared/lib/tasks/candidate.rake')
|
|
14
|
+
load 'spec/shared/lib/tasks/candidate.rake'
|
|
15
|
+
end
|
|
29
16
|
|
|
30
|
-
|
|
17
|
+
desc 'Build the gem'
|
|
31
18
|
task :build do
|
|
32
|
-
|
|
19
|
+
command = %w[ gem build ]
|
|
20
|
+
command << "--output=#{ENV['GEM_FILE_NAME']}" if ENV['GEM_FILE_NAME']
|
|
21
|
+
command << (ENV['GEMSPEC'] || 'mongoid.gemspec')
|
|
22
|
+
system(*command)
|
|
33
23
|
end
|
|
34
24
|
|
|
35
|
-
|
|
36
|
-
|
|
25
|
+
# `rake version` is used by the deployment system so get the release version
|
|
26
|
+
# of the product beng deployed. It must do nothing more than just print the
|
|
27
|
+
# product version number.
|
|
28
|
+
#
|
|
29
|
+
# See the mongodb-labs/driver-github-tools/ruby/publish Github action.
|
|
30
|
+
desc "Print the current value of Mongoid::VERSION"
|
|
31
|
+
task :version do
|
|
32
|
+
require 'mongoid/version'
|
|
33
|
+
|
|
34
|
+
puts Mongoid::VERSION
|
|
37
35
|
end
|
|
38
36
|
|
|
37
|
+
# overrides the default Bundler-provided `release` task, which also
|
|
38
|
+
# builds the gem. Our release process assumes the gem has already
|
|
39
|
+
# been built (and signed via GPG), so we just need `rake release` to
|
|
40
|
+
# push the gem to rubygems.
|
|
39
41
|
task :release do
|
|
40
|
-
|
|
42
|
+
require 'mongoid/version'
|
|
43
|
+
|
|
44
|
+
if ENV['GITHUB_ACTION'].nil?
|
|
45
|
+
abort <<~WARNING
|
|
46
|
+
`rake release` must be invoked from the `Mongoid Release` GitHub action,
|
|
47
|
+
and must not be invoked locally. This ensures the gem is properly signed
|
|
48
|
+
and distributed by the appropriate user.
|
|
49
|
+
|
|
50
|
+
Note that it is the `rubygems/release-gem@v1` step in the `Mongoid Release`
|
|
51
|
+
action that invokes this task. Do not rename or remove this task, or the
|
|
52
|
+
release-gem step will fail. Reimplement this task with caution.
|
|
53
|
+
|
|
54
|
+
mongoid-#{Mongoid::VERSION}.gem was NOT pushed to RubyGems.
|
|
55
|
+
WARNING
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
system 'bundle', 'exec', 'gem', 'push', "mongoid-#{Mongoid::VERSION}.gem"
|
|
41
59
|
end
|
|
42
60
|
|
|
43
61
|
RSpec::Core::RakeTask.new("spec") do |spec|
|
|
@@ -64,6 +82,8 @@ RUN_PRIORITY = %i(
|
|
|
64
82
|
)
|
|
65
83
|
|
|
66
84
|
def spec_organizer
|
|
85
|
+
require 'mrss/spec_organizer'
|
|
86
|
+
|
|
67
87
|
Mrss::SpecOrganizer.new(
|
|
68
88
|
root: ROOT,
|
|
69
89
|
classifiers: CLASSIFIERS,
|
|
@@ -99,32 +119,10 @@ task :docs => 'docs:yard'
|
|
|
99
119
|
namespace :docs do
|
|
100
120
|
desc "Generate yard documention"
|
|
101
121
|
task :yard do
|
|
122
|
+
require "mongoid/version"
|
|
123
|
+
|
|
102
124
|
out = File.join('yard-docs', Mongoid::VERSION)
|
|
103
125
|
FileUtils.rm_rf(out)
|
|
104
126
|
system "yardoc -o #{out} --title mongoid-#{Mongoid::VERSION}"
|
|
105
127
|
end
|
|
106
128
|
end
|
|
107
|
-
|
|
108
|
-
namespace :release do
|
|
109
|
-
task :check_private_key do
|
|
110
|
-
unless File.exist?('gem-private_key.pem')
|
|
111
|
-
raise "No private key present, cannot release"
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
desc 'Verifies that all built gems in pkg/ are valid'
|
|
117
|
-
task :verify do
|
|
118
|
-
gems = Dir['pkg/*.gem']
|
|
119
|
-
if gems.empty?
|
|
120
|
-
puts 'There are no gems in pkg/ to verify'
|
|
121
|
-
else
|
|
122
|
-
gems.each do |gem|
|
|
123
|
-
if signed_gem?(gem)
|
|
124
|
-
puts "#{gem} is signed"
|
|
125
|
-
else
|
|
126
|
-
abort "#{gem} is not signed"
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
end
|
|
@@ -115,7 +115,11 @@ module Mongoid
|
|
|
115
115
|
# during binding or when cascading callbacks. Whenever we retrieve
|
|
116
116
|
# associations within the codebase, we use without_autobuild.
|
|
117
117
|
if !without_autobuild? && association.embedded? && attribute_missing?(field_name)
|
|
118
|
-
|
|
118
|
+
# We always allow accessing the parent document of an embedded one.
|
|
119
|
+
try_get_parent = association.is_a?(
|
|
120
|
+
Mongoid::Association::Embedded::EmbeddedIn
|
|
121
|
+
) && field_name == association.key
|
|
122
|
+
raise ActiveModel::MissingAttributeError, "Missing attribute: '#{field_name}'" unless try_get_parent
|
|
119
123
|
end
|
|
120
124
|
|
|
121
125
|
if !reload && (value = ivar(name)) != false
|
|
@@ -31,6 +31,9 @@ module Mongoid
|
|
|
31
31
|
docs_map = {}
|
|
32
32
|
queue = [ klass.to_s ]
|
|
33
33
|
|
|
34
|
+
# account for single-collection inheritance
|
|
35
|
+
queue.push(klass.root_class.to_s) if klass != klass.root_class
|
|
36
|
+
|
|
34
37
|
while klass = queue.shift
|
|
35
38
|
if as = assoc_map.delete(klass)
|
|
36
39
|
as.each do |assoc|
|
|
@@ -227,9 +227,24 @@ module Mongoid
|
|
|
227
227
|
# @example Are there persisted documents?
|
|
228
228
|
# person.posts.exists?
|
|
229
229
|
#
|
|
230
|
-
# @
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
# @param [ :none | nil | false | Hash | Object ] id_or_conditions
|
|
231
|
+
# When :none (the default), returns true if any persisted
|
|
232
|
+
# documents exist in the association. When nil or false, this
|
|
233
|
+
# will always return false. When a Hash is given, this queries
|
|
234
|
+
# the documents in the association for those that match the given
|
|
235
|
+
# conditions, and returns true if any match which have been
|
|
236
|
+
# persisted. Any other argument is interpreted as an id, and
|
|
237
|
+
# queries for the existence of persisted documents in the
|
|
238
|
+
# association with a matching _id.
|
|
239
|
+
#
|
|
240
|
+
# @return [ true | false ] True if persisted documents exist, false if not.
|
|
241
|
+
def exists?(id_or_conditions = :none)
|
|
242
|
+
case id_or_conditions
|
|
243
|
+
when :none then _target.any?(&:persisted?)
|
|
244
|
+
when nil, false then false
|
|
245
|
+
when Hash then where(id_or_conditions).any?(&:persisted?)
|
|
246
|
+
else where(_id: id_or_conditions).any?(&:persisted?)
|
|
247
|
+
end
|
|
233
248
|
end
|
|
234
249
|
|
|
235
250
|
# Finds a document in this association through several different
|
|
@@ -422,11 +422,28 @@ module Mongoid
|
|
|
422
422
|
#
|
|
423
423
|
# @return [ Integer ] The size of the enumerable.
|
|
424
424
|
def size
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
425
|
+
# If _unloaded is present, then it will match the set of documents
|
|
426
|
+
# that belong to this association, which have already been persisted
|
|
427
|
+
# to the database. This set of documents must be considered when
|
|
428
|
+
# computing the size of the association, along with anything that has
|
|
429
|
+
# since been added.
|
|
430
|
+
if _unloaded
|
|
431
|
+
if _added.any?
|
|
432
|
+
# Note that _added may include records that _unloaded already
|
|
433
|
+
# matches. This is the case if the association is assigned an array
|
|
434
|
+
# of items and some of them were already elements of the association.
|
|
435
|
+
#
|
|
436
|
+
# we need to thus make sure _unloaded.count excludes any elements
|
|
437
|
+
# that already exist in _added.
|
|
438
|
+
|
|
439
|
+
count = _unloaded.not(:_id.in => _added.values.map(&:id)).count
|
|
440
|
+
count + _added.values.count
|
|
441
|
+
else
|
|
442
|
+
_unloaded.count
|
|
443
|
+
end
|
|
444
|
+
|
|
428
445
|
else
|
|
429
|
-
count + _added.
|
|
446
|
+
_loaded.count + _added.count
|
|
430
447
|
end
|
|
431
448
|
end
|
|
432
449
|
|
|
@@ -172,9 +172,18 @@ module Mongoid
|
|
|
172
172
|
# @example Are there persisted documents?
|
|
173
173
|
# person.posts.exists?
|
|
174
174
|
#
|
|
175
|
+
# @param [ :none | nil | false | Hash | Object ] id_or_conditions
|
|
176
|
+
# When :none (the default), returns true if any persisted
|
|
177
|
+
# documents exist in the association. When nil or false, this
|
|
178
|
+
# will always return false. When a Hash is given, this queries
|
|
179
|
+
# the documents in the association for those that match the given
|
|
180
|
+
# conditions, and returns true if any match. Any other argument is
|
|
181
|
+
# interpreted as an id, and queries for the existence of documents
|
|
182
|
+
# in the association with a matching _id.
|
|
183
|
+
#
|
|
175
184
|
# @return [ true | false ] True is persisted documents exist, false if not.
|
|
176
|
-
def exists?
|
|
177
|
-
criteria.exists?
|
|
185
|
+
def exists?(id_or_conditions = :none)
|
|
186
|
+
criteria.exists?(id_or_conditions)
|
|
178
187
|
end
|
|
179
188
|
|
|
180
189
|
# Find the matching document on the association, either based on id or
|
data/lib/mongoid/atomic.rb
CHANGED
|
@@ -178,13 +178,15 @@ module Mongoid
|
|
|
178
178
|
#
|
|
179
179
|
# @return [ Object ] The associated path.
|
|
180
180
|
def atomic_paths
|
|
181
|
-
@atomic_paths
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
181
|
+
return @atomic_paths if @atomic_paths
|
|
182
|
+
|
|
183
|
+
paths = if _association
|
|
184
|
+
_association.path(self)
|
|
185
|
+
else
|
|
186
|
+
Atomic::Paths::Root.new(self)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
paths.tap { @atomic_paths = paths unless new_record? }
|
|
188
190
|
end
|
|
189
191
|
|
|
190
192
|
# Get all the attributes that need to be pulled.
|
|
@@ -22,7 +22,7 @@ module Mongoid
|
|
|
22
22
|
# @return [ true | false ] If the document is new, or if the field is not
|
|
23
23
|
# readonly.
|
|
24
24
|
def attribute_writable?(name)
|
|
25
|
-
new_record? || (!readonly_attributes.include?(name) && _loaded?(name))
|
|
25
|
+
new_record? || (!self.class.readonly_attributes.include?(name) && _loaded?(name))
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
private
|
|
@@ -62,12 +62,17 @@ module Mongoid
|
|
|
62
62
|
# end
|
|
63
63
|
#
|
|
64
64
|
# @param [ Symbol... ] *names The names of the fields.
|
|
65
|
+
# @note When a parent class contains readonly attributes and is then
|
|
66
|
+
# inherited by a child class, the child class will inherit the
|
|
67
|
+
# parent's readonly attributes at the time of its creation.
|
|
68
|
+
# Updating the parent does not propagate down to child classes after wards.
|
|
65
69
|
def attr_readonly(*names)
|
|
70
|
+
self.readonly_attributes = self.readonly_attributes.dup
|
|
66
71
|
names.each do |name|
|
|
67
|
-
readonly_attributes << database_field_name(name)
|
|
72
|
+
self.readonly_attributes << database_field_name(name)
|
|
68
73
|
end
|
|
69
74
|
end
|
|
70
75
|
end
|
|
71
76
|
end
|
|
72
77
|
end
|
|
73
|
-
end
|
|
78
|
+
end
|
|
@@ -1091,7 +1091,7 @@ module Mongoid
|
|
|
1091
1091
|
end
|
|
1092
1092
|
|
|
1093
1093
|
def retrieve_nth_to_last_with_limit(n, limit)
|
|
1094
|
-
v = view.sort(inverse_sorting).
|
|
1094
|
+
v = view.sort(inverse_sorting).limit(limit || 1)
|
|
1095
1095
|
v = v.skip(n) if n > 0
|
|
1096
1096
|
raw_docs = v.to_a.reverse
|
|
1097
1097
|
process_raw_docs(raw_docs, limit)
|
|
@@ -43,7 +43,21 @@ module Mongoid
|
|
|
43
43
|
#
|
|
44
44
|
# @return [ Object ] The converted number.
|
|
45
45
|
def __numeric__(object)
|
|
46
|
-
|
|
46
|
+
str = object.to_s
|
|
47
|
+
raise ArgumentError if str.empty?
|
|
48
|
+
|
|
49
|
+
# These requirements seem a bit odd, but they're explicitly specified in the tests,
|
|
50
|
+
# so we're obligated to keep them, for now. (This code was rewritten from a one-line
|
|
51
|
+
# regex, due to security concerns with a polynomial regex being used on uncontrolled
|
|
52
|
+
# data).
|
|
53
|
+
|
|
54
|
+
str = str.chop if str.end_with?('.')
|
|
55
|
+
return 0 if str.empty?
|
|
56
|
+
|
|
57
|
+
result = Integer(str) rescue Float(object)
|
|
58
|
+
|
|
59
|
+
integer = result.to_i
|
|
60
|
+
integer == result ? integer : result
|
|
47
61
|
end
|
|
48
62
|
|
|
49
63
|
# Evolve the object to an integer.
|
|
@@ -552,7 +552,7 @@ module Mongoid
|
|
|
552
552
|
# @return [ Selectable ] The new selectable.
|
|
553
553
|
def not(*criteria)
|
|
554
554
|
if criteria.empty?
|
|
555
|
-
dup.tap { |query| query.negating =
|
|
555
|
+
dup.tap { |query| query.negating = !query.negating }
|
|
556
556
|
else
|
|
557
557
|
criteria.compact.inject(self.clone) do |c, new_s|
|
|
558
558
|
if new_s.is_a?(Selectable)
|
data/lib/mongoid/document.rb
CHANGED
|
@@ -133,7 +133,14 @@ module Mongoid
|
|
|
133
133
|
#
|
|
134
134
|
# @return [ Hash ] A hash of all attributes in the hierarchy.
|
|
135
135
|
def as_document
|
|
136
|
-
|
|
136
|
+
attrs = as_attributes
|
|
137
|
+
|
|
138
|
+
# legacy attributes have a tendency to leak internal state via
|
|
139
|
+
# `as_document`; we have to deep_dup the attributes here to prevent
|
|
140
|
+
# that.
|
|
141
|
+
attrs = attrs.deep_dup if Mongoid.legacy_attributes
|
|
142
|
+
|
|
143
|
+
BSON::Document.new(attrs)
|
|
137
144
|
end
|
|
138
145
|
|
|
139
146
|
# Calls #as_json on the document with additional, Mongoid-specific options.
|
data/lib/mongoid/equality.rb
CHANGED
|
@@ -49,7 +49,7 @@ module Mongoid
|
|
|
49
49
|
consolidated[key].update(value)
|
|
50
50
|
else
|
|
51
51
|
consolidated["$set"] ||= {}
|
|
52
|
-
consolidated["$set"].update(key => mongoize_for(
|
|
52
|
+
consolidated["$set"].update(key => mongoize_for("$set", klass, key, value))
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
consolidated
|
|
@@ -187,7 +187,7 @@ module Mongoid
|
|
|
187
187
|
|
|
188
188
|
# Get the value for the provided operator, klass, key and value.
|
|
189
189
|
#
|
|
190
|
-
# This is necessary for special cases like $rename, $addToSet and $
|
|
190
|
+
# This is necessary for special cases like $rename, $addToSet, $push, $pull and $pop.
|
|
191
191
|
#
|
|
192
192
|
# @param [ String ] operator The operator.
|
|
193
193
|
# @param [ Class ] klass The model class.
|
|
@@ -198,8 +198,8 @@ module Mongoid
|
|
|
198
198
|
def value_for(operator, klass, key, value)
|
|
199
199
|
case operator
|
|
200
200
|
when "$rename" then value.to_s
|
|
201
|
-
when "$addToSet", "$push" then value.mongoize
|
|
202
|
-
else mongoize_for(operator, klass,
|
|
201
|
+
when "$addToSet", "$push", '$pull', '$pop' then value.mongoize
|
|
202
|
+
else mongoize_for(operator, klass, key, value)
|
|
203
203
|
end
|
|
204
204
|
end
|
|
205
205
|
|
data/lib/mongoid/fields.rb
CHANGED
|
@@ -47,6 +47,11 @@ module Mongoid
|
|
|
47
47
|
# @api private
|
|
48
48
|
INVALID_BSON_CLASSES = [ BSON::Decimal128, BSON::Int32, BSON::Int64 ].freeze
|
|
49
49
|
|
|
50
|
+
# The suffix for generated translated fields.
|
|
51
|
+
#
|
|
52
|
+
# @api private
|
|
53
|
+
TRANSLATIONS_SFX = '_translations'
|
|
54
|
+
|
|
50
55
|
module ClassMethods
|
|
51
56
|
# Returns the list of id fields for this model class, as both strings
|
|
52
57
|
# and symbols.
|
|
@@ -99,8 +104,8 @@ module Mongoid
|
|
|
99
104
|
ar.each_with_index do |fn, i|
|
|
100
105
|
key = fn
|
|
101
106
|
unless klass.fields.key?(fn) || klass.relations.key?(fn)
|
|
102
|
-
if
|
|
103
|
-
key =
|
|
107
|
+
if fn.end_with?(TRANSLATIONS_SFX)
|
|
108
|
+
key = fn.delete_suffix(TRANSLATIONS_SFX)
|
|
104
109
|
else
|
|
105
110
|
key = fn
|
|
106
111
|
end
|
|
@@ -405,12 +410,12 @@ module Mongoid
|
|
|
405
410
|
#
|
|
406
411
|
# @api private
|
|
407
412
|
def database_field_name(name, relations, aliased_fields, aliased_associations)
|
|
413
|
+
return '' unless name.present?
|
|
414
|
+
|
|
408
415
|
if Mongoid.broken_alias_handling
|
|
409
|
-
return nil unless name
|
|
410
416
|
normalized = name.to_s
|
|
411
417
|
aliased_fields[normalized] || normalized
|
|
412
418
|
else
|
|
413
|
-
return nil unless name.present?
|
|
414
419
|
key = name.to_s
|
|
415
420
|
segment, remaining = key.split('.', 2)
|
|
416
421
|
|
|
@@ -726,11 +731,11 @@ module Mongoid
|
|
|
726
731
|
# @api private
|
|
727
732
|
def create_translations_getter(name, meth)
|
|
728
733
|
generated_methods.module_eval do
|
|
729
|
-
re_define_method("#{meth}
|
|
734
|
+
re_define_method("#{meth}#{TRANSLATIONS_SFX}") do
|
|
730
735
|
attributes[name] ||= {}
|
|
731
736
|
attributes[name].with_indifferent_access
|
|
732
737
|
end
|
|
733
|
-
alias_method :"#{meth}_t", :"#{meth}
|
|
738
|
+
alias_method :"#{meth}_t", :"#{meth}#{TRANSLATIONS_SFX}"
|
|
734
739
|
end
|
|
735
740
|
end
|
|
736
741
|
|
|
@@ -746,14 +751,14 @@ module Mongoid
|
|
|
746
751
|
# @api private
|
|
747
752
|
def create_translations_setter(name, meth, field)
|
|
748
753
|
generated_methods.module_eval do
|
|
749
|
-
re_define_method("#{meth}
|
|
754
|
+
re_define_method("#{meth}#{TRANSLATIONS_SFX}=") do |value|
|
|
750
755
|
attribute_will_change!(name)
|
|
751
756
|
value&.transform_values! do |_value|
|
|
752
757
|
field.type.mongoize(_value)
|
|
753
758
|
end
|
|
754
759
|
attributes[name] = value
|
|
755
760
|
end
|
|
756
|
-
alias_method :"#{meth}_t=", :"#{meth}
|
|
761
|
+
alias_method :"#{meth}_t=", :"#{meth}#{TRANSLATIONS_SFX}="
|
|
757
762
|
end
|
|
758
763
|
end
|
|
759
764
|
|
|
@@ -43,8 +43,6 @@ module Mongoid
|
|
|
43
43
|
# @api private
|
|
44
44
|
define_model_callbacks :persist_parent
|
|
45
45
|
|
|
46
|
-
define_model_callbacks :commit, :rollback, only: :after
|
|
47
|
-
|
|
48
46
|
attr_accessor :before_callback_halted
|
|
49
47
|
end
|
|
50
48
|
|
|
@@ -143,9 +141,13 @@ module Mongoid
|
|
|
143
141
|
# @api private
|
|
144
142
|
def _mongoid_run_child_callbacks(kind, children: nil, &block)
|
|
145
143
|
if Mongoid::Config.around_callbacks_for_embeds
|
|
146
|
-
_mongoid_run_child_callbacks_with_around(kind,
|
|
144
|
+
_mongoid_run_child_callbacks_with_around(kind,
|
|
145
|
+
children: children,
|
|
146
|
+
&block)
|
|
147
147
|
else
|
|
148
|
-
_mongoid_run_child_callbacks_without_around(kind,
|
|
148
|
+
_mongoid_run_child_callbacks_without_around(kind,
|
|
149
|
+
children: children,
|
|
150
|
+
&block)
|
|
149
151
|
end
|
|
150
152
|
end
|
|
151
153
|
|
|
@@ -221,9 +223,6 @@ module Mongoid
|
|
|
221
223
|
return false if env.halted
|
|
222
224
|
env.value = !env.halted
|
|
223
225
|
callback_list << [next_sequence, env]
|
|
224
|
-
if (grandchildren = child.send(:cascadable_children, kind))
|
|
225
|
-
_mongoid_run_child_before_callbacks(kind, children: grandchildren, callback_list: callback_list)
|
|
226
|
-
end
|
|
227
226
|
end
|
|
228
227
|
callback_list
|
|
229
228
|
end
|
data/lib/mongoid/matcher.rb
CHANGED
|
@@ -35,11 +35,25 @@ module Mongoid
|
|
|
35
35
|
# from and behaves identically to association traversal for the purposes
|
|
36
36
|
# of, for example, subsequent array element retrieval.
|
|
37
37
|
#
|
|
38
|
-
# @param [ Document | Hash ] document The document to extract from.
|
|
38
|
+
# @param [ Document | Hash | String ] document The document to extract from.
|
|
39
39
|
# @param [ String ] key The key path to extract.
|
|
40
40
|
#
|
|
41
41
|
# @return [ Object | Array ] Field value or values.
|
|
42
42
|
module_function def extract_attribute(document, key)
|
|
43
|
+
# The matcher system will wind up sending atomic values to this as well,
|
|
44
|
+
# when attepting to match more complex types. If anything other than a
|
|
45
|
+
# Document or a Hash is given, we'll short-circuit the logic and just
|
|
46
|
+
# return an empty array.
|
|
47
|
+
return [] unless document.is_a?(Hash) || document.is_a?(Document)
|
|
48
|
+
|
|
49
|
+
# Performance optimization; if the key does not include a '.' character,
|
|
50
|
+
# it must reference an immediate attribute of the document.
|
|
51
|
+
unless key.include?('.')
|
|
52
|
+
hash = document.respond_to?(:attributes) ? document.attributes : document
|
|
53
|
+
key = find_exact_key(hash, key)
|
|
54
|
+
return key ? [ hash[key] ] : []
|
|
55
|
+
end
|
|
56
|
+
|
|
43
57
|
if document.respond_to?(:as_attributes, true)
|
|
44
58
|
# If a document has hash fields, as_attributes would keep those fields
|
|
45
59
|
# as Hash instances which do not offer indifferent access.
|
data/lib/mongoid/serializable.rb
CHANGED
|
@@ -12,13 +12,13 @@ module Mongoid
|
|
|
12
12
|
included do
|
|
13
13
|
|
|
14
14
|
class << self
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
def include_root_in_json
|
|
16
|
+
@include_root_in_json.nil? ? ::Mongoid.include_root_in_json : @include_root_in_json
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def include_root_in_json=(new_value)
|
|
20
|
+
@include_root_in_json = new_value
|
|
21
|
+
end
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -22,13 +22,20 @@ module Mongoid
|
|
|
22
22
|
# @example Set the created at time.
|
|
23
23
|
# person.set_created_at
|
|
24
24
|
def set_created_at
|
|
25
|
-
if
|
|
25
|
+
if able_to_set_created_at?
|
|
26
26
|
time = Time.configured.now
|
|
27
27
|
self.updated_at = time if is_a?(Updated) && !updated_at_changed?
|
|
28
28
|
self.created_at = time
|
|
29
29
|
end
|
|
30
30
|
clear_timeless_option
|
|
31
31
|
end
|
|
32
|
+
|
|
33
|
+
# Is the created timestamp able to be set?
|
|
34
|
+
#
|
|
35
|
+
# @return [ true, false ] If the timestamp can be set.
|
|
36
|
+
def able_to_set_created_at?
|
|
37
|
+
!frozen? && !timeless? && !created_at
|
|
38
|
+
end
|
|
32
39
|
end
|
|
33
40
|
end
|
|
34
41
|
end
|
data/lib/mongoid/touchable.rb
CHANGED
|
@@ -25,7 +25,7 @@ module Mongoid
|
|
|
25
25
|
current = Time.configured.now
|
|
26
26
|
field = database_field_name(field)
|
|
27
27
|
write_attribute(:updated_at, current) if respond_to?("updated_at=")
|
|
28
|
-
write_attribute(field, current) if field
|
|
28
|
+
write_attribute(field, current) if field.present?
|
|
29
29
|
|
|
30
30
|
# If the document being touched is embedded, touch its parents
|
|
31
31
|
# all the way through the composition hierarchy to the root object,
|
data/lib/mongoid/traversable.rb
CHANGED
|
@@ -7,6 +7,29 @@ module Mongoid
|
|
|
7
7
|
# Provides behavior around traversing the document graph.
|
|
8
8
|
module Traversable
|
|
9
9
|
extend ActiveSupport::Concern
|
|
10
|
+
# This code is extracted from ActiveSupport so that we do not depend on
|
|
11
|
+
# their private API that may change at any time.
|
|
12
|
+
# This code should be reviewed and maybe removed when implementing
|
|
13
|
+
# https://jira.mongodb.org/browse/MONGOID-5832
|
|
14
|
+
class << self
|
|
15
|
+
# @api private
|
|
16
|
+
def __redefine(owner, name, value)
|
|
17
|
+
if owner.singleton_class?
|
|
18
|
+
owner.redefine_method(name) { value }
|
|
19
|
+
owner.send(:public, name)
|
|
20
|
+
end
|
|
21
|
+
owner.redefine_singleton_method(name) { value }
|
|
22
|
+
owner.singleton_class.send(:public, name)
|
|
23
|
+
owner.redefine_singleton_method("#{name}=") do |new_value|
|
|
24
|
+
if owner.equal?(self)
|
|
25
|
+
value = new_value
|
|
26
|
+
else
|
|
27
|
+
::Mongoid::Traversable.redefine(self, name, new_value)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
owner.singleton_class.send(:public, "#{name}=")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
10
33
|
|
|
11
34
|
def _parent
|
|
12
35
|
@__parent ||= nil
|
|
@@ -30,7 +53,7 @@ module Mongoid
|
|
|
30
53
|
if value
|
|
31
54
|
Mongoid::Fields::Validators::Macro.validate_field_name(self, value)
|
|
32
55
|
value = value.to_s
|
|
33
|
-
|
|
56
|
+
::Mongoid::Traversable.__redefine(self, 'discriminator_key', value)
|
|
34
57
|
else
|
|
35
58
|
# When discriminator key is set to nil, replace the class's definition
|
|
36
59
|
# of the discriminator key reader (provided by class_attribute earlier)
|
|
@@ -300,6 +323,18 @@ module Mongoid
|
|
|
300
323
|
!!(Mongoid::Document > superclass)
|
|
301
324
|
end
|
|
302
325
|
|
|
326
|
+
# Returns the root class of the STI tree that the current
|
|
327
|
+
# class participates in. If the class is not an STI subclass, this
|
|
328
|
+
# returns the class itself.
|
|
329
|
+
#
|
|
330
|
+
# @return [ Mongoid::Document ] the root of the STI tree
|
|
331
|
+
def root_class
|
|
332
|
+
root = self
|
|
333
|
+
root = root.superclass while root.hereditary?
|
|
334
|
+
|
|
335
|
+
root
|
|
336
|
+
end
|
|
337
|
+
|
|
303
338
|
# When inheriting, we want to copy the fields from the parent class and
|
|
304
339
|
# set the on the child to start, mimicking the behavior of the old
|
|
305
340
|
# class_inheritable_accessor that was deprecated in Rails edge.
|