mongo 2.16.0 → 2.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +1 -1
  4. data/lib/mongo/auth/aws/request.rb +0 -1
  5. data/lib/mongo/client.rb +4 -0
  6. data/lib/mongo/collection/view/aggregation.rb +62 -17
  7. data/lib/mongo/collection/view/builder/aggregation.rb +11 -13
  8. data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
  9. data/lib/mongo/collection/view/change_stream.rb +7 -3
  10. data/lib/mongo/collection/view/iterable.rb +2 -3
  11. data/lib/mongo/collection/view/map_reduce.rb +2 -0
  12. data/lib/mongo/collection/view/readable.rb +24 -1
  13. data/lib/mongo/collection/view/writable.rb +23 -0
  14. data/lib/mongo/collection.rb +21 -1
  15. data/lib/mongo/database/view.rb +4 -2
  16. data/lib/mongo/database.rb +6 -6
  17. data/lib/mongo/error/snapshot_session_invalid_server_version.rb +31 -0
  18. data/lib/mongo/error/snapshot_session_transaction_prohibited.rb +30 -0
  19. data/lib/mongo/error.rb +2 -0
  20. data/lib/mongo/operation/delete/op_msg.rb +2 -1
  21. data/lib/mongo/operation/find/builder/command.rb +1 -0
  22. data/lib/mongo/operation/result.rb +6 -0
  23. data/lib/mongo/operation/shared/executable.rb +4 -0
  24. data/lib/mongo/operation/shared/sessions_supported.rb +18 -2
  25. data/lib/mongo/operation/update/op_msg.rb +2 -1
  26. data/lib/mongo/server/description/features.rb +3 -1
  27. data/lib/mongo/server/push_monitor.rb +4 -1
  28. data/lib/mongo/server_selector/base.rb +26 -4
  29. data/lib/mongo/session.rb +19 -0
  30. data/lib/mongo/socket/ocsp_cache.rb +2 -3
  31. data/lib/mongo/socket.rb +1 -5
  32. data/lib/mongo/utils.rb +0 -6
  33. data/lib/mongo/version.rb +1 -1
  34. data/mongo.gemspec +1 -1
  35. data/spec/integration/read_preference_spec.rb +16 -12
  36. data/spec/mongo/collection/view/aggregation_spec.rb +71 -95
  37. data/spec/mongo/collection/view/change_stream_spec.rb +1 -1
  38. data/spec/mongo/collection/view/map_reduce_spec.rb +14 -1
  39. data/spec/mongo/operation/read_preference_op_msg_spec.rb +24 -1
  40. data/spec/mongo/server/monitor/connection_spec.rb +22 -0
  41. data/spec/mongo/server/push_monitor_spec.rb +101 -0
  42. data/spec/mongo/server_selector_spec.rb +136 -15
  43. data/spec/mongo/socket/ssl_spec.rb +26 -58
  44. data/spec/mongo/utils_spec.rb +0 -14
  45. data/spec/runners/crud/verifier.rb +1 -2
  46. data/spec/runners/unified/assertions.rb +3 -1
  47. data/spec/runners/unified/crud_operations.rb +77 -23
  48. data/spec/runners/unified/ddl_operations.rb +29 -1
  49. data/spec/runners/unified/entity_map.rb +3 -3
  50. data/spec/runners/unified/support_operations.rb +6 -1
  51. data/spec/runners/unified/test.rb +15 -3
  52. data/spec/spec_tests/data/crud_unified/aggregate-let.yml +138 -0
  53. data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +155 -0
  54. data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +151 -0
  55. data/spec/spec_tests/data/crud_unified/deleteMany-let.yml +91 -0
  56. data/spec/spec_tests/data/crud_unified/deleteOne-let.yml +89 -0
  57. data/spec/spec_tests/data/crud_unified/find-let.yml +71 -0
  58. data/spec/spec_tests/data/crud_unified/findOneAndDelete-let.yml +88 -0
  59. data/spec/spec_tests/data/crud_unified/findOneAndReplace-let.yml +94 -0
  60. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-let.yml +96 -0
  61. data/spec/spec_tests/data/crud_unified/updateMany-let.yml +103 -0
  62. data/spec/spec_tests/data/crud_unified/updateOne-let.yml +98 -0
  63. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +2 -2
  64. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +3 -3
  65. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest.yml +3 -3
  66. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +3 -3
  67. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +2 -2
  68. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +2 -2
  69. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Secondary.yml +4 -4
  70. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +2 -2
  71. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +4 -4
  72. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/ZeroMaxStaleness.yml +2 -2
  73. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +2 -2
  74. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +3 -3
  75. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat.yml +2 -2
  76. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat2.yml +2 -2
  77. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +2 -2
  78. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +2 -2
  79. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest.yml +3 -3
  80. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +3 -3
  81. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +2 -2
  82. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +2 -2
  83. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +2 -2
  84. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +5 -5
  85. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +3 -3
  86. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +5 -5
  87. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +3 -3
  88. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +2 -2
  89. data/spec/spec_tests/data/max_staleness/Sharded/SmallMaxStaleness.yml +2 -2
  90. data/spec/spec_tests/data/max_staleness/Single/SmallMaxStaleness.yml +1 -1
  91. data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -1
  92. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-client-error.yml +69 -0
  93. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-server-error.yml +102 -0
  94. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-unsupported-ops.yml +258 -0
  95. data/spec/spec_tests/data/sessions_unified/snapshot-sessions.yml +482 -0
  96. data/spec/spec_tests/sessions_unified_spec.rb +13 -0
  97. data.tar.gz.sig +0 -0
  98. metadata +1076 -1040
  99. metadata.gz.sig +2 -2
@@ -136,6 +136,28 @@ describe Mongo::Server::Monitor::Connection do
136
136
  end
137
137
  end
138
138
 
139
+ describe '#connect!' do
140
+
141
+ let(:options) do
142
+ SpecConfig.instance.test_options.merge(
143
+ app_metadata: monitor_app_metadata,
144
+ )
145
+ end
146
+
147
+ context 'when address resolution fails' do
148
+ let(:connection) { described_class.new(server.address, options) }
149
+
150
+ it 'propagates the exception' do
151
+ connection
152
+
153
+ expect(Socket).to receive(:getaddrinfo).and_raise(SocketError.new('Test exception'))
154
+ lambda do
155
+ connection.connect!
156
+ end.should raise_error(SocketError, 'Test exception')
157
+ end
158
+ end
159
+ end
160
+
139
161
  describe '#check_document' do
140
162
  context 'with API version' do
141
163
  let(:meta) do
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Mongo::Server::PushMonitor do
7
+ before(:all) do
8
+ ClientRegistry.instance.close_all_clients
9
+ end
10
+
11
+ let(:address) do
12
+ default_address
13
+ end
14
+
15
+ let(:listeners) do
16
+ Mongo::Event::Listeners.new
17
+ end
18
+
19
+ let(:monitor_options) do
20
+ {}
21
+ end
22
+
23
+ let(:monitor_app_metadata) do
24
+ Mongo::Server::Monitor::AppMetadata.new(
25
+ server_api: SpecConfig.instance.ruby_options[:server_api],
26
+ )
27
+ end
28
+
29
+ let(:cluster) do
30
+ double('cluster').tap do |cluster|
31
+ allow(cluster).to receive(:run_sdam_flow)
32
+ allow(cluster).to receive(:heartbeat_interval).and_return(1000)
33
+ end
34
+ end
35
+
36
+ let(:server) do
37
+ Mongo::Server.new(address, cluster, Mongo::Monitoring.new, listeners,
38
+ monitoring_io: false)
39
+ end
40
+
41
+ let(:monitor) do
42
+ register_background_thread_object(
43
+ Mongo::Server::Monitor.new(server, listeners, Mongo::Monitoring.new,
44
+ SpecConfig.instance.test_options.merge(cluster: cluster).merge(monitor_options).update(
45
+ app_metadata: monitor_app_metadata,
46
+ push_monitor_app_metadata: monitor_app_metadata))
47
+ )
48
+ end
49
+
50
+ let(:topology_version) do
51
+ Mongo::TopologyVersion.new('processId' => BSON::ObjectId.new, 'counter' => 1)
52
+ end
53
+
54
+ let(:check_document) do
55
+ {hello: 1}
56
+ end
57
+
58
+ let(:push_monitor) do
59
+ described_class.new(monitor, topology_version, monitor.monitoring,
60
+ **monitor.options.merge(check_document: check_document))
61
+ end
62
+
63
+ describe '#do_work' do
64
+ it 'works' do
65
+ lambda do
66
+ push_monitor.do_work
67
+ end.should_not raise_error
68
+ end
69
+
70
+ context 'network error during check' do
71
+ it 'does not propagate the exception' do
72
+ push_monitor
73
+
74
+ expect(Socket).to receive(:getaddrinfo).and_raise(SocketError.new('Test exception'))
75
+ lambda do
76
+ push_monitor.do_work
77
+ end.should_not raise_error
78
+ end
79
+
80
+ it 'throttles checks' do
81
+ push_monitor
82
+
83
+ start = Mongo::Utils.monotonic_time
84
+
85
+ expect(Socket).to receive(:getaddrinfo).and_raise(SocketError.new('Test exception'))
86
+ lambda do
87
+ push_monitor.do_work
88
+ end.should_not raise_error
89
+
90
+ expect(Socket).to receive(:getaddrinfo).and_raise(SocketError.new('Test exception'))
91
+ lambda do
92
+ push_monitor.do_work
93
+ end.should_not raise_error
94
+
95
+ elapsed = Mongo::Utils.monotonic_time - start
96
+ elapsed.should > 0.5
97
+ end
98
+ end
99
+ end
100
+
101
+ end
@@ -202,12 +202,7 @@ describe Mongo::ServerSelector do
202
202
  describe "#select_server" do
203
203
  require_no_linting
204
204
 
205
- context 'when #select_in_replica_set returns a list of nils' do
206
-
207
- let(:servers) do
208
- [ make_server(:primary) ]
209
- end
210
-
205
+ context 'replica set topology' do
211
206
  let(:cluster) do
212
207
  double('cluster').tap do |c|
213
208
  allow(c).to receive(:connected?).and_return(true)
@@ -223,19 +218,141 @@ describe Mongo::ServerSelector do
223
218
  allow(c).to receive(:scan!).and_return(true)
224
219
  allow(c).to receive(:options).and_return(server_selection_timeout: 0.1)
225
220
  allow(c).to receive(:server_selection_semaphore).and_return(nil)
221
+ allow(topology).to receive(:compatible?).and_return(true)
226
222
  end
227
223
  end
228
224
 
229
- let(:read_pref) do
230
- described_class.get(mode: :primary).tap do |pref|
231
- allow(pref).to receive(:select_in_replica_set).and_return([ nil, nil ])
225
+ let(:primary) do
226
+ make_server(:primary).tap do |server|
227
+ allow(server).to receive(:features).and_return(double("primary features"))
232
228
  end
233
229
  end
234
230
 
235
- it 'raises a NoServerAvailable error' do
236
- expect do
237
- read_pref.select_server(cluster)
238
- end.to raise_exception(Mongo::Error::NoServerAvailable)
231
+ let(:secondary) do
232
+ make_server(:secondary).tap do |server|
233
+ allow(server).to receive(:features).and_return(double("secondary features"))
234
+ end
235
+ end
236
+
237
+ context "when #select_in_replica_set returns a list of nils" do
238
+ let(:servers) do
239
+ [ primary ]
240
+ end
241
+
242
+ let(:read_pref) do
243
+ described_class.get(mode: :primary).tap do |pref|
244
+ allow(pref).to receive(:select_in_replica_set).and_return([ nil, nil ])
245
+ end
246
+ end
247
+
248
+ it 'raises a NoServerAvailable error' do
249
+ expect do
250
+ read_pref.select_server(cluster)
251
+ end.to raise_exception(Mongo::Error::NoServerAvailable)
252
+ end
253
+ end
254
+
255
+ context "write_aggregation is true" do
256
+
257
+ before do
258
+ # It does not matter for this context whether primary supports secondary wites or not,
259
+ # but we need to mock out this call.
260
+ allow(primary.features).to receive(:merge_out_on_secondary_enabled?).and_return(false)
261
+ end
262
+
263
+ context "read preference is primary" do
264
+ let(:selector) { Mongo::ServerSelector::Primary.new }
265
+
266
+ let(:servers) do
267
+ [ primary, secondary ]
268
+ end
269
+
270
+ [true, false].each do |secondary_support_writes|
271
+ context "secondary #{secondary_support_writes ? 'supports' : 'does not support' } writes" do
272
+ it "selects a primary" do
273
+ allow(secondary.features).to receive(:merge_out_on_secondary_enabled?).and_return(secondary_support_writes)
274
+
275
+ expect(selector.select_server(cluster, write_aggregation: true)).to eq(primary)
276
+ end
277
+ end
278
+ end
279
+ end
280
+
281
+ context "read preference is primary preferred" do
282
+ let(:selector) { Mongo::ServerSelector::PrimaryPreferred.new }
283
+
284
+ let(:servers) do
285
+ [ primary, secondary ]
286
+ end
287
+
288
+ [true, false].each do |secondary_support_writes|
289
+ context "secondary #{secondary_support_writes ? 'supports' : 'does not support' } writes" do
290
+ it "selects a primary" do
291
+ allow(secondary.features).to receive(:merge_out_on_secondary_enabled?).and_return(secondary_support_writes)
292
+
293
+ expect(selector.select_server(cluster, write_aggregation: true)).to eq(primary)
294
+ end
295
+ end
296
+ end
297
+ end
298
+
299
+ context "read preference is secondary preferred" do
300
+ let(:selector) { Mongo::ServerSelector::SecondaryPreferred.new }
301
+
302
+ let(:servers) do
303
+ [ primary, secondary ]
304
+ end
305
+
306
+ context "secondary supports writes" do
307
+ it "selects a secondary" do
308
+ allow(secondary.features).to receive(:merge_out_on_secondary_enabled?).and_return(true)
309
+
310
+ expect(selector.select_server(cluster, write_aggregation: true)).to eq(secondary)
311
+ end
312
+ end
313
+
314
+ context "secondary does not support writes" do
315
+ it "selects a primary" do
316
+ allow(secondary.features).to receive(:merge_out_on_secondary_enabled?).and_return(false)
317
+
318
+ expect(selector.select_server(cluster, write_aggregation: true)).to eq(primary)
319
+ end
320
+ end
321
+ end
322
+
323
+ context "read preference is secondary" do
324
+ let(:selector) { Mongo::ServerSelector::Secondary.new }
325
+
326
+ let(:servers) do
327
+ [ primary, secondary ]
328
+ end
329
+
330
+ context "secondary supports writes" do
331
+ it "selects a secondary" do
332
+ allow(secondary.features).to receive(:merge_out_on_secondary_enabled?).and_return(true)
333
+
334
+ expect(selector.select_server(cluster, write_aggregation: true)).to eq(secondary)
335
+ end
336
+ end
337
+
338
+ context "secondary does not support writes" do
339
+ it "selects a primary" do
340
+ allow(secondary.features).to receive(:merge_out_on_secondary_enabled?).and_return(false)
341
+
342
+ expect(selector.select_server(cluster, write_aggregation: true)).to eq(primary)
343
+ end
344
+ end
345
+
346
+ context "no secondaries in cluster" do
347
+ let(:servers) do
348
+ [ primary ]
349
+ end
350
+
351
+ it "selects a primary" do
352
+ expect(selector.select_server(cluster, write_aggregation: true)).to eq(primary)
353
+ end
354
+ end
355
+ end
239
356
  end
240
357
  end
241
358
 
@@ -381,8 +498,12 @@ describe Mongo::ServerSelector do
381
498
  let(:servers) { [unknown, mongos] }
382
499
  let(:selector) { described_class.primary }
383
500
 
384
- it 'returns the mongos' do
385
- expect(selector.select_server(cluster)).to eq(mongos)
501
+ [true, false].each do |write_aggregation|
502
+ context "write_aggregation is #{write_aggregation}" do
503
+ it 'returns the mongos' do
504
+ expect(selector.select_server(cluster, write_aggregation: write_aggregation)).to eq(mongos)
505
+ end
506
+ end
386
507
  end
387
508
  end
388
509
  end
@@ -306,67 +306,40 @@ describe Mongo::Socket::SSL, retry: 3 do
306
306
  end
307
307
  end
308
308
 
309
- context 'when ruby version is < 2.4.1' do
310
- ruby_version_lt '2.4.1'
311
-
312
- context 'when a key is passed, but it is not of the right type' do
313
-
314
- let(:ssl_options) do
315
- key = "This is a string not a key"
316
- {
317
- :ssl => true,
318
- :ssl_key_object => key,
319
- :ssl_cert => SpecConfig.instance.client_cert_path,
320
- :ssl_verify => false
321
- }
322
- end
323
-
324
- it 'raises a TypeError' do
325
- expect do
326
- socket
327
- end.to raise_exception(TypeError)
328
- end
329
- end
330
- end
331
-
332
309
  # Note that as of MRI 2.4, Creating a socket with the wrong key type raises
333
310
  # a NoMethodError because #private? is attempted to be called on the key.
334
311
  # In jruby 9.2 a TypeError is raised.
335
312
  # In jruby 9.1 a OpenSSL::PKey::PKeyError is raised.
336
- context 'when ruby version is >= 2.4.1' do
337
- ruby_version_gte '2.4.1'
313
+ context 'when a key is passed, but it is not of the right type' do
338
314
 
339
- context 'when a key is passed, but it is not of the right type' do
315
+ let(:ssl_options) do
316
+ key = "This is a string not a key"
317
+ {
318
+ :ssl => true,
319
+ :ssl_key_object => key,
320
+ :ssl_cert => SpecConfig.instance.client_cert_path,
321
+ :ssl_verify => false
322
+ }
323
+ end
340
324
 
341
- let(:ssl_options) do
342
- key = "This is a string not a key"
343
- {
344
- :ssl => true,
345
- :ssl_key_object => key,
346
- :ssl_cert => SpecConfig.instance.client_cert_path,
347
- :ssl_verify => false
348
- }
349
- end
350
-
351
- let(:expected_exception) do
352
- if SpecConfig.instance.jruby?
353
- if RUBY_VERSION >= '2.5.0'
354
- # jruby 9.2
355
- TypeError
356
- else
357
- # jruby 9.1
358
- OpenSSL::OpenSSLError
359
- end
325
+ let(:expected_exception) do
326
+ if SpecConfig.instance.jruby?
327
+ if RUBY_VERSION >= '2.5.0'
328
+ # jruby 9.2
329
+ TypeError
360
330
  else
361
- NoMethodError
331
+ # jruby 9.1
332
+ OpenSSL::OpenSSLError
362
333
  end
334
+ else
335
+ NoMethodError
363
336
  end
337
+ end
364
338
 
365
- it 'raises a NoMethodError' do
366
- expect do
367
- socket
368
- end.to raise_exception(expected_exception)
369
- end
339
+ it 'raises a NoMethodError' do
340
+ expect do
341
+ socket
342
+ end.to raise_exception(expected_exception)
370
343
  end
371
344
  end
372
345
 
@@ -403,13 +376,8 @@ describe Mongo::Socket::SSL, retry: 3 do
403
376
  context 'when a bad key is provided' do
404
377
 
405
378
  let(:expected_exception) do
406
- if RUBY_VERSION >= '2.4.0'
407
- # OpenSSL::PKey::PKeyError: Could not parse PKey: no start line
408
- [OpenSSL::OpenSSLError, /Could not parse PKey/]
409
- else
410
- # ArgumentError: Could not parse PKey: no start line
411
- [ArgumentError, /Could not parse PKey/]
412
- end
379
+ # OpenSSL::PKey::PKeyError: Could not parse PKey: no start line
380
+ [OpenSSL::OpenSSLError, /Could not parse PKey/]
413
381
  end
414
382
 
415
383
  let(:ssl_options) do
@@ -39,18 +39,4 @@ describe Mongo::Utils do
39
39
  }
40
40
  end
41
41
  end
42
-
43
- describe '#slice_hash' do
44
- it do
45
- hash = {'key1' => 1, :key2 => 's', :key3 => true}
46
- expect(
47
- described_class.slice_hash(hash, 'key1', :key3)
48
- ).to eq(
49
- {
50
- 'key1' => 1,
51
- :key3 => true
52
- }
53
- )
54
- end
55
- end
56
42
  end
@@ -110,8 +110,7 @@ EOT
110
110
  expected_command = expected_event.delete('command')
111
111
  actual_command = actual_event.delete('command')
112
112
 
113
- # Hash#compact is ruby 2.4+
114
- expected_presence = expected_command.select { |k, v| !v.nil? }
113
+ expected_presence = expected_command.compact
115
114
  expected_absence = expected_command.select { |k, v| v.nil? }
116
115
 
117
116
  expected_presence.each do |k, v|
@@ -62,7 +62,7 @@ module Unified
62
62
  def assert_outcome
63
63
  return unless outcome
64
64
 
65
- client = ClientRegistry.instance.global_client('authorized')
65
+ client = ClientRegistry.instance.global_client('root_authorized')
66
66
  outcome.each do |spec|
67
67
  spec = UsingHash[spec]
68
68
  collection = client.use(spec.use!('databaseName'))[spec.use!('collectionName')]
@@ -217,6 +217,8 @@ module Unified
217
217
  BSON::ObjectId === object
218
218
  when 'date'
219
219
  Time === object
220
+ when 'double'
221
+ Float === object
220
222
  else
221
223
  raise NotImplementedError, "Unhandled type #{type}"
222
224
  end
@@ -8,7 +8,9 @@ module Unified
8
8
  def find(op)
9
9
  collection = entities.get(:collection, op.use!('object'))
10
10
  use_arguments(op) do |args|
11
- opts = {}
11
+ opts = {
12
+ let: args.use('let'),
13
+ }
12
14
  if session = args.use('session')
13
15
  opts[:session] = entities.get(:session, session)
14
16
  end
@@ -29,7 +31,11 @@ module Unified
29
31
  def count_documents(op)
30
32
  collection = entities.get(:collection, op.use!('object'))
31
33
  use_arguments(op) do |args|
32
- collection.find(args.use!('filter')).count_documents
34
+ opts = {}
35
+ if session = args.use('session')
36
+ opts[:session] = entities.get(:session, session)
37
+ end
38
+ collection.find(args.use!('filter')).count_documents(**opts)
33
39
  end
34
40
  end
35
41
 
@@ -47,7 +53,11 @@ module Unified
47
53
  def distinct(op)
48
54
  collection = entities.get(:collection, op.use!('object'))
49
55
  use_arguments(op) do |args|
50
- req = collection.find(args.use!('filter')).distinct(args.use!('fieldName'))
56
+ opts = {}
57
+ if session = args.use('session')
58
+ opts[:session] = entities.get(:session, session)
59
+ end
60
+ req = collection.find(args.use!('filter'), **opts).distinct(args.use!('fieldName'), **opts)
51
61
  result = req.to_a
52
62
  end
53
63
  end
@@ -57,10 +67,15 @@ module Unified
57
67
  use_arguments(op) do |args|
58
68
  filter = args.use!('filter')
59
69
  update = args.use!('update')
60
- opts = {}
70
+ opts = {
71
+ let: args.use('let'),
72
+ }
61
73
  if return_document = args.use('returnDocument')
62
74
  opts[:return_document] = return_document.downcase.to_sym
63
75
  end
76
+ if session = args.use('session')
77
+ opts[:session] = entities.get(:session, session)
78
+ end
64
79
  collection.find_one_and_update(filter, update, **opts)
65
80
  end
66
81
  end
@@ -70,7 +85,13 @@ module Unified
70
85
  use_arguments(op) do |args|
71
86
  filter = args.use!('filter')
72
87
  update = args.use!('replacement')
73
- collection.find_one_and_replace(filter, update)
88
+ opts = {
89
+ let: args.use('let'),
90
+ }
91
+ if session = args.use('session')
92
+ opts[:session] = entities.get(:session, session)
93
+ end
94
+ collection.find_one_and_replace(filter, update, **opts)
74
95
  end
75
96
  end
76
97
 
@@ -78,7 +99,13 @@ module Unified
78
99
  collection = entities.get(:collection, op.use!('object'))
79
100
  use_arguments(op) do |args|
80
101
  filter = args.use!('filter')
81
- collection.find_one_and_delete(filter)
102
+ opts = {
103
+ let: args.use('let'),
104
+ }
105
+ if session = args.use('session')
106
+ opts[:session] = entities.get(:session, session)
107
+ end
108
+ collection.find_one_and_delete(filter, **opts)
82
109
  end
83
110
  end
84
111
 
@@ -96,25 +123,37 @@ module Unified
96
123
  def insert_many(op)
97
124
  collection = entities.get(:collection, op.use!('object'))
98
125
  use_arguments(op) do |args|
99
- options = {}
126
+ opts = {}
100
127
  unless (ordered = args.use('ordered')).nil?
101
- options[:ordered] = ordered
128
+ opts[:ordered] = ordered
129
+ end
130
+ if session = args.use('session')
131
+ opts[:session] = entities.get(:session, session)
102
132
  end
103
- collection.insert_many(args.use!('documents'), **options)
133
+ collection.insert_many(args.use!('documents'), **opts)
104
134
  end
105
135
  end
106
136
 
107
137
  def update_one(op)
108
138
  collection = entities.get(:collection, op.use!('object'))
109
139
  use_arguments(op) do |args|
110
- collection.update_one(args.use!('filter'), args.use!('update'))
140
+ opts = {
141
+ let: args.use('let'),
142
+ }
143
+ if session = args.use('session')
144
+ opts[:session] = entities.get(:session, session)
145
+ end
146
+ collection.update_one(args.use!('filter'), args.use!('update'), **opts)
111
147
  end
112
148
  end
113
149
 
114
150
  def update_many(op)
115
151
  collection = entities.get(:collection, op.use!('object'))
116
152
  use_arguments(op) do |args|
117
- collection.update_many(args.use!('filter'), args.use!('update'))
153
+ opts = {
154
+ let: args.use('let'),
155
+ }
156
+ collection.update_many(args.use!('filter'), args.use!('update'), **opts)
118
157
  end
119
158
  end
120
159
 
@@ -132,14 +171,23 @@ module Unified
132
171
  def delete_one(op)
133
172
  collection = entities.get(:collection, op.use!('object'))
134
173
  use_arguments(op) do |args|
135
- collection.delete_one(args.use!('filter'))
174
+ opts = {
175
+ let: args.use('let'),
176
+ }
177
+ if session = args.use('session')
178
+ opts[:session] = entities.get(:session, session)
179
+ end
180
+ collection.delete_one(args.use!('filter'), **opts)
136
181
  end
137
182
  end
138
183
 
139
184
  def delete_many(op)
140
185
  collection = entities.get(:collection, op.use!('object'))
141
186
  use_arguments(op) do |args|
142
- collection.delete_many(args.use!('filter'))
187
+ opts = {
188
+ let: args.use('let'),
189
+ }
190
+ collection.delete_many(args.use!('filter'), **opts)
143
191
  end
144
192
  end
145
193
 
@@ -157,6 +205,22 @@ module Unified
157
205
  end
158
206
  end
159
207
 
208
+ def aggregate(op)
209
+ obj = entities.get_any(op.use!('object'))
210
+ args = op.use!('arguments')
211
+ pipeline = args.use!('pipeline')
212
+ opts = {
213
+ let: args.use('let'),
214
+ }
215
+ if session = args.use('session')
216
+ opts[:session] = entities.get(:session, session)
217
+ end
218
+ unless args.empty?
219
+ raise NotImplementedError, "Unhandled spec keys: #{args} in #{test_spec}"
220
+ end
221
+ obj.aggregate(pipeline, **opts).to_a
222
+ end
223
+
160
224
  private
161
225
 
162
226
  def convert_bulk_write_spec(spec)
@@ -192,15 +256,5 @@ module Unified
192
256
  end
193
257
  {Utils.underscore(op) =>out}
194
258
  end
195
-
196
- def aggregate(op)
197
- obj = entities.get_any(op.use!('object'))
198
- args = op.use!('arguments')
199
- pipeline = args.use!('pipeline')
200
- unless args.empty?
201
- raise NotImplementedError, "Unhandled spec keys: #{test_spec}"
202
- end
203
- obj.aggregate(pipeline).to_a
204
- end
205
259
  end
206
260
  end