mongoid 6.3.0 → 6.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +12 -0
  5. data/lib/config/locales/en.yml +21 -0
  6. data/lib/mongoid.rb +2 -2
  7. data/lib/mongoid/clients.rb +2 -0
  8. data/lib/mongoid/clients/sessions.rb +113 -0
  9. data/lib/mongoid/clients/storage_options.rb +1 -0
  10. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  11. data/lib/mongoid/contextual/map_reduce.rb +7 -3
  12. data/lib/mongoid/contextual/memory.rb +7 -2
  13. data/lib/mongoid/contextual/mongo.rb +11 -2
  14. data/lib/mongoid/criteria.rb +1 -0
  15. data/lib/mongoid/criteria/modifiable.rb +12 -2
  16. data/lib/mongoid/criteria/queryable/mergeable.rb +3 -1
  17. data/lib/mongoid/criteria/queryable/selectable.rb +34 -7
  18. data/lib/mongoid/document.rb +4 -4
  19. data/lib/mongoid/errors.rb +1 -0
  20. data/lib/mongoid/errors/invalid_session_use.rb +24 -0
  21. data/lib/mongoid/extensions/big_decimal.rb +1 -1
  22. data/lib/mongoid/extensions/regexp.rb +1 -0
  23. data/lib/mongoid/extensions/string.rb +3 -1
  24. data/lib/mongoid/indexable.rb +4 -4
  25. data/lib/mongoid/matchable.rb +3 -0
  26. data/lib/mongoid/matchable/nor.rb +37 -0
  27. data/lib/mongoid/persistable.rb +1 -1
  28. data/lib/mongoid/persistable/creatable.rb +4 -2
  29. data/lib/mongoid/persistable/deletable.rb +4 -2
  30. data/lib/mongoid/persistable/destroyable.rb +1 -5
  31. data/lib/mongoid/persistable/settable.rb +5 -5
  32. data/lib/mongoid/persistable/updatable.rb +2 -2
  33. data/lib/mongoid/persistable/upsertable.rb +2 -1
  34. data/lib/mongoid/persistence_context.rb +4 -0
  35. data/lib/mongoid/railtie.rb +17 -0
  36. data/lib/mongoid/railties/controller_runtime.rb +86 -0
  37. data/lib/mongoid/relations/embedded/batchable.rb +10 -4
  38. data/lib/mongoid/relations/embedded/many.rb +23 -0
  39. data/lib/mongoid/relations/many.rb +4 -0
  40. data/lib/mongoid/relations/referenced/many.rb +1 -1
  41. data/lib/mongoid/relations/touchable.rb +1 -1
  42. data/lib/mongoid/reloadable.rb +1 -1
  43. data/lib/mongoid/scopable.rb +3 -3
  44. data/lib/mongoid/tasks/database.rb +3 -2
  45. data/lib/mongoid/threaded.rb +74 -0
  46. data/lib/mongoid/version.rb +1 -1
  47. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -0
  48. data/spec/app/models/array_field.rb +7 -0
  49. data/spec/app/models/delegating_patient.rb +16 -0
  50. data/spec/integration/document_spec.rb +22 -0
  51. data/spec/mongoid/attributes/nested_spec.rb +4 -0
  52. data/spec/mongoid/clients/factory_spec.rb +52 -28
  53. data/spec/mongoid/clients/options_spec.rb +30 -15
  54. data/spec/mongoid/clients/sessions_spec.rb +334 -0
  55. data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
  56. data/spec/mongoid/contextual/mongo_spec.rb +40 -2
  57. data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
  58. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +3 -3
  59. data/spec/mongoid/criteria/queryable/selectable_spec.rb +74 -6
  60. data/spec/mongoid/criteria/queryable/selector_spec.rb +2 -2
  61. data/spec/mongoid/criteria/scopable_spec.rb +81 -0
  62. data/spec/mongoid/criteria_spec.rb +4 -1
  63. data/spec/mongoid/document_spec.rb +54 -0
  64. data/spec/mongoid/extensions/big_decimal_spec.rb +9 -9
  65. data/spec/mongoid/extensions/regexp_spec.rb +23 -0
  66. data/spec/mongoid/extensions/string_spec.rb +35 -7
  67. data/spec/mongoid/fields_spec.rb +1 -1
  68. data/spec/mongoid/findable_spec.rb +1 -1
  69. data/spec/mongoid/interceptable_spec.rb +1 -1
  70. data/spec/mongoid/matchable/nor_spec.rb +209 -0
  71. data/spec/mongoid/matchable_spec.rb +26 -1
  72. data/spec/mongoid/persistable/deletable_spec.rb +19 -0
  73. data/spec/mongoid/persistable/destroyable_spec.rb +19 -0
  74. data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
  75. data/spec/mongoid/persistable/settable_spec.rb +35 -1
  76. data/spec/mongoid/persistable_spec.rb +16 -16
  77. data/spec/mongoid/relations/embedded/many_spec.rb +246 -16
  78. data/spec/mongoid/scopable_spec.rb +13 -0
  79. data/spec/mongoid/threaded_spec.rb +68 -0
  80. data/spec/rails/controller_extension/controller_runtime_spec.rb +110 -0
  81. data/spec/spec_helper.rb +79 -0
  82. data/spec/support/cluster_config.rb +158 -0
  83. data/spec/support/constraints.rb +101 -0
  84. data/spec/support/macros.rb +20 -0
  85. data/spec/support/spec_config.rb +42 -0
  86. metadata +471 -443
  87. metadata.gz.sig +0 -0
@@ -228,6 +228,25 @@ describe Mongoid::Persistable::Deletable do
228
228
  expect(removed).to eq(1)
229
229
  end
230
230
  end
231
+
232
+ context 'when the write concern is unacknowledged' do
233
+
234
+ before do
235
+ Person.create(title: 'miss')
236
+ end
237
+
238
+ let!(:deleted) do
239
+ Person.with(write: { w: 0 }) { |klass| klass.delete_all(title: "sir") }
240
+ end
241
+
242
+ it "removes the matching documents" do
243
+ expect(Person.where(title: 'miss').count).to eq(1)
244
+ end
245
+
246
+ it "returns 0" do
247
+ expect(deleted).to eq(0)
248
+ end
249
+ end
231
250
  end
232
251
  end
233
252
  end
@@ -222,6 +222,25 @@ describe Mongoid::Persistable::Destroyable do
222
222
  end
223
223
  end
224
224
 
225
+ context 'when the write concern is unacknowledged' do
226
+
227
+ before do
228
+ Person.create(title: 'miss')
229
+ end
230
+
231
+ let!(:removed) do
232
+ Person.with(write: { w: 0 }) { |klass| klass.destroy_all(title: "sir") }
233
+ end
234
+
235
+ it "removes the matching documents" do
236
+ expect(Person.where(title: 'miss').count).to eq(1)
237
+ end
238
+
239
+ it "returns 0" do
240
+ expect(removed).to eq(0)
241
+ end
242
+ end
243
+
225
244
  context 'when removing a list of embedded documents' do
226
245
 
227
246
  context 'when the embedded documents list is reversed in memory' do
@@ -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
@@ -278,7 +278,22 @@ describe Mongoid::Persistable::Settable do
278
278
  end
279
279
  end
280
280
 
281
- context 'when the field is a bested hash' do
281
+ context 'when the field is a nested hash' do
282
+
283
+ context 'when the field is reset to an empty hash' do
284
+
285
+ before do
286
+ church.set('location' => {})
287
+ end
288
+
289
+ it 'updates the field locally' do
290
+ expect(church.location).to eq({})
291
+ end
292
+
293
+ it 'updates the field in the database' do
294
+ expect(church.reload.location).to eq({})
295
+ end
296
+ end
282
297
 
283
298
  context 'when a leaf value in the nested hash is updated' do
284
299
 
@@ -300,6 +315,25 @@ describe Mongoid::Persistable::Settable do
300
315
  end
301
316
  end
302
317
 
318
+ context 'when a leaf value in the nested hash is updated to a number' do
319
+
320
+ let(:church) do
321
+ Church.new.tap do |a|
322
+ a.location = {'address' => {'city' => 'Berlin', 'street' => 'Yorckstr'}}
323
+ a.name = 'Church1'
324
+ a.save
325
+ end
326
+ end
327
+
328
+ before do
329
+ church.set('location.address.city' => 12345)
330
+ end
331
+
332
+ it 'updates the nested value to the correct value' do
333
+ expect(church.name).to eq('Church1')
334
+ expect(church.location).to eql({'address' => {'city' => 12345, 'street' => 'Yorckstr'}})
335
+ end
336
+ end
303
337
 
304
338
  context 'when the nested hash is many levels deep' do
305
339
 
@@ -52,16 +52,16 @@ describe Mongoid::Persistable do
52
52
  context "when not chaining the operations" do
53
53
 
54
54
  let(:operations) do
55
- {
55
+ [{
56
56
  "$inc" => { "member_count" => 10 },
57
57
  "$bit" => { "likes" => { :and => 13 }},
58
58
  "$set" => { "name" => "Placebo" },
59
- "$unset" => { "origin" => true }
60
- }
59
+ "$unset" => { "origin" => true }},
60
+ { session: nil }]
61
61
  end
62
62
 
63
63
  before do
64
- expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(operations).and_call_original
64
+ expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(*operations).and_call_original
65
65
  end
66
66
 
67
67
  let!(:update) do
@@ -79,16 +79,16 @@ describe Mongoid::Persistable do
79
79
  context "when chaining the operations" do
80
80
 
81
81
  let(:operations) do
82
- {
82
+ [{
83
83
  "$inc" => { "member_count" => 10 },
84
84
  "$bit" => { "likes" => { :and => 13 }},
85
85
  "$set" => { "name" => "Placebo" },
86
- "$unset" => { "origin" => true }
87
- }
86
+ "$unset" => { "origin" => true }},
87
+ { :session => nil } ]
88
88
  end
89
89
 
90
90
  before do
91
- expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(operations).and_call_original
91
+ expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(*operations).and_call_original
92
92
  end
93
93
 
94
94
  let!(:update) do
@@ -107,16 +107,16 @@ describe Mongoid::Persistable do
107
107
  context "when given multiple operations of the same type" do
108
108
 
109
109
  let(:operations) do
110
- {
110
+ [{
111
111
  "$inc" => { "member_count" => 10, "other_count" => 10 },
112
112
  "$bit" => { "likes" => { :and => 13 }},
113
113
  "$set" => { "name" => "Placebo" },
114
- "$unset" => { "origin" => true }
115
- }
114
+ "$unset" => { "origin" => true }},
115
+ { session: nil }]
116
116
  end
117
117
 
118
118
  before do
119
- expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(operations).and_call_original
119
+ expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(*operations).and_call_original
120
120
  end
121
121
 
122
122
  let!(:update) do
@@ -144,16 +144,16 @@ describe Mongoid::Persistable do
144
144
  context "when expecting the document to be yielded" do
145
145
 
146
146
  let(:operations) do
147
- {
147
+ [{
148
148
  "$inc" => { "member_count" => 10 },
149
149
  "$bit" => { "likes" => { :and => 13 }},
150
150
  "$set" => { "name" => "Placebo" },
151
- "$unset" => { "origin" => true }
152
- }
151
+ "$unset" => { "origin" => true }},
152
+ { session: nil }]
153
153
  end
154
154
 
155
155
  before do
156
- expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(operations).and_call_original
156
+ expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(*operations).and_call_original
157
157
  end
158
158
 
159
159
  let!(:update) do
@@ -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