mongo 2.3.1 → 2.4.0.rc0

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 (170) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -3
  4. data/lib/mongo/bulk_write.rb +8 -7
  5. data/lib/mongo/bulk_write/combineable.rb +4 -0
  6. data/lib/mongo/bulk_write/transformable.rb +17 -5
  7. data/lib/mongo/bulk_write/validatable.rb +1 -0
  8. data/lib/mongo/client.rb +3 -0
  9. data/lib/mongo/cluster.rb +8 -0
  10. data/lib/mongo/cluster/app_metadata.rb +135 -0
  11. data/lib/mongo/collection.rb +42 -10
  12. data/lib/mongo/collection/view.rb +15 -1
  13. data/lib/mongo/collection/view/aggregation.rb +5 -0
  14. data/lib/mongo/collection/view/builder/aggregation.rb +13 -3
  15. data/lib/mongo/collection/view/builder/find_command.rb +7 -21
  16. data/lib/mongo/collection/view/builder/map_reduce.rb +22 -5
  17. data/lib/mongo/collection/view/iterable.rb +1 -0
  18. data/lib/mongo/collection/view/map_reduce.rb +5 -0
  19. data/lib/mongo/collection/view/readable.rb +35 -14
  20. data/lib/mongo/collection/view/writable.rb +54 -23
  21. data/lib/mongo/cursor/builder/get_more_command.rb +2 -3
  22. data/lib/mongo/database.rb +10 -2
  23. data/lib/mongo/error.rb +2 -0
  24. data/lib/mongo/error/invalid_application_name.rb +38 -0
  25. data/lib/mongo/error/invalid_server_preference.rb +24 -3
  26. data/lib/mongo/error/unsupported_collation.rb +51 -0
  27. data/lib/mongo/index/view.rb +28 -15
  28. data/lib/mongo/operation.rb +6 -0
  29. data/lib/mongo/operation/commands.rb +3 -0
  30. data/lib/mongo/operation/commands/aggregate.rb +10 -10
  31. data/lib/mongo/operation/commands/create.rb +45 -0
  32. data/lib/mongo/operation/commands/drop.rb +45 -0
  33. data/lib/mongo/operation/commands/drop_database.rb +45 -0
  34. data/lib/mongo/operation/commands/map_reduce.rb +12 -1
  35. data/lib/mongo/operation/commands/parallel_scan.rb +1 -0
  36. data/lib/mongo/operation/read_preference.rb +9 -9
  37. data/lib/mongo/operation/specifiable.rb +34 -0
  38. data/lib/mongo/operation/takes_write_concern.rb +35 -0
  39. data/lib/mongo/operation/write/bulk/bulkable.rb +1 -1
  40. data/lib/mongo/operation/write/command/create_index.rb +6 -0
  41. data/lib/mongo/operation/write/command/drop_index.rb +6 -0
  42. data/lib/mongo/operation/write/command/insert.rb +1 -1
  43. data/lib/mongo/operation/write/command/update.rb +1 -0
  44. data/lib/mongo/operation/write/command/writable.rb +2 -2
  45. data/lib/mongo/operation/write/create_index.rb +2 -2
  46. data/lib/mongo/operation/write/create_user.rb +1 -1
  47. data/lib/mongo/operation/write/delete.rb +5 -1
  48. data/lib/mongo/operation/write/gle.rb +1 -1
  49. data/lib/mongo/operation/write/insert.rb +2 -2
  50. data/lib/mongo/operation/write/remove_user.rb +1 -1
  51. data/lib/mongo/operation/write/update.rb +5 -1
  52. data/lib/mongo/operation/write/update_user.rb +1 -1
  53. data/lib/mongo/operation/write/write_command_enabled.rb +10 -2
  54. data/lib/mongo/protocol/insert.rb +1 -2
  55. data/lib/mongo/protocol/query.rb +3 -7
  56. data/lib/mongo/server.rb +8 -3
  57. data/lib/mongo/server/connection.rb +17 -11
  58. data/lib/mongo/server/description.rb +22 -0
  59. data/lib/mongo/server/description/features.rb +2 -0
  60. data/lib/mongo/server/monitor.rb +5 -0
  61. data/lib/mongo/server/monitor/connection.rb +11 -0
  62. data/lib/mongo/server_selector/nearest.rb +9 -6
  63. data/lib/mongo/server_selector/primary.rb +4 -0
  64. data/lib/mongo/server_selector/primary_preferred.rb +7 -1
  65. data/lib/mongo/server_selector/secondary.rb +5 -0
  66. data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
  67. data/lib/mongo/server_selector/selectable.rb +57 -10
  68. data/lib/mongo/socket/ssl.rb +1 -0
  69. data/lib/mongo/uri.rb +4 -0
  70. data/lib/mongo/version.rb +1 -1
  71. data/lib/mongo/write_concern.rb +1 -0
  72. data/mongo.gemspec +1 -1
  73. data/spec/mongo/auth/cr_spec.rb +7 -1
  74. data/spec/mongo/auth/ldap_spec.rb +7 -1
  75. data/spec/mongo/auth/scram_spec.rb +7 -1
  76. data/spec/mongo/auth/x509_spec.rb +7 -1
  77. data/spec/mongo/bulk_write_spec.rb +598 -5
  78. data/spec/mongo/client_spec.rb +47 -1
  79. data/spec/mongo/cluster/app_metadata_spec.rb +104 -0
  80. data/spec/mongo/cluster/topology/replica_set_spec.rb +14 -8
  81. data/spec/mongo/cluster/topology/sharded_spec.rb +9 -3
  82. data/spec/mongo/cluster/topology/single_spec.rb +10 -4
  83. data/spec/mongo/cluster_spec.rb +29 -0
  84. data/spec/mongo/collection/view/aggregation_spec.rb +139 -0
  85. data/spec/mongo/collection/view/builder/find_command_spec.rb +6 -243
  86. data/spec/mongo/collection/view/map_reduce_spec.rb +104 -0
  87. data/spec/mongo/collection/view/readable_spec.rb +83 -0
  88. data/spec/mongo/collection/view/writable_spec.rb +447 -1
  89. data/spec/mongo/collection/view_spec.rb +57 -0
  90. data/spec/mongo/collection_spec.rb +926 -101
  91. data/spec/mongo/crud_spec.rb +4 -5
  92. data/spec/mongo/database_spec.rb +99 -1
  93. data/spec/mongo/index/view_spec.rb +360 -31
  94. data/spec/mongo/max_staleness_spec.rb +108 -0
  95. data/spec/mongo/operation/read_preference_spec.rb +8 -8
  96. data/spec/mongo/operation/write/command/delete_spec.rb +1 -1
  97. data/spec/mongo/operation/write/command/insert_spec.rb +1 -1
  98. data/spec/mongo/operation/write/command/update_spec.rb +1 -1
  99. data/spec/mongo/server/connection_pool_spec.rb +3 -1
  100. data/spec/mongo/server/connection_spec.rb +17 -7
  101. data/spec/mongo/server/description/features_spec.rb +50 -0
  102. data/spec/mongo/server/description_spec.rb +9 -3
  103. data/spec/mongo/server_selection_spec.rb +5 -3
  104. data/spec/mongo/server_selector/nearest_spec.rb +73 -0
  105. data/spec/mongo/server_selector/primary_preferred_spec.rb +73 -0
  106. data/spec/mongo/server_selector/primary_spec.rb +36 -0
  107. data/spec/mongo/server_selector/secondary_preferred_spec.rb +73 -0
  108. data/spec/mongo/server_selector/secondary_spec.rb +73 -0
  109. data/spec/mongo/server_selector_spec.rb +53 -0
  110. data/spec/mongo/server_spec.rb +3 -1
  111. data/spec/mongo/uri_spec.rb +54 -0
  112. data/spec/mongo/write_concern_spec.rb +18 -0
  113. data/spec/spec_helper.rb +10 -0
  114. data/spec/support/authorization.rb +8 -1
  115. data/spec/support/crud.rb +15 -0
  116. data/spec/support/crud/read.rb +27 -19
  117. data/spec/support/crud/write.rb +28 -3
  118. data/spec/support/crud_tests/read/aggregate.yml +15 -3
  119. data/spec/support/crud_tests/read/count.yml +14 -3
  120. data/spec/support/crud_tests/read/distinct.yml +13 -1
  121. data/spec/support/crud_tests/read/find.yml +12 -2
  122. data/spec/support/crud_tests/write/deleteMany.yml +22 -1
  123. data/spec/support/crud_tests/write/deleteOne.yml +20 -1
  124. data/spec/support/crud_tests/write/findOneAndDelete.yml +27 -2
  125. data/spec/support/crud_tests/write/findOneAndReplace.yml +43 -14
  126. data/spec/support/crud_tests/write/findOneAndUpdate.yml +50 -8
  127. data/spec/support/crud_tests/write/replaceOne.yml +34 -10
  128. data/spec/support/crud_tests/write/updateMany.yml +42 -11
  129. data/spec/support/crud_tests/write/updateOne.yml +32 -7
  130. data/spec/support/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +26 -0
  131. data/spec/support/max_staleness/ReplicaSetNoPrimary/Incompatible.yml +25 -0
  132. data/spec/support/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +33 -0
  133. data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest.yml +33 -0
  134. data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +33 -0
  135. data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +27 -0
  136. data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +36 -0
  137. data/spec/support/max_staleness/ReplicaSetNoPrimary/Secondary.yml +51 -0
  138. data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +26 -0
  139. data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +51 -0
  140. data/spec/support/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +26 -0
  141. data/spec/support/max_staleness/ReplicaSetWithPrimary/Incompatible.yml +25 -0
  142. data/spec/support/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +35 -0
  143. data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +25 -0
  144. data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +23 -0
  145. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest.yml +33 -0
  146. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +33 -0
  147. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +36 -0
  148. data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +27 -0
  149. data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred_incompatible.yml +27 -0
  150. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +26 -0
  151. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +59 -0
  152. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +43 -0
  153. data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +59 -0
  154. data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +43 -0
  155. data/spec/support/max_staleness/ReplicaSetWithPrimary/ShortHeartbeartShortMaxStaleness.yml +29 -0
  156. data/spec/support/max_staleness/ReplicaSetWithPrimary/ShortHeartbeartShortMaxStaleness2.yml +29 -0
  157. data/spec/support/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +27 -0
  158. data/spec/support/max_staleness/Sharded/Incompatible.yml +25 -0
  159. data/spec/support/max_staleness/Sharded/SmallMaxStaleness.yml +20 -0
  160. data/spec/support/max_staleness/Single/Incompatible.yml +18 -0
  161. data/spec/support/max_staleness/Single/SmallMaxStaleness.yml +20 -0
  162. data/spec/support/server_selection.rb +25 -0
  163. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest_multiple.yml +27 -0
  164. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_multi_tags.yml +31 -0
  165. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_multi_tags2.yml +31 -0
  166. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest_multiple.yml +34 -0
  167. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/SecondaryPreferred_tags.yml +28 -0
  168. data/spec/support/shared/server_selector.rb +4 -3
  169. metadata +91 -6
  170. metadata.gz.sig +0 -0
@@ -48,7 +48,8 @@ describe Mongo::Collection::View::Builder::FindCommand do
48
48
  no_cursor_timeout: true,
49
49
  await_data: true,
50
50
  allow_partial_results: true,
51
- read_concern: { level: 'local' }
51
+ read_concern: { level: 'local' },
52
+ collation: { locale: 'en_US' }
52
53
  }
53
54
  end
54
55
 
@@ -143,258 +144,20 @@ describe Mongo::Collection::View::Builder::FindCommand do
143
144
  it 'maps allow partial results' do
144
145
  expect(selector['allowPartialResults']).to be true
145
146
  end
146
- end
147
-
148
-
149
- context 'when there is a limit' do
150
-
151
- let(:filter) do
152
- { 'name' => 'test' }
153
- end
154
-
155
- context 'when limit is 0' do
156
-
157
- context 'when batch_size is also 0' do
158
-
159
- let(:options) do
160
- { limit: 0, batch_size: 0 }
161
- end
162
-
163
- it 'does not set the singleBatch' do
164
- expect(selector['singleBatch']).to be nil
165
- end
166
-
167
- it 'does not set the limit' do
168
- expect(selector['limit']).to be nil
169
- end
170
-
171
- it 'does not set the batch size' do
172
- expect(selector['batchSize']).to be nil
173
- end
174
- end
175
-
176
- context 'when batch_size is not set' do
177
-
178
- let(:options) do
179
- { limit: 0 }
180
- end
181
-
182
- it 'does not set the singleBatch' do
183
- expect(selector['singleBatch']).to be nil
184
- end
185
-
186
- it 'does not set the limit' do
187
- expect(selector['limit']).to be nil
188
- end
189
-
190
- it 'does not set the batch size' do
191
- expect(selector['batchSize']).to be nil
192
- end
193
- end
194
- end
195
-
196
- context 'when the limit is negative' do
197
-
198
- context 'when there is a batch_size' do
199
-
200
- context 'when the batch_size is positive' do
201
-
202
- let(:options) do
203
- { limit: -1, batch_size: 3 }
204
- end
205
-
206
- it 'sets single batch to true' do
207
- expect(selector['singleBatch']).to be true
208
- end
209
-
210
- it 'converts the limit to a positive value' do
211
- expect(selector['limit']).to be(options[:limit].abs)
212
- end
213
-
214
- it 'sets the batch size' do
215
- expect(selector['batchSize']).to be(options[:batch_size])
216
- end
217
- end
218
-
219
- context 'when the batch_size is negative' do
220
-
221
- let(:options) do
222
- { limit: -1, batch_size: -3 }
223
- end
224
-
225
- it 'sets single batch to true' do
226
- expect(selector['singleBatch']).to be true
227
- end
228
-
229
- it 'converts the limit to a positive value' do
230
- expect(selector['limit']).to be(options[:limit].abs)
231
- end
232
-
233
- it 'sets the batch size to the limit' do
234
- expect(selector['batchSize']).to be(options[:limit].abs)
235
- end
236
- end
237
- end
238
-
239
- context 'when there is not a batch_size' do
240
-
241
- let(:options) do
242
- { limit: -5 }
243
- end
244
-
245
- it 'sets single batch to true' do
246
- expect(selector['singleBatch']).to be true
247
- end
248
-
249
- it 'converts the limit to a positive value' do
250
- expect(selector['limit']).to be(options[:limit].abs)
251
- end
252
-
253
- it 'does not set the batch size' do
254
- expect(selector['batchSize']).to be_nil
255
- end
256
- end
257
- end
258
-
259
- context 'when the limit is positive' do
260
-
261
- context 'when there is a batch_size' do
262
147
 
263
- context 'when the batch_size is positive' do
264
-
265
- let(:options) do
266
- { limit: 5, batch_size: 3 }
267
- end
268
-
269
- it 'does not set singleBatch' do
270
- expect(selector['singleBatch']).to be nil
271
- end
272
-
273
- it 'sets the limit' do
274
- expect(selector['limit']).to be(options[:limit])
275
- end
276
-
277
- it 'sets the batch size' do
278
- expect(selector['batchSize']).to be(options[:batch_size])
279
- end
280
- end
281
-
282
- context 'when the batch_size is negative' do
283
-
284
- let(:options) do
285
- { limit: 5, batch_size: -3 }
286
- end
287
-
288
- it 'sets the singleBatch' do
289
- expect(selector['singleBatch']).to be true
290
- end
291
-
292
- it 'sets the limit' do
293
- expect(selector['limit']).to be(options[:limit])
294
- end
295
-
296
- it 'sets the batch size to a positive value' do
297
- expect(selector['batchSize']).to be(options[:batch_size].abs)
298
- end
299
- end
300
- end
301
-
302
- context 'when there is not a batch_size' do
303
-
304
- let(:options) do
305
- { limit: 5 }
306
- end
307
-
308
- it 'does not set the singleBatch' do
309
- expect(selector['singleBatch']).to be nil
310
- end
311
-
312
- it 'sets the limit' do
313
- expect(selector['limit']).to be(options[:limit])
314
- end
315
-
316
- it 'does not set the batch size' do
317
- expect(selector['batchSize']).to be nil
318
- end
319
- end
320
- end
321
- end
322
-
323
- context 'when there is a batch_size' do
324
-
325
- let(:filter) do
326
- { 'name' => 'test' }
327
- end
328
-
329
- context 'when there is no limit' do
330
-
331
- context 'when the batch_size is positive' do
332
-
333
- let(:options) do
334
- { batch_size: 3 }
335
- end
336
-
337
- it 'does not set the singleBatch' do
338
- expect(selector['singleBatch']).to be nil
339
- end
340
-
341
- it 'does not set the limit' do
342
- expect(selector['limit']).to be nil
343
- end
344
-
345
- it 'sets the batch size' do
346
- expect(selector['batchSize']).to be(options[:batch_size])
347
- end
348
- end
349
-
350
- context 'when the batch_size is negative' do
351
-
352
- let(:options) do
353
- { batch_size: -3 }
354
- end
355
-
356
- it 'sets the singleBatch' do
357
- expect(selector['singleBatch']).to be true
358
- end
359
-
360
- it 'does not set the limit' do
361
- expect(selector['limit']).to be nil
362
- end
363
-
364
- it 'sets the batch size to a positive value' do
365
- expect(selector['batchSize']).to be(options[:batch_size].abs)
366
- end
367
- end
368
-
369
- context 'when batch_size is 0' do
370
-
371
- let(:options) do
372
- { batch_size: 0 }
373
- end
374
-
375
- it 'does not set the singleBatch' do
376
- expect(selector['singleBatch']).to be nil
377
- end
378
-
379
- it 'does not set the limit' do
380
- expect(selector['limit']).to be nil
381
- end
382
-
383
- it 'does not set the batch size' do
384
- expect(selector['batchSize']).to be nil
385
- end
386
- end
148
+ it 'maps collation' do
149
+ expect(selector['collation']).to eq('locale' => 'en_US')
387
150
  end
388
151
  end
389
152
 
390
- context 'when limit and batch_size are negative' do
153
+ context 'when limit is negative' do
391
154
 
392
155
  let(:filter) do
393
156
  { 'name' => 'test' }
394
157
  end
395
158
 
396
159
  let(:options) do
397
- { limit: -1, batch_size: -3 }
160
+ { limit: -1 }
398
161
  end
399
162
 
400
163
  it 'sets single batch to true' do
@@ -335,6 +335,65 @@ describe Mongo::Collection::View::MapReduce do
335
335
  expect(Mongo::Logger.logger).to receive(:warn?).and_call_original
336
336
  map_reduce.to_a
337
337
  end
338
+
339
+ context 'when the view has a write concern' do
340
+
341
+ let(:collection) do
342
+ authorized_collection.with(write: { w: WRITE_CONCERN[:w]+1 })
343
+ end
344
+
345
+ let(:view) do
346
+ Mongo::Collection::View.new(collection, selector, view_options)
347
+ end
348
+
349
+ shared_examples_for 'map reduce that writes accepting write concern' do
350
+
351
+ context 'when the server supports write concern on the mapReduce command', if: (collation_enabled? && standalone?) do
352
+
353
+ it 'uses the write concern' do
354
+ expect {
355
+ map_reduce.to_a
356
+ }.to raise_exception(Mongo::Error::OperationFailure)
357
+ end
358
+ end
359
+
360
+ context 'when the server does not support write concern on the mapReduce command', unless: collation_enabled? do
361
+
362
+ it 'does not apply the write concern' do
363
+ expect(map_reduce.to_a.size).to eq(2)
364
+ end
365
+ end
366
+ end
367
+
368
+ context 'when out is a String' do
369
+
370
+ let(:options) do
371
+ { :out => 'new-collection' }
372
+ end
373
+
374
+ it_behaves_like 'map reduce that writes accepting write concern'
375
+ end
376
+
377
+ context 'when out is a document and not inline' do
378
+
379
+ let(:options) do
380
+ { :out => { merge: 'exisiting-collection' } }
381
+ end
382
+
383
+ it_behaves_like 'map reduce that writes accepting write concern'
384
+ end
385
+
386
+ context 'when out is a document but inline is specified' do
387
+
388
+ let(:options) do
389
+ { :out => { inline: 1 } }
390
+ end
391
+
392
+ it 'does not use the write concern' do
393
+ expect(map_reduce.to_a.size).to eq(2)
394
+ end
395
+ end
396
+ end
338
397
  end
339
398
 
340
399
  context 'when the server is a valid for writing' do
@@ -426,4 +485,49 @@ describe Mongo::Collection::View::MapReduce do
426
485
  expect(map_reduce.send(:map_reduce_spec)[:read]).to eq(read_preference)
427
486
  end
428
487
  end
488
+
489
+ context 'when collation is specified' do
490
+
491
+ let(:map) do
492
+ %Q{
493
+ function() {
494
+ emit(this.name, 1);
495
+ }}
496
+ end
497
+
498
+ let(:reduce) do
499
+ %Q{
500
+ function(key, values) {
501
+ return Array.sum(values);
502
+ }}
503
+ end
504
+
505
+ before do
506
+ authorized_collection.insert_many([ { name: 'bang' }, { name: 'bang' }])
507
+ end
508
+
509
+ let(:options) do
510
+ { collation: { locale: 'en_US', strength: 2 } }
511
+ end
512
+
513
+ let(:selector) do
514
+ { name: 'BANG' }
515
+ end
516
+
517
+ context 'when the server selected supports collations', if: collation_enabled? do
518
+
519
+ it 'applies the collation' do
520
+ expect(map_reduce.first['value']).to eq(2)
521
+ end
522
+ end
523
+
524
+ context 'when the server selected does not support collations', unless: collation_enabled? do
525
+
526
+ it 'raises an exception' do
527
+ expect {
528
+ map_reduce.to_a
529
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
530
+ end
531
+ end
532
+ end
429
533
  end
@@ -405,6 +405,41 @@ describe Mongo::Collection::View::Readable do
405
405
  it 'sets the max_time_ms option on the command', if: write_command_enabled? do
406
406
  expect(view.count(max_time_ms: 100)).to eq(10)
407
407
  end
408
+
409
+ context 'when a collation is specified' do
410
+
411
+ let(:selector) do
412
+ { name: 'BANG' }
413
+ end
414
+
415
+ let(:result) do
416
+ view.count(count_options)
417
+ end
418
+
419
+ before do
420
+ authorized_collection.insert_one(name: 'bang')
421
+ end
422
+
423
+ let(:count_options) do
424
+ { collation: { locale: 'en_US', strength: 2 } }
425
+ end
426
+
427
+ context 'when the server selected supports collations', if: collation_enabled? do
428
+
429
+ it 'applies the collation to the count' do
430
+ expect(result).to eq(1)
431
+ end
432
+ end
433
+
434
+ context 'when the server selected does not support collations', unless: collation_enabled? do
435
+
436
+ it 'raises an exception' do
437
+ expect {
438
+ result
439
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
440
+ end
441
+ end
442
+ end
408
443
  end
409
444
 
410
445
  describe '#distinct' do
@@ -648,6 +683,54 @@ describe Mongo::Collection::View::Readable do
648
683
  expect(view.distinct(:nofieldexists)).to be_empty
649
684
  end
650
685
  end
686
+
687
+ context 'when a collation is specified' do
688
+
689
+ let(:result) do
690
+ view.distinct(:name, distinct_options)
691
+ end
692
+
693
+ before do
694
+ authorized_collection.insert_one(name: 'bang')
695
+ authorized_collection.insert_one(name: 'BANG')
696
+ end
697
+
698
+ let(:distinct_options) do
699
+ { collation: { locale: 'en_US', strength: 2 } }
700
+ end
701
+
702
+ context 'when the server selected supports collations', if: collation_enabled? do
703
+
704
+ it 'applies the collation to the distinct' do
705
+ expect(result).to eq(['bang'])
706
+ end
707
+ end
708
+
709
+ context 'when the server selected does not support collations', unless: collation_enabled? do
710
+
711
+ it 'raises an exception' do
712
+ expect {
713
+ result
714
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
715
+ end
716
+ end
717
+ end
718
+
719
+ context 'when a collation is not specified' do
720
+
721
+ let(:result) do
722
+ view.distinct(:name)
723
+ end
724
+
725
+ before do
726
+ authorized_collection.insert_one(name: 'bang')
727
+ authorized_collection.insert_one(name: 'BANG')
728
+ end
729
+
730
+ it 'does not apply the collation to the distinct' do
731
+ expect(result).to eq(['bang', 'BANG'])
732
+ end
733
+ end
651
734
  end
652
735
 
653
736
  describe '#hint' do