mongoid 5.1.5 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/config/locales/en.yml +15 -0
- data/lib/mongoid.rb +5 -0
- data/lib/mongoid/attributes/dynamic.rb +3 -3
- data/lib/mongoid/clients/factory.rb +2 -0
- data/lib/mongoid/config.rb +1 -0
- data/lib/mongoid/config/options.rb +1 -1
- data/lib/mongoid/contextual/aggregable/mongo.rb +0 -1
- data/lib/mongoid/contextual/map_reduce.rb +20 -97
- data/lib/mongoid/contextual/memory.rb +1 -0
- data/lib/mongoid/contextual/mongo.rb +20 -15
- data/lib/mongoid/criteria.rb +2 -0
- data/lib/mongoid/document.rb +1 -0
- data/lib/mongoid/errors.rb +1 -0
- data/lib/mongoid/errors/in_memory_collation_not_supported.rb +20 -0
- data/lib/mongoid/errors/mongoid_error.rb +1 -1
- data/lib/mongoid/extensions.rb +1 -0
- data/lib/mongoid/extensions/decimal128.rb +39 -0
- data/lib/mongoid/fields/localized.rb +8 -3
- data/lib/mongoid/indexable/validators/options.rb +2 -1
- data/lib/mongoid/persistable/deletable.rb +3 -7
- data/lib/mongoid/persistable/settable.rb +3 -1
- data/lib/mongoid/query_cache.rb +24 -2
- data/lib/mongoid/relations/accessors.rb +1 -1
- data/lib/mongoid/relations/builders.rb +2 -2
- data/lib/mongoid/relations/eager.rb +2 -2
- data/lib/mongoid/relations/reflections.rb +5 -3
- data/lib/mongoid/relations/touchable.rb +1 -1
- data/lib/mongoid/scopable.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +6 -2
- data/spec/app/models/band.rb +1 -0
- data/spec/config/mongoid.yml +5 -0
- data/spec/mongoid/clients/factory_spec.rb +8 -0
- data/spec/mongoid/clients_spec.rb +78 -1
- data/spec/mongoid/config_spec.rb +31 -0
- data/spec/mongoid/contextual/atomic_spec.rb +342 -76
- data/spec/mongoid/contextual/map_reduce_spec.rb +111 -119
- data/spec/mongoid/contextual/memory_spec.rb +316 -56
- data/spec/mongoid/contextual/mongo_spec.rb +391 -11
- data/spec/mongoid/criteria_spec.rb +21 -2
- data/spec/mongoid/extensions/decimal128_spec.rb +44 -0
- data/spec/mongoid/extensions/time_spec.rb +2 -2
- data/spec/mongoid/fields/localized_spec.rb +91 -0
- data/spec/mongoid/indexable_spec.rb +44 -0
- data/spec/mongoid/persistable/settable_spec.rb +44 -0
- data/spec/mongoid/query_cache_spec.rb +86 -0
- data/spec/mongoid/relations/cyclic_spec.rb +22 -0
- data/spec/mongoid/relations/referenced/many_spec.rb +11 -0
- data/spec/mongoid/relations/referenced/many_to_many_spec.rb +11 -0
- data/spec/mongoid/relations/reflections_spec.rb +9 -9
- data/spec/mongoid/scopable_spec.rb +12 -0
- data/spec/spec_helper.rb +9 -0
- metadata +26 -16
- metadata.gz.sig +0 -0
data/lib/mongoid/extensions.rb
CHANGED
@@ -30,6 +30,7 @@ require "mongoid/extensions/big_decimal"
|
|
30
30
|
require "mongoid/extensions/boolean"
|
31
31
|
require "mongoid/extensions/date"
|
32
32
|
require "mongoid/extensions/date_time"
|
33
|
+
require "mongoid/extensions/decimal128"
|
33
34
|
require "mongoid/extensions/false_class"
|
34
35
|
require "mongoid/extensions/float"
|
35
36
|
require "mongoid/extensions/hash"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
module Extensions
|
4
|
+
module Decimal128
|
5
|
+
|
6
|
+
# Evolve the decimal128.
|
7
|
+
#
|
8
|
+
# @example Evolve the decimal128.
|
9
|
+
# decimal128.__evolve_decimal128__
|
10
|
+
#
|
11
|
+
# @return [ BSON::Decimal128 ] self.
|
12
|
+
#
|
13
|
+
# @since 5.2.0
|
14
|
+
def __evolve_decimal128__
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
|
20
|
+
# Evolve the object into a mongo-friendly value to query with.
|
21
|
+
#
|
22
|
+
# @example Evolve the object.
|
23
|
+
# Decimal128.evolve(dec)
|
24
|
+
#
|
25
|
+
# @param [ Object ] object The object to evolve.
|
26
|
+
#
|
27
|
+
# @return [ BSON::Decimal128 ] The decimal128.
|
28
|
+
#
|
29
|
+
# @since 5.2.0
|
30
|
+
def evolve(object)
|
31
|
+
object.__evolve_decimal128__
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
BSON::Decimal128.__send__(:include, Mongoid::Extensions::Decimal128)
|
39
|
+
BSON::Decimal128.extend(Mongoid::Extensions::Decimal128::ClassMethods)
|
@@ -77,9 +77,14 @@ module Mongoid
|
|
77
77
|
# @since 3.0.0
|
78
78
|
def lookup(object)
|
79
79
|
locale = ::I18n.locale
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
|
81
|
+
value = if object.key?(locale.to_s)
|
82
|
+
object[locale.to_s]
|
83
|
+
elsif object.key?(locale)
|
84
|
+
object[locale]
|
85
|
+
end
|
86
|
+
return value unless value.nil?
|
87
|
+
if fallbacks? && ::I18n.respond_to?(:fallbacks)
|
83
88
|
object[::I18n.fallbacks[locale].map(&:to_s).find{ |loc| object.has_key?(loc) }]
|
84
89
|
end
|
85
90
|
end
|
@@ -135,13 +135,9 @@ module Mongoid
|
|
135
135
|
# @return [ Integer ] The number of documents deleted.
|
136
136
|
#
|
137
137
|
# @since 1.0.0
|
138
|
-
def delete_all(conditions =
|
139
|
-
selector = conditions
|
140
|
-
|
141
|
-
coll = collection
|
142
|
-
deleted = coll.find(selector).count
|
143
|
-
coll.find(selector).delete_many
|
144
|
-
deleted
|
138
|
+
def delete_all(conditions = {})
|
139
|
+
selector = hereditary? ? conditions.merge(_type: name) : conditions
|
140
|
+
collection.find(selector).delete_many.deleted_count
|
145
141
|
end
|
146
142
|
end
|
147
143
|
end
|
@@ -27,7 +27,9 @@ module Mongoid
|
|
27
27
|
field = field_and_value_hash.keys.first.to_s
|
28
28
|
|
29
29
|
if fields[field] && fields[field].type == Hash && attributes.key?(field)
|
30
|
-
|
30
|
+
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
31
|
+
value = attributes[field].merge(field_and_value_hash[field], &merger)
|
32
|
+
process_attribute(field.to_s, value)
|
31
33
|
else
|
32
34
|
process_attribute(field.to_s, field_and_value_hash[field])
|
33
35
|
end
|
data/lib/mongoid/query_cache.rb
CHANGED
@@ -70,6 +70,20 @@ module Mongoid
|
|
70
70
|
ensure
|
71
71
|
QueryCache.enabled = enabled
|
72
72
|
end
|
73
|
+
|
74
|
+
# Execute the block with the query cache disabled.
|
75
|
+
#
|
76
|
+
# @example Execute without the cache.
|
77
|
+
# QueryCache.uncached { collection.find }
|
78
|
+
#
|
79
|
+
# @return [ Object ] The result of the block.
|
80
|
+
def uncached
|
81
|
+
enabled = QueryCache.enabled?
|
82
|
+
QueryCache.enabled = false
|
83
|
+
yield
|
84
|
+
ensure
|
85
|
+
QueryCache.enabled = enabled
|
86
|
+
end
|
73
87
|
end
|
74
88
|
|
75
89
|
# The middleware to be added to a rack application in order to activate the
|
@@ -222,7 +236,7 @@ module Mongoid
|
|
222
236
|
|
223
237
|
def cached_cursor
|
224
238
|
if limit
|
225
|
-
key = [ collection.namespace, selector, nil, skip, projection ]
|
239
|
+
key = [ collection.namespace, selector, nil, skip, sort, projection, collation ]
|
226
240
|
cursor = QueryCache.cache_table[key]
|
227
241
|
if cursor
|
228
242
|
limited_docs = cursor.to_a[0...limit.abs]
|
@@ -233,7 +247,7 @@ module Mongoid
|
|
233
247
|
end
|
234
248
|
|
235
249
|
def cache_key
|
236
|
-
[ collection.namespace, selector, limit, skip, projection ]
|
250
|
+
[ collection.namespace, selector, limit, skip, sort, projection, collation ]
|
237
251
|
end
|
238
252
|
|
239
253
|
def system_collection?
|
@@ -252,8 +266,16 @@ module Mongoid
|
|
252
266
|
alias_query_cache_clear :insert_one, :insert_many
|
253
267
|
end
|
254
268
|
end
|
269
|
+
|
270
|
+
# Bypass the query cache when reloading a document.
|
271
|
+
module Document
|
272
|
+
def reload
|
273
|
+
QueryCache.uncached { super }
|
274
|
+
end
|
275
|
+
end
|
255
276
|
end
|
256
277
|
end
|
257
278
|
|
258
279
|
Mongo::Collection.__send__(:include, Mongoid::QueryCache::Collection)
|
259
280
|
Mongo::Collection::View.__send__(:include, Mongoid::QueryCache::View)
|
281
|
+
Mongoid::Document.__send__(:include, Mongoid::QueryCache::Document)
|
@@ -64,7 +64,7 @@ module Mongoid
|
|
64
64
|
# @since 2.0.0.rc.1
|
65
65
|
def builder(name, metadata)
|
66
66
|
re_define_method("build_#{name}") do |*args|
|
67
|
-
attributes,
|
67
|
+
attributes, _options = parse_args(*args)
|
68
68
|
document = Factory.build(metadata.klass, attributes)
|
69
69
|
_building do
|
70
70
|
child = send("#{name}=", document)
|
@@ -89,7 +89,7 @@ module Mongoid
|
|
89
89
|
# @since 2.0.0.rc.1
|
90
90
|
def creator(name, metadata)
|
91
91
|
re_define_method("create_#{name}") do |*args|
|
92
|
-
attributes,
|
92
|
+
attributes, _options = parse_args(*args)
|
93
93
|
document = Factory.build(metadata.klass, attributes)
|
94
94
|
doc = _assigning do
|
95
95
|
send("#{name}=", document)
|
@@ -24,7 +24,7 @@ module Mongoid
|
|
24
24
|
# @example Find multiple relation metadata by macro.
|
25
25
|
# person.reflect_on_all_associations(:embeds_many)
|
26
26
|
#
|
27
|
-
# @param [ Array<
|
27
|
+
# @param [ Array<Symbol> ] *macros The relation macros.
|
28
28
|
#
|
29
29
|
# @return [ Array<Metadata> ] The matching relation metadata.
|
30
30
|
def reflect_on_all_associations(*macros)
|
@@ -50,11 +50,13 @@ module Mongoid
|
|
50
50
|
# @example Find multiple relation metadata by macro.
|
51
51
|
# Person.reflect_on_all_associations(:embeds_many)
|
52
52
|
#
|
53
|
-
# @param [ Array<
|
53
|
+
# @param [ Array<Symbol> ] *macros The relation macros.
|
54
54
|
#
|
55
55
|
# @return [ Array<Metadata> ] The matching relation metadata.
|
56
56
|
def reflect_on_all_associations(*macros)
|
57
|
-
relations.values
|
57
|
+
association_reflections = relations.values
|
58
|
+
association_reflections.select! { |reflection| macros.include?(reflection.macro) } unless macros.empty?
|
59
|
+
association_reflections
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
@@ -78,7 +78,7 @@ module Mongoid
|
|
78
78
|
# @return [ Symbol ] The method name.
|
79
79
|
def define_relation_touch_method(name)
|
80
80
|
method_name = "touch_#{name}_after_create_or_destroy"
|
81
|
-
class_eval <<-TOUCH
|
81
|
+
class_eval <<-TOUCH, __FILE__, __LINE__ + 1
|
82
82
|
def #{method_name}
|
83
83
|
without_autobuild do
|
84
84
|
relation = __send__(:#{name})
|
data/lib/mongoid/scopable.rb
CHANGED
@@ -117,7 +117,7 @@ module Mongoid
|
|
117
117
|
# @since 3.0.0
|
118
118
|
def queryable
|
119
119
|
crit = Threaded.current_scope(self) || Criteria.new(self)
|
120
|
-
crit.embedded = true if crit.klass.embedded?
|
120
|
+
crit.embedded = true if (crit.klass.embedded? && !crit.klass.cyclic?)
|
121
121
|
crit
|
122
122
|
end
|
123
123
|
|
data/lib/mongoid/version.rb
CHANGED
@@ -50,8 +50,8 @@ development:
|
|
50
50
|
# via ismaster commands. (default: 10)
|
51
51
|
# heartbeat_frequency: 10
|
52
52
|
|
53
|
-
# The time in seconds for selecting servers for a near read preference. (default:
|
54
|
-
# local_threshold:
|
53
|
+
# The time in seconds for selecting servers for a near read preference. (default: 0.015)
|
54
|
+
# local_threshold: 0.015
|
55
55
|
|
56
56
|
# The timeout in seconds for selecting a server for an operation. (default: 30)
|
57
57
|
# server_selection_timeout: 30
|
@@ -130,6 +130,10 @@ development:
|
|
130
130
|
# environment. The Mongoid logger will be set to the Rails logger
|
131
131
|
# otherwise.(default: :info)
|
132
132
|
# log_level: :info
|
133
|
+
|
134
|
+
# Application name that is printed to the mongodb logs upon establishing a
|
135
|
+
# connection in server versions >= 3.4. Note that the name cannot exceed 128 bytes.
|
136
|
+
# app_name: MyApplicationName
|
133
137
|
test:
|
134
138
|
clients:
|
135
139
|
default:
|
data/spec/app/models/band.rb
CHANGED
@@ -13,6 +13,7 @@ class Band
|
|
13
13
|
field :upserted, type: Mongoid::Boolean, default: false
|
14
14
|
field :created, type: DateTime
|
15
15
|
field :sales, type: BigDecimal
|
16
|
+
field :decimal, type: BSON::Decimal128
|
16
17
|
field :y, as: :years, type: Integer
|
17
18
|
field :founded, type: Date
|
18
19
|
field :deleted, type: Boolean
|
data/spec/config/mongoid.yml
CHANGED
@@ -13,6 +13,10 @@ test:
|
|
13
13
|
tag_sets:
|
14
14
|
- use: web
|
15
15
|
max_pool_size: 1
|
16
|
+
reports:
|
17
|
+
database: reports
|
18
|
+
hosts:
|
19
|
+
- <%=ENV["MONGOID_SPEC_HOST"]%>:<%=ENV["MONGOID_SPEC_PORT"]%>
|
16
20
|
options:
|
17
21
|
include_root_in_json: false
|
18
22
|
include_type_for_serialization: false
|
@@ -22,3 +26,4 @@ test:
|
|
22
26
|
use_activesupport_time_zone: true
|
23
27
|
use_utc: false
|
24
28
|
log_level: :warn
|
29
|
+
app_name: 'testing'
|
@@ -36,6 +36,10 @@ describe Mongoid::Clients::Factory do
|
|
36
36
|
it "sets the cluster's seeds" do
|
37
37
|
expect(cluster.addresses.first.to_s).to eq("127.0.0.1:27017")
|
38
38
|
end
|
39
|
+
|
40
|
+
it "sets the platform to Mongoid's platform constant" do
|
41
|
+
expect(client.options[:platform]).to eq(Mongoid::PLATFORM_DETAILS)
|
42
|
+
end
|
39
43
|
end
|
40
44
|
|
41
45
|
context "when the configuration has no ports" do
|
@@ -280,5 +284,9 @@ describe Mongoid::Clients::Factory do
|
|
280
284
|
it "sets the write concern" do
|
281
285
|
expect(client.write_concern).to be_a(Mongo::WriteConcern::Acknowledged)
|
282
286
|
end
|
287
|
+
|
288
|
+
it "sets the platform to Mongoid's platform constant" do
|
289
|
+
expect(client.options[:platform]).to eq(Mongoid::PLATFORM_DETAILS)
|
290
|
+
end
|
283
291
|
end
|
284
292
|
end
|
@@ -408,6 +408,14 @@ describe Mongoid::Clients do
|
|
408
408
|
it "returns the default client" do
|
409
409
|
expect(mongo_client.options[:database].to_s).to eq(database_id)
|
410
410
|
end
|
411
|
+
|
412
|
+
it "sets the platform to Mongoid's platform constant" do
|
413
|
+
expect(mongo_client.options[:platform]).to eq(Mongoid::PLATFORM_DETAILS)
|
414
|
+
end
|
415
|
+
|
416
|
+
it "sets the app_name to the config value" do
|
417
|
+
expect(mongo_client.options[:app_name]).to eq('testing')
|
418
|
+
end
|
411
419
|
end
|
412
420
|
|
413
421
|
context "when no client exists with the key" do
|
@@ -416,6 +424,10 @@ describe Mongoid::Clients do
|
|
416
424
|
Band.store_in(client: :nonexistent)
|
417
425
|
end
|
418
426
|
|
427
|
+
after do
|
428
|
+
Band.reset_storage_options!
|
429
|
+
end
|
430
|
+
|
419
431
|
let(:band) do
|
420
432
|
Band.new
|
421
433
|
end
|
@@ -426,6 +438,63 @@ describe Mongoid::Clients do
|
|
426
438
|
}.to raise_error(Mongoid::Errors::NoClientConfig)
|
427
439
|
end
|
428
440
|
end
|
441
|
+
|
442
|
+
context "when getting a client by name", if: testing_locally? do
|
443
|
+
|
444
|
+
let(:file) do
|
445
|
+
File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml")
|
446
|
+
end
|
447
|
+
|
448
|
+
before do
|
449
|
+
described_class.clear
|
450
|
+
Mongoid.load!(file, :test)
|
451
|
+
Band.store_in(client: :reports)
|
452
|
+
end
|
453
|
+
|
454
|
+
after do
|
455
|
+
mongo_client.close
|
456
|
+
Mongoid::Config.reset
|
457
|
+
Band.reset_storage_options!
|
458
|
+
end
|
459
|
+
|
460
|
+
let!(:band) do
|
461
|
+
Band.store_in(client: :reports)
|
462
|
+
end
|
463
|
+
|
464
|
+
let!(:mongo_client) do
|
465
|
+
Band.new.mongo_client
|
466
|
+
end
|
467
|
+
|
468
|
+
it "uses the reports client" do
|
469
|
+
expect(mongo_client.options[:database].to_s).to eq('reports')
|
470
|
+
end
|
471
|
+
|
472
|
+
it "sets the platform to Mongoid's platform constant" do
|
473
|
+
expect(mongo_client.options[:platform]).to eq(Mongoid::PLATFORM_DETAILS)
|
474
|
+
end
|
475
|
+
|
476
|
+
it "sets the app_name to the config value" do
|
477
|
+
expect(mongo_client.options[:app_name]).to eq('testing')
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
context 'when the app_name is not set in the config' do
|
482
|
+
|
483
|
+
before do
|
484
|
+
Mongoid::Config.reset
|
485
|
+
Mongoid.configure do |config|
|
486
|
+
config.load_configuration(CONFIG)
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
let(:mongo_client) do
|
491
|
+
Band.new.mongo_client
|
492
|
+
end
|
493
|
+
|
494
|
+
it 'does not set the Mongoid.app_name option' do
|
495
|
+
expect(mongo_client.options.has_key?(:app_name)).to be(false)
|
496
|
+
end
|
497
|
+
end
|
429
498
|
end
|
430
499
|
|
431
500
|
describe ".mongo_client", if: non_legacy_server? do
|
@@ -457,13 +526,21 @@ describe Mongoid::Clients do
|
|
457
526
|
Mongoid.clients[:default][:database] = database_id
|
458
527
|
end
|
459
528
|
|
460
|
-
let
|
529
|
+
let(:mongo_client) do
|
461
530
|
Band.mongo_client
|
462
531
|
end
|
463
532
|
|
464
533
|
it "returns the default client" do
|
465
534
|
expect(mongo_client.options[:database].to_s).to eq(database_id)
|
466
535
|
end
|
536
|
+
|
537
|
+
it "sets the platform to Mongoid's platform constant" do
|
538
|
+
expect(mongo_client.options[:platform]).to eq(Mongoid::PLATFORM_DETAILS)
|
539
|
+
end
|
540
|
+
|
541
|
+
it "sets the app_name to the config value" do
|
542
|
+
expect(mongo_client.options[:app_name]).to eq('testing')
|
543
|
+
end
|
467
544
|
end
|
468
545
|
|
469
546
|
context "when no client exists with the key" do
|
data/spec/mongoid/config_spec.rb
CHANGED
@@ -82,6 +82,37 @@ describe Mongoid::Config do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
+
context 'when the app_name is set in the config' do
|
86
|
+
|
87
|
+
let(:conf) do
|
88
|
+
CONFIG.merge(options: {app_name: 'admin-reporting'})
|
89
|
+
end
|
90
|
+
|
91
|
+
before do
|
92
|
+
Mongoid.configure do |config|
|
93
|
+
config.load_configuration(conf)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'sets the Mongoid.app_name to the provided value' do
|
98
|
+
expect(Mongoid.app_name).to eq('admin-reporting')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when the app_name is not set in the config' do
|
103
|
+
|
104
|
+
before do
|
105
|
+
Mongoid::Config.reset
|
106
|
+
Mongoid.configure do |config|
|
107
|
+
config.load_configuration(CONFIG)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'does not set the Mongoid.app_name option' do
|
112
|
+
expect(Mongoid.app_name).to be_nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
85
116
|
describe "#load!" do
|
86
117
|
|
87
118
|
before(:all) do
|