mongoid 9.0.6 → 9.0.8

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +9 -9
  3. data/lib/mongoid/association/embedded/batchable.rb +11 -10
  4. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +61 -0
  5. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
  6. data/lib/mongoid/association/nested/many.rb +2 -0
  7. data/lib/mongoid/association/nested/one.rb +1 -1
  8. data/lib/mongoid/association/referenced/has_many/proxy.rb +0 -4
  9. data/lib/mongoid/changeable.rb +10 -1
  10. data/lib/mongoid/clients/sessions.rb +3 -4
  11. data/lib/mongoid/config.rb +1 -1
  12. data/lib/mongoid/contextual/aggregable/mongo.rb +6 -1
  13. data/lib/mongoid/contextual/mongo.rb +1 -1
  14. data/lib/mongoid/railties/bson_object_id_serializer.rb +7 -0
  15. data/lib/mongoid/reloadable.rb +6 -0
  16. data/lib/mongoid/validatable/associated.rb +1 -1
  17. data/lib/mongoid/validatable/macros.rb +15 -0
  18. data/lib/mongoid/validatable/numericality.rb +19 -0
  19. data/lib/mongoid/validatable.rb +1 -0
  20. data/lib/mongoid/version.rb +5 -2
  21. data/spec/integration/app_spec.rb +6 -0
  22. data/spec/integration/associations/embeds_many_spec.rb +110 -0
  23. data/spec/integration/associations/embeds_one_spec.rb +25 -6
  24. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +81 -0
  25. data/spec/integration/associations/has_many_spec.rb +56 -0
  26. data/spec/integration/associations/has_one_spec.rb +55 -3
  27. data/spec/mongoid/association/referenced/has_many_models.rb +24 -0
  28. data/spec/mongoid/association/referenced/has_one_models.rb +10 -2
  29. data/spec/mongoid/association_spec.rb +0 -60
  30. data/spec/mongoid/clients/transactions_spec.rb +162 -1
  31. data/spec/mongoid/clients/transactions_spec_models.rb +93 -0
  32. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +33 -0
  33. data/spec/mongoid/contextual/mongo_spec.rb +6 -0
  34. data/spec/mongoid/reloadable_spec.rb +24 -0
  35. data/spec/mongoid/validatable/numericality_spec.rb +16 -0
  36. data/spec/shared/LICENSE +20 -0
  37. data/spec/shared/bin/get-mongodb-download-url +17 -0
  38. data/spec/shared/bin/s3-copy +45 -0
  39. data/spec/shared/bin/s3-upload +69 -0
  40. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  41. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  42. data/spec/shared/lib/mrss/constraints.rb +378 -0
  43. data/spec/shared/lib/mrss/docker_runner.rb +298 -0
  44. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  45. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  46. data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
  47. data/spec/shared/lib/mrss/release/candidate.rb +281 -0
  48. data/spec/shared/lib/mrss/release/product_data.rb +144 -0
  49. data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
  50. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  51. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  52. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  53. data/spec/shared/lib/mrss/utils.rb +37 -0
  54. data/spec/shared/lib/tasks/candidate.rake +64 -0
  55. data/spec/shared/share/Dockerfile.erb +251 -0
  56. data/spec/shared/share/haproxy-1.conf +16 -0
  57. data/spec/shared/share/haproxy-2.conf +17 -0
  58. data/spec/shared/shlib/config.sh +27 -0
  59. data/spec/shared/shlib/distro.sh +84 -0
  60. data/spec/shared/shlib/server.sh +423 -0
  61. data/spec/shared/shlib/set_env.sh +110 -0
  62. data/spec/support/expectations.rb +20 -18
  63. metadata +59 -6
@@ -126,4 +126,60 @@ describe 'has_many associations' do
126
126
  end
127
127
  end
128
128
  end
129
+
130
+ context 'with deeply nested trees' do
131
+ let(:post) { HmmPost.create!(title: 'Post') }
132
+ let(:child) { post.comments.create!(title: 'Child') }
133
+
134
+ # creating grandchild will cascade to create the other documents
135
+ let!(:grandchild) { child.comments.create!(title: 'Grandchild') }
136
+
137
+ let(:updated_parent_title) { 'Post Updated' }
138
+ let(:updated_grandchild_title) { 'Grandchild Updated' }
139
+
140
+ context 'with nested attributes' do
141
+ let(:attributes) do
142
+ {
143
+ title: updated_parent_title,
144
+ comments_attributes: [
145
+ {
146
+ # no change for comment1
147
+ _id: child.id,
148
+ comments_attributes: [
149
+ {
150
+ _id: grandchild.id,
151
+ title: updated_grandchild_title,
152
+ num: updated_grandchild_num,
153
+ }
154
+ ]
155
+ }
156
+ ]
157
+ }
158
+ end
159
+
160
+ context 'when the grandchild is invalid' do
161
+ let(:updated_grandchild_num) { -1 } # invalid value
162
+
163
+ it 'will not save the parent' do
164
+ expect(post.update(attributes)).to be_falsey
165
+ expect(post.errors).not_to be_empty
166
+ expect(post.reload.title).not_to eq(updated_parent_title)
167
+ expect(grandchild.reload.title).not_to eq(updated_grandchild_title)
168
+ expect(grandchild.num).not_to eq(updated_grandchild_num)
169
+ end
170
+ end
171
+
172
+ context 'when the grandchild is valid' do
173
+ let(:updated_grandchild_num) { 1 }
174
+
175
+ it 'will save the parent' do
176
+ expect(post.update(attributes)).to be_truthy
177
+ expect(post.errors).to be_empty
178
+ expect(post.reload.title).to eq(updated_parent_title)
179
+ expect(grandchild.reload.title).to eq(updated_grandchild_title)
180
+ expect(grandchild.num).to eq(updated_grandchild_num)
181
+ end
182
+ end
183
+ end
184
+ end
129
185
  end
@@ -224,7 +224,7 @@ describe 'has_one associations' do
224
224
  end
225
225
 
226
226
  context "when explicitly setting the foreign key" do
227
- let(:comment2) { HomComment.new(post_id: post.id, content: "2") }
227
+ let(:comment2) { HomComment.new(container_id: post.id, container_type: post.class.name, content: "2") }
228
228
 
229
229
  it "persists the new comment" do
230
230
  post.comment = comment1
@@ -264,10 +264,62 @@ describe 'has_one associations' do
264
264
 
265
265
  it "does not overwrite the original value" do
266
266
  pending "MONGOID-3999"
267
- p1 = comment.post
267
+ p1 = comment.container
268
268
  expect(p1.title).to eq("post 1")
269
- comment.post = post2
269
+ comment.container = post2
270
270
  expect(p1.title).to eq("post 1")
271
271
  end
272
272
  end
273
+
274
+ context 'with deeply nested trees' do
275
+ let(:post) { HomPost.create!(title: 'Post') }
276
+ let(:child) { post.create_comment(content: 'Child') }
277
+
278
+ # creating grandchild will cascade to create the other documents
279
+ let!(:grandchild) { child.create_comment(content: 'Grandchild') }
280
+
281
+ let(:updated_parent_title) { 'Post Updated' }
282
+ let(:updated_grandchild_content) { 'Grandchild Updated' }
283
+
284
+ context 'with nested attributes' do
285
+ let(:attributes) do
286
+ {
287
+ title: updated_parent_title,
288
+ comment_attributes: {
289
+ # no change for child
290
+ _id: child.id,
291
+ comment_attributes: {
292
+ _id: grandchild.id,
293
+ content: updated_grandchild_content,
294
+ num: updated_grandchild_num,
295
+ }
296
+ }
297
+ }
298
+ end
299
+
300
+ context 'when the grandchild is invalid' do
301
+ let(:updated_grandchild_num) { -1 } # invalid value
302
+
303
+ it 'will not save the parent' do
304
+ expect(post.update(attributes)).to be_falsey
305
+ expect(post.errors).not_to be_empty
306
+ expect(post.reload.title).not_to eq(updated_parent_title)
307
+ expect(grandchild.reload.content).not_to eq(updated_grandchild_content)
308
+ expect(grandchild.num).not_to eq(updated_grandchild_num)
309
+ end
310
+ end
311
+
312
+ context 'when the grandchild is valid' do
313
+ let(:updated_grandchild_num) { 1 }
314
+
315
+ it 'will save the parent' do
316
+ expect(post.update(attributes)).to be_truthy
317
+ expect(post.errors).to be_empty
318
+ expect(post.reload.title).to eq(updated_parent_title)
319
+ expect(grandchild.reload.content).to eq(updated_grandchild_content)
320
+ expect(grandchild.num).to eq(updated_grandchild_num)
321
+ end
322
+ end
323
+ end
324
+ end
273
325
  end
@@ -96,3 +96,27 @@ class HmmAnimal
96
96
 
97
97
  belongs_to :trainer, class_name: 'HmmTrainer', scope: -> { where(name: 'Dave') }
98
98
  end
99
+
100
+ class HmmPost
101
+ include Mongoid::Document
102
+
103
+ field :title, type: String
104
+
105
+ has_many :comments, class_name: 'HmmComment', as: :container
106
+
107
+ accepts_nested_attributes_for :comments, allow_destroy: true
108
+ end
109
+
110
+ class HmmComment
111
+ include Mongoid::Document
112
+
113
+ field :title, type: String
114
+ field :num, type: Integer, default: 0
115
+
116
+ belongs_to :container, polymorphic: true
117
+ has_many :comments, class_name: 'HmmComment', as: :container
118
+
119
+ accepts_nested_attributes_for :comments, allow_destroy: true
120
+
121
+ validates :num, numericality: { greater_than_or_equal_to: 0 }
122
+ end
@@ -102,13 +102,21 @@ class HomPost
102
102
 
103
103
  field :title, type: String
104
104
 
105
- has_one :comment, inverse_of: :post, class_name: 'HomComment'
105
+ has_one :comment, as: :container, class_name: 'HomComment'
106
+
107
+ accepts_nested_attributes_for :comment, allow_destroy: true
106
108
  end
107
109
 
108
110
  class HomComment
109
111
  include Mongoid::Document
110
112
 
111
113
  field :content, type: String
114
+ field :num, type: Integer, default: 0
115
+
116
+ validates :num, numericality: { greater_than_or_equal_to: 0 }
117
+
118
+ belongs_to :container, polymorphic: true, optional: true
119
+ has_one :comment, as: :container, class_name: 'HomComment'
112
120
 
113
- belongs_to :post, inverse_of: :comment, optional: true, class_name: 'HomPost'
121
+ accepts_nested_attributes_for :comment, allow_destroy: true
114
122
  end
@@ -115,66 +115,6 @@ describe Mongoid::Association do
115
115
  expect(name).to_not be_an_embedded_many
116
116
  end
117
117
  end
118
-
119
- context "when validation depends on association" do
120
- before(:all) do
121
- class Author
122
- include Mongoid::Document
123
- embeds_many :books, cascade_callbacks: true
124
- field :condition, type: Boolean
125
- end
126
-
127
- class Book
128
- include Mongoid::Document
129
- embedded_in :author
130
- validate :parent_condition_is_not_true
131
-
132
- def parent_condition_is_not_true
133
- return unless author&.condition
134
- errors.add :base, "Author condition is true."
135
- end
136
- end
137
-
138
- Author.delete_all
139
- Book.delete_all
140
- end
141
-
142
- let(:author) { Author.new }
143
- let(:book) { Book.new }
144
-
145
- context "when author is not persisted" do
146
- it "is valid without books" do
147
- expect(author.valid?).to be true
148
- end
149
-
150
- it "is valid with a book" do
151
- author.books << book
152
- expect(author.valid?).to be true
153
- end
154
-
155
- it "is not valid when condition is true with a book" do
156
- author.condition = true
157
- author.books << book
158
- expect(author.valid?).to be false
159
- end
160
- end
161
-
162
- context "when author is persisted" do
163
- before do
164
- author.books << book
165
- author.save
166
- end
167
-
168
- it "remains valid initially" do
169
- expect(author.valid?).to be true
170
- end
171
-
172
- it "becomes invalid when condition is set to true" do
173
- author.update_attributes(condition: true)
174
- expect(author.valid?).to be false
175
- end
176
- end
177
- end
178
118
  end
179
119
 
180
120
  describe "#embedded_one?" do
@@ -716,7 +716,7 @@ describe Mongoid::Clients::Sessions do
716
716
  require_transaction_support
717
717
 
718
718
  context 'when no error raised' do
719
- before do
719
+ let!(:person) do
720
720
  Mongoid.transaction do
721
721
  Person.create!
722
722
  end
@@ -727,6 +727,10 @@ describe Mongoid::Clients::Sessions do
727
727
  expect(other_events.count { |e| e.command_name == 'commitTransaction'}).to be(1)
728
728
  end
729
729
 
730
+ it 'returns the value from the block' do
731
+ expect(person).to be_a(Person)
732
+ end
733
+
730
734
  it 'executes the commands inside the transaction' do
731
735
  expect(Person.count).to be(1)
732
736
  end
@@ -787,8 +791,12 @@ describe Mongoid::Clients::Sessions do
787
791
  Mongoid::Clients.with_name(:default).database.collections.each(&:drop)
788
792
  TransactionsSpecPerson.collection.create
789
793
  TransactionsSpecPersonWithOnCreate.collection.create
794
+ TransactionsSpecPersonWithAfterCreateCommit.collection.create
790
795
  TransactionsSpecPersonWithOnUpdate.collection.create
796
+ TransactionsSpecPersonWithAfterUpdateCommit.collection.create
797
+ TransactionsSpecPersonWithAfterSaveCommit.collection.create
791
798
  TransactionsSpecPersonWithOnDestroy.collection.create
799
+ TransactionsSpecPersonWithAfterDestroyCommit.collection.create
792
800
  TransactionSpecRaisesBeforeSave.collection.create
793
801
  TransactionSpecRaisesAfterSave.collection.create
794
802
  end
@@ -818,6 +826,18 @@ describe Mongoid::Clients::Sessions do
818
826
 
819
827
  it_behaves_like 'commit callbacks are called'
820
828
  end
829
+
830
+ context 'when callback is after_create_commit' do
831
+ let!(:subject) do
832
+ person = nil
833
+ TransactionsSpecPersonWithAfterCreateCommit.transaction do
834
+ person = TransactionsSpecPersonWithAfterCreateCommit.create!(name: 'James Bond')
835
+ end
836
+ person
837
+ end
838
+
839
+ it_behaves_like 'commit callbacks are called'
840
+ end
821
841
  end
822
842
 
823
843
  context 'save' do
@@ -886,6 +906,94 @@ describe Mongoid::Clients::Sessions do
886
906
  it_behaves_like 'commit callbacks are called'
887
907
  end
888
908
  end
909
+
910
+ context 'with after_update_commit callback' do
911
+ let(:subject) do
912
+ TransactionsSpecPersonWithAfterUpdateCommit.create!(name: 'James Bond').tap do |subject|
913
+ subject.after_commit_counter.reset
914
+ subject.after_rollback_counter.reset
915
+ end
916
+ end
917
+
918
+ context 'when modified once' do
919
+ before do
920
+ subject.transaction do
921
+ subject.name = 'Austin Powers'
922
+ subject.save!
923
+ end
924
+ end
925
+
926
+ it_behaves_like 'commit callbacks are called'
927
+ end
928
+
929
+ context 'when modified multiple times' do
930
+ before do
931
+ subject.transaction do
932
+ subject.name = 'Austin Powers'
933
+ subject.save!
934
+ subject.name = 'Jason Bourne'
935
+ subject.save!
936
+ end
937
+ end
938
+
939
+ it_behaves_like 'commit callbacks are called'
940
+ end
941
+ end
942
+
943
+ context 'with after_save_commit callback' do
944
+ let(:subject) do
945
+ TransactionsSpecPersonWithAfterSaveCommit.create!(name: 'James Bond').tap do |subject|
946
+ subject.after_commit_counter.reset
947
+ subject.after_rollback_counter.reset
948
+ end
949
+ end
950
+
951
+ context 'when modified once' do
952
+ before do
953
+ subject.transaction do
954
+ subject.name = 'Austin Powers'
955
+ subject.save!
956
+ end
957
+ end
958
+
959
+ it_behaves_like 'commit callbacks are called'
960
+ end
961
+
962
+ context 'when created' do
963
+ before do
964
+ TransactionsSpecPersonWithAfterSaveCommit.transaction do
965
+ subject
966
+ end
967
+ end
968
+
969
+ it_behaves_like 'commit callbacks are called'
970
+ end
971
+
972
+ context 'when modified multiple times' do
973
+ before do
974
+ subject.transaction do
975
+ subject.name = 'Austin Powers'
976
+ subject.save!
977
+ subject.name = 'Jason Bourne'
978
+ subject.save!
979
+ end
980
+ end
981
+
982
+ it_behaves_like 'commit callbacks are called'
983
+ end
984
+
985
+ context 'when created and modified' do
986
+ before do
987
+ TransactionsSpecPersonWithAfterSaveCommit.transaction do
988
+ subject
989
+ subject.name = 'Jason Bourne'
990
+ subject.save!
991
+ end
992
+ end
993
+
994
+ it_behaves_like 'commit callbacks are called'
995
+ end
996
+ end
889
997
  end
890
998
 
891
999
  context 'update_attributes' do
@@ -919,6 +1027,34 @@ describe Mongoid::Clients::Sessions do
919
1027
 
920
1028
  it_behaves_like 'commit callbacks are called'
921
1029
  end
1030
+
1031
+ context 'when callback is after_update_commit' do
1032
+ let(:subject) do
1033
+ TransactionsSpecPersonWithAfterUpdateCommit.create!(name: 'Jason Bourne')
1034
+ end
1035
+
1036
+ before do
1037
+ TransactionsSpecPersonWithAfterUpdateCommit.transaction do
1038
+ subject.update_attributes!(name: 'Foma Kiniaev')
1039
+ end
1040
+ end
1041
+
1042
+ it_behaves_like 'commit callbacks are called'
1043
+ end
1044
+
1045
+ context 'when callback is after_save_commit' do
1046
+ let(:subject) do
1047
+ TransactionsSpecPersonWithAfterSaveCommit.create!(name: 'Jason Bourne')
1048
+ end
1049
+
1050
+ before do
1051
+ TransactionsSpecPersonWithAfterSaveCommit.transaction do
1052
+ subject.update_attributes!(name: 'Foma Kiniaev')
1053
+ end
1054
+ end
1055
+
1056
+ it_behaves_like 'commit callbacks are called'
1057
+ end
922
1058
  end
923
1059
 
924
1060
  context 'destroy' do
@@ -971,6 +1107,31 @@ describe Mongoid::Clients::Sessions do
971
1107
 
972
1108
  it_behaves_like 'commit callbacks are called'
973
1109
  end
1110
+
1111
+ context 'with after_destroy_commit' do
1112
+ let(:after_commit_counter) do
1113
+ TransactionsSpecCounter.new
1114
+ end
1115
+
1116
+ let(:after_rollback_counter) do
1117
+ TransactionsSpecCounter.new
1118
+ end
1119
+
1120
+ let(:subject) do
1121
+ TransactionsSpecPersonWithAfterDestroyCommit.create!(name: 'James Bond').tap do |p|
1122
+ p.after_commit_counter = after_commit_counter
1123
+ p.after_rollback_counter = after_rollback_counter
1124
+ end
1125
+ end
1126
+
1127
+ before do
1128
+ subject.transaction do
1129
+ subject.destroy
1130
+ end
1131
+ end
1132
+
1133
+ it_behaves_like 'commit callbacks are called'
1134
+ end
974
1135
  end
975
1136
  end
976
1137
 
@@ -33,6 +33,38 @@ module TransactionsSpecCountable
33
33
  def after_rollback_counter=(new_counter)
34
34
  @after_rollback_counter = new_counter
35
35
  end
36
+
37
+ def after_save_commit_counter
38
+ @after_save_commit_counter ||= TransactionsSpecCounter.new
39
+ end
40
+
41
+ def after_save_commit_counter=(new_counter)
42
+ @after_save_commit_counter = new_counter
43
+ end
44
+
45
+ def after_create_commit_counter
46
+ @after_create_commit_counter ||= TransactionsSpecCounter.new
47
+ end
48
+
49
+ def after_create_commit_counter=(new_counter)
50
+ @after_create_commit_counter = new_counter
51
+ end
52
+
53
+ def after_update_commit_counter
54
+ @after_update_commit_counter ||= TransactionsSpecCounter.new
55
+ end
56
+
57
+ def after_update_commit_counter=(new_counter)
58
+ @after_update_commit_counter = new_counter
59
+ end
60
+
61
+ def after_destroy_commit_counter
62
+ @after_destroy_commit_counter ||= TransactionsSpecCounter.new
63
+ end
64
+
65
+ def after_destroy_commit_counter=(new_counter)
66
+ @after_destroy_commit_counter = new_counter
67
+ end
36
68
  end
37
69
 
38
70
  class TransactionsSpecPerson
@@ -65,6 +97,21 @@ class TransactionsSpecPersonWithOnCreate
65
97
  end
66
98
  end
67
99
 
100
+ class TransactionsSpecPersonWithAfterCreateCommit
101
+ include Mongoid::Document
102
+ include TransactionsSpecCountable
103
+
104
+ field :name, type: String
105
+
106
+ after_create_commit do
107
+ after_commit_counter.inc
108
+ end
109
+
110
+ after_rollback on: :create do
111
+ after_rollback_counter.inc
112
+ end
113
+ end
114
+
68
115
  class TransactionsSpecPersonWithOnUpdate
69
116
  include Mongoid::Document
70
117
  include TransactionsSpecCountable
@@ -80,6 +127,36 @@ class TransactionsSpecPersonWithOnUpdate
80
127
  end
81
128
  end
82
129
 
130
+ class TransactionsSpecPersonWithAfterUpdateCommit
131
+ include Mongoid::Document
132
+ include TransactionsSpecCountable
133
+
134
+ field :name, type: String
135
+
136
+ after_update_commit do
137
+ after_commit_counter.inc
138
+ end
139
+
140
+ after_rollback on: :create do
141
+ after_rollback_counter.inc
142
+ end
143
+ end
144
+
145
+ class TransactionsSpecPersonWithAfterSaveCommit
146
+ include Mongoid::Document
147
+ include TransactionsSpecCountable
148
+
149
+ field :name, type: String
150
+
151
+ after_save_commit do
152
+ after_commit_counter.inc
153
+ end
154
+
155
+ after_rollback on: :create do
156
+ after_rollback_counter.inc
157
+ end
158
+ end
159
+
83
160
  class TransactionsSpecPersonWithOnDestroy
84
161
  include Mongoid::Document
85
162
  include TransactionsSpecCountable
@@ -94,6 +171,22 @@ class TransactionsSpecPersonWithOnDestroy
94
171
  after_rollback_counter.inc
95
172
  end
96
173
  end
174
+
175
+ class TransactionsSpecPersonWithAfterDestroyCommit
176
+ include Mongoid::Document
177
+ include TransactionsSpecCountable
178
+
179
+ field :name, type: String
180
+
181
+ after_destroy_commit do
182
+ after_commit_counter.inc
183
+ end
184
+
185
+ after_rollback on: :create do
186
+ after_rollback_counter.inc
187
+ end
188
+ end
189
+
97
190
  class TransactionSpecRaisesBeforeSave
98
191
  include Mongoid::Document
99
192
  include TransactionsSpecCountable
@@ -244,6 +244,39 @@ describe Mongoid::Contextual::Aggregable::Mongo do
244
244
  end
245
245
  end
246
246
  end
247
+
248
+ context 'regarding hints' do
249
+ let(:client) { Person.collection.client }
250
+ let(:subscriber) { Mrss::EventSubscriber.new }
251
+
252
+ before do
253
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
254
+ maybe_hint.aggregates(:age)
255
+ end
256
+
257
+ after do
258
+ client.unsubscribe(Mongo::Monitoring::COMMAND, subscriber)
259
+ end
260
+
261
+ let(:event) { subscriber.single_command_started_event('aggregate') }
262
+ let(:command) { event.command }
263
+
264
+ context 'when no hint is provided' do
265
+ let(:maybe_hint) { Person }
266
+
267
+ it 'does not include the hint in the command' do
268
+ expect(command['hint']).to be_nil
269
+ end
270
+ end
271
+
272
+ context 'when a hint is provided' do
273
+ let(:maybe_hint) { Person.hint(age: 1) }
274
+
275
+ it 'includes the hint with the command' do
276
+ expect(command['hint']).to eq({ 'age' => 1 })
277
+ end
278
+ end
279
+ end
247
280
  end
248
281
 
249
282
  describe "#avg" do
@@ -3282,6 +3282,12 @@ describe Mongoid::Contextual::Mongo do
3282
3282
  it "limits the results" do
3283
3283
  expect(context.skip(1).entries).to eq([ new_order ])
3284
3284
  end
3285
+
3286
+ context "with #last" do
3287
+ it "returns the nth from last element" do
3288
+ expect(context.skip(1).last).to eq(depeche_mode)
3289
+ end
3290
+ end
3285
3291
  end
3286
3292
 
3287
3293
  describe "#sort" do
@@ -134,6 +134,16 @@ describe Mongoid::Reloadable do
134
134
 
135
135
  agent.title.should == '007'
136
136
  end
137
+
138
+ it 'sets new_record to false' do
139
+ expect(agent.new_record?).to be true
140
+
141
+ lambda do
142
+ agent.reload
143
+ end.should_not raise_error
144
+
145
+ expect(agent.new_record?).to be false
146
+ end
137
147
  end
138
148
  end
139
149
 
@@ -596,6 +606,20 @@ describe Mongoid::Reloadable do
596
606
  band.id.should_not == original_id
597
607
  end
598
608
  end
609
+
610
+ context 'when there is no document matching our id' do
611
+ let(:agent) { Agent.new(id: BSON::ObjectId.new) }
612
+
613
+ it 'does not set new_record to false' do
614
+ expect(agent.new_record?).to be true
615
+
616
+ lambda do
617
+ agent.reload
618
+ end.should_not raise_error
619
+
620
+ expect(agent.new_record?).to be true
621
+ end
622
+ end
599
623
  end
600
624
 
601
625
  context 'when document has referenced associations' do
@@ -29,5 +29,21 @@ describe ActiveModel::Validations::NumericalityValidator do
29
29
  expect(model).to_not be_valid
30
30
  end
31
31
  end
32
+
33
+ context 'when the value is numeric' do
34
+ let(:model) { TestModel.new(amount: '15.0') }
35
+
36
+ it 'returns true' do
37
+ expect(model).to be_valid
38
+ end
39
+ end
40
+
41
+ context 'when the value is a BSON::Decimal128' do
42
+ let(:model) { TestModel.new(amount: BSON::Decimal128.new('15.0')) }
43
+
44
+ it 'returns true' do
45
+ expect(model).to be_valid
46
+ end
47
+ end
32
48
  end
33
49
  end