mongoid 6.4.0 → 6.4.7

Sign up to get free protection for your applications and to get access to all the features.
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