mongoid 6.3.0 → 6.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Rakefile +12 -0
- data/lib/config/locales/en.yml +21 -0
- data/lib/mongoid.rb +2 -2
- data/lib/mongoid/clients.rb +2 -0
- data/lib/mongoid/clients/sessions.rb +113 -0
- data/lib/mongoid/clients/storage_options.rb +1 -0
- data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
- data/lib/mongoid/contextual/map_reduce.rb +7 -3
- data/lib/mongoid/contextual/memory.rb +7 -2
- data/lib/mongoid/contextual/mongo.rb +11 -2
- data/lib/mongoid/criteria.rb +1 -0
- data/lib/mongoid/criteria/modifiable.rb +12 -2
- data/lib/mongoid/criteria/queryable/mergeable.rb +3 -1
- data/lib/mongoid/criteria/queryable/selectable.rb +34 -7
- data/lib/mongoid/document.rb +4 -4
- data/lib/mongoid/errors.rb +1 -0
- data/lib/mongoid/errors/invalid_session_use.rb +24 -0
- data/lib/mongoid/extensions/big_decimal.rb +1 -1
- data/lib/mongoid/extensions/regexp.rb +1 -0
- data/lib/mongoid/extensions/string.rb +3 -1
- data/lib/mongoid/indexable.rb +4 -4
- data/lib/mongoid/matchable.rb +3 -0
- data/lib/mongoid/matchable/nor.rb +37 -0
- data/lib/mongoid/persistable.rb +1 -1
- data/lib/mongoid/persistable/creatable.rb +4 -2
- data/lib/mongoid/persistable/deletable.rb +4 -2
- data/lib/mongoid/persistable/destroyable.rb +1 -5
- data/lib/mongoid/persistable/settable.rb +5 -5
- data/lib/mongoid/persistable/updatable.rb +2 -2
- data/lib/mongoid/persistable/upsertable.rb +2 -1
- data/lib/mongoid/persistence_context.rb +4 -0
- data/lib/mongoid/railtie.rb +17 -0
- data/lib/mongoid/railties/controller_runtime.rb +86 -0
- data/lib/mongoid/relations/embedded/batchable.rb +10 -4
- data/lib/mongoid/relations/embedded/many.rb +23 -0
- data/lib/mongoid/relations/many.rb +4 -0
- data/lib/mongoid/relations/referenced/many.rb +1 -1
- data/lib/mongoid/relations/touchable.rb +1 -1
- data/lib/mongoid/reloadable.rb +1 -1
- data/lib/mongoid/scopable.rb +3 -3
- data/lib/mongoid/tasks/database.rb +3 -2
- data/lib/mongoid/threaded.rb +74 -0
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -0
- data/spec/app/models/array_field.rb +7 -0
- data/spec/app/models/delegating_patient.rb +16 -0
- data/spec/integration/document_spec.rb +22 -0
- data/spec/mongoid/attributes/nested_spec.rb +4 -0
- data/spec/mongoid/clients/factory_spec.rb +52 -28
- data/spec/mongoid/clients/options_spec.rb +30 -15
- data/spec/mongoid/clients/sessions_spec.rb +334 -0
- data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
- data/spec/mongoid/contextual/mongo_spec.rb +40 -2
- data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
- data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +3 -3
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +74 -6
- data/spec/mongoid/criteria/queryable/selector_spec.rb +2 -2
- data/spec/mongoid/criteria/scopable_spec.rb +81 -0
- data/spec/mongoid/criteria_spec.rb +4 -1
- data/spec/mongoid/document_spec.rb +54 -0
- data/spec/mongoid/extensions/big_decimal_spec.rb +9 -9
- data/spec/mongoid/extensions/regexp_spec.rb +23 -0
- data/spec/mongoid/extensions/string_spec.rb +35 -7
- data/spec/mongoid/fields_spec.rb +1 -1
- data/spec/mongoid/findable_spec.rb +1 -1
- data/spec/mongoid/interceptable_spec.rb +1 -1
- data/spec/mongoid/matchable/nor_spec.rb +209 -0
- data/spec/mongoid/matchable_spec.rb +26 -1
- data/spec/mongoid/persistable/deletable_spec.rb +19 -0
- data/spec/mongoid/persistable/destroyable_spec.rb +19 -0
- data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
- data/spec/mongoid/persistable/settable_spec.rb +35 -1
- data/spec/mongoid/persistable_spec.rb +16 -16
- data/spec/mongoid/relations/embedded/many_spec.rb +246 -16
- data/spec/mongoid/scopable_spec.rb +13 -0
- data/spec/mongoid/threaded_spec.rb +68 -0
- data/spec/rails/controller_extension/controller_runtime_spec.rb +110 -0
- data/spec/spec_helper.rb +79 -0
- data/spec/support/cluster_config.rb +158 -0
- data/spec/support/constraints.rb +101 -0
- data/spec/support/macros.rb +20 -0
- data/spec/support/spec_config.rb +42 -0
- metadata +471 -443
- metadata.gz.sig +0 -0
@@ -477,7 +477,7 @@ module Mongoid
|
|
477
477
|
# @since 3.0.0
|
478
478
|
def persist_delayed(docs, inserts)
|
479
479
|
unless docs.empty?
|
480
|
-
collection.insert_many(inserts)
|
480
|
+
collection.insert_many(inserts, session: _session)
|
481
481
|
docs.each do |doc|
|
482
482
|
doc.new_record = false
|
483
483
|
doc.run_after_callbacks(:create, :save)
|
@@ -31,7 +31,7 @@ module Mongoid
|
|
31
31
|
touches = touch_atomic_updates(field)
|
32
32
|
unless touches["$set"].blank?
|
33
33
|
selector = atomic_selector
|
34
|
-
_root.collection.find(selector).update_one(positionally(selector, touches))
|
34
|
+
_root.collection.find(selector).update_one(positionally(selector, touches), session: _session)
|
35
35
|
end
|
36
36
|
run_callbacks(:touch)
|
37
37
|
true
|
data/lib/mongoid/reloadable.rb
CHANGED
@@ -58,7 +58,7 @@ module Mongoid
|
|
58
58
|
#
|
59
59
|
# @since 2.3.2
|
60
60
|
def reload_root_document
|
61
|
-
{}.merge(collection.find(_id: _id).read(mode: :primary).first || {})
|
61
|
+
{}.merge(collection.find({ _id: _id }, session: _session).read(mode: :primary).first || {})
|
62
62
|
end
|
63
63
|
|
64
64
|
# Reload the embedded document.
|
data/lib/mongoid/scopable.rb
CHANGED
@@ -102,7 +102,7 @@ module Mongoid
|
|
102
102
|
#
|
103
103
|
# @since 3.0.0
|
104
104
|
def default_scopable?
|
105
|
-
default_scoping? && !Threaded.
|
105
|
+
default_scoping? && !Threaded.without_default_scope?(self)
|
106
106
|
end
|
107
107
|
|
108
108
|
# Get a queryable, either the last one on the scope stack or a fresh one.
|
@@ -244,10 +244,10 @@ module Mongoid
|
|
244
244
|
#
|
245
245
|
# @since 3.0.0
|
246
246
|
def without_default_scope
|
247
|
-
Threaded.
|
247
|
+
Threaded.begin_without_default_scope(self)
|
248
248
|
yield
|
249
249
|
ensure
|
250
|
-
Threaded.
|
250
|
+
Threaded.exit_without_default_scope(self)
|
251
251
|
end
|
252
252
|
|
253
253
|
private
|
@@ -44,7 +44,7 @@ module Mongoid
|
|
44
44
|
models.each do |model|
|
45
45
|
unless model.embedded?
|
46
46
|
begin
|
47
|
-
model.collection.indexes.each do |index|
|
47
|
+
model.collection.indexes(session: model.send(:_session)).each do |index|
|
48
48
|
# ignore default index
|
49
49
|
unless index['name'] == '_id_'
|
50
50
|
key = index['key'].symbolize_keys
|
@@ -77,7 +77,7 @@ module Mongoid
|
|
77
77
|
indexes.each do |index|
|
78
78
|
key = index['key'].symbolize_keys
|
79
79
|
collection = model.collection
|
80
|
-
collection.indexes.drop_one(key)
|
80
|
+
collection.indexes(session: model.send(:_session)).drop_one(key)
|
81
81
|
logger.info(
|
82
82
|
"MONGOID: Removed index '#{index['name']}' on collection " +
|
83
83
|
"'#{collection.name}' in database '#{collection.database.name}'."
|
@@ -107,6 +107,7 @@ module Mongoid
|
|
107
107
|
end
|
108
108
|
|
109
109
|
private
|
110
|
+
|
110
111
|
def logger
|
111
112
|
Mongoid.logger
|
112
113
|
end
|
data/lib/mongoid/threaded.rb
CHANGED
@@ -163,6 +163,30 @@ module Mongoid
|
|
163
163
|
validations_for(document.class).delete_one(document._id)
|
164
164
|
end
|
165
165
|
|
166
|
+
# Begin suppressing default scopes for given model on the current thread.
|
167
|
+
#
|
168
|
+
# @example Begin without default scope stack.
|
169
|
+
# Threaded.begin_without_default_scope(klass)
|
170
|
+
#
|
171
|
+
# @param [ Class ] klass The model to suppress default scoping on.
|
172
|
+
#
|
173
|
+
# @api private
|
174
|
+
def begin_without_default_scope(klass)
|
175
|
+
stack(:without_default_scope).push(klass)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Exit suppressing default scopes for given model on the current thread.
|
179
|
+
#
|
180
|
+
# @example Exit without default scope stack.
|
181
|
+
# Threaded.exit_without_default_scope(klass)
|
182
|
+
#
|
183
|
+
# @param [ Class ] klass The model to unsuppress default scoping on.
|
184
|
+
#
|
185
|
+
# @api private
|
186
|
+
def exit_without_default_scope(klass)
|
187
|
+
stack(:without_default_scope).delete(klass)
|
188
|
+
end
|
189
|
+
|
166
190
|
# Get the global client override.
|
167
191
|
#
|
168
192
|
# @example Get the global client override.
|
@@ -247,6 +271,18 @@ module Mongoid
|
|
247
271
|
end
|
248
272
|
end
|
249
273
|
|
274
|
+
# Is the given klass' default scope suppressed on the current thread?
|
275
|
+
#
|
276
|
+
# @example Is the given klass' default scope suppressed?
|
277
|
+
# Threaded.without_default_scope?(klass)
|
278
|
+
#
|
279
|
+
# @param [ Class ] klass The model to check for default scope suppression.
|
280
|
+
#
|
281
|
+
# @api private
|
282
|
+
def without_default_scope?(klass)
|
283
|
+
stack(:without_default_scope).include?(klass)
|
284
|
+
end
|
285
|
+
|
250
286
|
# Is the document autosaved on the current thread?
|
251
287
|
#
|
252
288
|
# @example Is the document autosaved?
|
@@ -325,5 +361,43 @@ module Mongoid
|
|
325
361
|
def validations_for(klass)
|
326
362
|
validations[klass] ||= []
|
327
363
|
end
|
364
|
+
|
365
|
+
# Cache a session for this thread.
|
366
|
+
#
|
367
|
+
# @example Save a session for this thread.
|
368
|
+
# Threaded.set_session(session)
|
369
|
+
#
|
370
|
+
# @param [ Mongo::Session ] session The session to save.
|
371
|
+
#
|
372
|
+
# @since 6.4.0
|
373
|
+
def set_session(session)
|
374
|
+
Thread.current[:session] = session
|
375
|
+
end
|
376
|
+
|
377
|
+
# Get the cached session for this thread.
|
378
|
+
#
|
379
|
+
# @example Get the session for this thread.
|
380
|
+
# Threaded.get_session
|
381
|
+
#
|
382
|
+
# @return [ Mongo::Session, nil ] The session cached on this thread or nil.
|
383
|
+
#
|
384
|
+
# @since 6.4.0
|
385
|
+
def get_session
|
386
|
+
Thread.current[:session]
|
387
|
+
end
|
388
|
+
|
389
|
+
# Clear the cached session for this thread.
|
390
|
+
#
|
391
|
+
# @example Clear this thread's session.
|
392
|
+
# Threaded.clear_session
|
393
|
+
#
|
394
|
+
# @return [ nil ]
|
395
|
+
#
|
396
|
+
# @since 6.4.0
|
397
|
+
def clear_session
|
398
|
+
session = get_session
|
399
|
+
session.end_session if session
|
400
|
+
Thread.current[:session] = nil
|
401
|
+
end
|
328
402
|
end
|
329
403
|
end
|
data/lib/mongoid/version.rb
CHANGED
@@ -11,6 +11,10 @@ development:
|
|
11
11
|
hosts:
|
12
12
|
- localhost:27017
|
13
13
|
options:
|
14
|
+
# Note that all options listed below are Ruby driver client options (the mongo gem).
|
15
|
+
# Please refer to the driver documentation of the version of the mongo gem you are using
|
16
|
+
# for the most up-to-date list of options.
|
17
|
+
#
|
14
18
|
# Change the default write concern. (default = { w: 1 })
|
15
19
|
# write:
|
16
20
|
# w: 1
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
class DelegatingPatient
|
5
|
+
include Mongoid::Document
|
6
|
+
|
7
|
+
embeds_one :email
|
8
|
+
|
9
|
+
# Instance level delegation
|
10
|
+
delegate :address, to: :email
|
11
|
+
|
12
|
+
class << self
|
13
|
+
# Class level delegation
|
14
|
+
delegate :default_client, to: ::Mongoid
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
describe Mongoid::Document do
|
7
|
+
context 'when including class uses delegate' do
|
8
|
+
let(:patient) do
|
9
|
+
DelegatingPatient.new(
|
10
|
+
email: Email.new(address: 'test@example.com'),
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'works for instance level delegation' do
|
15
|
+
patient.address.should == 'test@example.com'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'works for class level delegation' do
|
19
|
+
DelegatingPatient.default_client.should be Mongoid.default_client
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,7 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
1
4
|
require "spec_helper"
|
2
5
|
|
3
6
|
describe Mongoid::Clients::Factory do
|
4
7
|
|
8
|
+
shared_examples_for 'includes seed address' do
|
9
|
+
let(:configured_address) do
|
10
|
+
address = SpecConfig.instance.addresses.first
|
11
|
+
unless address.include?(':')
|
12
|
+
address = "#{address}:27017"
|
13
|
+
end
|
14
|
+
address
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:expected_addresses) do
|
18
|
+
[
|
19
|
+
configured_address,
|
20
|
+
configured_address.sub(/\Alocalhost:/, '127.0.0.1:'),
|
21
|
+
configured_address.sub(/\A127\.0\.0\.1:/, 'localhost:'),
|
22
|
+
].uniq
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'includes seed address' do
|
26
|
+
ok = cluster_addresses.any? do |address|
|
27
|
+
expected_addresses.include?(address)
|
28
|
+
end
|
29
|
+
expect(ok).to be true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
5
33
|
describe ".create" do
|
6
34
|
|
7
35
|
context "when provided a name" do
|
@@ -12,8 +40,8 @@ describe Mongoid::Clients::Factory do
|
|
12
40
|
|
13
41
|
let(:config) do
|
14
42
|
{
|
15
|
-
default: { hosts:
|
16
|
-
secondary: { hosts:
|
43
|
+
default: { hosts: SpecConfig.instance.addresses, database: database_id },
|
44
|
+
secondary: { hosts: SpecConfig.instance.addresses, database: database_id }
|
17
45
|
}
|
18
46
|
end
|
19
47
|
|
@@ -37,10 +65,12 @@ describe Mongoid::Clients::Factory do
|
|
37
65
|
expect(client).to be_a(Mongo::Client)
|
38
66
|
end
|
39
67
|
|
40
|
-
|
41
|
-
|
68
|
+
let(:cluster_addresses) do
|
69
|
+
cluster.addresses.map(&:to_s)
|
42
70
|
end
|
43
71
|
|
72
|
+
it_behaves_like 'includes seed address'
|
73
|
+
|
44
74
|
it "sets the platform to Mongoid's platform constant" do
|
45
75
|
expect(client.options[:platform]).to eq(Mongoid::PLATFORM_DETAILS)
|
46
76
|
end
|
@@ -80,11 +110,11 @@ describe Mongoid::Clients::Factory do
|
|
80
110
|
end
|
81
111
|
|
82
112
|
it "sets the cluster's seed ports to 27017" do
|
83
|
-
expect(
|
113
|
+
expect(%w(127.0.0.1:27017 localhost:27017)).to include(cluster.addresses.first.to_s)
|
84
114
|
end
|
85
115
|
|
86
116
|
it "sets ips with no ports to 27017" do
|
87
|
-
expect(
|
117
|
+
expect(%w(127.0.0.1:27017 localhost:27017)).to include(cluster.addresses.first.to_s)
|
88
118
|
end
|
89
119
|
end
|
90
120
|
|
@@ -120,7 +150,7 @@ describe Mongoid::Clients::Factory do
|
|
120
150
|
end
|
121
151
|
|
122
152
|
it "sets the cluster's seeds" do
|
123
|
-
expect(
|
153
|
+
expect(%w(127.0.0.1:27017 localhost:27017)).to include(cluster.addresses.first.to_s)
|
124
154
|
end
|
125
155
|
|
126
156
|
it "sets the database" do
|
@@ -132,8 +162,8 @@ describe Mongoid::Clients::Factory do
|
|
132
162
|
|
133
163
|
let(:config) do
|
134
164
|
{
|
135
|
-
default: { hosts: [ "127.0.0.1:
|
136
|
-
secondary: { uri: "mongodb://127.0.0.1:
|
165
|
+
default: { hosts: [ "127.0.0.1:1234" ], database: database_id, server_selection_timeout: 1 },
|
166
|
+
secondary: { uri: "mongodb://127.0.0.1:1234,127.0.0.1:5678/mongoid_test?serverSelectionTimeoutMS=1000" }
|
137
167
|
}
|
138
168
|
end
|
139
169
|
|
@@ -162,7 +192,7 @@ describe Mongoid::Clients::Factory do
|
|
162
192
|
end
|
163
193
|
|
164
194
|
it "sets the cluster's seeds" do
|
165
|
-
expect(seeds).to eq([ "127.0.0.1:
|
195
|
+
expect(seeds).to eq([ "127.0.0.1:1234", "127.0.0.1:5678" ])
|
166
196
|
end
|
167
197
|
end
|
168
198
|
end
|
@@ -181,7 +211,7 @@ describe Mongoid::Clients::Factory do
|
|
181
211
|
context "when no name is provided" do
|
182
212
|
|
183
213
|
let(:config) do
|
184
|
-
{ default: { hosts:
|
214
|
+
{ default: { hosts: SpecConfig.instance.addresses, database: database_id }}
|
185
215
|
end
|
186
216
|
|
187
217
|
before do
|
@@ -200,17 +230,15 @@ describe Mongoid::Clients::Factory do
|
|
200
230
|
client.cluster
|
201
231
|
end
|
202
232
|
|
203
|
-
let(:
|
204
|
-
cluster.addresses.map
|
233
|
+
let(:cluster_addresses) do
|
234
|
+
cluster.addresses.map(&:to_s)
|
205
235
|
end
|
206
236
|
|
207
237
|
it "returns the default client" do
|
208
238
|
expect(client).to be_a(Mongo::Client)
|
209
239
|
end
|
210
240
|
|
211
|
-
|
212
|
-
expect(seeds).to eq([ "127.0.0.1:27017" ])
|
213
|
-
end
|
241
|
+
it_behaves_like 'includes seed address'
|
214
242
|
end
|
215
243
|
|
216
244
|
context "when nil is provided and no default config" do
|
@@ -230,7 +258,7 @@ describe Mongoid::Clients::Factory do
|
|
230
258
|
describe ".default" do
|
231
259
|
|
232
260
|
let(:config) do
|
233
|
-
{ default: { hosts:
|
261
|
+
{ default: { hosts: SpecConfig.instance.addresses, database: database_id }}
|
234
262
|
end
|
235
263
|
|
236
264
|
before do
|
@@ -249,17 +277,15 @@ describe Mongoid::Clients::Factory do
|
|
249
277
|
client.cluster
|
250
278
|
end
|
251
279
|
|
252
|
-
let(:
|
253
|
-
cluster.addresses.map
|
280
|
+
let(:cluster_addresses) do
|
281
|
+
cluster.addresses.map(&:to_s)
|
254
282
|
end
|
255
283
|
|
256
284
|
it "returns the default client" do
|
257
285
|
expect(client).to be_a(Mongo::Client)
|
258
286
|
end
|
259
287
|
|
260
|
-
|
261
|
-
expect(seeds).to eq([ "127.0.0.1:27017" ])
|
262
|
-
end
|
288
|
+
it_behaves_like 'includes seed address'
|
263
289
|
end
|
264
290
|
|
265
291
|
context "when options are provided with string keys" do
|
@@ -267,7 +293,7 @@ describe Mongoid::Clients::Factory do
|
|
267
293
|
let(:config) do
|
268
294
|
{
|
269
295
|
default: {
|
270
|
-
hosts:
|
296
|
+
hosts: SpecConfig.instance.addresses,
|
271
297
|
database: database_id,
|
272
298
|
options: {
|
273
299
|
"server_selection_timeout" => 10,
|
@@ -293,17 +319,15 @@ describe Mongoid::Clients::Factory do
|
|
293
319
|
client.cluster
|
294
320
|
end
|
295
321
|
|
296
|
-
let(:
|
297
|
-
cluster.addresses.map
|
322
|
+
let(:cluster_addresses) do
|
323
|
+
cluster.addresses.map(&:to_s)
|
298
324
|
end
|
299
325
|
|
300
326
|
it "returns the default client" do
|
301
327
|
expect(client).to be_a(Mongo::Client)
|
302
328
|
end
|
303
329
|
|
304
|
-
|
305
|
-
expect(seeds).to eq([ "127.0.0.1:27017" ])
|
306
|
-
end
|
330
|
+
it_behaves_like 'includes seed address'
|
307
331
|
|
308
332
|
it "sets the server selection timeout" do
|
309
333
|
expect(cluster.options[:server_selection_timeout]).to eq(10)
|