mongoid 9.0.0 → 9.0.2

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/Rakefile +44 -21
  4. data/lib/config/locales/en.yml +20 -0
  5. data/lib/mongoid/association/accessors.rb +7 -2
  6. data/lib/mongoid/association/nested/one.rb +14 -1
  7. data/lib/mongoid/association/referenced/belongs_to/binding.rb +7 -1
  8. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  9. data/lib/mongoid/association/referenced/belongs_to.rb +15 -0
  10. data/lib/mongoid/association/referenced/has_many.rb +9 -8
  11. data/lib/mongoid/association/referenced/has_one/buildable.rb +3 -8
  12. data/lib/mongoid/association/referenced/with_polymorphic_criteria.rb +41 -0
  13. data/lib/mongoid/atomic_update_preparer.rb +7 -6
  14. data/lib/mongoid/attributes/nested.rb +2 -1
  15. data/lib/mongoid/clients/sessions.rb +12 -15
  16. data/lib/mongoid/composable.rb +2 -0
  17. data/lib/mongoid/config.rb +9 -0
  18. data/lib/mongoid/contextual/aggregable/memory.rb +3 -2
  19. data/lib/mongoid/contextual/aggregable/mongo.rb +5 -2
  20. data/lib/mongoid/criteria/findable.rb +2 -2
  21. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -1
  22. data/lib/mongoid/document.rb +2 -0
  23. data/lib/mongoid/errors/invalid_around_callback.rb +16 -0
  24. data/lib/mongoid/errors/unrecognized_model_alias.rb +53 -0
  25. data/lib/mongoid/errors/unrecognized_resolver.rb +27 -0
  26. data/lib/mongoid/errors/unregistered_class.rb +47 -0
  27. data/lib/mongoid/errors.rb +4 -0
  28. data/lib/mongoid/fields.rb +13 -7
  29. data/lib/mongoid/identifiable.rb +28 -0
  30. data/lib/mongoid/interceptable.rb +18 -13
  31. data/lib/mongoid/model_resolver.rb +154 -0
  32. data/lib/mongoid/persistence_context.rb +2 -1
  33. data/lib/mongoid/scopable.rb +7 -1
  34. data/lib/mongoid/touchable.rb +1 -7
  35. data/lib/mongoid/traversable.rb +5 -0
  36. data/lib/mongoid/version.rb +1 -1
  37. data/spec/integration/associations/belongs_to_spec.rb +129 -0
  38. data/spec/integration/persistence/collection_options_spec.rb +36 -0
  39. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +4 -0
  40. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +1 -0
  41. data/spec/mongoid/association/referenced/belongs_to_spec.rb +58 -21
  42. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +4 -0
  43. data/spec/mongoid/association_spec.rb +14 -0
  44. data/spec/mongoid/attributes/nested_spec.rb +1 -0
  45. data/spec/mongoid/attributes_spec.rb +16 -0
  46. data/spec/mongoid/clients/transactions_spec.rb +2 -2
  47. data/spec/mongoid/contextual/aggregable/memory_spec.rb +11 -0
  48. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +11 -0
  49. data/spec/mongoid/contextual/mongo_spec.rb +72 -3
  50. data/spec/mongoid/fields_spec.rb +2 -2
  51. data/spec/mongoid/interceptable_spec.rb +31 -0
  52. data/spec/mongoid/model_resolver_spec.rb +167 -0
  53. data/spec/mongoid/monkey_patches_spec.rb +1 -1
  54. data/spec/mongoid/persistence_context_spec.rb +17 -4
  55. data/spec/mongoid/scopable_spec.rb +88 -85
  56. data/spec/mongoid/serializable_spec.rb +16 -9
  57. data/spec/mongoid/touchable_spec.rb +75 -0
  58. data/spec/mongoid/touchable_spec_models.rb +16 -0
  59. data/spec/support/models/band.rb +1 -0
  60. data/spec/support/models/lat_lng.rb +6 -0
  61. metadata +20 -82
  62. checksums.yaml.gz.sig +0 -1
  63. data/spec/shared/LICENSE +0 -20
  64. data/spec/shared/bin/get-mongodb-download-url +0 -17
  65. data/spec/shared/bin/s3-copy +0 -45
  66. data/spec/shared/bin/s3-upload +0 -69
  67. data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
  68. data/spec/shared/lib/mrss/cluster_config.rb +0 -231
  69. data/spec/shared/lib/mrss/constraints.rb +0 -378
  70. data/spec/shared/lib/mrss/docker_runner.rb +0 -298
  71. data/spec/shared/lib/mrss/eg_config_utils.rb +0 -51
  72. data/spec/shared/lib/mrss/event_subscriber.rb +0 -210
  73. data/spec/shared/lib/mrss/lite_constraints.rb +0 -238
  74. data/spec/shared/lib/mrss/server_version_registry.rb +0 -113
  75. data/spec/shared/lib/mrss/session_registry.rb +0 -69
  76. data/spec/shared/lib/mrss/session_registry_legacy.rb +0 -60
  77. data/spec/shared/lib/mrss/spec_organizer.rb +0 -179
  78. data/spec/shared/lib/mrss/utils.rb +0 -37
  79. data/spec/shared/share/Dockerfile.erb +0 -281
  80. data/spec/shared/share/haproxy-1.conf +0 -16
  81. data/spec/shared/share/haproxy-2.conf +0 -17
  82. data/spec/shared/shlib/config.sh +0 -27
  83. data/spec/shared/shlib/distro.sh +0 -74
  84. data/spec/shared/shlib/server.sh +0 -417
  85. data/spec/shared/shlib/set_env.sh +0 -146
  86. data.tar.gz.sig +0 -0
  87. metadata.gz.sig +0 -1
@@ -3,6 +3,19 @@
3
3
 
4
4
  require "spec_helper"
5
5
 
6
+ # Retrieve the singleton class for the given class.
7
+ def singleton_class_for(klass)
8
+ class <<klass; self; end
9
+ end
10
+
11
+ # Helper method for removing a declared scope
12
+ def remove_scope(klass, scope)
13
+ if klass._declared_scopes[scope]
14
+ singleton_class_for(klass).remove_method(scope)
15
+ klass._declared_scopes.delete(scope)
16
+ end
17
+ end
18
+
6
19
  describe Mongoid::Scopable do
7
20
 
8
21
  describe ".default_scope" do
@@ -349,6 +362,10 @@ describe Mongoid::Scopable do
349
362
  Band.create!(name: 'testing')
350
363
  end
351
364
 
365
+ after do
366
+ remove_scope(Band, :tests)
367
+ end
368
+
352
369
  it 'applies the collation' do
353
370
  expect(Band.tests.first['name']).to eq('testing')
354
371
  end
@@ -365,10 +382,7 @@ describe Mongoid::Scopable do
365
382
  end
366
383
 
367
384
  after do
368
- class << Band
369
- undef_method :active
370
- end
371
- Band._declared_scopes.clear
385
+ remove_scope(Band, :active)
372
386
  end
373
387
 
374
388
  let(:scope) do
@@ -390,10 +404,7 @@ describe Mongoid::Scopable do
390
404
  end
391
405
 
392
406
  after do
393
- class << Record
394
- undef_method :tool
395
- end
396
- Record._declared_scopes.clear
407
+ remove_scope(Record, :tool)
397
408
  end
398
409
 
399
410
  context "when calling the scope" do
@@ -423,10 +434,7 @@ describe Mongoid::Scopable do
423
434
  end
424
435
 
425
436
  after do
426
- class << Band
427
- undef_method :active
428
- end
429
- Band._declared_scopes.clear
437
+ remove_scope(Band, :active)
430
438
  end
431
439
 
432
440
  it "adds a method for the scope" do
@@ -461,10 +469,7 @@ describe Mongoid::Scopable do
461
469
  end
462
470
 
463
471
  after do
464
- class << Band
465
- undef_method :english
466
- end
467
- Band._declared_scopes.clear
472
+ remove_scope(Band, :english)
468
473
  end
469
474
 
470
475
  let(:scope) do
@@ -527,10 +532,7 @@ describe Mongoid::Scopable do
527
532
  config_override :scope_overwrite_exception, true
528
533
 
529
534
  after do
530
- class << Band
531
- undef_method :active
532
- end
533
- Band._declared_scopes.clear
535
+ remove_scope(Band, :active)
534
536
  end
535
537
 
536
538
  it "raises an exception" do
@@ -545,10 +547,7 @@ describe Mongoid::Scopable do
545
547
  config_override :scope_overwrite_exception, false
546
548
 
547
549
  after do
548
- class << Band
549
- undef_method :active
550
- end
551
- Band._declared_scopes.clear
550
+ remove_scope(Band, :active)
552
551
  end
553
552
 
554
553
  it "raises no exception" do
@@ -589,10 +588,7 @@ describe Mongoid::Scopable do
589
588
  end
590
589
 
591
590
  after do
592
- class << Band
593
- undef_method :active
594
- end
595
- Band._declared_scopes.clear
591
+ remove_scope(Band, :active)
596
592
  end
597
593
 
598
594
  let(:scope) do
@@ -652,11 +648,8 @@ describe Mongoid::Scopable do
652
648
  end
653
649
 
654
650
  after do
655
- class << Band
656
- undef_method :active
657
- undef_method :named_by
658
- end
659
- Band._declared_scopes.clear
651
+ remove_scope(Band, :active)
652
+ remove_scope(Band, :named_by)
660
653
  end
661
654
 
662
655
  it "adds a method for the scope" do
@@ -698,10 +691,7 @@ describe Mongoid::Scopable do
698
691
  end
699
692
 
700
693
  after do
701
- class << Band
702
- undef_method :english
703
- end
704
- Band._declared_scopes.clear
694
+ remove_scope(Band, :english)
705
695
  end
706
696
 
707
697
  let(:scope) do
@@ -775,15 +765,9 @@ describe Mongoid::Scopable do
775
765
  end
776
766
 
777
767
  after do
778
- class << Article
779
- undef_method :is_public
780
- undef_method :authored
781
- end
782
- Article._declared_scopes.clear
783
- class << Author
784
- undef_method :author
785
- end
786
- Author._declared_scopes.clear
768
+ remove_scope(Article, :is_public)
769
+ remove_scope(Article, :authored)
770
+ remove_scope(Author, :author)
787
771
  end
788
772
 
789
773
  context "when calling another model's scope from within a scope" do
@@ -816,10 +800,7 @@ describe Mongoid::Scopable do
816
800
  config_override :scope_overwrite_exception, true
817
801
 
818
802
  after do
819
- class << Band
820
- undef_method :active
821
- end
822
- Band._declared_scopes.clear
803
+ remove_scope(Band, :active)
823
804
  end
824
805
 
825
806
  it "raises an exception" do
@@ -834,10 +815,7 @@ describe Mongoid::Scopable do
834
815
  config_override :scope_overwrite_exception, false
835
816
 
836
817
  after do
837
- class << Band
838
- undef_method :active
839
- end
840
- Band._declared_scopes.clear
818
+ remove_scope(Band, :active)
841
819
  end
842
820
 
843
821
  it "raises no exception" do
@@ -867,11 +845,8 @@ describe Mongoid::Scopable do
867
845
  end
868
846
 
869
847
  after do
870
- class << Band
871
- undef_method :xxx
872
- undef_method :yyy
873
- end
874
- Band._declared_scopes.clear
848
+ remove_scope(Band, :xxx)
849
+ remove_scope(Band, :yyy)
875
850
  end
876
851
 
877
852
  let(:criteria) do
@@ -901,15 +876,8 @@ describe Mongoid::Scopable do
901
876
  end
902
877
 
903
878
  after do
904
- class << Shape
905
- undef_method :located_at
906
- end
907
- Shape._declared_scopes.clear
908
-
909
- class << Circle
910
- undef_method :with_radius
911
- end
912
- Circle._declared_scopes.clear
879
+ remove_scope(Shape, :located_at)
880
+ remove_scope(Circle, :with_radius)
913
881
  end
914
882
 
915
883
  let(:shape_scope_keys) do
@@ -950,16 +918,9 @@ describe Mongoid::Scopable do
950
918
  end
951
919
 
952
920
  after do
953
- class << Shape
954
- undef_method :visible
955
- undef_method :large
956
- end
957
- Shape._declared_scopes.clear
958
-
959
- class << Circle
960
- undef_method :large
961
- end
962
- Circle._declared_scopes.clear
921
+ remove_scope(Shape, :visible)
922
+ remove_scope(Shape, :large)
923
+ remove_scope(Circle, :large)
963
924
  end
964
925
 
965
926
  it "uses subclass context for all the other used scopes" do
@@ -1099,9 +1060,7 @@ describe Mongoid::Scopable do
1099
1060
  end
1100
1061
 
1101
1062
  after do
1102
- class << Band
1103
- undef_method :active
1104
- end
1063
+ remove_scope(Band, :active)
1105
1064
  end
1106
1065
 
1107
1066
  let(:unscoped) do
@@ -1143,10 +1102,7 @@ describe Mongoid::Scopable do
1143
1102
  end
1144
1103
 
1145
1104
  after do
1146
- class << Band
1147
- undef_method :skipped
1148
- end
1149
- Band._declared_scopes.clear
1105
+ remove_scope(Band, :skipped)
1150
1106
  end
1151
1107
 
1152
1108
  it "does not allow the default scope to be applied" do
@@ -1290,4 +1246,51 @@ describe Mongoid::Scopable do
1290
1246
  end
1291
1247
  end
1292
1248
  end
1249
+
1250
+ describe "scoped queries" do
1251
+ context "with a default scope" do
1252
+ let(:criteria) do
1253
+ Band.where(name: "Depeche Mode")
1254
+ end
1255
+
1256
+ before do
1257
+ Band.default_scope ->{ criteria }
1258
+ Band.scope :unscoped_everyone, -> { unscoped }
1259
+ Band.scope :removed_default, -> { scoped.remove_scoping(all) }
1260
+
1261
+ Band.create name: 'Depeche Mode'
1262
+ Band.create name: 'They Might Be Giants'
1263
+ end
1264
+
1265
+ after do
1266
+ Band.default_scoping = nil
1267
+ remove_scope Band, :unscoped_everyone
1268
+ remove_scope Band, :removed_default
1269
+ end
1270
+
1271
+ context "when allow_scopes_to_unset_default_scope == false" do # default for <= 9
1272
+ config_override :allow_scopes_to_unset_default_scope, false
1273
+
1274
+ it 'merges the default scope into the query with unscoped' do
1275
+ expect(Band.unscoped_everyone.selector).to include('name' => 'Depeche Mode')
1276
+ end
1277
+
1278
+ it 'merges the default scope into the query with remove_scoping' do
1279
+ expect(Band.removed_default.selector).to include('name' => 'Depeche Mode')
1280
+ end
1281
+ end
1282
+
1283
+ context "when allow_scopes_to_unset_default_scope == true" do # default for >= 10
1284
+ config_override :allow_scopes_to_unset_default_scope, true
1285
+
1286
+ it 'does not merge the default scope into the query with unscoped' do
1287
+ expect(Band.unscoped_everyone.selector).not_to include('name' => 'Depeche Mode')
1288
+ end
1289
+
1290
+ it 'does not merge merges the default scope into the query with remove_scoping' do
1291
+ expect(Band.removed_default.selector).not_to include('name' => 'Depeche Mode')
1292
+ end
1293
+ end
1294
+ end
1295
+ end
1293
1296
  end
@@ -511,13 +511,15 @@ describe Mongoid::Serializable do
511
511
  end
512
512
 
513
513
  it "includes the first relation" do
514
- expect(relation_hash[0]).to include
514
+ expect(relation_hash[0]).to include(
515
515
  { "_id" => "kudamm", "street" => "Kudamm" }
516
+ )
516
517
  end
517
518
 
518
519
  it "includes the second relation" do
519
- expect(relation_hash[1]).to include
520
+ expect(relation_hash[1]).to include(
520
521
  { "_id" => "tauentzienstr", "street" => "Tauentzienstr" }
522
+ )
521
523
  end
522
524
  end
523
525
 
@@ -528,13 +530,15 @@ describe Mongoid::Serializable do
528
530
  end
529
531
 
530
532
  it "includes the first relation" do
531
- expect(relation_hash[0]).to include
533
+ expect(relation_hash[0]).to include(
532
534
  { "_id" => "kudamm", "street" => "Kudamm" }
535
+ )
533
536
  end
534
537
 
535
538
  it "includes the second relation" do
536
- expect(relation_hash[1]).to include
539
+ expect(relation_hash[1]).to include(
537
540
  { "_id" => "tauentzienstr", "street" => "Tauentzienstr" }
541
+ )
538
542
  end
539
543
  end
540
544
 
@@ -653,8 +657,9 @@ describe Mongoid::Serializable do
653
657
  end
654
658
 
655
659
  it "includes the specified relation" do
656
- expect(relation_hash).to include
657
- { "_id" => "leo-marvin", "first_name" => "Leo", "last_name" => "Marvin" }
660
+ expect(relation_hash).to include(
661
+ { "_id" => "Leo-Marvin", "first_name" => "Leo", "last_name" => "Marvin" }
662
+ )
658
663
  end
659
664
  end
660
665
 
@@ -665,8 +670,9 @@ describe Mongoid::Serializable do
665
670
  end
666
671
 
667
672
  it "includes the specified relation" do
668
- expect(relation_hash).to include
669
- { "_id" => "leo-marvin", "first_name" => "Leo", "last_name" => "Marvin" }
673
+ expect(relation_hash).to include(
674
+ { "_id" => "Leo-Marvin", "first_name" => "Leo", "last_name" => "Marvin" }
675
+ )
670
676
  end
671
677
  end
672
678
 
@@ -677,8 +683,9 @@ describe Mongoid::Serializable do
677
683
  end
678
684
 
679
685
  it "includes the specified relation sans exceptions" do
680
- expect(relation_hash).to include
686
+ expect(relation_hash).to include(
681
687
  { "first_name" => "Leo", "last_name" => "Marvin" }
688
+ )
682
689
  end
683
690
  end
684
691
  end
@@ -733,6 +733,81 @@ describe Mongoid::Touchable do
733
733
  end
734
734
  end
735
735
 
736
+ context "when a custom field is specified" do
737
+
738
+ shared_examples "updates the child's updated_at" do
739
+
740
+ let!(:start_time) { Timecop.freeze(Time.at(Time.now.to_i)) }
741
+
742
+ let(:update_time) { Timecop.freeze(Time.at(Time.now.to_i) + 2) }
743
+
744
+ after do
745
+ Timecop.return
746
+ end
747
+
748
+ let!(:label) do
749
+ TouchableSpec::Referenced::Label.create!
750
+ end
751
+
752
+ let(:band) do
753
+ TouchableSpec::Referenced::Band.create!(label: label)
754
+ end
755
+
756
+ before do
757
+ update_time
758
+ band.send(meth)
759
+ end
760
+
761
+ it "updates the child's timestamp" do
762
+ expect(band.updated_at).to eq(update_time)
763
+ expect(band.reload.updated_at).to eq(update_time)
764
+ end
765
+ end
766
+
767
+ shared_examples "updates the parent's custom field and updated_at" do
768
+
769
+ let!(:start_time) { Timecop.freeze(Time.at(Time.now.to_i)) }
770
+
771
+ let(:update_time) { Timecop.freeze(Time.at(Time.now.to_i) + 2) }
772
+
773
+ after do
774
+ Timecop.return
775
+ end
776
+
777
+ let!(:label) do
778
+ TouchableSpec::Referenced::Label.create!
779
+ end
780
+
781
+ let!(:band) do
782
+ TouchableSpec::Referenced::Band.create!(label: label)
783
+ end
784
+
785
+ before do
786
+ update_time
787
+ band.send(meth)
788
+ end
789
+
790
+ it "updates the parent's custom field" do
791
+ expect(label.bands_updated_at).to eq(update_time)
792
+ expect(label.reload.bands_updated_at).to eq(update_time)
793
+ end
794
+
795
+ it "updates the parent's timestamp" do
796
+ expect(label.updated_at).to eq(update_time)
797
+ expect(label.reload.updated_at).to eq(update_time)
798
+ end
799
+
800
+ end
801
+
802
+ [:save, :destroy, :touch].each do |meth|
803
+ context "with #{meth} on referenced associations" do
804
+ let(:meth) { meth }
805
+ include_examples "updates the child's updated_at" unless meth == :destroy
806
+ include_examples "updates the parent's custom field and updated_at"
807
+ end
808
+ end
809
+ end
810
+
736
811
  context 'multi-level' do
737
812
 
738
813
  let!(:start_time) { Timecop.freeze(Time.at(Time.now.to_i)) }
@@ -150,5 +150,21 @@ module TouchableSpec
150
150
 
151
151
  embedded_in :floor, touch: true, class_name: "TouchableSpec::Referenced::Floor"
152
152
  end
153
+
154
+ class Label
155
+ include Mongoid::Document
156
+ include Mongoid::Timestamps
157
+
158
+ field :bands_updated_at, type: DateTime
159
+ has_many :bands, class_name: "TouchableSpec::Referenced::Band"
160
+ end
161
+
162
+ class Band
163
+ include Mongoid::Document
164
+ include Mongoid::Timestamps
165
+
166
+ belongs_to :label, touch: :bands_updated_at, class_name: "TouchableSpec::Referenced::Label"
167
+ end
168
+
153
169
  end
154
170
  end
@@ -26,6 +26,7 @@ class Band
26
26
  field :mojo, type: Object
27
27
  field :tags, type: Hash
28
28
  field :fans
29
+ field :location, type: LatLng
29
30
 
30
31
  alias_attribute :d, :deleted
31
32
 
@@ -5,6 +5,8 @@ class LatLng
5
5
  attr_accessor :lat, :lng
6
6
 
7
7
  def self.demongoize(object)
8
+ return if object.nil?
9
+
8
10
  LatLng.new(object[1], object[0])
9
11
  end
10
12
 
@@ -15,4 +17,8 @@ class LatLng
15
17
  def mongoize
16
18
  [ lng, lat ]
17
19
  end
20
+
21
+ def ==(other)
22
+ lat == other.lat && lng == other.lng
23
+ end
18
24
  end