mongoid 7.0.2 → 7.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/mongoid/association/referenced/eager.rb +4 -1
  4. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +3 -1
  5. data/lib/mongoid/association/referenced/has_many/proxy.rb +2 -2
  6. data/lib/mongoid/association/relatable.rb +90 -10
  7. data/lib/mongoid/clients/options.rb +6 -4
  8. data/lib/mongoid/copyable.rb +2 -2
  9. data/lib/mongoid/criteria/options.rb +2 -2
  10. data/lib/mongoid/criteria/queryable/selectable.rb +33 -6
  11. data/lib/mongoid/document.rb +11 -4
  12. data/lib/mongoid/extensions/big_decimal.rb +1 -1
  13. data/lib/mongoid/extensions/regexp.rb +1 -0
  14. data/lib/mongoid/matchable.rb +3 -1
  15. data/lib/mongoid/matchable/eq.rb +22 -0
  16. data/lib/mongoid/matchable/ne.rb +1 -1
  17. data/lib/mongoid/persistence_context.rb +20 -5
  18. data/lib/mongoid/query_cache.rb +8 -4
  19. data/lib/mongoid/railtie.rb +17 -0
  20. data/lib/mongoid/railties/controller_runtime.rb +86 -0
  21. data/lib/mongoid/scopable.rb +3 -3
  22. data/lib/mongoid/threaded.rb +36 -0
  23. data/lib/mongoid/version.rb +1 -1
  24. data/spec/app/models/minim.rb +7 -0
  25. data/spec/app/models/store_as_dup_test3.rb +7 -0
  26. data/spec/app/models/store_as_dup_test4.rb +7 -0
  27. data/spec/config/mongoid.yml +12 -3
  28. data/spec/integration/associations/belongs_to_spec.rb +13 -0
  29. data/spec/lite_spec_helper.rb +56 -0
  30. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +24 -5
  31. data/spec/mongoid/association/referenced/belongs_to_spec.rb +46 -3
  32. data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +21 -2
  33. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +56 -0
  34. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +26 -0
  35. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +3 -3
  36. data/spec/mongoid/association/referenced/has_many/proxy_query_spec.rb +23 -0
  37. data/spec/mongoid/association/referenced/has_many_models.rb +37 -0
  38. data/spec/mongoid/association/referenced/has_many_spec.rb +3 -3
  39. data/spec/mongoid/association/referenced/has_one_models.rb +48 -0
  40. data/spec/mongoid/association/referenced/has_one_spec.rb +51 -4
  41. data/spec/mongoid/clients/factory_spec.rb +24 -18
  42. data/spec/mongoid/clients/options_spec.rb +40 -37
  43. data/spec/mongoid/clients_spec.rb +68 -8
  44. data/spec/mongoid/config_spec.rb +3 -1
  45. data/spec/mongoid/contextual/mongo_spec.rb +5 -2
  46. data/spec/mongoid/copyable_spec.rb +40 -6
  47. data/spec/mongoid/copyable_spec_models.rb +17 -0
  48. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +3 -3
  49. data/spec/mongoid/criteria/queryable/selectable_spec.rb +42 -3
  50. data/spec/mongoid/criteria/queryable/selector_spec.rb +2 -2
  51. data/spec/mongoid/criteria/scopable_spec.rb +81 -0
  52. data/spec/mongoid/criteria_spec.rb +18 -3
  53. data/spec/mongoid/document_spec.rb +81 -2
  54. data/spec/mongoid/extensions/big_decimal_spec.rb +9 -9
  55. data/spec/mongoid/extensions/regexp_spec.rb +23 -0
  56. data/spec/mongoid/fields_spec.rb +1 -1
  57. data/spec/mongoid/findable_spec.rb +1 -1
  58. data/spec/mongoid/matchable/eq_spec.rb +48 -0
  59. data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
  60. data/spec/mongoid/persistence_context_spec.rb +1 -1
  61. data/spec/mongoid/query_cache_spec.rb +59 -6
  62. data/spec/mongoid/scopable_spec.rb +13 -0
  63. data/spec/mongoid/threaded_spec.rb +68 -0
  64. data/spec/rails/controller_extension/controller_runtime_spec.rb +110 -0
  65. data/spec/spec_helper.rb +35 -25
  66. data/spec/support/constraints.rb +101 -0
  67. data/spec/support/macros.rb +20 -0
  68. data/spec/support/spec_config.rb +39 -0
  69. metadata +471 -460
  70. checksums.yaml.gz.sig +0 -0
  71. data.tar.gz.sig +0 -2
  72. metadata.gz.sig +0 -0
@@ -10,7 +10,7 @@ describe Mongoid::Findable do
10
10
  end
11
11
 
12
12
  it "returns the distinct values for the field" do
13
- expect(Band.distinct(:name)).to eq([ "Tool", "Photek" ])
13
+ expect(Band.distinct(:name).sort).to eq([ "Photek", "Tool" ])
14
14
  end
15
15
  end
16
16
 
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Mongoid::Matchable::Eq do
6
+
7
+ let(:matcher) do
8
+ described_class.new("first")
9
+ end
10
+
11
+ describe "#_matches?" do
12
+
13
+ context "when the values are equal" do
14
+
15
+ it "returns true" do
16
+ expect(matcher._matches?("$eq" => "first")).to be true
17
+ end
18
+ end
19
+
20
+ context "when the values are not equal" do
21
+
22
+ it "returns false" do
23
+ expect(matcher._matches?("$eq" => "second")).to be false
24
+ end
25
+ end
26
+
27
+ context "when the value is an array" do
28
+
29
+ let(:array_matcher) do
30
+ described_class.new([ "first" ])
31
+ end
32
+
33
+ context "when the value is in the array" do
34
+
35
+ it "returns true" do
36
+ expect(array_matcher._matches?("$eq" => "first")).to be true
37
+ end
38
+ end
39
+
40
+ context "when the value is not in the array" do
41
+
42
+ it "returns false" do
43
+ expect(array_matcher._matches?("$eq" => "second")).to be false
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -66,15 +66,15 @@ describe Mongoid::Persistable::Incrementable do
66
66
  context "when providing big decimal values" do
67
67
 
68
68
  let(:five) do
69
- BigDecimal.new("5.0")
69
+ BigDecimal("5.0")
70
70
  end
71
71
 
72
72
  let(:neg_ten) do
73
- BigDecimal.new("-10.0")
73
+ BigDecimal("-10.0")
74
74
  end
75
75
 
76
76
  let(:thirty) do
77
- BigDecimal.new("30.0")
77
+ BigDecimal("30.0")
78
78
  end
79
79
 
80
80
  let!(:inc) do
@@ -151,15 +151,15 @@ describe Mongoid::Persistable::Incrementable do
151
151
  context "when providing big decimal values" do
152
152
 
153
153
  let(:five) do
154
- BigDecimal.new("5.0")
154
+ BigDecimal("5.0")
155
155
  end
156
156
 
157
157
  let(:neg_ten) do
158
- BigDecimal.new("-10.0")
158
+ BigDecimal("-10.0")
159
159
  end
160
160
 
161
161
  let(:thirty) do
162
- BigDecimal.new("30.0")
162
+ BigDecimal("30.0")
163
163
  end
164
164
 
165
165
  let!(:inc) do
@@ -536,7 +536,7 @@ describe Mongoid::PersistenceContext do
536
536
  end
537
537
 
538
538
  before do
539
- Mongoid.clients[:alternative] = { database: :mongoid_test, hosts: [ "#{HOST}:#{PORT}" ] }
539
+ Mongoid.clients[:alternative] = { database: :mongoid_test, hosts: SpecConfig.instance.addresses }
540
540
  end
541
541
 
542
542
  after do
@@ -123,6 +123,36 @@ describe Mongoid::QueryCache do
123
123
  end
124
124
  end
125
125
 
126
+ context 'querying all documents after a single document' do
127
+ before do
128
+ 3.times do
129
+ Person.create
130
+ end
131
+ end
132
+
133
+ it 'returns all documents' do
134
+ expect(Person.all.to_a.count).to eq(3)
135
+ Person.first
136
+ expect(Person.all.to_a.count).to eq(3)
137
+ end
138
+
139
+ context 'with conditions specified' do
140
+ it 'returns all documents' do
141
+ expect(Person.gt(age: 0).to_a.count).to eq(3)
142
+ Person.gt(age: 0).first
143
+ expect(Person.gt(age: 0).to_a.count).to eq(3)
144
+ end
145
+ end
146
+
147
+ context 'with order specified' do
148
+ it 'returns all documents' do
149
+ expect(Person.order_by(name: 1).to_a.count).to eq(3)
150
+ Person.order_by(name: 1).first
151
+ expect(Person.order_by(name: 1).to_a.count).to eq(3)
152
+ end
153
+ end
154
+ end
155
+
126
156
  context "when querying in the same collection" do
127
157
 
128
158
  before do
@@ -411,18 +441,18 @@ describe Mongoid::QueryCache do
411
441
  end
412
442
  end
413
443
 
414
- context "when querying a very large collection" do
444
+ context "when querying collection smaller than the batch size" do
415
445
 
416
446
  before do
417
- 123.times { Band.create! }
447
+ 99.times { Band.create! }
418
448
  end
419
449
 
420
450
  it "returns the right number of records" do
421
- expect(Band.all.to_a.length).to eq(123)
451
+ expect(Band.all.to_a.length).to eq(99)
422
452
  end
423
453
 
424
454
  it "#pluck returns the same count of objects" do
425
- expect(Band.pluck(:name).length).to eq(123)
455
+ expect(Band.pluck(:name).length).to eq(99)
426
456
  end
427
457
 
428
458
  context "when loading all the documents" do
@@ -433,12 +463,12 @@ describe Mongoid::QueryCache do
433
463
 
434
464
  it "caches the complete result of the query" do
435
465
  expect_no_queries do
436
- expect(Band.all.to_a.length).to eq(123)
466
+ expect(Band.all.to_a.length).to eq(99)
437
467
  end
438
468
  end
439
469
 
440
470
  it "returns the same count of objects when using #pluck" do
441
- expect(Band.pluck(:name).length).to eq(123)
471
+ expect(Band.pluck(:name).length).to eq(99)
442
472
  end
443
473
  end
444
474
  end
@@ -450,6 +480,29 @@ describe Mongoid::QueryCache do
450
480
  Band.collection.indexes.create_one(name: 1)
451
481
  end
452
482
  end
483
+
484
+ context 'when the initial query does not exhaust the results' do
485
+ before do
486
+ Mongoid::QueryCache.enabled = true
487
+ 10.times { Band.create! }
488
+
489
+ Band.batch_size(4).all.any?
490
+ end
491
+
492
+ it 'does not cache the result' do
493
+ expect(Band.all.map(&:id).size).to eq(10)
494
+ end
495
+
496
+ context 'when a batch size smaller than the result set is specified' do
497
+ let(:batch_size) do
498
+ 4
499
+ end
500
+
501
+ it 'does not cache the result' do
502
+ expect(Band.batch_size(batch_size).all.map(&:id).size).to eq(10)
503
+ end
504
+ end
505
+ end
453
506
  end
454
507
 
455
508
  describe Mongoid::QueryCache::Middleware do
@@ -1130,6 +1130,19 @@ describe Mongoid::Scopable do
1130
1130
  it "sets the threading options" do
1131
1131
  Band.without_default_scope do
1132
1132
  expect(Mongoid::Threaded).to be_executing(:without_default_scope)
1133
+ expect(Mongoid::Threaded.without_default_scope?(Band)).to be(true)
1134
+ end
1135
+ end
1136
+
1137
+ it "suppresses default scope on the given model within the given block" do
1138
+ Appointment.without_default_scope do
1139
+ expect(Appointment.all.selector).to be_empty
1140
+ end
1141
+ end
1142
+
1143
+ it "does not affect other models' default scopes within the given block" do
1144
+ Appointment.without_default_scope do
1145
+ expect(Audio.all.selector).not_to be_empty
1133
1146
  end
1134
1147
  end
1135
1148
  end
@@ -233,4 +233,72 @@ describe Mongoid::Threaded do
233
233
  end
234
234
  end
235
235
  end
236
+
237
+ describe "#begin_without_default_scope" do
238
+
239
+ let(:klass) do
240
+ Appointment
241
+ end
242
+
243
+ after do
244
+ described_class.exit_without_default_scope(klass)
245
+ end
246
+
247
+ it "adds the given class to the without_default_scope stack" do
248
+ described_class.begin_without_default_scope(klass)
249
+
250
+ expect(described_class.stack(:without_default_scope)).to include(klass)
251
+ end
252
+ end
253
+
254
+ describe "#exit_without_default_scope" do
255
+
256
+ let(:klass) do
257
+ Appointment
258
+ end
259
+
260
+ before do
261
+ described_class.begin_without_default_scope(klass)
262
+ end
263
+
264
+ it "removes the given class from the without_default_scope stack" do
265
+ described_class.exit_without_default_scope(klass)
266
+
267
+ expect(described_class.stack(:without_default_scope)).not_to include(klass)
268
+ end
269
+ end
270
+
271
+ describe "#without_default_scope?" do
272
+
273
+ let(:klass) do
274
+ Appointment
275
+ end
276
+
277
+ context "when klass has begun without_default_scope" do
278
+
279
+ before do
280
+ described_class.begin_without_default_scope(klass)
281
+ end
282
+
283
+ after do
284
+ described_class.exit_without_default_scope(klass)
285
+ end
286
+
287
+ it "returns true" do
288
+ expect(described_class.without_default_scope?(klass)).to be(true)
289
+ end
290
+ end
291
+
292
+ context "when klass has exited without_default_scope" do
293
+
294
+ before do
295
+ described_class.begin_without_default_scope(klass)
296
+ described_class.exit_without_default_scope(klass)
297
+ end
298
+
299
+ it "returns false" do
300
+ expect(described_class.without_default_scope?(klass)).to be(false)
301
+ end
302
+ end
303
+ end
236
304
  end
@@ -0,0 +1,110 @@
1
+ require "spec_helper"
2
+ require "mongoid/railties/controller_runtime"
3
+
4
+ describe "Mongoid::Railties::ControllerRuntime" do
5
+ controller_runtime = Mongoid::Railties::ControllerRuntime
6
+ collector = controller_runtime::Collector
7
+
8
+ def set_metric value
9
+ Thread.current["Mongoid.controller_runtime"] = value
10
+ end
11
+
12
+ def clear_metric!
13
+ set_metric 0
14
+ end
15
+
16
+ describe "Collector" do
17
+
18
+ it "stores the metric in thread-safe manner" do
19
+ clear_metric!
20
+ expect(collector.runtime).to eq(0)
21
+ set_metric 42
22
+ expect(collector.runtime).to eq(42)
23
+ end
24
+
25
+ it "sets metric on both succeeded and failed" do
26
+ instance = collector.new
27
+ event_payload = OpenStruct.new duration: 42
28
+
29
+ clear_metric!
30
+ instance.succeeded event_payload
31
+ expect(collector.runtime).to eq(42)
32
+
33
+ clear_metric!
34
+ instance.failed event_payload
35
+ expect(collector.runtime).to eq(42)
36
+ end
37
+
38
+ it "resets the metric and returns the value" do
39
+ clear_metric!
40
+ expect(collector.reset_runtime).to eq(0)
41
+ set_metric 42
42
+ expect(collector.reset_runtime).to eq(42)
43
+ expect(collector.runtime).to eq(0)
44
+ end
45
+
46
+ end
47
+
48
+ reference_controller_class = Class.new do
49
+ def process_action *_
50
+ @process_action = true
51
+ end
52
+
53
+ def cleanup_view_runtime *_
54
+ @cleanup_view_runtime.call
55
+ end
56
+
57
+ def append_info_to_payload *_
58
+ @append_info_to_payload = true
59
+ end
60
+
61
+ def self.log_process_action *_
62
+ @log_process_action.call
63
+ end
64
+ end
65
+
66
+ controller_class = Class.new reference_controller_class do
67
+ include controller_runtime::ControllerExtension
68
+ end
69
+
70
+ let(:controller){ controller_class.new }
71
+
72
+ it "resets the metric before each action" do
73
+ set_metric 42
74
+ controller.send(:process_action, 'foo')
75
+ expect(collector.runtime).to be(0)
76
+ expect(controller.instance_variable_get "@process_action").to be(true)
77
+ end
78
+
79
+ it "strips the metric of other sources of the runtime" do
80
+ set_metric 1
81
+ controller.instance_variable_set "@cleanup_view_runtime", ->{
82
+ controller.instance_variable_set "@cleanup_view_runtime", true
83
+ set_metric 13
84
+ 42
85
+ }
86
+ returned = controller.send :cleanup_view_runtime
87
+ expect(controller.instance_variable_get "@cleanup_view_runtime").to be(true)
88
+ expect(controller.mongoid_runtime).to eq(14)
89
+ expect(returned).to be(29)
90
+ end
91
+
92
+ it "appends the metric to payload" do
93
+ payload = {}
94
+ set_metric 42
95
+ controller.send :append_info_to_payload, payload
96
+ expect(controller.instance_variable_get "@append_info_to_payload").to be(true)
97
+ expect(payload[:mongoid_runtime]).to eq(42)
98
+ end
99
+
100
+ it "adds metric to log message" do
101
+ controller_class.instance_variable_set "@log_process_action", ->{
102
+ controller_class.instance_variable_set "@log_process_action", true
103
+ []
104
+ }
105
+ messages = controller_class.log_process_action mongoid_runtime: 42.101
106
+ expect(controller_class.instance_variable_get "@log_process_action").to be(true)
107
+ expect(messages).to eq(["MongoDB: 42.1ms"])
108
+ end
109
+
110
+ end
@@ -1,24 +1,20 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
1
+ # frozen_string_literal: true
2
+
3
+ require 'lite_spec_helper'
3
4
 
4
5
  MODELS = File.join(File.dirname(__FILE__), "app/models")
5
6
  $LOAD_PATH.unshift(MODELS)
6
7
 
7
8
  require "action_controller"
8
- require "mongoid"
9
- require "rspec"
10
-
11
- # These environment variables can be set if wanting to test against a database
12
- # that is not on the local machine.
13
- ENV["MONGOID_SPEC_HOST"] ||= "127.0.0.1"
14
- ENV["MONGOID_SPEC_PORT"] ||= "27017"
15
-
16
- # These are used when creating any connection in the test suite.
17
- HOST = ENV["MONGOID_SPEC_HOST"]
18
- PORT = ENV["MONGOID_SPEC_PORT"].to_i
9
+ require 'rspec/retry'
19
10
 
20
- Mongo::Logger.logger.level = Logger::INFO
21
- # Mongoid.logger.level = Logger::DEBUG
11
+ if SpecConfig.instance.client_debug?
12
+ Mongoid.logger.level = Logger::DEBUG
13
+ Mongo::Logger.logger.level = Logger::DEBUG
14
+ else
15
+ Mongoid.logger.level = Logger::INFO
16
+ Mongo::Logger.logger.level = Logger::INFO
17
+ end
22
18
 
23
19
  # When testing locally we use the database named mongoid_test. However when
24
20
  # tests are running in parallel on Travis we need to use different database
@@ -34,11 +30,13 @@ end
34
30
 
35
31
  require 'support/authorization'
36
32
  require 'support/expectations'
33
+ require 'support/macros'
34
+ require 'support/constraints'
37
35
 
38
36
  # Give MongoDB time to start up on the travis ci environment.
39
37
  if (ENV['CI'] == 'travis' || ENV['CI'] == 'evergreen')
40
38
  starting = true
41
- client = Mongo::Client.new(['127.0.0.1:27017'])
39
+ client = Mongo::Client.new(SpecConfig.instance.addresses)
42
40
  while starting
43
41
  begin
44
42
  client.command(Mongo::Server::Monitor::Connection::ISMASTER)
@@ -54,10 +52,10 @@ CONFIG = {
54
52
  clients: {
55
53
  default: {
56
54
  database: database_id,
57
- hosts: [ "#{HOST}:#{PORT}" ],
55
+ hosts: SpecConfig.instance.addresses,
58
56
  options: {
59
- server_selection_timeout: 0.5,
60
- wait_queue_timeout: 5,
57
+ server_selection_timeout: 3.42,
58
+ wait_queue_timeout: 1,
61
59
  max_pool_size: 5,
62
60
  heartbeat_frequency: 180,
63
61
  user: MONGOID_ROOT_USER.name,
@@ -67,7 +65,12 @@ CONFIG = {
67
65
  }
68
66
  },
69
67
  options: {
70
- belongs_to_required_by_default: false
68
+ belongs_to_required_by_default: false,
69
+ log_level: if SpecConfig.instance.client_debug?
70
+ :debug
71
+ else
72
+ :info
73
+ end,
71
74
  }
72
75
  }
73
76
 
@@ -89,6 +92,12 @@ def array_filters_supported?
89
92
  end
90
93
  alias :sessions_supported? :array_filters_supported?
91
94
 
95
+ def testing_geo_near?
96
+ $geo_near_enabled ||= (Mongoid::Clients.default
97
+ .command(serverStatus: 1)
98
+ .first['version'] < '4.1')
99
+ end
100
+
92
101
  def transactions_supported?
93
102
  Mongoid::Clients.default.cluster.next_primary.features.transactions_enabled?
94
103
  end
@@ -138,9 +147,11 @@ I18n.config.enforce_available_locales = false
138
147
  RSpec.configure do |config|
139
148
  config.raise_errors_for_deprecations!
140
149
  config.include(Mongoid::Expectations)
150
+ config.extend(Constraints)
151
+ config.extend(Mongoid::Macros)
141
152
 
142
153
  config.before(:suite) do
143
- client = Mongo::Client.new(["#{HOST}:#{PORT}"])
154
+ client = Mongo::Client.new(SpecConfig.instance.addresses, server_selection_timeout: 3.03)
144
155
  begin
145
156
  # Create the root user administrator as the first user to be added to the
146
157
  # database. This user will need to be authenticated in order to add any
@@ -153,14 +164,13 @@ RSpec.configure do |config|
153
164
 
154
165
  # Drop all collections and clear the identity map before each spec.
155
166
  config.before(:each) do
167
+ unless Mongoid.default_client.cluster.connected?
168
+ Mongoid.default_client.reconnect
169
+ end
156
170
  Mongoid.default_client.collections.each do |coll|
157
171
  coll.delete_many
158
172
  end
159
173
  end
160
-
161
- config.after(:suite) do
162
- Mongoid.purge!
163
- end
164
174
  end
165
175
 
166
176
  # A subscriber to be used with the Ruby driver for testing.