mongoid 7.5.4 → 7.6.1
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/README.md +4 -4
- data/Rakefile +85 -46
- data/lib/mongoid/clients/factory.rb +4 -0
- data/lib/mongoid/contextual/mongo.rb +26 -1
- data/lib/mongoid/extensions/hash.rb +27 -1
- data/lib/mongoid/version.rb +5 -1
- data/spec/mongoid/clients/factory_spec.rb +31 -0
- data/spec/mongoid/config_spec.rb +1 -0
- data/spec/mongoid/contextual/mongo_spec.rb +10 -0
- data/spec/mongoid/copyable_spec.rb +1 -0
- data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +2 -1
- data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +2 -1
- data/spec/mongoid/extensions/hash_spec.rb +236 -0
- data/spec/mongoid/query_cache_spec.rb +2 -1
- data/spec/mongoid/serializable_spec.rb +7 -14
- data/spec/shared/CANDIDATE.md +28 -0
- data/spec/shared/lib/mrss/docker_runner.rb +8 -1
- data/spec/shared/lib/mrss/lite_constraints.rb +2 -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 +17 -24
- data/spec/shared/lib/mrss/spec_organizer.rb +32 -3
- data/spec/shared/lib/mrss/utils.rb +28 -6
- data/spec/shared/lib/tasks/candidate.rake +64 -0
- data/spec/shared/share/Dockerfile.erb +33 -107
- data/spec/shared/shlib/distro.sh +10 -0
- data/spec/shared/shlib/server.sh +60 -29
- data/spec/shared/shlib/set_env.sh +12 -71
- data/spec/support/expectations.rb +20 -17
- metadata +16 -38
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7d6b4091f7d54b2e65649f2c41aa1ae9d79ba5d45eda1f25402a977921af378b
|
|
4
|
+
data.tar.gz: 11c42c8f504d870e6d49a823874855c88bec5cae51254b2e3246d4e6fe3b5992
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 42b67f419f6e4632f25d6b498e774627d0f7111c7d05cdab5d02fe9f33189448a7abb572b2c351d97d2ce97a22cf2cdc3e96e61b3163337a6d4e6f921c69522a
|
|
7
|
+
data.tar.gz: 48991d86f760c6f3a1b5cd87b8a19f501a1c7ebbb5cf07c5f9164c116e999ae0e4304b92b55225e7b3ca1252ee9675e4987f5998cd627f0fa1db451ddf524b50
|
data/README.md
CHANGED
|
@@ -19,9 +19,9 @@ Compatibility
|
|
|
19
19
|
|
|
20
20
|
Mongoid supports and is tested against:
|
|
21
21
|
|
|
22
|
-
- MRI 2.
|
|
23
|
-
- JRuby 9.
|
|
24
|
-
- MongoDB server
|
|
22
|
+
- MRI 2.7 - 3.1
|
|
23
|
+
- JRuby 9.3
|
|
24
|
+
- MongoDB server 3.6 - 8.0
|
|
25
25
|
|
|
26
26
|
Issues
|
|
27
27
|
------
|
|
@@ -40,7 +40,7 @@ License
|
|
|
40
40
|
-------
|
|
41
41
|
|
|
42
42
|
Copyright (c) 2009-2016 Durran Jordan
|
|
43
|
-
Copyright (c) 2015-
|
|
43
|
+
Copyright (c) 2015-present MongoDB, Inc.
|
|
44
44
|
|
|
45
45
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
46
46
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# rubocop:todo all
|
|
2
3
|
|
|
3
4
|
require "bundler"
|
|
4
|
-
require "bundler/gem_tasks"
|
|
5
5
|
Bundler.setup
|
|
6
6
|
|
|
7
7
|
ROOT = File.expand_path(File.join(File.dirname(__FILE__)))
|
|
@@ -10,34 +10,53 @@ $: << File.join(ROOT, 'spec/shared/lib')
|
|
|
10
10
|
|
|
11
11
|
require "rake"
|
|
12
12
|
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
13
|
|
|
27
|
-
|
|
28
|
-
|
|
14
|
+
if File.exist?('./spec/shared/lib/tasks/candidate.rake')
|
|
15
|
+
load 'spec/shared/lib/tasks/candidate.rake'
|
|
16
|
+
end
|
|
29
17
|
|
|
30
|
-
|
|
18
|
+
desc 'Build the gem'
|
|
31
19
|
task :build do
|
|
32
|
-
|
|
20
|
+
command = %w[ gem build ]
|
|
21
|
+
command << "--output=#{ENV['GEM_FILE_NAME']}" if ENV['GEM_FILE_NAME']
|
|
22
|
+
command << (ENV['GEMSPEC'] || 'mongoid.gemspec')
|
|
23
|
+
system(*command)
|
|
33
24
|
end
|
|
34
25
|
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
# `rake version` is used by the deployment system so get the release version
|
|
27
|
+
# of the product beng deployed. It must do nothing more than just print the
|
|
28
|
+
# product version number.
|
|
29
|
+
#
|
|
30
|
+
# See the mongodb-labs/driver-github-tools/ruby/publish Github action.
|
|
31
|
+
desc "Print the current value of Mongoid::VERSION"
|
|
32
|
+
task :version do
|
|
33
|
+
require 'mongoid/version'
|
|
34
|
+
|
|
35
|
+
puts Mongoid::VERSION
|
|
37
36
|
end
|
|
38
37
|
|
|
38
|
+
# overrides the default Bundler-provided `release` task, which also
|
|
39
|
+
# builds the gem. Our release process assumes the gem has already
|
|
40
|
+
# been built (and signed via GPG), so we just need `rake release` to
|
|
41
|
+
# push the gem to rubygems.
|
|
39
42
|
task :release do
|
|
40
|
-
|
|
43
|
+
require 'mongoid/version'
|
|
44
|
+
|
|
45
|
+
if ENV['GITHUB_ACTION'].nil?
|
|
46
|
+
abort <<~WARNING
|
|
47
|
+
`rake release` must be invoked from the `Mongoid Release` GitHub action,
|
|
48
|
+
and must not be invoked locally. This ensures the gem is properly signed
|
|
49
|
+
and distributed by the appropriate user.
|
|
50
|
+
|
|
51
|
+
Note that it is the `rubygems/release-gem@v1` step in the `Mongoid Release`
|
|
52
|
+
action that invokes this task. Do not rename or remove this task, or the
|
|
53
|
+
release-gem step will fail. Reimplement this task with caution.
|
|
54
|
+
|
|
55
|
+
mongoid-#{Mongoid::VERSION}.gem was NOT pushed to RubyGems.
|
|
56
|
+
WARNING
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
system 'gem', 'push', "mongoid-#{Mongoid::VERSION}.gem"
|
|
41
60
|
end
|
|
42
61
|
|
|
43
62
|
RSpec::Core::RakeTask.new("spec") do |spec|
|
|
@@ -49,6 +68,46 @@ RSpec::Core::RakeTask.new('spec:progress') do |spec|
|
|
|
49
68
|
spec.pattern = "spec/**/*_spec.rb"
|
|
50
69
|
end
|
|
51
70
|
|
|
71
|
+
desc 'Build and validate the evergreen config'
|
|
72
|
+
task eg: %w[ eg:build eg:validate ]
|
|
73
|
+
|
|
74
|
+
# 'eg' == 'evergreen', but evergreen is too many letters for convenience
|
|
75
|
+
namespace :eg do
|
|
76
|
+
desc 'Builds the .evergreen/config.yml file from the templates'
|
|
77
|
+
task :build do
|
|
78
|
+
ruby '.evergreen/update-evergreen-configs'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
desc 'Validates the .evergreen/config.yml file'
|
|
82
|
+
task :validate do
|
|
83
|
+
system 'evergreen validate --project mongoid .evergreen/config.yml'
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
desc 'Updates the evergreen executable to the latest available version'
|
|
87
|
+
task :update do
|
|
88
|
+
system 'evergreen get-update --install'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
desc 'Runs the current branch as an evergreen patch'
|
|
92
|
+
task :patch do
|
|
93
|
+
system 'evergreen patch --uncommitted --project mongoid --browse --auto-description --yes'
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
namespace :generate do
|
|
98
|
+
desc 'Generates a mongoid.yml from the template'
|
|
99
|
+
task :config do
|
|
100
|
+
require 'mongoid'
|
|
101
|
+
require 'erb'
|
|
102
|
+
|
|
103
|
+
template_path = 'lib/rails/generators/mongoid/config/templates/mongoid.yml'
|
|
104
|
+
database_name = ENV['DATABASE_NAME'] || 'my_db'
|
|
105
|
+
|
|
106
|
+
config = ERB.new(File.read(template_path), trim_mode: '-').result(binding)
|
|
107
|
+
File.write('mongoid.yml', config)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
52
111
|
CLASSIFIERS = [
|
|
53
112
|
[%r,^mongoid/attribute,, :attributes],
|
|
54
113
|
[%r,^mongoid/association/[or],, :associations_referenced],
|
|
@@ -64,6 +123,8 @@ RUN_PRIORITY = %i(
|
|
|
64
123
|
)
|
|
65
124
|
|
|
66
125
|
def spec_organizer
|
|
126
|
+
require 'mrss/spec_organizer'
|
|
127
|
+
|
|
67
128
|
Mrss::SpecOrganizer.new(
|
|
68
129
|
root: ROOT,
|
|
69
130
|
classifiers: CLASSIFIERS,
|
|
@@ -97,34 +158,12 @@ desc "Generate all documentation"
|
|
|
97
158
|
task :docs => 'docs:yard'
|
|
98
159
|
|
|
99
160
|
namespace :docs do
|
|
100
|
-
desc "Generate yard
|
|
161
|
+
desc "Generate yard documentation"
|
|
101
162
|
task :yard do
|
|
163
|
+
require "mongoid/version"
|
|
164
|
+
|
|
102
165
|
out = File.join('yard-docs', Mongoid::VERSION)
|
|
103
166
|
FileUtils.rm_rf(out)
|
|
104
167
|
system "yardoc -o #{out} --title mongoid-#{Mongoid::VERSION}"
|
|
105
168
|
end
|
|
106
169
|
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
|
|
@@ -95,6 +95,10 @@ module Mongoid
|
|
|
95
95
|
[MONGOID_WRAPPING_LIBRARY] + options[:wrapping_libraries]
|
|
96
96
|
else
|
|
97
97
|
[MONGOID_WRAPPING_LIBRARY]
|
|
98
|
+
end.tap do |wrap|
|
|
99
|
+
if defined?(::Rails) && ::Rails.respond_to?(:version)
|
|
100
|
+
wrap << { name: 'Rails', version: ::Rails.version }
|
|
101
|
+
end
|
|
98
102
|
end
|
|
99
103
|
options[:wrapping_libraries] = wrap_lib
|
|
100
104
|
end
|
|
@@ -65,7 +65,14 @@ module Mongoid
|
|
|
65
65
|
# @return [ Integer ] The number of matches.
|
|
66
66
|
def count(options = {}, &block)
|
|
67
67
|
return super(&block) if block_given?
|
|
68
|
-
|
|
68
|
+
|
|
69
|
+
try_cache(:count) do
|
|
70
|
+
if valid_for_count_documents?
|
|
71
|
+
view.count_documents(options)
|
|
72
|
+
else
|
|
73
|
+
view.count(options)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
69
76
|
end
|
|
70
77
|
|
|
71
78
|
# Get the estimated number of documents matching the query.
|
|
@@ -902,6 +909,24 @@ module Mongoid
|
|
|
902
909
|
docs = eager_load(docs)
|
|
903
910
|
limit ? docs : docs.first
|
|
904
911
|
end
|
|
912
|
+
|
|
913
|
+
# Queries whether the current context is valid for use with
|
|
914
|
+
# the #count_documents? predicate. A context is valid if it
|
|
915
|
+
# does not include a `$where` operator.
|
|
916
|
+
#
|
|
917
|
+
# @return [ true | false ] whether or not the current context
|
|
918
|
+
# excludes a `$where` operator.
|
|
919
|
+
def valid_for_count_documents?(hash = view.filter)
|
|
920
|
+
# Note that `view.filter` is a BSON::Document, and all keys in a
|
|
921
|
+
# BSON::Document are strings; we don't need to worry about symbol
|
|
922
|
+
# representations of `$where`.
|
|
923
|
+
hash.keys.each do |key|
|
|
924
|
+
return false if key == '$where'
|
|
925
|
+
return false if hash[key].is_a?(Hash) && !valid_for_count_documents?(hash[key])
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
true
|
|
929
|
+
end
|
|
905
930
|
end
|
|
906
931
|
end
|
|
907
932
|
end
|
|
@@ -163,6 +163,28 @@ module Mongoid
|
|
|
163
163
|
true
|
|
164
164
|
end
|
|
165
165
|
|
|
166
|
+
ALLOWED_TO_CRITERIA_METHODS = %i[
|
|
167
|
+
all all_in all_of and any_in any_of asc ascending
|
|
168
|
+
batch_size between
|
|
169
|
+
collation comment cursor_type
|
|
170
|
+
desc descending
|
|
171
|
+
elem_match eq exists extras
|
|
172
|
+
geo_spatial group gt gte
|
|
173
|
+
hint
|
|
174
|
+
in includes
|
|
175
|
+
limit lt lte
|
|
176
|
+
max_distance max_scan max_time_ms merge mod
|
|
177
|
+
ne near near_sphere nin no_timeout none none_of nor not not_in
|
|
178
|
+
offset only or order order_by
|
|
179
|
+
project
|
|
180
|
+
raw read reorder
|
|
181
|
+
scoped skip slice snapshot
|
|
182
|
+
text_search type
|
|
183
|
+
unscoped unwind
|
|
184
|
+
where with_size with_type without
|
|
185
|
+
].freeze
|
|
186
|
+
private_constant :ALLOWED_TO_CRITERIA_METHODS
|
|
187
|
+
|
|
166
188
|
# Convert this hash to a criteria. Will iterate over each keys in the
|
|
167
189
|
# hash which must correspond to method on a criteria object. The hash
|
|
168
190
|
# must also include a "klass" key.
|
|
@@ -174,7 +196,11 @@ module Mongoid
|
|
|
174
196
|
def to_criteria
|
|
175
197
|
criteria = Criteria.new(delete(:klass) || delete("klass"))
|
|
176
198
|
each_pair do |method, args|
|
|
177
|
-
|
|
199
|
+
method_sym = method.to_sym
|
|
200
|
+
unless ALLOWED_TO_CRITERIA_METHODS.include?(method_sym)
|
|
201
|
+
raise ArgumentError, "Method '#{method}' is not allowed in to_criteria"
|
|
202
|
+
end
|
|
203
|
+
criteria = criteria.public_send(method_sym, args)
|
|
178
204
|
end
|
|
179
205
|
criteria
|
|
180
206
|
end
|
data/lib/mongoid/version.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Mongoid
|
|
4
|
-
|
|
4
|
+
# The current version of Mongoid
|
|
5
|
+
#
|
|
6
|
+
# Note that this file is automatically updated via `rake candidate:create`.
|
|
7
|
+
# Manual changes to this file will be overwritten by that rake task.
|
|
8
|
+
VERSION = '7.6.1'
|
|
5
9
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# rubocop:todo all
|
|
2
3
|
|
|
3
4
|
require "spec_helper"
|
|
4
5
|
|
|
@@ -29,6 +30,34 @@ describe Mongoid::Clients::Factory do
|
|
|
29
30
|
end
|
|
30
31
|
end
|
|
31
32
|
|
|
33
|
+
shared_examples_for 'includes rails wrapping library' do
|
|
34
|
+
context 'when Rails is available' do
|
|
35
|
+
around do |example|
|
|
36
|
+
rails_was_defined = defined?(::Rails)
|
|
37
|
+
|
|
38
|
+
if !rails_was_defined || !::Rails.respond_to?(:version)
|
|
39
|
+
module ::Rails
|
|
40
|
+
def self.version
|
|
41
|
+
'6.1.0'
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
example.run
|
|
47
|
+
|
|
48
|
+
if !rails_was_defined
|
|
49
|
+
Object.send(:remove_const, :Rails) if defined?(::Rails)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'adds Rails as another wrapping library' do
|
|
54
|
+
expect(client.options[:wrapping_libraries]).to include(
|
|
55
|
+
{'name' => 'Rails', 'version' => '6.1.0'},
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
32
61
|
describe ".create" do
|
|
33
62
|
|
|
34
63
|
context "when provided a name" do
|
|
@@ -116,6 +145,8 @@ describe Mongoid::Clients::Factory do
|
|
|
116
145
|
]
|
|
117
146
|
end
|
|
118
147
|
end
|
|
148
|
+
|
|
149
|
+
it_behaves_like 'includes rails wrapping library'
|
|
119
150
|
end
|
|
120
151
|
end
|
|
121
152
|
|
data/spec/mongoid/config_spec.rb
CHANGED
|
@@ -558,6 +558,7 @@ describe Mongoid::Config do
|
|
|
558
558
|
|
|
559
559
|
# Wrapping libraries are only recognized by driver 2.13.0+.
|
|
560
560
|
min_driver_version '2.13'
|
|
561
|
+
ruby_version_lt '3.0'
|
|
561
562
|
|
|
562
563
|
it 'passes uuid to driver' do
|
|
563
564
|
Mongo::Client.should receive(:new).with(SpecConfig.instance.addresses,
|
|
@@ -189,6 +189,16 @@ describe Mongoid::Contextual::Mongo do
|
|
|
189
189
|
end
|
|
190
190
|
end
|
|
191
191
|
end
|
|
192
|
+
|
|
193
|
+
context 'when for_js is present' do
|
|
194
|
+
let(:context) do
|
|
195
|
+
Band.for_js('this.name == "Depeche Mode"')
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'counts the expected records' do
|
|
199
|
+
expect(context.count).to eq(1)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
192
202
|
end
|
|
193
203
|
|
|
194
204
|
describe "#estimated_count" do
|
|
@@ -467,4 +467,240 @@ describe Mongoid::Extensions::Hash do
|
|
|
467
467
|
|
|
468
468
|
it_behaves_like 'unsatisfiable criteria method'
|
|
469
469
|
end
|
|
470
|
+
|
|
471
|
+
describe '#to_criteria' do
|
|
472
|
+
subject(:criteria) { hash.to_criteria }
|
|
473
|
+
|
|
474
|
+
context 'when klass is specified' do
|
|
475
|
+
let(:hash) do
|
|
476
|
+
{ klass: Band, where: { name: 'Songs Ohia' } }
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
it 'returns a criteria' do
|
|
480
|
+
expect(criteria).to be_a(Mongoid::Criteria)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
it 'sets the klass' do
|
|
484
|
+
expect(criteria.klass).to eq(Band)
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
it 'sets the selector' do
|
|
488
|
+
expect(criteria.selector).to eq({ 'name' => 'Songs Ohia' })
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
context 'when klass is missing' do
|
|
493
|
+
let(:hash) do
|
|
494
|
+
{ where: { name: 'Songs Ohia' } }
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
it 'returns a criteria' do
|
|
498
|
+
expect(criteria).to be_a(Mongoid::Criteria)
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
it 'has klass nil' do
|
|
502
|
+
expect(criteria.klass).to be_nil
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
it 'sets the selector' do
|
|
506
|
+
expect(criteria.selector).to eq({ 'name' => 'Songs Ohia' })
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
context 'with allowed methods' do
|
|
511
|
+
context 'when using multiple query methods' do
|
|
512
|
+
let(:hash) do
|
|
513
|
+
{
|
|
514
|
+
klass: Band,
|
|
515
|
+
where: { active: true },
|
|
516
|
+
limit: 10,
|
|
517
|
+
skip: 5,
|
|
518
|
+
order_by: { name: 1 }
|
|
519
|
+
}
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
it 'applies all methods successfully' do
|
|
523
|
+
expect(criteria.selector).to eq({ 'active' => true })
|
|
524
|
+
expect(criteria.options[:limit]).to eq(10)
|
|
525
|
+
expect(criteria.options[:skip]).to eq(5)
|
|
526
|
+
expect(criteria.options[:sort]).to eq({ 'name' => 1 })
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
context 'when using query selector methods' do
|
|
531
|
+
let(:hash) do
|
|
532
|
+
{
|
|
533
|
+
klass: Band,
|
|
534
|
+
gt: { members: 2 },
|
|
535
|
+
in: { genre: ['rock', 'metal'] }
|
|
536
|
+
}
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
it 'applies selector methods' do
|
|
540
|
+
expect(criteria.selector['members']).to eq({ '$gt' => 2 })
|
|
541
|
+
expect(criteria.selector['genre']).to eq({ '$in' => ['rock', 'metal'] })
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
context 'when using aggregation methods' do
|
|
546
|
+
let(:hash) do
|
|
547
|
+
{
|
|
548
|
+
klass: Band,
|
|
549
|
+
project: { name: 1, members: 1 }
|
|
550
|
+
}
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
it 'applies aggregation methods' do
|
|
554
|
+
expect { criteria }.not_to raise_error
|
|
555
|
+
end
|
|
556
|
+
end
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
context 'with disallowed methods' do
|
|
560
|
+
context 'when attempting to call create' do
|
|
561
|
+
let(:hash) do
|
|
562
|
+
{ klass: Band, create: { name: 'Malicious' } }
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
it 'raises ArgumentError' do
|
|
566
|
+
expect { criteria }.to raise_error(ArgumentError, "Method 'create' is not allowed in to_criteria")
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
context 'when attempting to call create!' do
|
|
571
|
+
let(:hash) do
|
|
572
|
+
{ klass: Band, 'create!': { name: 'Malicious' } }
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
it 'raises ArgumentError' do
|
|
576
|
+
expect { criteria }.to raise_error(ArgumentError, "Method 'create!' is not allowed in to_criteria")
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
context 'when attempting to call build' do
|
|
581
|
+
let(:hash) do
|
|
582
|
+
{ klass: Band, build: { name: 'Malicious' } }
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
it 'raises ArgumentError' do
|
|
586
|
+
expect { criteria }.to raise_error(ArgumentError, "Method 'build' is not allowed in to_criteria")
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
context 'when attempting to call find' do
|
|
591
|
+
let(:hash) do
|
|
592
|
+
{ klass: Band, find: 'some_id' }
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
it 'raises ArgumentError' do
|
|
596
|
+
expect { criteria }.to raise_error(ArgumentError, "Method 'find' is not allowed in to_criteria")
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
context 'when attempting to call execute_or_raise' do
|
|
601
|
+
let(:hash) do
|
|
602
|
+
{ klass: Band, execute_or_raise: ['id1', 'id2'] }
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
it 'raises ArgumentError' do
|
|
606
|
+
expect { criteria }.to raise_error(ArgumentError, "Method 'execute_or_raise' is not allowed in to_criteria")
|
|
607
|
+
end
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
context 'when attempting to call new' do
|
|
611
|
+
let(:hash) do
|
|
612
|
+
{ klass: Band, new: { name: 'Test' } }
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
it 'raises ArgumentError' do
|
|
616
|
+
expect { criteria }.to raise_error(ArgumentError, "Method 'new' is not allowed in to_criteria")
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
context 'when allowed method is combined with disallowed method' do
|
|
621
|
+
let(:hash) do
|
|
622
|
+
{
|
|
623
|
+
klass: Band,
|
|
624
|
+
where: { active: true },
|
|
625
|
+
create: { name: 'Malicious' }
|
|
626
|
+
}
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
it 'raises ArgumentError before executing any methods' do
|
|
630
|
+
expect { criteria }.to raise_error(ArgumentError, "Method 'create' is not allowed in to_criteria")
|
|
631
|
+
end
|
|
632
|
+
end
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
context 'security validation' do
|
|
636
|
+
# This test ensures that ALL public methods not in the allowlist are blocked
|
|
637
|
+
it 'blocks all dangerous public methods' do
|
|
638
|
+
dangerous_methods = %i[
|
|
639
|
+
build create create! new
|
|
640
|
+
find find_or_create_by find_or_create_by! find_or_initialize_by
|
|
641
|
+
first_or_create first_or_create! first_or_initialize
|
|
642
|
+
execute_or_raise multiple_from_db for_ids
|
|
643
|
+
documents= inclusions= scoping_options=
|
|
644
|
+
initialize freeze as_json
|
|
645
|
+
]
|
|
646
|
+
|
|
647
|
+
dangerous_methods.each do |method|
|
|
648
|
+
hash = { klass: Band, method => 'arg' }
|
|
649
|
+
expect { hash.to_criteria }.to raise_error(
|
|
650
|
+
ArgumentError,
|
|
651
|
+
"Method '#{method}' is not allowed in to_criteria"
|
|
652
|
+
), "Expected method '#{method}' to be blocked but it was allowed"
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
it 'blocks dangerous inherited methods from Object' do
|
|
657
|
+
# Critical security test: block send, instance_eval, etc.
|
|
658
|
+
inherited_dangerous = %i[
|
|
659
|
+
send __send__ instance_eval instance_exec
|
|
660
|
+
instance_variable_set method
|
|
661
|
+
]
|
|
662
|
+
|
|
663
|
+
inherited_dangerous.each do |method|
|
|
664
|
+
hash = { klass: Band, method => 'arg' }
|
|
665
|
+
expect { hash.to_criteria }.to raise_error(
|
|
666
|
+
ArgumentError,
|
|
667
|
+
"Method '#{method}' is not allowed in to_criteria"
|
|
668
|
+
), "Expected inherited method '#{method}' to be blocked"
|
|
669
|
+
end
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
it 'blocks Enumerable execution methods' do
|
|
673
|
+
# to_criteria should build queries, not execute them
|
|
674
|
+
enumerable_methods = %i[each map select count sum]
|
|
675
|
+
|
|
676
|
+
enumerable_methods.each do |method|
|
|
677
|
+
hash = { klass: Band, method => 'arg' }
|
|
678
|
+
expect { hash.to_criteria }.to raise_error(
|
|
679
|
+
ArgumentError,
|
|
680
|
+
"Method '#{method}' is not allowed in to_criteria"
|
|
681
|
+
), "Expected Enumerable method '#{method}' to be blocked"
|
|
682
|
+
end
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
it 'allows all whitelisted methods' do
|
|
686
|
+
# Sample of allowed methods from each category
|
|
687
|
+
allowed_sample = {
|
|
688
|
+
where: { name: 'Test' }, # Query selector
|
|
689
|
+
limit: 10, # Query option
|
|
690
|
+
skip: 5, # Query option
|
|
691
|
+
gt: { age: 18 }, # Query selector
|
|
692
|
+
in: { status: ['active'] }, # Query selector
|
|
693
|
+
ascending: :name, # Sorting
|
|
694
|
+
includes: :notes, # Eager loading
|
|
695
|
+
merge: { klass: Band }, # Merge
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
allowed_sample.each do |method, args|
|
|
699
|
+
hash = { klass: Band, method => args }
|
|
700
|
+
expect { hash.to_criteria }.not_to raise_error,
|
|
701
|
+
"Expected method '#{method}' to be allowed but it was blocked"
|
|
702
|
+
end
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
end
|
|
470
706
|
end
|
|
@@ -4,6 +4,7 @@ require "spec_helper"
|
|
|
4
4
|
require 'mongoid/association/referenced/has_many_models'
|
|
5
5
|
|
|
6
6
|
describe Mongoid::QueryCache do
|
|
7
|
+
require_mri
|
|
7
8
|
|
|
8
9
|
around do |spec|
|
|
9
10
|
Mongoid::QueryCache.clear_cache
|
|
@@ -21,7 +22,7 @@ describe Mongoid::QueryCache do
|
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
after do
|
|
24
|
-
Mrss::SessionRegistry.instance.verify_sessions_ended!
|
|
25
|
+
# Mrss::SessionRegistry.instance.verify_sessions_ended!
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
let(:reset_legacy_qc_warning) do
|