mongoid 6.4.0 → 6.4.7

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +26 -0
  5. data/lib/mongoid.rb +1 -1
  6. data/lib/mongoid/clients/sessions.rb +2 -2
  7. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  8. data/lib/mongoid/contextual/map_reduce.rb +4 -4
  9. data/lib/mongoid/contextual/memory.rb +4 -4
  10. data/lib/mongoid/contextual/mongo.rb +3 -3
  11. data/lib/mongoid/criteria/modifiable.rb +12 -2
  12. data/lib/mongoid/criteria/queryable/selectable.rb +34 -7
  13. data/lib/mongoid/document.rb +4 -4
  14. data/lib/mongoid/extensions/big_decimal.rb +1 -1
  15. data/lib/mongoid/extensions/regexp.rb +1 -0
  16. data/lib/mongoid/extensions/string.rb +3 -1
  17. data/lib/mongoid/indexable.rb +4 -4
  18. data/lib/mongoid/matchable.rb +3 -0
  19. data/lib/mongoid/matchable/nor.rb +37 -0
  20. data/lib/mongoid/persistable.rb +1 -1
  21. data/lib/mongoid/persistable/creatable.rb +2 -2
  22. data/lib/mongoid/persistable/deletable.rb +2 -2
  23. data/lib/mongoid/persistable/settable.rb +5 -5
  24. data/lib/mongoid/persistable/updatable.rb +2 -2
  25. data/lib/mongoid/persistable/upsertable.rb +1 -1
  26. data/lib/mongoid/persistence_context.rb +4 -0
  27. data/lib/mongoid/query_cache.rb +21 -10
  28. data/lib/mongoid/railtie.rb +17 -0
  29. data/lib/mongoid/railties/controller_runtime.rb +86 -0
  30. data/lib/mongoid/relations/embedded/batchable.rb +4 -4
  31. data/lib/mongoid/relations/embedded/many.rb +23 -0
  32. data/lib/mongoid/relations/many.rb +2 -2
  33. data/lib/mongoid/relations/referenced/many.rb +1 -1
  34. data/lib/mongoid/relations/touchable.rb +1 -1
  35. data/lib/mongoid/reloadable.rb +1 -1
  36. data/lib/mongoid/scopable.rb +3 -3
  37. data/lib/mongoid/tasks/database.rb +2 -2
  38. data/lib/mongoid/threaded.rb +36 -0
  39. data/lib/mongoid/version.rb +1 -1
  40. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -0
  41. data/spec/app/models/array_field.rb +7 -0
  42. data/spec/app/models/delegating_patient.rb +16 -0
  43. data/spec/integration/document_spec.rb +22 -0
  44. data/spec/mongoid/clients/factory_spec.rb +52 -28
  45. data/spec/mongoid/clients/options_spec.rb +30 -15
  46. data/spec/mongoid/clients/sessions_spec.rb +12 -3
  47. data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
  48. data/spec/mongoid/contextual/mongo_spec.rb +2 -2
  49. data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
  50. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +3 -3
  51. data/spec/mongoid/criteria/queryable/selectable_spec.rb +42 -3
  52. data/spec/mongoid/criteria/queryable/selector_spec.rb +2 -2
  53. data/spec/mongoid/criteria/scopable_spec.rb +81 -0
  54. data/spec/mongoid/criteria_spec.rb +4 -1
  55. data/spec/mongoid/document_spec.rb +54 -0
  56. data/spec/mongoid/extensions/big_decimal_spec.rb +9 -9
  57. data/spec/mongoid/extensions/regexp_spec.rb +23 -0
  58. data/spec/mongoid/extensions/string_spec.rb +35 -7
  59. data/spec/mongoid/fields_spec.rb +1 -1
  60. data/spec/mongoid/findable_spec.rb +1 -1
  61. data/spec/mongoid/matchable/nor_spec.rb +209 -0
  62. data/spec/mongoid/matchable_spec.rb +26 -1
  63. data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
  64. data/spec/mongoid/persistable/settable_spec.rb +35 -1
  65. data/spec/mongoid/query_cache_spec.rb +73 -18
  66. data/spec/mongoid/relations/embedded/many_spec.rb +246 -16
  67. data/spec/mongoid/scopable_spec.rb +13 -0
  68. data/spec/mongoid/threaded_spec.rb +68 -0
  69. data/spec/rails/controller_extension/controller_runtime_spec.rb +110 -0
  70. data/spec/spec_helper.rb +9 -0
  71. data/spec/support/cluster_config.rb +158 -0
  72. data/spec/support/constraints.rb +101 -0
  73. data/spec/support/macros.rb +20 -0
  74. data/spec/support/spec_config.rb +42 -0
  75. metadata +41 -23
  76. metadata.gz.sig +0 -0
@@ -2583,6 +2583,25 @@ describe Mongoid::Relations::Embedded::Many do
2583
2583
  person.addresses.create(street: "hermannstr")
2584
2584
  end
2585
2585
 
2586
+ context "when the number is zero" do
2587
+
2588
+ let!(:popped) do
2589
+ person.addresses.pop(0)
2590
+ end
2591
+
2592
+ it "returns an empty array" do
2593
+ expect(popped).to eq([])
2594
+ end
2595
+
2596
+ it "does not remove the document from the relation" do
2597
+ expect(person.addresses).to eq([ address_one, address_two ])
2598
+ end
2599
+
2600
+ it "does not persist the pop" do
2601
+ expect(person.reload.addresses).to eq([ address_one, address_two ])
2602
+ end
2603
+ end
2604
+
2586
2605
  context "when the number is not larger than the relation" do
2587
2606
 
2588
2607
  let!(:popped) do
@@ -2640,6 +2659,125 @@ describe Mongoid::Relations::Embedded::Many do
2640
2659
  end
2641
2660
  end
2642
2661
 
2662
+ describe "#shift" do
2663
+
2664
+ let(:person) do
2665
+ Person.create
2666
+ end
2667
+
2668
+ context "when no argument is provided" do
2669
+
2670
+ let!(:address_one) do
2671
+ person.addresses.create(street: "sonnenallee")
2672
+ end
2673
+
2674
+ let!(:address_two) do
2675
+ person.addresses.create(street: "hermannstr")
2676
+ end
2677
+
2678
+ let!(:shifted) do
2679
+ person.addresses.shift
2680
+ end
2681
+
2682
+ it "returns the shifted document" do
2683
+ expect(shifted).to eq(address_one)
2684
+ end
2685
+
2686
+ it "removes the document from the relation" do
2687
+ expect(person.addresses).to eq([ address_two ])
2688
+ end
2689
+
2690
+ it "persists the shift" do
2691
+ expect(person.reload.addresses).to eq([ address_two ])
2692
+ end
2693
+ end
2694
+
2695
+ context "when an integer is provided" do
2696
+
2697
+ let!(:address_one) do
2698
+ person.addresses.create(street: "sonnenallee")
2699
+ end
2700
+
2701
+ let!(:address_two) do
2702
+ person.addresses.create(street: "hermannstr")
2703
+ end
2704
+
2705
+ context "when the number is zero" do
2706
+
2707
+ let!(:shifted) do
2708
+ person.addresses.shift(0)
2709
+ end
2710
+
2711
+ it "returns an empty array" do
2712
+ expect(shifted).to eq([])
2713
+ end
2714
+
2715
+ it "does not remove the document from the relation" do
2716
+ expect(person.addresses).to eq([ address_one, address_two ])
2717
+ end
2718
+
2719
+ it "does not persist the shift" do
2720
+ expect(person.reload.addresses).to eq([ address_one, address_two ])
2721
+ end
2722
+ end
2723
+
2724
+ context "when the number is not larger than the relation" do
2725
+
2726
+ let!(:shifted) do
2727
+ person.addresses.shift(2)
2728
+ end
2729
+
2730
+ it "returns the shifted documents" do
2731
+ expect(shifted).to eq([ address_one, address_two ])
2732
+ end
2733
+
2734
+ it "removes the document from the relation" do
2735
+ expect(person.addresses).to be_empty
2736
+ end
2737
+
2738
+ it "persists the shift" do
2739
+ expect(person.reload.addresses).to be_empty
2740
+ end
2741
+ end
2742
+
2743
+ context "when the number is larger than the relation" do
2744
+
2745
+ let!(:shifted) do
2746
+ person.addresses.shift(4)
2747
+ end
2748
+
2749
+ it "returns the shifted documents" do
2750
+ expect(shifted).to eq([ address_one, address_two ])
2751
+ end
2752
+
2753
+ it "removes the document from the relation" do
2754
+ expect(person.addresses).to be_empty
2755
+ end
2756
+
2757
+ it "persists the shift" do
2758
+ expect(person.reload.addresses).to be_empty
2759
+ end
2760
+ end
2761
+ end
2762
+
2763
+ context "when the relation is empty" do
2764
+
2765
+ context "when providing no number" do
2766
+
2767
+ it "returns nil" do
2768
+ expect(person.addresses.shift).to be_nil
2769
+ end
2770
+ end
2771
+
2772
+ context "when providing a number" do
2773
+
2774
+ it "returns nil" do
2775
+ expect(person.addresses.shift(2)).to be_nil
2776
+ end
2777
+ end
2778
+ end
2779
+ end
2780
+
2643
2781
  describe "#scoped" do
2644
2782
 
2645
2783
  let(:person) do
@@ -3846,7 +3984,7 @@ describe Mongoid::Relations::Embedded::Many do
3846
3984
  end
3847
3985
  end
3848
3986
 
3849
- context "#delete or #clear with before_remove callback" do
3987
+ context "#delete, or #clear, or #pop, or #shift with before_remove callback" do
3850
3988
 
3851
3989
  let(:artist) do
3852
3990
  Artist.new
@@ -3892,35 +4030,81 @@ describe Mongoid::Relations::Embedded::Many do
3892
4030
  end
3893
4031
  end
3894
4032
 
3895
- context "when errors are raised" do
4033
+ describe "#pop" do
3896
4034
 
3897
4035
  before do
3898
- expect(artist).to receive(:before_remove_song).and_raise
4036
+ artist.songs.pop
3899
4037
  end
3900
4038
 
3901
- describe "#delete" do
4039
+ it "executes the callback" do
4040
+ artist.songs.pop
4041
+ expect(artist.before_remove_embedded_called).to be true
4042
+ end
4043
+ end
3902
4044
 
3903
- it "does not remove the document from the relation" do
3904
- begin; artist.songs.delete(song); rescue; end
3905
- expect(artist.songs).to eq([ song ])
3906
- end
4045
+ describe "#shift" do
4046
+
4047
+ before do
4048
+ artist.songs.shift
3907
4049
  end
3908
4050
 
3909
- describe "#clear" do
4051
+ it "executes the callback" do
4052
+ artist.songs.shift
4053
+ expect(artist.before_remove_embedded_called).to be true
4054
+ end
4055
+ end
4056
+ end
3910
4057
 
3911
- before do
3912
- begin; artist.songs.clear; rescue; end
3913
- end
4058
+ context "when errors are raised" do
3914
4059
 
3915
- it "removes the documents from the relation" do
3916
- expect(artist.songs).to eq([ song ])
3917
- end
4060
+ before do
4061
+ expect(artist).to receive(:before_remove_song).and_raise
4062
+ end
4063
+
4064
+ describe "#delete" do
4065
+
4066
+ it "does not remove the document from the relation" do
4067
+ begin; artist.songs.delete(song); rescue; end
4068
+ expect(artist.songs).to eq([ song ])
4069
+ end
4070
+ end
4071
+
4072
+ describe "#clear" do
4073
+
4074
+ before do
4075
+ begin; artist.songs.clear; rescue; end
4076
+ end
4077
+
4078
+ it "removes the documents from the relation" do
4079
+ expect(artist.songs).to eq([ song ])
4080
+ end
4081
+ end
4082
+
4083
+ describe "#pop" do
4084
+
4085
+ before do
4086
+ begin; artist.songs.pop; rescue; end
4087
+ end
4088
+
4089
+ it "should remove from collection" do
4090
+ expect(artist.songs).to eq([ song ])
4091
+ end
4092
+ end
4093
+
4094
+ describe "#shift" do
4095
+
4096
+ before do
4097
+ begin; artist.songs.shift; rescue; end
4098
+ end
4099
+
4100
+ it "should remove from collection" do
4101
+ expect(artist.songs).to eq([ song ])
3918
4102
  end
3919
4103
  end
3920
4104
  end
3921
4105
  end
3922
4106
 
3923
- context "#delete or #clear with after_remove callback" do
4107
+ context "#delete, or #clear, or #pop, or #shift with after_remove callback" do
3924
4108
 
3925
4109
  let(:artist) do
3926
4110
  Artist.new
@@ -3957,6 +4141,30 @@ describe Mongoid::Relations::Embedded::Many do
3957
4141
  expect(artist.after_remove_embedded_called).to be true
3958
4142
  end
3959
4143
  end
4144
+
4145
+ describe "#pop" do
4146
+
4147
+ before do
4148
+ artist.labels.pop
4149
+ end
4150
+
4151
+ it "executes the callback" do
4152
+ artist.labels.pop
4153
+ expect(artist.after_remove_embedded_called).to be true
4154
+ end
4155
+ end
4156
+
4157
+ describe "#shift" do
4158
+
4159
+ before do
4160
+ artist.labels.shift
4161
+ end
4162
+
4163
+ it "executes the callback" do
4164
+ artist.labels.shift
4165
+ expect(artist.after_remove_embedded_called).to be true
4166
+ end
4167
+ end
3960
4168
  end
3961
4169
 
3962
4170
  context "when errors are raised" do
@@ -3986,6 +4194,28 @@ describe Mongoid::Relations::Embedded::Many do
3986
4194
  expect(artist.labels).to be_empty
3987
4195
  end
3988
4196
  end
4197
+
4198
+ describe "#pop" do
4199
+
4200
+ before do
4201
+ begin; artist.labels.pop; rescue; end
4202
+ end
4203
+
4204
+ it "should remove from collection" do
4205
+ expect(artist.labels).to be_empty
4206
+ end
4207
+ end
4208
+
4209
+ describe "#shift" do
4210
+
4211
+ before do
4212
+ begin; artist.labels.shift; rescue; end
4213
+ end
4214
+
4215
+ it "should remove from collection" do
4216
+ expect(artist.labels).to be_empty
4217
+ end
4218
+ end
3989
4219
  end
3990
4220
  end
3991
4221
 
@@ -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