@mongosh/service-provider-node-driver 2.3.3
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.
- package/.depcheckrc +20 -0
- package/.eslintignore +2 -0
- package/.eslintrc.js +10 -0
- package/.prettierignore +6 -0
- package/.prettierrc.json +1 -0
- package/AUTHORS +3 -0
- package/LICENSE +201 -0
- package/lib/compass/compass-service-provider.d.ts +11 -0
- package/lib/compass/compass-service-provider.js +12 -0
- package/lib/compass/compass-service-provider.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/lib/mongodb-patches.d.ts +4 -0
- package/lib/mongodb-patches.js +18 -0
- package/lib/mongodb-patches.js.map +1 -0
- package/lib/node-driver-service-provider.d.ts +107 -0
- package/lib/node-driver-service-provider.js +622 -0
- package/lib/node-driver-service-provider.js.map +1 -0
- package/package.json +76 -0
- package/src/compass/compass-service-provider.ts +30 -0
- package/src/index.ts +4 -0
- package/src/mongodb-patches.spec.ts +67 -0
- package/src/mongodb-patches.ts +25 -0
- package/src/node-driver-provider.integration.spec.ts +841 -0
- package/src/node-driver-service-provider.spec.ts +1302 -0
- package/src/node-driver-service-provider.ts +1536 -0
- package/tsconfig-lint.json +5 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,841 @@
|
|
|
1
|
+
import type { DropDatabaseResult } from './node-driver-service-provider';
|
|
2
|
+
import { NodeDriverServiceProvider } from './node-driver-service-provider';
|
|
3
|
+
import { CompassServiceProvider } from './compass/compass-service-provider';
|
|
4
|
+
import { expect } from 'chai';
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { MongoClient } from 'mongodb';
|
|
7
|
+
import type {
|
|
8
|
+
AggregationCursor,
|
|
9
|
+
BulkWriteResult,
|
|
10
|
+
Db,
|
|
11
|
+
DeleteResult,
|
|
12
|
+
Document,
|
|
13
|
+
FindCursor,
|
|
14
|
+
InsertManyResult,
|
|
15
|
+
InsertOneResult,
|
|
16
|
+
UpdateResult,
|
|
17
|
+
} from 'mongodb';
|
|
18
|
+
import {
|
|
19
|
+
skipIfServerVersion,
|
|
20
|
+
startSharedTestServer,
|
|
21
|
+
} from '../../../testing/integration-testing-hooks';
|
|
22
|
+
import type {
|
|
23
|
+
DbOptions,
|
|
24
|
+
MongoClientOptions,
|
|
25
|
+
} from '@mongosh/service-provider-core';
|
|
26
|
+
import ConnectionString from 'mongodb-connection-string-url';
|
|
27
|
+
import { dummyOptions } from './node-driver-service-provider.spec';
|
|
28
|
+
|
|
29
|
+
describe('NodeDriverServiceProvider [integration]', function () {
|
|
30
|
+
const testServer = startSharedTestServer();
|
|
31
|
+
|
|
32
|
+
let serviceProvider: NodeDriverServiceProvider;
|
|
33
|
+
let client: MongoClient;
|
|
34
|
+
let dbName: string;
|
|
35
|
+
let db: Db;
|
|
36
|
+
let connectionString: string;
|
|
37
|
+
let bus: EventEmitter;
|
|
38
|
+
|
|
39
|
+
beforeEach(async function () {
|
|
40
|
+
connectionString = await testServer.connectionString();
|
|
41
|
+
client = await MongoClient.connect(
|
|
42
|
+
connectionString,
|
|
43
|
+
{} as MongoClientOptions
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
dbName = `test-db-${Date.now()}`;
|
|
47
|
+
db = client.db(dbName);
|
|
48
|
+
bus = new EventEmitter();
|
|
49
|
+
serviceProvider = new NodeDriverServiceProvider(
|
|
50
|
+
client,
|
|
51
|
+
bus,
|
|
52
|
+
dummyOptions,
|
|
53
|
+
new ConnectionString(connectionString)
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
afterEach(async function () {
|
|
58
|
+
await serviceProvider.close(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('.connect', function () {
|
|
62
|
+
let instance: NodeDriverServiceProvider;
|
|
63
|
+
beforeEach(async function () {
|
|
64
|
+
instance = await NodeDriverServiceProvider.connect(
|
|
65
|
+
connectionString,
|
|
66
|
+
dummyOptions,
|
|
67
|
+
{},
|
|
68
|
+
bus
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
afterEach(async function () {
|
|
73
|
+
await instance.close(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('returns a NodeDriverServiceProvider', function () {
|
|
77
|
+
expect(instance).to.be.instanceOf(NodeDriverServiceProvider);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('.getNewConnection', function () {
|
|
82
|
+
let instance: NodeDriverServiceProvider;
|
|
83
|
+
|
|
84
|
+
beforeEach(async function () {
|
|
85
|
+
instance = await serviceProvider.getNewConnection(connectionString);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
afterEach(async function () {
|
|
89
|
+
await instance.close(true);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('returns a NodeDriverServiceProvider', function () {
|
|
93
|
+
expect(instance).to.be.instanceOf(NodeDriverServiceProvider);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('differs from the original NodeDriverServiceProvider', function () {
|
|
97
|
+
expect(instance).to.not.equal(serviceProvider);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('.suspend', function () {
|
|
102
|
+
it('allows disconnecting and reconnecting the NodeDriverServiceProvider', async function () {
|
|
103
|
+
await serviceProvider.runCommandWithCheck('admin', { ping: 1 });
|
|
104
|
+
const reconnect = await serviceProvider.suspend();
|
|
105
|
+
try {
|
|
106
|
+
await serviceProvider.runCommandWithCheck('admin', { ping: 1 });
|
|
107
|
+
expect.fail('missed exception');
|
|
108
|
+
} catch (err: any) {
|
|
109
|
+
expect(err.name).to.equal('MongoNotConnectedError');
|
|
110
|
+
}
|
|
111
|
+
await reconnect();
|
|
112
|
+
await serviceProvider.runCommandWithCheck('admin', { ping: 1 });
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('.authenticate', function () {
|
|
117
|
+
beforeEach(async function () {
|
|
118
|
+
await serviceProvider.runCommandWithCheck('admin', {
|
|
119
|
+
createUser: 'xyz',
|
|
120
|
+
pwd: 'asdf',
|
|
121
|
+
roles: [],
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
afterEach(async function () {
|
|
126
|
+
await serviceProvider.runCommandWithCheck('admin', {
|
|
127
|
+
dropUser: 'xyz',
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('resets the MongoClient', async function () {
|
|
132
|
+
const mongoClientBefore = serviceProvider.mongoClient;
|
|
133
|
+
await serviceProvider.authenticate({
|
|
134
|
+
user: 'xyz',
|
|
135
|
+
pwd: 'asdf',
|
|
136
|
+
authDb: 'admin',
|
|
137
|
+
});
|
|
138
|
+
expect(serviceProvider.mongoClient).to.not.equal(mongoClientBefore);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('.resetConnectionOptions', function () {
|
|
143
|
+
it('resets the MongoClient', async function () {
|
|
144
|
+
const mongoClientBefore = serviceProvider.mongoClient;
|
|
145
|
+
await serviceProvider.resetConnectionOptions({
|
|
146
|
+
readPreference: 'secondaryPreferred',
|
|
147
|
+
});
|
|
148
|
+
expect(serviceProvider.mongoClient).to.not.equal(mongoClientBefore);
|
|
149
|
+
expect(serviceProvider.getReadPreference().mode).to.equal(
|
|
150
|
+
'secondaryPreferred'
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('.getConnectionInfo', function () {
|
|
156
|
+
context('when a uri has been passed', function () {
|
|
157
|
+
it("returns the connection's info", async function () {
|
|
158
|
+
const instance = new NodeDriverServiceProvider(
|
|
159
|
+
client,
|
|
160
|
+
bus,
|
|
161
|
+
dummyOptions,
|
|
162
|
+
new ConnectionString(connectionString)
|
|
163
|
+
);
|
|
164
|
+
const connectionInfo = await instance.getConnectionInfo();
|
|
165
|
+
|
|
166
|
+
expect(Object.keys(connectionInfo)).to.deep.equal([
|
|
167
|
+
'buildInfo',
|
|
168
|
+
'resolvedHostname',
|
|
169
|
+
'extraInfo',
|
|
170
|
+
]);
|
|
171
|
+
expect(connectionInfo.buildInfo?.version.length).to.be.greaterThan(1);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
context('when the optional uri has not been passed', function () {
|
|
176
|
+
it("returns the connection's info", async function () {
|
|
177
|
+
const instance = new NodeDriverServiceProvider(
|
|
178
|
+
client,
|
|
179
|
+
bus,
|
|
180
|
+
dummyOptions
|
|
181
|
+
);
|
|
182
|
+
const connectionInfo = await instance.getConnectionInfo();
|
|
183
|
+
|
|
184
|
+
expect(Object.keys(connectionInfo)).to.deep.equal([
|
|
185
|
+
'buildInfo',
|
|
186
|
+
'resolvedHostname',
|
|
187
|
+
'extraInfo',
|
|
188
|
+
]);
|
|
189
|
+
expect(connectionInfo.buildInfo?.version.length).to.be.greaterThan(1);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe('#aggregate', function () {
|
|
195
|
+
context(
|
|
196
|
+
'when passing a $function to be serialized by the driver',
|
|
197
|
+
function () {
|
|
198
|
+
skipIfServerVersion(testServer, '< 4.4');
|
|
199
|
+
|
|
200
|
+
let result: AggregationCursor;
|
|
201
|
+
|
|
202
|
+
beforeEach(function () {
|
|
203
|
+
const pipeline = [
|
|
204
|
+
{
|
|
205
|
+
$addFields: {
|
|
206
|
+
'attr.namespace': {
|
|
207
|
+
$function: {
|
|
208
|
+
body: function (value: any): any {
|
|
209
|
+
if (value) {
|
|
210
|
+
return value;
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
args: ['$attr.namespace'],
|
|
214
|
+
lang: 'js',
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
];
|
|
220
|
+
result = serviceProvider.aggregate('music', 'bands', pipeline);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('executes the command and resolves the result', async function () {
|
|
224
|
+
const docs = await result.toArray();
|
|
225
|
+
expect(docs).to.deep.equal([]);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
context('when running against a collection', function () {
|
|
231
|
+
let result: AggregationCursor;
|
|
232
|
+
|
|
233
|
+
beforeEach(function () {
|
|
234
|
+
result = serviceProvider.aggregate('music', 'bands', [
|
|
235
|
+
{ $match: { name: 'Aphex Twin' } },
|
|
236
|
+
]);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('executes the command and resolves the result', async function () {
|
|
240
|
+
const docs = await result.toArray();
|
|
241
|
+
expect(docs).to.deep.equal([]);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
context('when running against a database', function () {
|
|
246
|
+
let result: AggregationCursor;
|
|
247
|
+
|
|
248
|
+
beforeEach(function () {
|
|
249
|
+
result = serviceProvider.aggregateDb('admin', [{ $currentOp: {} }]);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('executes the command and resolves the result', async function () {
|
|
253
|
+
const docs = await result.toArray();
|
|
254
|
+
expect(docs[0].active).to.equal(true);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe('#bulkWrite', function () {
|
|
260
|
+
context('when the filter is empty', function () {
|
|
261
|
+
let result: BulkWriteResult;
|
|
262
|
+
const requests = [
|
|
263
|
+
{
|
|
264
|
+
insertOne: { name: 'Aphex Twin' },
|
|
265
|
+
} as any,
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
beforeEach(async function () {
|
|
269
|
+
result = await serviceProvider.bulkWrite('music', 'bands', requests);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
afterEach(function () {
|
|
273
|
+
return serviceProvider.deleteMany('music', 'bands', {});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
277
|
+
expect((result as any).result.nInserted).to.equal(1);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
describe('#count', function () {
|
|
283
|
+
context('when the filter is empty', function () {
|
|
284
|
+
let result: number;
|
|
285
|
+
|
|
286
|
+
beforeEach(async function () {
|
|
287
|
+
result = await serviceProvider.count('music', 'bands');
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
291
|
+
expect(result).to.equal(0);
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe('#countDocuments', function () {
|
|
297
|
+
context('when the filter is empty', function () {
|
|
298
|
+
let result: number;
|
|
299
|
+
|
|
300
|
+
beforeEach(async function () {
|
|
301
|
+
result = await serviceProvider.countDocuments('music', 'bands');
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
305
|
+
expect(result).to.equal(0);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
describe('#deleteMany', function () {
|
|
311
|
+
context('when the filter is empty', function () {
|
|
312
|
+
let result: DeleteResult;
|
|
313
|
+
|
|
314
|
+
beforeEach(async function () {
|
|
315
|
+
result = await serviceProvider.deleteMany('music', 'bands', {});
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
319
|
+
expect(result.deletedCount).to.equal(0);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
describe('#deleteOne', function () {
|
|
325
|
+
context('when the filter is empty', function () {
|
|
326
|
+
let result: DeleteResult;
|
|
327
|
+
|
|
328
|
+
beforeEach(async function () {
|
|
329
|
+
result = await serviceProvider.deleteOne('music', 'bands', {});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
333
|
+
expect(result.deletedCount).to.equal(0);
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
describe('#distinct', function () {
|
|
339
|
+
context('when the distinct is valid', function () {
|
|
340
|
+
let result: Document[];
|
|
341
|
+
|
|
342
|
+
beforeEach(async function () {
|
|
343
|
+
result = await serviceProvider.distinct('music', 'bands', 'name');
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('executes the command and resolves the result', function () {
|
|
347
|
+
expect(result).to.deep.equal([]);
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
describe('#estimatedDocumentCount', function () {
|
|
353
|
+
context('when no options are provided', function () {
|
|
354
|
+
let result: number;
|
|
355
|
+
|
|
356
|
+
beforeEach(async function () {
|
|
357
|
+
result = await serviceProvider.estimatedDocumentCount('music', 'bands');
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('executes the count and resolves the result', function () {
|
|
361
|
+
expect(result).to.equal(0);
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
describe('#find', function () {
|
|
367
|
+
context('when the find is valid', function () {
|
|
368
|
+
let result: FindCursor;
|
|
369
|
+
|
|
370
|
+
beforeEach(function () {
|
|
371
|
+
result = serviceProvider.find('music', 'bands', { name: 'Aphex Twin' });
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('executes the command and resolves the result', async function () {
|
|
375
|
+
const docs = await result.toArray();
|
|
376
|
+
expect(docs).to.deep.equal([]);
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
describe('#findOneAndDelete', function () {
|
|
382
|
+
context('when the find is valid', function () {
|
|
383
|
+
let result: Document | null;
|
|
384
|
+
const filter = { name: 'Aphex Twin' };
|
|
385
|
+
|
|
386
|
+
beforeEach(async function () {
|
|
387
|
+
result = await serviceProvider.findOneAndDelete(
|
|
388
|
+
'music',
|
|
389
|
+
'bands',
|
|
390
|
+
filter
|
|
391
|
+
);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it('executes the command and resolves the result', function () {
|
|
395
|
+
expect(result?.ok).to.equal(1);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
describe('#findOneAndReplace', function () {
|
|
401
|
+
context('when the find is valid', function () {
|
|
402
|
+
let result: Document;
|
|
403
|
+
const filter = { name: 'Aphex Twin' };
|
|
404
|
+
const replacement = { name: 'Richard James' };
|
|
405
|
+
|
|
406
|
+
beforeEach(async function () {
|
|
407
|
+
result = await serviceProvider.findOneAndReplace(
|
|
408
|
+
'music',
|
|
409
|
+
'bands',
|
|
410
|
+
filter,
|
|
411
|
+
replacement
|
|
412
|
+
);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it('executes the command and resolves the result', function () {
|
|
416
|
+
expect(result.ok).to.equal(1);
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
describe('#findOneAndUpdate', function () {
|
|
422
|
+
context('when the find is valid', function () {
|
|
423
|
+
let result: Document;
|
|
424
|
+
const filter = { name: 'Aphex Twin' };
|
|
425
|
+
const update = { $set: { name: 'Richard James' } };
|
|
426
|
+
|
|
427
|
+
beforeEach(async function () {
|
|
428
|
+
result = await serviceProvider.findOneAndUpdate(
|
|
429
|
+
'music',
|
|
430
|
+
'bands',
|
|
431
|
+
filter,
|
|
432
|
+
update
|
|
433
|
+
);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('executes the command and resolves the result', function () {
|
|
437
|
+
expect(result.ok).to.equal(1);
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
describe('#insertMany', function () {
|
|
443
|
+
context('when the insert is valid', function () {
|
|
444
|
+
let result: InsertManyResult;
|
|
445
|
+
|
|
446
|
+
beforeEach(async function () {
|
|
447
|
+
result = await serviceProvider.insertMany('music', 'bands', [
|
|
448
|
+
{ name: 'Aphex Twin' },
|
|
449
|
+
]);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
afterEach(function () {
|
|
453
|
+
return serviceProvider.deleteMany('music', 'bands', {});
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
457
|
+
expect(result.acknowledged).to.equal(true);
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
describe('#insertOne', function () {
|
|
463
|
+
context('when the insert is valid', function () {
|
|
464
|
+
let result: InsertOneResult;
|
|
465
|
+
|
|
466
|
+
beforeEach(async function () {
|
|
467
|
+
result = await serviceProvider.insertOne('music', 'bands', {
|
|
468
|
+
name: 'Aphex Twin',
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
afterEach(function () {
|
|
473
|
+
return serviceProvider.deleteMany('music', 'bands', {});
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
477
|
+
expect(result.acknowledged).to.equal(true);
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
describe('#listDatabases', function () {
|
|
483
|
+
let result: Document;
|
|
484
|
+
|
|
485
|
+
beforeEach(async function () {
|
|
486
|
+
result = await serviceProvider.listDatabases('admin');
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it('returns a list of databases', function () {
|
|
490
|
+
expect(result.ok).to.equal(1);
|
|
491
|
+
expect(
|
|
492
|
+
result.databases.map((db: { name: string }) => db.name)
|
|
493
|
+
).to.include('admin');
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
describe('#replaceOne', function () {
|
|
498
|
+
const filter = { name: 'Aphex Twin' };
|
|
499
|
+
const replacement = { name: 'Richard James' };
|
|
500
|
+
|
|
501
|
+
context('when the filter is empty', function () {
|
|
502
|
+
let result: UpdateResult;
|
|
503
|
+
|
|
504
|
+
beforeEach(async function () {
|
|
505
|
+
result = await serviceProvider.replaceOne(
|
|
506
|
+
'music',
|
|
507
|
+
'bands',
|
|
508
|
+
filter,
|
|
509
|
+
replacement
|
|
510
|
+
);
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
514
|
+
expect(result.acknowledged).to.equal(true);
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
describe('#runCommand', function () {
|
|
520
|
+
context('when the command is valid', function () {
|
|
521
|
+
let result: Document;
|
|
522
|
+
|
|
523
|
+
beforeEach(async function () {
|
|
524
|
+
result = await serviceProvider.runCommand('admin', { ismaster: true });
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
it('executes the command and resolves the result', function () {
|
|
528
|
+
expect(result.ismaster).to.equal(true);
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
describe('#updateMany', function () {
|
|
534
|
+
const filter = { name: 'Aphex Twin' };
|
|
535
|
+
const update = { $set: { name: 'Richard James' } };
|
|
536
|
+
context('when the filter is empty', function () {
|
|
537
|
+
let result: UpdateResult;
|
|
538
|
+
|
|
539
|
+
beforeEach(async function () {
|
|
540
|
+
result = await serviceProvider.updateMany(
|
|
541
|
+
'music',
|
|
542
|
+
'bands',
|
|
543
|
+
filter,
|
|
544
|
+
update
|
|
545
|
+
);
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
549
|
+
expect(result.acknowledged).to.equal(true);
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
describe('#updateOne', function () {
|
|
555
|
+
const filter = { name: 'Aphex Twin' };
|
|
556
|
+
const update = { $set: { name: 'Richard James' } };
|
|
557
|
+
context('when the filter is empty', function () {
|
|
558
|
+
let result: UpdateResult;
|
|
559
|
+
|
|
560
|
+
beforeEach(async function () {
|
|
561
|
+
result = await serviceProvider.updateOne(
|
|
562
|
+
'music',
|
|
563
|
+
'bands',
|
|
564
|
+
filter,
|
|
565
|
+
update
|
|
566
|
+
);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
it('executes the count with an empty filter and resolves the result', function () {
|
|
570
|
+
expect(result.acknowledged).to.equal(true);
|
|
571
|
+
});
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
describe('#dropCollection', function () {
|
|
576
|
+
context('when a collection existed', function () {
|
|
577
|
+
it('returns {ok: 1}', async function () {
|
|
578
|
+
await serviceProvider.createCollection('test', 'collectionexists');
|
|
579
|
+
const result = await serviceProvider.dropCollection(
|
|
580
|
+
'test',
|
|
581
|
+
'collectionexists'
|
|
582
|
+
);
|
|
583
|
+
expect(result).to.equal(true);
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
describe('#dropDatabase', function () {
|
|
589
|
+
context('when a database does not exist', function () {
|
|
590
|
+
let result: DropDatabaseResult;
|
|
591
|
+
|
|
592
|
+
it('returns {ok: 1}', async function () {
|
|
593
|
+
result = await serviceProvider.dropDatabase(`test-db-${Date.now()}`);
|
|
594
|
+
expect(result.ok).to.equal(1);
|
|
595
|
+
});
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
context('when a database exists', function () {
|
|
599
|
+
let result: DropDatabaseResult;
|
|
600
|
+
|
|
601
|
+
const dbExists = async (): Promise<boolean> => {
|
|
602
|
+
return (await db.admin().listDatabases()).databases
|
|
603
|
+
.map((database) => database.name)
|
|
604
|
+
.includes(dbName);
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
beforeEach(async function () {
|
|
608
|
+
await db.collection('coll1').insertOne({ doc: 1 });
|
|
609
|
+
expect(await dbExists()).to.be.true;
|
|
610
|
+
result = await serviceProvider.dropDatabase(dbName);
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
it('returns {ok: 1}', function () {
|
|
614
|
+
expect(result.ok).to.equal(1);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('deletes the database', async function () {
|
|
618
|
+
expect(await dbExists()).to.be.false;
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
describe('#createIndexes', function () {
|
|
624
|
+
it('creates a new index', async function () {
|
|
625
|
+
const collName = 'coll1';
|
|
626
|
+
const nativeCollection = db.collection(collName);
|
|
627
|
+
|
|
628
|
+
await db.createCollection(collName);
|
|
629
|
+
|
|
630
|
+
expect(await nativeCollection.indexExists('index-1')).to.be.false;
|
|
631
|
+
|
|
632
|
+
await serviceProvider.createIndexes(dbName, collName, [
|
|
633
|
+
{
|
|
634
|
+
name: 'index-1',
|
|
635
|
+
key: { x: 1 },
|
|
636
|
+
},
|
|
637
|
+
]);
|
|
638
|
+
|
|
639
|
+
expect(await nativeCollection.indexExists('index-1')).to.be.true;
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
describe('#getIndexes', function () {
|
|
644
|
+
it('returns indexes', async function () {
|
|
645
|
+
const collName = 'coll1';
|
|
646
|
+
const nativeCollection = db.collection(collName);
|
|
647
|
+
|
|
648
|
+
await nativeCollection.createIndex('x');
|
|
649
|
+
|
|
650
|
+
const result = await serviceProvider.getIndexes(dbName, collName);
|
|
651
|
+
|
|
652
|
+
expect(result.map((spec) => spec.key)).to.deep.equal([
|
|
653
|
+
{ _id: 1 },
|
|
654
|
+
{ x: 1 },
|
|
655
|
+
]);
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
// TODO(MONGOSH-1465): integration tests for search indexes
|
|
660
|
+
|
|
661
|
+
describe('#listCollections', function () {
|
|
662
|
+
it('returns the list of collections', async function () {
|
|
663
|
+
await db.createCollection('coll1');
|
|
664
|
+
|
|
665
|
+
expect(
|
|
666
|
+
(await serviceProvider.listCollections(dbName)).map((c: any) => c.name)
|
|
667
|
+
).to.deep.equal(['coll1']);
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
it('filter the list of collections', async function () {
|
|
671
|
+
await db.createCollection('coll1');
|
|
672
|
+
await db.createCollection('coll2');
|
|
673
|
+
|
|
674
|
+
expect(
|
|
675
|
+
(await serviceProvider.listCollections(dbName, { name: 'coll2' })).map(
|
|
676
|
+
(c: any) => c.name
|
|
677
|
+
)
|
|
678
|
+
).to.deep.equal(['coll2']);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
it('allows options', async function () {
|
|
682
|
+
await db.createCollection('coll1');
|
|
683
|
+
await db.createCollection('coll2');
|
|
684
|
+
|
|
685
|
+
const collections = await serviceProvider.listCollections(
|
|
686
|
+
dbName,
|
|
687
|
+
{},
|
|
688
|
+
{ nameOnly: true }
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
expect(collections).to.deep.contain({
|
|
692
|
+
name: 'coll1',
|
|
693
|
+
type: 'collection',
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
expect(collections).to.deep.contain({
|
|
697
|
+
name: 'coll2',
|
|
698
|
+
type: 'collection',
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
context('post-5.0', function () {
|
|
703
|
+
skipIfServerVersion(testServer, '< 5.0');
|
|
704
|
+
|
|
705
|
+
it('allows time-series', async function () {
|
|
706
|
+
await db.createCollection('coll1', {
|
|
707
|
+
timeseries: { timeField: 'time' },
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
const collections = await serviceProvider.listCollections(
|
|
711
|
+
dbName,
|
|
712
|
+
{},
|
|
713
|
+
{ nameOnly: true }
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
expect(collections).to.deep.contain({
|
|
717
|
+
name: 'coll1',
|
|
718
|
+
type: 'timeseries',
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
expect(collections).to.deep.contain({
|
|
722
|
+
name: 'system.buckets.coll1',
|
|
723
|
+
type: 'collection',
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
expect(collections).to.deep.contain({
|
|
727
|
+
name: 'system.views',
|
|
728
|
+
type: 'collection',
|
|
729
|
+
});
|
|
730
|
+
});
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
context('post-5.3', function () {
|
|
734
|
+
skipIfServerVersion(testServer, '< 5.3');
|
|
735
|
+
|
|
736
|
+
it('allows clustered indexes on collections', async function () {
|
|
737
|
+
await db.createCollection('coll1', {
|
|
738
|
+
clusteredIndex: {
|
|
739
|
+
key: { _id: 1 },
|
|
740
|
+
unique: true,
|
|
741
|
+
},
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
const collections = await serviceProvider.listCollections(
|
|
745
|
+
dbName,
|
|
746
|
+
{},
|
|
747
|
+
{}
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
const matchingCollection = collections.find(
|
|
751
|
+
(collection) => collection.name === 'coll1'
|
|
752
|
+
);
|
|
753
|
+
expect(matchingCollection).to.not.be.undefined;
|
|
754
|
+
expect(matchingCollection?.options).to.deep.contain({
|
|
755
|
+
clusteredIndex: {
|
|
756
|
+
v: 2,
|
|
757
|
+
key: { _id: 1 },
|
|
758
|
+
name: '_id_',
|
|
759
|
+
unique: true,
|
|
760
|
+
},
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
const indexes = await serviceProvider.getIndexes(dbName, 'coll1');
|
|
764
|
+
|
|
765
|
+
expect(indexes).to.deep.contain({
|
|
766
|
+
key: {
|
|
767
|
+
_id: 1,
|
|
768
|
+
},
|
|
769
|
+
name: '_id_',
|
|
770
|
+
v: 2,
|
|
771
|
+
clustered: true,
|
|
772
|
+
unique: true,
|
|
773
|
+
});
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
describe('db fetching', function () {
|
|
779
|
+
it('returns the same db instance when used with the same name and options', function () {
|
|
780
|
+
const db1 = serviceProvider._dbTestWrapper('foo', {
|
|
781
|
+
readPreference: { mode: 'secondary' },
|
|
782
|
+
} as DbOptions);
|
|
783
|
+
const db2 = serviceProvider._dbTestWrapper('foo', {
|
|
784
|
+
readPreference: { mode: 'secondary' },
|
|
785
|
+
} as DbOptions);
|
|
786
|
+
expect(db1).to.equal(db2);
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
it('returns the different db instances when used with different names', function () {
|
|
790
|
+
const db1 = serviceProvider._dbTestWrapper('bar', {
|
|
791
|
+
readPreference: { mode: 'secondary' },
|
|
792
|
+
} as DbOptions);
|
|
793
|
+
const db2 = serviceProvider._dbTestWrapper('foo', {
|
|
794
|
+
readPreference: { mode: 'secondary' },
|
|
795
|
+
} as DbOptions);
|
|
796
|
+
expect(db1).not.to.equal(db2);
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
it('returns the different db instances when used with different options', function () {
|
|
800
|
+
const db1 = serviceProvider._dbTestWrapper('foo', {
|
|
801
|
+
readPreference: { mode: 'primary' },
|
|
802
|
+
} as DbOptions);
|
|
803
|
+
const db2 = serviceProvider._dbTestWrapper('foo', {
|
|
804
|
+
readPreference: { mode: 'secondary' },
|
|
805
|
+
} as DbOptions);
|
|
806
|
+
expect(db1).not.to.equal(db2);
|
|
807
|
+
});
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
describe('#driverMetadata', function () {
|
|
811
|
+
it('returns information about the driver instance', function () {
|
|
812
|
+
expect(serviceProvider.driverMetadata?.driver.name).to.equal('nodejs');
|
|
813
|
+
});
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
describe('#getURI', function () {
|
|
817
|
+
it('returns the current URI', function () {
|
|
818
|
+
expect(serviceProvider.getURI()).to.equal(connectionString);
|
|
819
|
+
});
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
describe('CompassServiceProvider', function () {
|
|
823
|
+
let instance: NodeDriverServiceProvider;
|
|
824
|
+
|
|
825
|
+
afterEach(async function () {
|
|
826
|
+
await instance?.close(true);
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
it('.connect() returns a CompassServiceProvider instance', async function () {
|
|
830
|
+
instance = await CompassServiceProvider.connect(
|
|
831
|
+
connectionString,
|
|
832
|
+
dummyOptions,
|
|
833
|
+
{},
|
|
834
|
+
bus
|
|
835
|
+
);
|
|
836
|
+
|
|
837
|
+
expect(instance).to.be.instanceOf(CompassServiceProvider);
|
|
838
|
+
expect(instance.platform).to.equal('Compass');
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
});
|