mongo 2.4.1 → 2.4.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 (62) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +3 -3
  5. data/lib/mongo/client.rb +16 -7
  6. data/lib/mongo/cluster.rb +9 -4
  7. data/lib/mongo/cluster/cursor_reaper.rb +1 -0
  8. data/lib/mongo/cluster/topology.rb +1 -1
  9. data/lib/mongo/collection.rb +0 -3
  10. data/lib/mongo/collection/view.rb +12 -5
  11. data/lib/mongo/collection/view/builder/find_command.rb +2 -2
  12. data/lib/mongo/collection/view/readable.rb +4 -4
  13. data/lib/mongo/collection/view/writable.rb +12 -10
  14. data/lib/mongo/cursor.rb +1 -0
  15. data/lib/mongo/error.rb +1 -0
  16. data/lib/mongo/error/invalid_min_pool_size.rb +35 -0
  17. data/lib/mongo/error/operation_failure.rb +24 -5
  18. data/lib/mongo/operation/write/bulk/update/result.rb +1 -10
  19. data/lib/mongo/operation/write/update/result.rb +26 -7
  20. data/lib/mongo/retryable.rb +30 -35
  21. data/lib/mongo/socket.rb +1 -1
  22. data/lib/mongo/socket/tcp.rb +1 -0
  23. data/lib/mongo/version.rb +1 -1
  24. data/spec/mongo/bulk_write_spec.rb +113 -43
  25. data/spec/mongo/client_spec.rb +253 -0
  26. data/spec/mongo/cluster/topology_spec.rb +37 -0
  27. data/spec/mongo/cluster_spec.rb +1 -1
  28. data/spec/mongo/collection/view/aggregation_spec.rb +2 -2
  29. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  30. data/spec/mongo/collection_spec.rb +55 -19
  31. data/spec/mongo/command_monitoring_spec.rb +1 -1
  32. data/spec/mongo/database_spec.rb +5 -5
  33. data/spec/mongo/grid/stream/write_spec.rb +2 -2
  34. data/spec/mongo/index/view_spec.rb +5 -5
  35. data/spec/mongo/max_staleness_spec.rb +0 -4
  36. data/spec/mongo/operation/write/update_spec.rb +15 -3
  37. data/spec/mongo/retryable_spec.rb +26 -22
  38. data/spec/mongo/server/connection_spec.rb +26 -0
  39. data/spec/mongo/shell_examples_spec.rb +981 -0
  40. data/spec/mongo/socket/ssl_spec.rb +51 -18
  41. data/spec/spec_helper.rb +26 -16
  42. data/spec/support/authorization.rb +38 -16
  43. data/spec/support/connection_string.rb +3 -3
  44. data/spec/support/crud.rb +38 -10
  45. data/spec/support/crud/write.rb +6 -3
  46. data/spec/support/crud_tests/write/findOneAndReplace-upsert.yml +48 -4
  47. data/spec/support/crud_tests/write/findOneAndReplace-upsert_pre_2.6.yml +88 -0
  48. data/spec/support/crud_tests/write/findOneAndReplace.yml +0 -29
  49. data/spec/support/crud_tests/write/findOneAndUpdate.yml +4 -1
  50. data/spec/support/crud_tests/write/replaceOne-collation.yml +1 -0
  51. data/spec/support/crud_tests/write/replaceOne-pre_2.6.yml +98 -0
  52. data/spec/support/crud_tests/write/replaceOne.yml +21 -5
  53. data/spec/support/crud_tests/write/updateMany-collation.yml +1 -0
  54. data/spec/support/crud_tests/write/updateMany-pre_2.6.yml +86 -0
  55. data/spec/support/crud_tests/write/updateMany.yml +5 -0
  56. data/spec/support/crud_tests/write/updateOne-collation.yml +1 -0
  57. data/spec/support/crud_tests/write/updateOne-pre_2.6.yml +83 -0
  58. data/spec/support/crud_tests/write/updateOne.yml +7 -2
  59. data/spec/support/gridfs.rb +1 -0
  60. metadata +13 -4
  61. metadata.gz.sig +2 -1
  62. data/spec/support/helpers.rb +0 -140
@@ -51,7 +51,7 @@ describe 'Command Monitoring Events' do
51
51
  test.run(authorized_collection)
52
52
  event = subscriber.send(expectation.event_type)[expectation.command_name]
53
53
  expect(event).to send(expectation.matcher, expectation)
54
- rescue Mongo::Error::OperationFailure, Mongo::Error::BulkWriteError => e
54
+ rescue Mongo::Error::OperationFailure, Mongo::Error::BulkWriteError
55
55
  event = subscriber.send(expectation.event_type)[expectation.command_name]
56
56
  expect(event).to send(expectation.matcher, expectation)
57
57
  end
@@ -67,7 +67,7 @@ describe Mongo::Database do
67
67
  context 'when the client has options' do
68
68
 
69
69
  let(:client) do
70
- Mongo::Client.new([default_address.host], read: { mode: :secondary })
70
+ Mongo::Client.new([default_address.host], TEST_OPTIONS.merge(read: { mode: :secondary }))
71
71
  end
72
72
 
73
73
  let(:database) do
@@ -336,7 +336,7 @@ describe Mongo::Database do
336
336
  {
337
337
  insert: TEST_COLL,
338
338
  documents: [ { a: 1 } ],
339
- writeConcern: { w: WRITE_CONCERN[:w]+1 }
339
+ writeConcern: INVALID_WRITE_CONCERN
340
340
  }
341
341
  end
342
342
 
@@ -352,7 +352,7 @@ describe Mongo::Database do
352
352
 
353
353
  let(:client_options) do
354
354
  {
355
- write: { w: WRITE_CONCERN[:w] + 1 }
355
+ write: INVALID_WRITE_CONCERN
356
356
  }
357
357
  end
358
358
 
@@ -380,7 +380,7 @@ describe Mongo::Database do
380
380
  {
381
381
  insert: TEST_COLL,
382
382
  documents: [ { a: 1 } ],
383
- writeConcern: { w: WRITE_CONCERN[:w]+1 }
383
+ writeConcern: INVALID_WRITE_CONCERN
384
384
  }
385
385
  end
386
386
 
@@ -413,7 +413,7 @@ describe Mongo::Database do
413
413
 
414
414
  let(:client_options) do
415
415
  {
416
- write: { w: WRITE_CONCERN[:w] + 1 },
416
+ write: INVALID_WRITE_CONCERN,
417
417
  database: :safe_to_drop
418
418
  }
419
419
  end
@@ -56,7 +56,7 @@ describe Mongo::Grid::FSBucket::Stream::Write do
56
56
  context 'when the fs has a write concern', if: standalone? do
57
57
 
58
58
  let(:fs_options) do
59
- { write: { w: (WRITE_CONCERN[:w] + 1) } }
59
+ { write: INVALID_WRITE_CONCERN }
60
60
  end
61
61
 
62
62
  it 'uses the write concern of the fs as a default' do
@@ -83,7 +83,7 @@ describe Mongo::Grid::FSBucket::Stream::Write do
83
83
 
84
84
  let(:extra_options) do
85
85
  {
86
- write: { w: (WRITE_CONCERN[:w] + 1) }
86
+ write: INVALID_WRITE_CONCERN
87
87
  }
88
88
  end
89
89
 
@@ -43,7 +43,7 @@ describe Mongo::Index::View do
43
43
  context 'when the collection has a write concern' do
44
44
 
45
45
  let(:collection) do
46
- authorized_collection.with(write: { w: WRITE_CONCERN[:w] + 1})
46
+ authorized_collection.with(write: INVALID_WRITE_CONCERN)
47
47
  end
48
48
 
49
49
  let(:view_with_write_concern) do
@@ -126,7 +126,7 @@ describe Mongo::Index::View do
126
126
  context 'when the collection has a write concern' do
127
127
 
128
128
  let(:collection) do
129
- authorized_collection.with(write: { w: WRITE_CONCERN[:w] + 1})
129
+ authorized_collection.with(write: INVALID_WRITE_CONCERN)
130
130
  end
131
131
 
132
132
  let(:view_with_write_concern) do
@@ -252,7 +252,7 @@ describe Mongo::Index::View do
252
252
  end
253
253
 
254
254
  let(:collection) do
255
- authorized_collection.with(write: { w: WRITE_CONCERN[:w] + 1})
255
+ authorized_collection.with(write: INVALID_WRITE_CONCERN)
256
256
  end
257
257
 
258
258
  let(:view_with_write_concern) do
@@ -382,7 +382,7 @@ describe Mongo::Index::View do
382
382
  end
383
383
 
384
384
  let(:collection) do
385
- authorized_collection.with(write: { w: WRITE_CONCERN[:w] + 1})
385
+ authorized_collection.with(write: INVALID_WRITE_CONCERN)
386
386
  end
387
387
 
388
388
  let(:view_with_write_concern) do
@@ -474,7 +474,7 @@ describe Mongo::Index::View do
474
474
  context 'when the collection has a write concern' do
475
475
 
476
476
  let(:collection) do
477
- authorized_collection.with(write: { w: WRITE_CONCERN[:w] + 1})
477
+ authorized_collection.with(write: INVALID_WRITE_CONCERN)
478
478
  end
479
479
 
480
480
  let(:view_with_write_concern) do
@@ -18,10 +18,6 @@ describe 'Max Staleness Spec' do
18
18
  Mongo::Monitoring.new(monitoring: false)
19
19
  end
20
20
 
21
- let(:monitoring) do
22
- Mongo::Monitoring.new
23
- end
24
-
25
21
  let(:listeners) do
26
22
  Mongo::Event::Listeners.new
27
23
  end
@@ -106,10 +106,14 @@ describe Mongo::Operation::Write::Update do
106
106
  expect(result.written_count).to eq(1)
107
107
  end
108
108
 
109
- it 'reports the modified count' do
109
+ it 'reports the modified count', if: write_command_enabled? do
110
110
  expect(result.modified_count).to eq(1)
111
111
  end
112
112
 
113
+ it 'returns nil for the modified count', unless: write_command_enabled? do
114
+ expect(result.modified_count).to be_nil
115
+ end
116
+
113
117
  it 'reports the matched count' do
114
118
  expect(result.matched_count).to eq(1)
115
119
  end
@@ -158,10 +162,14 @@ describe Mongo::Operation::Write::Update do
158
162
  expect(result.written_count).to eq(2)
159
163
  end
160
164
 
161
- it 'reports the modified count' do
165
+ it 'reports the modified count', if: write_command_enabled? do
162
166
  expect(result.modified_count).to eq(2)
163
167
  end
164
168
 
169
+ it 'returns nil for the modified count', unless: write_command_enabled? do
170
+ expect(result.modified_count).to be_nil
171
+ end
172
+
165
173
  it 'reports the matched count' do
166
174
  expect(result.matched_count).to eq(2)
167
175
  end
@@ -211,10 +219,14 @@ describe Mongo::Operation::Write::Update do
211
219
  expect(result.written_count).to eq(1)
212
220
  end
213
221
 
214
- it 'reports the modified count' do
222
+ it 'reports the modified count', if: write_command_enabled? do
215
223
  expect(result.modified_count).to eq(0)
216
224
  end
217
225
 
226
+ it 'returns nil for the modified count', unless: write_command_enabled? do
227
+ expect(result.modified_count).to be_nil
228
+ end
229
+
218
230
  it 'reports the matched count' do
219
231
  expect(result.matched_count).to eq(0)
220
232
  end
@@ -36,19 +36,19 @@ describe Mongo::Retryable do
36
36
  end
37
37
  end
38
38
 
39
- describe '#read_with_retry' do
39
+ let(:operation) do
40
+ double('operation')
41
+ end
40
42
 
41
- let(:operation) do
42
- double('operation')
43
- end
43
+ let(:cluster) do
44
+ double('cluster')
45
+ end
44
46
 
45
- let(:cluster) do
46
- double('cluster')
47
- end
47
+ let(:retryable) do
48
+ klass.new(operation, cluster)
49
+ end
48
50
 
49
- let(:retryable) do
50
- klass.new(operation, cluster)
51
- end
51
+ describe '#read_with_retry' do
52
52
 
53
53
  context 'when no exception occurs' do
54
54
 
@@ -65,6 +65,7 @@ describe Mongo::Retryable do
65
65
 
66
66
  before do
67
67
  expect(operation).to receive(:execute).and_raise(Mongo::Error::SocketError).ordered
68
+ expect(cluster).to receive(:max_read_retries).and_return(1).ordered
68
69
  expect(cluster).to receive(:scan!).and_return(true).ordered
69
70
  expect(operation).to receive(:execute).and_return(true).ordered
70
71
  end
@@ -78,6 +79,7 @@ describe Mongo::Retryable do
78
79
 
79
80
  before do
80
81
  expect(operation).to receive(:execute).and_raise(Mongo::Error::SocketTimeoutError).ordered
82
+ expect(cluster).to receive(:max_read_retries).and_return(1).ordered
81
83
  expect(cluster).to receive(:scan!).and_return(true).ordered
82
84
  expect(operation).to receive(:execute).and_return(true).ordered
83
85
  end
@@ -169,18 +171,6 @@ describe Mongo::Retryable do
169
171
 
170
172
  describe '#write_with_retry' do
171
173
 
172
- let(:operation) do
173
- double('operation')
174
- end
175
-
176
- let(:cluster) do
177
- double('cluster')
178
- end
179
-
180
- let(:retryable) do
181
- klass.new(operation, cluster)
182
- end
183
-
184
174
  context 'when no exception occurs' do
185
175
 
186
176
  before do
@@ -205,6 +195,19 @@ describe Mongo::Retryable do
205
195
  end
206
196
  end
207
197
 
198
+ context 'when a not primary error occurs' do
199
+
200
+ before do
201
+ expect(operation).to receive(:execute).and_raise(Mongo::Error::OperationFailure.new('Not primary')).ordered
202
+ expect(cluster).to receive(:scan!).and_return(true).ordered
203
+ expect(operation).to receive(:execute).and_return(true).ordered
204
+ end
205
+
206
+ it 'executes the operation twice' do
207
+ expect(retryable.write).to be true
208
+ end
209
+ end
210
+
208
211
  context 'when a normal operation failure occurs' do
209
212
 
210
213
  before do
@@ -217,5 +220,6 @@ describe Mongo::Retryable do
217
220
  }.to raise_error(Mongo::Error::OperationFailure)
218
221
  end
219
222
  end
223
+
220
224
  end
221
225
  end
@@ -444,6 +444,32 @@ describe Mongo::Server::Connection do
444
444
  end_time = Time.now
445
445
  expect(end_time - start).to be_within(0.2).of(1.5)
446
446
  end
447
+
448
+ context 'when the socket_timeout is negative' do
449
+
450
+ let(:connection) do
451
+ described_class.new(server, server.options)
452
+ end
453
+
454
+ let(:messages) do
455
+ [ insert ]
456
+ end
457
+
458
+ before do
459
+ connection.send(:write, messages)
460
+ connection.send(:socket).instance_variable_set(:@timeout, -(Time.now.to_i))
461
+ end
462
+
463
+ let(:reply) do
464
+ connection.send(:read, messages.last.request_id)
465
+ end
466
+
467
+ it 'raises a timeout error' do
468
+ expect {
469
+ reply
470
+ }.to raise_exception(Timeout::Error)
471
+ end
472
+ end
447
473
  end
448
474
 
449
475
  context 'when the process is forked' do
@@ -0,0 +1,981 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'shell examples in Ruby' do
4
+
5
+ let(:client) do
6
+ authorized_client
7
+ end
8
+
9
+ before do
10
+ client[:inventory].drop
11
+ end
12
+
13
+ after do
14
+ client[:inventory].drop
15
+ end
16
+
17
+ context 'insert examples' do
18
+
19
+ before do
20
+ # Start Example 1
21
+ client[:inventory].insert_one({ item: 'canvas',
22
+ qty: 100,
23
+ tags: [ 'cotton' ],
24
+ size: { h: 28, w: 35.5, uom: 'cm' } })
25
+ # End Example 1
26
+ end
27
+
28
+
29
+ context 'example 2' do
30
+
31
+ let(:example) do
32
+ # Start Example 2
33
+ client[:inventory].find(item: 'canvas')
34
+ # End Example 2
35
+ end
36
+
37
+ it 'matches the expected output' do
38
+ expect(example.count).to eq(1)
39
+ end
40
+ end
41
+
42
+ context 'example 3' do
43
+
44
+ let(:example) do
45
+ # Start Example 3
46
+ client[:inventory].insert_many([{ item: 'journal',
47
+ qty: 25,
48
+ tags: ['blank', 'red'],
49
+ size: { h: 14, w: 21, uom: 'cm' }
50
+ },
51
+ { item: 'mat',
52
+ qty: 85,
53
+ tags: ['gray'],
54
+ size: { h: 27.9, w: 35.5, uom: 'cm' }
55
+ },
56
+ { item: 'mousepad',
57
+ qty: 25,
58
+ tags: ['gel', 'blue'],
59
+ size: { h: 19, w: 22.85, uom: 'cm' }
60
+ }
61
+ ])
62
+ # End Example 3
63
+ end
64
+
65
+ it 'matches the expected output' do
66
+ expect(example.inserted_count).to eq(3)
67
+ end
68
+ end
69
+ end
70
+
71
+ context 'query top-level' do
72
+
73
+ before do
74
+ # Start Example 6
75
+ client[:inventory].insert_many([{ item: 'journal',
76
+ qty: 25,
77
+ size: { h: 14, w: 21, uom: 'cm' },
78
+ status: 'A' },
79
+ { item: 'notebook',
80
+ qty: 50,
81
+ size: { h: 8.5, w: 11, uom: 'in' },
82
+ status: 'A' },
83
+ { item: 'paper',
84
+ qty: 100,
85
+ size: { h: 8.5, w: 11, uom: 'in' },
86
+ status: 'D' },
87
+ { item: 'planner',
88
+ qty: 75,
89
+ size: { h: 22.85, w: 30, uom: 'cm' },
90
+ status: 'D' },
91
+ { item: 'postcard',
92
+ qty: 45,
93
+ size: { h: 10, w: 15.25, uom: 'cm' },
94
+ status: 'A' }
95
+ ])
96
+ # End Example 6
97
+
98
+ end
99
+
100
+ context 'example 7' do
101
+
102
+ let(:example) do
103
+ # Start Example 7
104
+ client[:inventory].find({})
105
+ # End Example 7
106
+ end
107
+
108
+ it 'matches the expected output' do
109
+ expect(example.to_a.size).to eq(5)
110
+ end
111
+ end
112
+
113
+ context 'example 8' do
114
+
115
+ let(:example) do
116
+ # Start Example 8
117
+ client[:inventory].find
118
+ # End Example 8
119
+ end
120
+
121
+ it 'matches the expected output' do
122
+ expect(example.to_a.size).to eq(5)
123
+ end
124
+ end
125
+
126
+ context 'example 9' do
127
+
128
+ let(:example) do
129
+ # Start Example 9
130
+ client[:inventory].find(status: 'D')
131
+ # End Example 9
132
+ end
133
+
134
+ it 'matches the expected output' do
135
+ expect(example.to_a.size).to eq(2)
136
+ end
137
+ end
138
+
139
+ context 'example 10' do
140
+
141
+ let(:example) do
142
+ # Start Example 10
143
+ client[:inventory].find(status: { '$in' => [ 'A', 'D' ]})
144
+ # End Example 10
145
+ end
146
+
147
+ it 'matches the expected output' do
148
+ expect(example.to_a.size).to eq(5)
149
+ end
150
+ end
151
+
152
+ context 'example 11' do
153
+
154
+ let(:example) do
155
+ # Start Example 11
156
+ client[:inventory].find(status: 'A', qty: { '$lt' => 30 })
157
+ # End Example 11
158
+ end
159
+
160
+ it 'matches the expected output' do
161
+ expect(example.to_a.size).to eq(1)
162
+ end
163
+ end
164
+
165
+ context 'example 12' do
166
+
167
+ let(:example) do
168
+ # Start Example 12
169
+ client[:inventory].find('$or' => [{ status: 'A' },
170
+ { qty: { '$lt' => 30 } }
171
+ ])
172
+ # End Example 12
173
+ end
174
+
175
+ it 'matches the expected output' do
176
+ expect(example.to_a.size).to eq(3)
177
+ end
178
+ end
179
+
180
+ context 'example 13' do
181
+
182
+ let(:example) do
183
+ # Start Example 13
184
+ client[:inventory].find(status: 'A',
185
+ '$or' => [{ qty: { '$lt' => 30 } },
186
+ { item: { '$regex' => BSON::Regexp::Raw.new('^p') } }
187
+ ])
188
+ # End Example 13
189
+ end
190
+
191
+ it 'matches the expected output' do
192
+ expect(example.to_a.size).to eq(2)
193
+ end
194
+ end
195
+ end
196
+
197
+ context 'query embedded documents' do
198
+
199
+ before do
200
+ # Start Example 14
201
+ client[:inventory].insert_many([
202
+ { item: 'journal',
203
+ qty: 25,
204
+ size: { h: 14, w: 21, uom: 'cm' },
205
+ status: 'A' },
206
+ { item: 'notebook',
207
+ qty: 50,
208
+ size: { h: 8.5, w: 11, uom: 'in' },
209
+ status: 'A' },
210
+ { item: 'paper',
211
+ qty: 100,
212
+ size: { h: 8.5, w: 11, uom: 'in' },
213
+ status: 'D' },
214
+ { item: 'planner',
215
+ qty: 75,
216
+ size: { h: 22.85, w: 30, uom: 'cm' },
217
+ status: 'D' },
218
+ { item: 'postcard',
219
+ qty: 45,
220
+ size: { h: 10, w: 15.25, uom: 'cm' },
221
+ status: 'A' }
222
+ ])
223
+ # End Example 14
224
+ end
225
+
226
+ context 'example 15' do
227
+
228
+ let(:example) do
229
+ # Start Example 15
230
+ client[:inventory].find(size: { h: 14, w: 21, uom: 'cm' })
231
+ # End Example 15
232
+ end
233
+
234
+ it 'matches the expected output' do
235
+ expect(example.to_a.size).to eq(1)
236
+ end
237
+ end
238
+
239
+ context 'example 16' do
240
+
241
+ let(:example) do
242
+ # Start Example 16
243
+ client[:inventory].find(size: { h: 21, w: 14, uom: 'cm' })
244
+ # End Example 16
245
+ end
246
+
247
+ it 'matches the expected output' do
248
+ expect(example.to_a.size).to eq(0)
249
+ end
250
+ end
251
+
252
+ context 'example 17' do
253
+
254
+ let(:example) do
255
+ # Start Example 17
256
+ client[:inventory].find('size.uom' => 'in')
257
+ # End Example 17
258
+ end
259
+
260
+ it 'matches the expected output' do
261
+ expect(example.to_a.size).to eq(2)
262
+ end
263
+ end
264
+
265
+ context 'example 18' do
266
+
267
+ let(:example) do
268
+ # Start Example 18
269
+ client[:inventory].find('size.h' => { '$lt' => 15 })
270
+ # End Example 18
271
+ end
272
+
273
+ it 'matches the expected output' do
274
+ expect(example.to_a.size).to eq(4)
275
+ end
276
+ end
277
+
278
+ context 'example 19' do
279
+
280
+ let(:example) do
281
+ # Start Example 19
282
+ client[:inventory].find('size.h' => { '$lt' => 15 },
283
+ 'size.uom' => 'in',
284
+ 'status' => 'D')
285
+ # End Example 19
286
+ end
287
+
288
+ it 'matches the expected output' do
289
+ expect(example.to_a.size).to eq(1)
290
+ end
291
+ end
292
+ end
293
+
294
+ context 'query arrays' do
295
+
296
+ before do
297
+ # Start Example 20
298
+ client[:inventory].insert_many([{ item: 'journal',
299
+ qty: 25,
300
+ tags: ['blank', 'red'],
301
+ dim_cm: [ 14, 21 ] },
302
+ { item: 'notebook',
303
+ qty: 50,
304
+ tags: ['red', 'blank'],
305
+ dim_cm: [ 14, 21 ] },
306
+ { item: 'paper',
307
+ qty: 100,
308
+ tags: ['red', 'blank', 'plain'],
309
+ dim_cm: [ 14, 21 ] },
310
+ { item: 'planner',
311
+ qty: 75,
312
+ tags: ['blank', 'red'],
313
+ dim_cm: [ 22.85, 30 ] },
314
+ { item: 'postcard',
315
+ qty: 45,
316
+ tags: ['blue'],
317
+ dim_cm: [ 10, 15.25 ] }
318
+ ])
319
+ # End Example 20
320
+ end
321
+
322
+ context 'example 21' do
323
+
324
+ let(:example) do
325
+ # Start Example 21
326
+ client[:inventory].find(tags: ['red', 'blank'])
327
+ # End Example 21
328
+ end
329
+
330
+ it 'matches the expected output' do
331
+ expect(example.to_a.size).to eq(1)
332
+ end
333
+ end
334
+
335
+ context 'example 22' do
336
+
337
+ let(:example) do
338
+ # Start Example 22
339
+ client[:inventory].find(tags: { '$all' => ['red', 'blank'] })
340
+ # End Example 22
341
+ end
342
+
343
+ it 'matches the expected output' do
344
+ expect(example.to_a.size).to eq(4)
345
+ end
346
+ end
347
+
348
+ context 'example 23' do
349
+
350
+ let(:example) do
351
+ # Start Example 23
352
+ client[:inventory].find(tags: 'red')
353
+ # End Example 23
354
+ end
355
+
356
+ it 'matches the expected output' do
357
+ expect(example.count).to eq(4)
358
+ end
359
+ end
360
+
361
+ context 'example 24' do
362
+
363
+ let(:example) do
364
+ # Start Example 24
365
+ client[:inventory].find(dim_cm: { '$gt' => 25 })
366
+ # End Example 24
367
+ end
368
+
369
+ it 'matches the expected output' do
370
+ expect(example.count).to eq(1)
371
+ end
372
+ end
373
+
374
+ context 'example 25' do
375
+
376
+ let(:example) do
377
+ # Start Example 25
378
+ client[:inventory].find(dim_cm: { '$gt' => 15,
379
+ '$lt' => 20 })
380
+ # End Example 25
381
+ end
382
+
383
+ it 'matches the expected output' do
384
+ expect(example.count).to eq(4)
385
+ end
386
+ end
387
+
388
+ context 'example 26' do
389
+
390
+ let(:example) do
391
+ # Start Example 26
392
+ client[:inventory].find(dim_cm: { '$elemMatch' => { '$gt' => 22,
393
+ '$lt' => 30 } })
394
+ # End Example 26
395
+ end
396
+
397
+ it 'matches the expected output' do
398
+ expect(example.count).to eq(1)
399
+ end
400
+ end
401
+
402
+ context 'example 27' do
403
+
404
+ let(:example) do
405
+ # Start Example 27
406
+ client[:inventory].find('dim_cm.1' => { '$gt' => 25 })
407
+ # End Example 27
408
+ end
409
+
410
+ it 'matches the expected output' do
411
+ expect(example.count).to eq(1)
412
+ end
413
+ end
414
+
415
+ context 'example 28' do
416
+
417
+ let(:example) do
418
+ # Start Example 28
419
+ client[:inventory].find(tags: { '$size' => 3 })
420
+ # End Example 28
421
+ end
422
+
423
+ it 'matches the expected output' do
424
+ expect(example.count).to eq(1)
425
+ end
426
+ end
427
+ end
428
+
429
+ context 'query array of embedded documents' do
430
+
431
+ before do
432
+ # Start Example 29
433
+ client[:inventory].insert_many([{ item: 'journal',
434
+ instock: [ { warehouse: 'A', qty: 5 },
435
+ { warehouse: 'C', qty: 15 }] },
436
+ { item: 'notebook',
437
+ instock: [ { warehouse: 'C', qty: 5 }] },
438
+ { item: 'paper',
439
+ instock: [ { warehouse: 'A', qty: 60 },
440
+ { warehouse: 'B', qty: 15 }] },
441
+ { item: 'planner',
442
+ instock: [ { warehouse: 'A', qty: 40 },
443
+ { warehouse: 'B', qty: 5 }] },
444
+ { item: 'postcard',
445
+ instock: [ { warehouse: 'B', qty: 15 },
446
+ { warehouse: 'C', qty: 35 }] }
447
+ ])
448
+ # End Example 29
449
+ end
450
+
451
+
452
+ context 'example 30' do
453
+
454
+ let(:example) do
455
+ # Start Example 30
456
+ client[:inventory].find(instock: { warehouse: 'A', qty: 5 })
457
+ # End Example 30
458
+ end
459
+
460
+ it 'matches the expected output' do
461
+ expect(example.to_a.size).to eq(1)
462
+ end
463
+ end
464
+
465
+ context 'example 31' do
466
+
467
+ let(:example) do
468
+ # Start Example 31
469
+ client[:inventory].find(instock: { qty: 5, warehouse: 'A' } )
470
+ # End Example 31
471
+ end
472
+
473
+ it 'matches the expected output' do
474
+ expect(example.to_a.size).to eq(0)
475
+ end
476
+ end
477
+
478
+ context 'example 32' do
479
+
480
+ let(:example) do
481
+ # Start Example 32
482
+ client[:inventory].find('instock.0.qty' => { '$lte' => 20 })
483
+ # End Example 32
484
+ end
485
+
486
+ it 'matches the expected output' do
487
+ expect(example.to_a.size).to eq(3)
488
+ end
489
+ end
490
+
491
+ context 'example 33' do
492
+
493
+ let(:example) do
494
+ # Start Example 33
495
+ client[:inventory].find('instock.qty' => { '$lte' => 20 })
496
+ # End Example 33
497
+ end
498
+
499
+ it 'matches the expected output' do
500
+ expect(example.to_a.size).to eq(5)
501
+ end
502
+ end
503
+
504
+ context 'example 34' do
505
+
506
+ let(:example) do
507
+ # Start Example 34
508
+ client[:inventory].find(instock: { '$elemMatch' => { qty: 5,
509
+ warehouse: 'A' } })
510
+ # End Example 34
511
+ end
512
+
513
+ it 'matches the expected output' do
514
+ expect(example.to_a.size).to eq(1)
515
+ end
516
+ end
517
+
518
+ context 'example 35' do
519
+
520
+ let(:example) do
521
+ # Start Example 35
522
+ client[:inventory].find(instock: { '$elemMatch' => { qty: { '$gt' => 10,
523
+ '$lte' => 20 } } })
524
+ # End Example 35
525
+ end
526
+
527
+ it 'matches the expected output' do
528
+ expect(example.to_a.size).to eq(3)
529
+ end
530
+ end
531
+
532
+ context 'example 36' do
533
+
534
+ let(:example) do
535
+ # Start Example 36
536
+ client[:inventory].find('instock.qty' => { '$gt' => 10, '$lte' => 20 })
537
+ # End Example 36
538
+ end
539
+
540
+ it 'matches the expected output' do
541
+ expect(example.to_a.size).to eq(4)
542
+ end
543
+ end
544
+
545
+ context 'example 37' do
546
+
547
+ let(:example) do
548
+ # Start Example 37
549
+ client[:inventory].find('instock.qty' => 5,
550
+ 'instock.warehouse' => 'A')
551
+ # End Example 37
552
+ end
553
+
554
+ it 'matches the expected output' do
555
+ expect(example.to_a.size).to eq(2)
556
+ end
557
+ end
558
+ end
559
+
560
+ context 'query null' do
561
+
562
+ before do
563
+ # Start Example 38
564
+ client[:inventory].insert_many([{ _id: 1, item: nil },
565
+ { _id: 2 }])
566
+ # End Example 38
567
+ end
568
+
569
+ context 'example 39' do
570
+
571
+ let(:example) do
572
+ # Start Example 39
573
+ client[:inventory].find(item: nil)
574
+ # End Example 39
575
+ end
576
+
577
+ it 'matches the expected output' do
578
+ expect(example.to_a.size).to eq(2)
579
+ end
580
+ end
581
+
582
+ context 'example 40' do
583
+
584
+ let(:example) do
585
+ # Start Example 40
586
+ client[:inventory].find(item: { '$type' => 10 })
587
+ # End Example 40
588
+ end
589
+
590
+ it 'matches the expected output' do
591
+ expect(example.to_a.size).to eq(1)
592
+ end
593
+ end
594
+
595
+ context 'example 41' do
596
+
597
+ let(:example) do
598
+ # Start Example 41
599
+ client[:inventory].find(item: { '$exists' => false })
600
+ # End Example 41
601
+ end
602
+
603
+ it 'matches the expected output' do
604
+ expect(example.to_a.size).to eq(1)
605
+ end
606
+ end
607
+ end
608
+
609
+ context 'projection' do
610
+
611
+ before do
612
+ # Start Example 42
613
+ client[:inventory].insert_many([{ item: 'journal',
614
+ status: 'A',
615
+ size: { h: 14, w: 21, uom: 'cm' },
616
+ instock: [ { warehouse: 'A', qty: 5 }] },
617
+ { item: 'notebook',
618
+ status: 'A',
619
+ size: { h: 8.5, w: 11, uom: 'in' },
620
+ instock: [ { warehouse: 'C', qty: 5 }] },
621
+ { item: 'paper',
622
+ status: 'D',
623
+ size: { h: 8.5, w: 11, uom: 'in' },
624
+ instock: [ { warehouse: 'A', qty: 60 }] },
625
+ { item: 'planner',
626
+ status: 'D',
627
+ size: { h: 22.85, w: 30, uom: 'cm' },
628
+ instock: [ { warehouse: 'A', qty: 40 }] },
629
+ { item: 'postcard',
630
+ status: 'A',
631
+ size: { h: 10, w: 15.25, uom: 'cm' },
632
+ instock: [ { warehouse: 'B', qty: 15 },
633
+ { warehouse: 'C', qty: 35 }] }])
634
+ # End Example 42
635
+ end
636
+
637
+
638
+ context 'example 43' do
639
+
640
+ let(:example) do
641
+ # Start Example 43
642
+ client[:inventory].find(status: 'A')
643
+ # End Example 43
644
+ end
645
+
646
+ it 'matches the expected output' do
647
+ expect(example.to_a.size).to eq(3)
648
+ end
649
+ end
650
+
651
+ context 'example 44' do
652
+
653
+ let!(:example) do
654
+ # Start Example 44
655
+ client[:inventory].find({ status: 'A' },
656
+ projection: { item: 1, status: 1 })
657
+ # End Example 44
658
+ end
659
+
660
+ it 'matches the expected output' do
661
+ expect(example.to_a[1]['_id']).not_to be_nil
662
+ expect(example.to_a[1]['item']).not_to be_nil
663
+ expect(example.to_a[1]['status']).not_to be_nil
664
+ expect(example.to_a[1]['size']).to be_nil
665
+ expect(example.to_a[1]['instock']).to be_nil
666
+ end
667
+ end
668
+
669
+ context 'example 45' do
670
+
671
+ let!(:example) do
672
+ # Start Example 45
673
+ client[:inventory].find({ status: 'A' },
674
+ projection: { item: 1, status: 1, _id: 0 })
675
+ # End Example 45
676
+ end
677
+
678
+ it 'matches the expected output' do
679
+ expect(example.to_a[1]['_id']).to be_nil
680
+ expect(example.to_a[1]['item']).not_to be_nil
681
+ expect(example.to_a[1]['status']).not_to be_nil
682
+ expect(example.to_a[1]['size']).to be_nil
683
+ expect(example.to_a[1]['instock']).to be_nil
684
+ end
685
+ end
686
+
687
+ context 'example 46' do
688
+
689
+ let!(:example) do
690
+ # Start Example 46
691
+ client[:inventory].find({ status: 'A' },
692
+ projection: { status: 0, instock: 0 })
693
+ # End Example 46
694
+ end
695
+
696
+ it 'matches the expected output' do
697
+ expect(example.to_a[1]['_id']).not_to be_nil
698
+ expect(example.to_a[1]['item']).not_to be_nil
699
+ expect(example.to_a[1]['status']).to be_nil
700
+ expect(example.to_a[1]['size']).not_to be_nil
701
+ expect(example.to_a[1]['instock']).to be_nil
702
+ end
703
+ end
704
+
705
+ context 'example 47' do
706
+
707
+ let!(:example) do
708
+ # Start Example 47
709
+ client[:inventory].find({ status: 'A' },
710
+ projection: { 'item' => 1, 'status' => 1, 'size.uom' => 1 })
711
+ # End Example 47
712
+ end
713
+
714
+ it 'matches the expected output' do
715
+ expect(example.to_a[1]['_id']).not_to be_nil
716
+ expect(example.to_a[1]['item']).not_to be_nil
717
+ expect(example.to_a[1]['status']).not_to be_nil
718
+ expect(example.to_a[1]['size']).not_to be_nil
719
+ expect(example.to_a[1]['instock']).to be_nil
720
+ expect(example.to_a[1]['size']).not_to be_nil
721
+ expect(example.to_a[1]['size']['uom']).not_to be_nil
722
+ expect(example.to_a[1]['size']['h']).to be_nil
723
+ expect(example.to_a[1]['size']['w']).to be_nil
724
+ end
725
+ end
726
+
727
+ context 'example 48' do
728
+
729
+ let!(:example) do
730
+ # Start Example 48
731
+ client[:inventory].find({ status: 'A' },
732
+ projection: { 'size.uom' => 0 })
733
+ # End Example 48
734
+ end
735
+
736
+ it 'matches the expected output' do
737
+ expect(example.to_a[1]['_id']).not_to be_nil
738
+ expect(example.to_a[1]['item']).not_to be_nil
739
+ expect(example.to_a[1]['status']).not_to be_nil
740
+ expect(example.to_a[1]['size']).not_to be_nil
741
+ expect(example.to_a[1]['instock']).not_to be_nil
742
+ expect(example.to_a[1]['size']).not_to be_nil
743
+ expect(example.to_a[1]['size']['uom']).to be_nil
744
+ expect(example.to_a[1]['size']['h']).not_to be_nil
745
+ expect(example.to_a[1]['size']['w']).not_to be_nil
746
+ end
747
+ end
748
+
749
+ context 'example 49' do
750
+
751
+ let!(:example) do
752
+ # Start Example 49
753
+ client[:inventory].find({ status: 'A' },
754
+ projection: {'item' => 1, 'status' => 1, 'instock.qty' => 1 })
755
+ # End Example 49
756
+ end
757
+
758
+ let(:instock_list) do
759
+ example.to_a[1]['instock']
760
+ end
761
+
762
+ it 'matches the expected output' do
763
+ expect(example.to_a[1]['_id']).not_to be_nil
764
+ expect(example.to_a[1]['item']).not_to be_nil
765
+ expect(example.to_a[1]['status']).not_to be_nil
766
+ expect(example.to_a[1]['size']).to be_nil
767
+ expect(example.to_a[1]['instock']).not_to be_nil
768
+ expect(instock_list.collect { |doc| doc['warehouse'] }.compact).to be_empty
769
+ expect(instock_list.collect { |doc| doc['qty'] }).to eq([5])
770
+ end
771
+ end
772
+
773
+ context 'example 50' do
774
+
775
+ let!(:example) do
776
+ # Start Example 50
777
+ client[:inventory].find({ status: 'A' },
778
+ projection: {'item' => 1,
779
+ 'status' => 1,
780
+ 'instock' => { '$slice' => -1 } })
781
+ # End Example 50
782
+ end
783
+
784
+ let(:instock_list) do
785
+ example.to_a[1]['instock']
786
+ end
787
+
788
+ it 'matches the expected output' do
789
+ expect(example.to_a[1]['_id']).not_to be_nil
790
+ expect(example.to_a[1]['item']).not_to be_nil
791
+ expect(example.to_a[1]['status']).not_to be_nil
792
+ expect(example.to_a[1]['size']).to be_nil
793
+ expect(example.to_a[1]['instock']).not_to be_nil
794
+ expect(instock_list.size).to eq(1)
795
+ end
796
+ end
797
+ end
798
+
799
+ context 'update' do
800
+
801
+ before do
802
+ # Start Example 51
803
+ client[:inventory].insert_many([
804
+ { item: 'canvas',
805
+ qty: 100,
806
+ size: { h: 28, w: 35.5, uom: 'cm' },
807
+ status: 'A' },
808
+ { item: 'journal',
809
+ qty: 25,
810
+ size: { h: 14, w: 21, uom: 'cm' },
811
+ status: 'A' },
812
+ { item: 'mat',
813
+ qty: 85,
814
+ size: { h: 27.9, w: 35.5, uom: 'cm' },
815
+ status: 'A' },
816
+ { item: 'mousepad',
817
+ qty: 25,
818
+ size: { h: 19, w: 22.85, uom: 'cm' },
819
+ status: 'P' },
820
+ { item: 'notebook',
821
+ qty: 50,
822
+ size: { h: 8.5, w: 11, uom: 'in' },
823
+ status: 'P' },
824
+ { item: 'paper',
825
+ qty: 100,
826
+ size: { h: 8.5, w: 11, uom: 'in' },
827
+ status: 'D' },
828
+ { item: 'planner',
829
+ qty: 75,
830
+ size: { h: 22.85, w: 30, uom: 'cm' },
831
+ status: 'D' },
832
+ { item: 'postcard',
833
+ qty: 45,
834
+ size: { h: 10, w: 15.25, uom: 'cm' },
835
+ status: 'A' },
836
+ { item: 'sketchbook',
837
+ qty: 80,
838
+ size: { h: 14, w: 21, uom: 'cm' },
839
+ status: 'A' },
840
+ { item: 'sketch pad',
841
+ qty: 95,
842
+ size: { h: 22.85, w: 30.5, uom: 'cm' },
843
+ status: 'A' }
844
+ ])
845
+ # End Example 51
846
+ end
847
+
848
+ context 'example 52', if: write_command_enabled? do
849
+
850
+ let!(:example) do
851
+ # Start Example 52
852
+ client[:inventory].update_one({ item: 'paper'},
853
+ { '$set' => { 'size.uom' => 'cm', 'status' => 'P' },
854
+ '$currentDate' => { 'lastModified' => true } })
855
+ # End Example 52
856
+ end
857
+
858
+ it 'matches the expected output' do
859
+ expect(client[:inventory].find(item: 'paper').all? { |doc| doc['size']['uom'] == 'cm'}).to be(true)
860
+ expect(client[:inventory].find(item: 'paper').all? { |doc| doc['status'] == 'P'}).to be(true)
861
+ expect(client[:inventory].find(item: 'paper').all? { |doc| doc['lastModified'] }).to be(true)
862
+ end
863
+ end
864
+
865
+ context 'example 53', if: write_command_enabled? do
866
+
867
+ let!(:example) do
868
+ # Start Example 53
869
+ client[:inventory].update_many({ qty: { '$lt' => 50 } },
870
+ { '$set' => { 'size.uom' => 'in', 'status' => 'P' },
871
+ '$currentDate' => { 'lastModified' => true } })
872
+ # End Example 53
873
+ end
874
+
875
+ let(:from_db) do
876
+ client[:inventory].find(qty: { '$lt' => 50 })
877
+ end
878
+
879
+ it 'matches the expected output' do
880
+ expect(from_db.all? { |doc| doc['size']['uom'] == 'in'}).to be(true)
881
+ expect(from_db.all? { |doc| doc['status'] == 'P'}).to be(true)
882
+ expect(from_db.all? { |doc| doc['lastModified'] }).to be(true)
883
+ end
884
+ end
885
+
886
+ context 'example 54' do
887
+
888
+ let!(:example) do
889
+ # Start Example 54
890
+ client[:inventory].replace_one({ item: 'paper' },
891
+ { item: 'paper',
892
+ instock: [ { warehouse: 'A', qty: 60 },
893
+ { warehouse: 'B', qty: 40 } ] })
894
+ # End Example 54
895
+ end
896
+
897
+ let(:from_db) do
898
+ client[:inventory].find({ item: 'paper' }, projection: { _id: 0 })
899
+ end
900
+
901
+ it 'matches the expected output' do
902
+ expect(from_db.first.keys.size).to eq(2)
903
+ expect(from_db.first.key?('item')).to be(true)
904
+ expect(from_db.first.key?('instock')).to be(true)
905
+ expect(from_db.first['instock'].size).to eq(2)
906
+ end
907
+ end
908
+ end
909
+
910
+ context 'delete' do
911
+
912
+ before do
913
+ # Start Example 55
914
+ client[:inventory].insert_many([
915
+ { item: 'journal',
916
+ qty: 25,
917
+ size: { h: 14, w: 21, uom: 'cm' },
918
+ status: 'A' },
919
+ { item: 'notebook',
920
+ qty: 50,
921
+ size: { h: 8.5, w: 11, uom: 'in' },
922
+ status: 'P' },
923
+ { item: 'paper',
924
+ qty: 100,
925
+ size: { h: 8.5, w: 11, uom: 'in' },
926
+ status: 'D' },
927
+ { item: 'planner',
928
+ qty: 75,
929
+ size: { h: 22.85, w: 30, uom: 'cm' },
930
+ status: 'D' },
931
+ { item: 'postcard',
932
+ qty: 45,
933
+ size: { h: 10, w: 15.25, uom: 'cm' },
934
+ status: 'A' },
935
+ ])
936
+ # End Example 55
937
+ end
938
+
939
+ context 'example 56' do
940
+
941
+ let(:example) do
942
+ # Start Example 56
943
+ client[:inventory].delete_many({})
944
+ # End Example 56
945
+ end
946
+
947
+ it 'matches the expected output' do
948
+ expect(example.deleted_count).to eq(5)
949
+ expect(client[:inventory].find.to_a.size).to eq(0)
950
+ end
951
+ end
952
+
953
+ context 'example 57' do
954
+
955
+ let(:example) do
956
+ # Start Example 57
957
+ client[:inventory].delete_many(status: 'A')
958
+ # End Example 57
959
+ end
960
+
961
+ it 'matches the expected output' do
962
+ expect(example.deleted_count).to eq(2)
963
+ expect(client[:inventory].find.to_a.size).to eq(3)
964
+ end
965
+ end
966
+
967
+ context 'example 58' do
968
+
969
+ let(:example) do
970
+ # Start Example 58
971
+ client[:inventory].delete_one(status: 'D')
972
+ # End Example 58
973
+ end
974
+
975
+ it 'matches the expected output' do
976
+ expect(example.deleted_count).to eq(1)
977
+ expect(client[:inventory].find.to_a.size).to eq(4)
978
+ end
979
+ end
980
+ end
981
+ end