mongoid 7.0.0.beta → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/config/locales/en.yml +21 -0
  5. data/lib/mongoid.rb +1 -1
  6. data/lib/mongoid/association/embedded/batchable.rb +39 -13
  7. data/lib/mongoid/association/many.rb +4 -0
  8. data/lib/mongoid/association/referenced/has_many.rb +2 -0
  9. data/lib/mongoid/association/referenced/has_many/enumerable.rb +38 -7
  10. data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -2
  11. data/lib/mongoid/association/referenced/syncable.rb +1 -1
  12. data/lib/mongoid/association/touchable.rb +1 -1
  13. data/lib/mongoid/atomic.rb +3 -3
  14. data/lib/mongoid/atomic/modifiers.rb +12 -8
  15. data/lib/mongoid/attributes.rb +20 -12
  16. data/lib/mongoid/attributes/dynamic.rb +2 -2
  17. data/lib/mongoid/changeable.rb +1 -1
  18. data/lib/mongoid/clients.rb +2 -0
  19. data/lib/mongoid/clients/sessions.rb +113 -0
  20. data/lib/mongoid/clients/storage_options.rb +1 -0
  21. data/lib/mongoid/composable.rb +1 -0
  22. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  23. data/lib/mongoid/contextual/atomic.rb +6 -3
  24. data/lib/mongoid/contextual/geo_near.rb +1 -1
  25. data/lib/mongoid/contextual/map_reduce.rb +6 -2
  26. data/lib/mongoid/contextual/memory.rb +25 -2
  27. data/lib/mongoid/contextual/mongo.rb +33 -14
  28. data/lib/mongoid/copyable.rb +2 -2
  29. data/lib/mongoid/criteria.rb +1 -0
  30. data/lib/mongoid/criteria/queryable/extensions/string.rb +1 -1
  31. data/lib/mongoid/criteria/queryable/mergeable.rb +3 -1
  32. data/lib/mongoid/errors.rb +1 -0
  33. data/lib/mongoid/errors/invalid_session_use.rb +24 -0
  34. data/lib/mongoid/extensions.rb +0 -4
  35. data/lib/mongoid/extensions/hash.rb +5 -2
  36. data/lib/mongoid/factory.rb +14 -5
  37. data/lib/mongoid/fields.rb +2 -2
  38. data/lib/mongoid/indexable.rb +4 -4
  39. data/lib/mongoid/matchable/and.rb +1 -1
  40. data/lib/mongoid/matchable/elem_match.rb +9 -3
  41. data/lib/mongoid/persistable.rb +2 -2
  42. data/lib/mongoid/persistable/creatable.rb +4 -2
  43. data/lib/mongoid/persistable/deletable.rb +4 -2
  44. data/lib/mongoid/persistable/destroyable.rb +1 -5
  45. data/lib/mongoid/persistable/updatable.rb +2 -2
  46. data/lib/mongoid/persistable/upsertable.rb +2 -1
  47. data/lib/mongoid/persistence_context.rb +5 -4
  48. data/lib/mongoid/query_cache.rb +5 -3
  49. data/lib/mongoid/reloadable.rb +1 -1
  50. data/lib/mongoid/serializable.rb +1 -1
  51. data/lib/mongoid/shardable.rb +1 -1
  52. data/lib/mongoid/tasks/database.rb +3 -2
  53. data/lib/mongoid/threaded.rb +38 -0
  54. data/lib/mongoid/traversable.rb +1 -1
  55. data/lib/mongoid/version.rb +1 -1
  56. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -0
  57. data/spec/app/models/band.rb +1 -0
  58. data/spec/app/models/shipment_address.rb +1 -0
  59. data/spec/mongoid/association/macros_spec.rb +20 -0
  60. data/spec/mongoid/association/referenced/has_many/eager_spec.rb +15 -0
  61. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +229 -0
  62. data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
  63. data/spec/mongoid/atomic_spec.rb +17 -17
  64. data/spec/mongoid/attributes_spec.rb +38 -2
  65. data/spec/mongoid/clients/sessions_spec.rb +325 -0
  66. data/spec/mongoid/contextual/memory_spec.rb +19 -0
  67. data/spec/mongoid/contextual/mongo_spec.rb +133 -0
  68. data/spec/mongoid/copyable_spec.rb +34 -0
  69. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +43 -0
  70. data/spec/mongoid/criteria/queryable/selectable_spec.rb +32 -3
  71. data/spec/mongoid/extensions/hash_spec.rb +18 -1
  72. data/spec/mongoid/factory_spec.rb +11 -0
  73. data/spec/mongoid/interceptable_spec.rb +3 -1
  74. data/spec/mongoid/matchable/elem_match_spec.rb +20 -0
  75. data/spec/mongoid/persistable/deletable_spec.rb +19 -0
  76. data/spec/mongoid/persistable/destroyable_spec.rb +19 -0
  77. data/spec/mongoid/persistable/savable_spec.rb +2 -2
  78. data/spec/mongoid/persistable/updatable_spec.rb +2 -2
  79. data/spec/mongoid/persistable_spec.rb +31 -16
  80. data/spec/mongoid/persistence_context_spec.rb +14 -0
  81. data/spec/mongoid/positional_spec.rb +10 -10
  82. data/spec/mongoid/query_cache_spec.rb +2 -16
  83. data/spec/mongoid/shardable_spec.rb +32 -12
  84. data/spec/spec_helper.rb +74 -0
  85. metadata +456 -446
  86. metadata.gz.sig +0 -0
@@ -20,6 +20,7 @@ class Band
20
20
 
21
21
  embeds_many :records, cascade_callbacks: true
22
22
  embeds_many :notes, as: :noteable, cascade_callbacks: true, validate: false
23
+ embeds_many :labels
23
24
  embeds_one :label, cascade_callbacks: true
24
25
 
25
26
  has_many :same_name, class_name: 'Agent', inverse_of: :same_name
@@ -1,2 +1,3 @@
1
1
  class ShipmentAddress < Address
2
+ field :shipping_name, localize: true
2
3
  end
@@ -20,6 +20,26 @@ describe Mongoid::Association::Macros do
20
20
  klass.validators.clear
21
21
  end
22
22
 
23
+ describe 'Model loading' do
24
+
25
+ let(:model_associations) do
26
+ class TestModel
27
+ include Mongoid::Document
28
+ field :associations
29
+ end
30
+ end
31
+
32
+ after do
33
+ Object.send(:remove_const, :TestModel)
34
+ end
35
+
36
+ it 'prohibits the use of :associations as an attribute' do
37
+ expect {
38
+ model_associations
39
+ }.to raise_exception(Mongoid::Errors::InvalidField)
40
+ end
41
+ end
42
+
23
43
  describe ".embedded_in" do
24
44
 
25
45
  it "defines the macro" do
@@ -91,6 +91,15 @@ describe Mongoid::Association::Referenced::HasMany::Eager do
91
91
  end
92
92
  end
93
93
  end
94
+
95
+ it "does not query when accessing the base on each document" do
96
+ persons = Person.all.includes(:drugs).to_a
97
+ expect_query(0) do
98
+ persons.each do |person|
99
+ person.drugs.collect(&:person)
100
+ end
101
+ end
102
+ end
94
103
  end
95
104
 
96
105
  context "when the relation is not polymorphic" do
@@ -120,6 +129,12 @@ describe Mongoid::Association::Referenced::HasMany::Eager do
120
129
  eager.posts.first.title = "New title"
121
130
  end
122
131
  end
132
+
133
+ it "does not query when accessing the base on each document" do
134
+ expect_query(0) do
135
+ eager.posts.collect(&:person)
136
+ end
137
+ end
123
138
  end
124
139
 
125
140
  context "when the eager load has not returned documents" do
@@ -189,6 +189,12 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
189
189
  it "returns the added documents" do
190
190
  expect(added).to eq([ post ])
191
191
  end
192
+
193
+ it "sets the base on the new document" do
194
+ expect_query(0) do
195
+ added.collect(&:person)
196
+ end
197
+ end
192
198
  end
193
199
  end
194
200
 
@@ -622,6 +628,22 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
622
628
  it "becomes loaded" do
623
629
  expect(enumerable).to be__loaded
624
630
  end
631
+
632
+ context 'when the base relation is accessed from each document' do
633
+
634
+ let(:persons) do
635
+ described_class.new(criteria).collect(&:person)
636
+ end
637
+
638
+ before do
639
+ Post.create(person_id: person.id)
640
+ Post.create(person_id: person.id)
641
+ end
642
+
643
+ it 'sets the base relation from the criteria' do
644
+ expect(persons.uniq.size).to eq(1)
645
+ end
646
+ end
625
647
  end
626
648
 
627
649
  context "when only an array target exists" do
@@ -928,6 +950,60 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
928
950
  end
929
951
  end
930
952
  end
953
+
954
+ context 'when the id_sort option is none' do
955
+
956
+ let(:person) do
957
+ Person.create
958
+ end
959
+
960
+ let(:criteria) do
961
+ Post.where(person_id: person.id)
962
+ end
963
+
964
+ let(:enumerable) do
965
+ described_class.new(criteria)
966
+ end
967
+
968
+ let!(:first_post) do
969
+ person.posts.create(title: "One")
970
+ end
971
+
972
+ let!(:second_post) do
973
+ person.posts.create(title: "Two")
974
+ end
975
+
976
+ it 'does not use the sort on id' do
977
+ expect(enumerable.first(id_sort: :none)).to eq(first_post)
978
+ end
979
+ end
980
+
981
+ context 'when the id_sort option is not provided' do
982
+
983
+ let(:person) do
984
+ Person.create
985
+ end
986
+
987
+ let(:criteria) do
988
+ Post.where(person_id: person.id)
989
+ end
990
+
991
+ let(:enumerable) do
992
+ described_class.new(criteria)
993
+ end
994
+
995
+ let!(:first_post) do
996
+ person.posts.create(title: "One")
997
+ end
998
+
999
+ let!(:second_post) do
1000
+ person.posts.create(title: "Two")
1001
+ end
1002
+
1003
+ it 'uses the sort on id' do
1004
+ expect(enumerable.first).to eq(first_post)
1005
+ end
1006
+ end
931
1007
  end
932
1008
 
933
1009
  describe "#include?" do
@@ -1344,6 +1420,60 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
1344
1420
  end
1345
1421
  end
1346
1422
  end
1423
+
1424
+ context 'when the id_sort option is none' do
1425
+
1426
+ let(:person) do
1427
+ Person.create
1428
+ end
1429
+
1430
+ let(:criteria) do
1431
+ Post.where(person_id: person.id)
1432
+ end
1433
+
1434
+ let(:enumerable) do
1435
+ described_class.new(criteria)
1436
+ end
1437
+
1438
+ let!(:first_post) do
1439
+ person.posts.create(title: "One")
1440
+ end
1441
+
1442
+ let!(:second_post) do
1443
+ person.posts.create(title: "Two")
1444
+ end
1445
+
1446
+ it 'does not use the sort on id' do
1447
+ expect(enumerable.last(id_sort: :none)).to eq(first_post)
1448
+ end
1449
+ end
1450
+
1451
+ context 'when the id_sort option is not provided' do
1452
+
1453
+ let(:person) do
1454
+ Person.create
1455
+ end
1456
+
1457
+ let(:criteria) do
1458
+ Post.where(person_id: person.id)
1459
+ end
1460
+
1461
+ let(:enumerable) do
1462
+ described_class.new(criteria)
1463
+ end
1464
+
1465
+ let!(:first_post) do
1466
+ person.posts.create(title: "One")
1467
+ end
1468
+
1469
+ let!(:second_post) do
1470
+ person.posts.create(title: "Two")
1471
+ end
1472
+
1473
+ it 'uses the sort on id' do
1474
+ expect(enumerable.last).to eq(second_post)
1475
+ end
1476
+ end
1347
1477
  end
1348
1478
 
1349
1479
  describe "#kind_of?" do
@@ -1714,4 +1844,103 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
1714
1844
  expect(enumerable).to be__loaded
1715
1845
  end
1716
1846
  end
1847
+
1848
+ describe 'setting the same parent object on enumerated children objects' do
1849
+
1850
+ let(:person) do
1851
+ Person.create
1852
+ end
1853
+
1854
+ context 'when a single child is fetched' do
1855
+
1856
+ let!(:post) do
1857
+ person.posts << Post.new
1858
+ person.posts.first
1859
+ end
1860
+
1861
+ it 'does not query the database to access the parent' do
1862
+ expect_query(0) do
1863
+ expect(post.person).to eq(person)
1864
+ end
1865
+ end
1866
+ end
1867
+
1868
+ context 'when a single child is fetched with a scope' do
1869
+
1870
+ let!(:post) do
1871
+ person.posts << Post.new(title: 'open')
1872
+ person.posts.open.first
1873
+ end
1874
+
1875
+ it 'does not query the database to access the parent' do
1876
+ expect_query(0) do
1877
+ expect(post.person).to eq(person)
1878
+ end
1879
+ end
1880
+ end
1881
+
1882
+ context 'when multiple children are fetched' do
1883
+
1884
+ let!(:posts) do
1885
+ person.posts << Post.new
1886
+ person.posts << Post.new
1887
+ person.posts << Post.new
1888
+ person.posts.to_a
1889
+ end
1890
+
1891
+ it 'does not query the database to access the parent' do
1892
+ expect_query(0) do
1893
+ expect(posts.all? { |post| post.person == person }).to be(true)
1894
+ end
1895
+ end
1896
+ end
1897
+
1898
+ context 'when multiple children are fetched with query criteria' do
1899
+
1900
+ let!(:posts) do
1901
+ person.posts << Post.new(title: 'open')
1902
+ person.posts << Post.new(title: 'open')
1903
+ person.posts << Post.new(title: 'not-a-test')
1904
+ person.posts.where(title: 'open').to_a
1905
+ end
1906
+
1907
+ it 'does not query the database to access the parent' do
1908
+ expect_query(0) do
1909
+ expect(posts.all? { |post| post.person == person }).to be(true)
1910
+ end
1911
+ end
1912
+ end
1913
+
1914
+ context 'when multiple children are fetched with a scope' do
1915
+
1916
+ let!(:posts) do
1917
+ person.posts << Post.new(title: 'open')
1918
+ person.posts << Post.new(title: 'open')
1919
+ person.posts << Post.new(title: 'not-a-test')
1920
+ person.posts.open.to_a
1921
+ end
1922
+
1923
+ it 'does not query the database to access the parent' do
1924
+ expect_query(0) do
1925
+ expect(posts.all? { |post| post.person == person }).to be(true)
1926
+ end
1927
+ end
1928
+ end
1929
+
1930
+ context 'when the parent is updated in memory' do
1931
+
1932
+ let!(:posts) do
1933
+ person.posts << Post.new
1934
+ person.posts << Post.new
1935
+ person.username = 'emily'
1936
+ person.posts.to_a
1937
+ end
1938
+
1939
+ it 'does not query the database to access the parent' do
1940
+ expect_query(0) do
1941
+ expect(posts.all? { |post| post.person.username == 'emily' }).to be(true)
1942
+ end
1943
+ end
1944
+ end
1945
+ end
1717
1946
  end
@@ -211,10 +211,10 @@ describe Mongoid::Atomic::Modifiers do
211
211
 
212
212
  it "adds the push all modifiers" do
213
213
  expect(modifiers).to eq(
214
- { "$pushAll" =>
215
- { "addresses" => [
214
+ { "$push" =>
215
+ { "addresses" => { '$each' => [
216
216
  { "street" => "Oxford St" }
217
- ]
217
+ ] }
218
218
  }
219
219
  }
220
220
  )
@@ -238,11 +238,11 @@ describe Mongoid::Atomic::Modifiers do
238
238
 
239
239
  it "adds the push all modifiers" do
240
240
  expect(modifiers).to eq(
241
- { "$pushAll" =>
242
- { "addresses" => [
241
+ { "$push" =>
242
+ { "addresses" => { '$each' => [
243
243
  { "street" => "Hobrechtstr." },
244
244
  { "street" => "Pflugerstr." }
245
- ]
245
+ ] }
246
246
  }
247
247
  }
248
248
  )
@@ -270,10 +270,10 @@ describe Mongoid::Atomic::Modifiers do
270
270
  it "adds the push all modifiers to the conflicts hash" do
271
271
  expect(modifiers).to eq(
272
272
  { "$set" => { "addresses.0.street" => "Bond" },
273
- conflicts: { "$pushAll" =>
274
- { "addresses" => [
273
+ conflicts: { "$push" =>
274
+ { "addresses" => { '$each' => [
275
275
  { "street" => "Oxford St" }
276
- ]
276
+ ] }
277
277
  }
278
278
  }
279
279
  }
@@ -300,10 +300,10 @@ describe Mongoid::Atomic::Modifiers do
300
300
  expect(modifiers).to eq(
301
301
  { "$pullAll" => {
302
302
  "addresses" => { "street" => "Bond St" }},
303
- conflicts: { "$pushAll" =>
304
- { "addresses" => [
303
+ conflicts: { "$push" =>
304
+ { "addresses" => { '$each' => [
305
305
  { "street" => "Oxford St" }
306
- ]
306
+ ]}
307
307
  }
308
308
  }
309
309
  }
@@ -328,12 +328,12 @@ describe Mongoid::Atomic::Modifiers do
328
328
 
329
329
  it "adds the push all modifiers to the conflicts hash" do
330
330
  expect(modifiers).to eq(
331
- { "$pushAll" => {
332
- "addresses.0.locations" => [{ "street" => "Bond St" }]},
333
- conflicts: { "$pushAll" =>
334
- { "addresses" => [
331
+ { "$push" => {
332
+ "addresses.0.locations" => { '$each' => [{ "street" => "Bond St" }] } },
333
+ conflicts: { "$push" =>
334
+ { "addresses" => { '$each' => [
335
335
  { "street" => "Oxford St" }
336
- ]
336
+ ] }
337
337
  }
338
338
  }
339
339
  }
@@ -76,13 +76,13 @@ describe Mongoid::Atomic do
76
76
  person.addresses.build(street: "Oxford St")
77
77
  end
78
78
 
79
- it "returns a $set and $pushAll for modifications" do
79
+ it "returns a $set and $push with $each for modifications" do
80
80
  expect(person.atomic_updates).to eq(
81
81
  {
82
82
  "$set" => { "title" => "Sir" },
83
- "$pushAll" => { "addresses" => [
83
+ "$push" => { "addresses" => { "$each" => [
84
84
  { "_id" => "oxford-st", "street" => "Oxford St" }
85
- ]}
85
+ ] } }
86
86
  }
87
87
  )
88
88
  end
@@ -197,8 +197,8 @@ describe Mongoid::Atomic do
197
197
  "addresses.0.street" => "Bond St"
198
198
  },
199
199
  conflicts: {
200
- "$pushAll" => {
201
- "addresses.0.locations" => [{ "_id" => location.id, "name" => "Home" }]
200
+ "$push" => {
201
+ "addresses.0.locations" => { '$each' => [{ "_id" => location.id, "name" => "Home" }] }
202
202
  }
203
203
  }
204
204
  }
@@ -215,8 +215,8 @@ describe Mongoid::Atomic do
215
215
  "addresses.0.street" => "Bond St"
216
216
  },
217
217
  conflicts: {
218
- "$pushAll" => {
219
- "addresses.0.locations" => [{ "_id" => location.id, "name" => "Home" }]
218
+ "$push" => {
219
+ "addresses.0.locations" => { '$each' => [{ "_id" => location.id, "name" => "Home" }] }
220
220
  }
221
221
  }
222
222
  }
@@ -263,15 +263,15 @@ describe Mongoid::Atomic do
263
263
  "addresses.0.street" => "Bond St"
264
264
  },
265
265
  conflicts: {
266
- "$pushAll" => {
267
- "addresses" => [{
266
+ "$push" => {
267
+ "addresses" => { '$each' => [{
268
268
  "_id" => new_address.id,
269
269
  "street" => "Another",
270
270
  "locations" => [
271
271
  "_id" => location.id,
272
272
  "name" => "Home"
273
273
  ]
274
- }]
274
+ }]}
275
275
  }
276
276
  }
277
277
  }
@@ -310,15 +310,15 @@ describe Mongoid::Atomic do
310
310
  "$set" => {
311
311
  "title" => "Sir"
312
312
  },
313
- "$pushAll" => {
314
- "addresses" => [{
313
+ "$push" => {
314
+ "addresses" => { '$each' => [{
315
315
  "_id" => new_address.id,
316
316
  "street" => "Ipanema",
317
317
  "locations" => [
318
318
  "_id" => location.id,
319
319
  "name" => "Home"
320
320
  ]
321
- }]
321
+ }] }
322
322
  },
323
323
  conflicts: {
324
324
  "$set" => { "addresses.0.street"=>"Bond St" }
@@ -339,21 +339,21 @@ describe Mongoid::Atomic do
339
339
  address.locations.build(name: "Home")
340
340
  end
341
341
 
342
- it "returns the proper $sets and $pushAlls for all levels" do
342
+ it "returns the proper $sets and $pushes for all levels" do
343
343
  expect(person.atomic_updates).to eq(
344
344
  {
345
345
  "$set" => {
346
346
  "title" => "Sir",
347
347
  },
348
- "$pushAll" => {
349
- "addresses" => [{
348
+ "$push" => {
349
+ "addresses" => { '$each' => [{
350
350
  "_id" => address.id,
351
351
  "street" => "Another",
352
352
  "locations" => [
353
353
  "_id" => location.id,
354
354
  "name" => "Home"
355
355
  ]
356
- }]
356
+ }] }
357
357
  }
358
358
  }
359
359
  )