Skip to content

Commit 4431221

Browse files
authored
MONGOSH-296 - Bulk API (#283)
* bulk * unit tests * Update i18n * integration tests * remove arrayFilters * CR comments
1 parent 36f4667 commit 4431221

File tree

12 files changed

+1403
-12
lines changed

12 files changed

+1403
-12
lines changed

packages/cli-repl/src/cli-repl.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,11 +298,15 @@ class CliRepl {
298298
// This checks for error instances.
299299
// The writer gets called immediately by the internal `this.repl.eval`
300300
// in case of errors.
301-
if (result && result.message && typeof result.stack === 'string') {
302-
this.bus.emit('mongosh:error', result);
301+
if (result && (
302+
(result.message !== undefined && typeof result.stack === 'string') ||
303+
(result.code !== undefined && result.errmsg !== undefined)
304+
)) {
303305
this.shellEvaluator.revertState();
304306

305-
return formatOutput({ type: 'Error', value: result });
307+
const output = { ...result, message: result.message || result.errmsg, name: result.name || 'MongoshInternalError' };
308+
this.bus.emit('mongosh:error', output);
309+
return formatOutput({ type: 'Error', value: output });
306310
}
307311

308312
return formatOutput(result);

packages/cli-repl/test/e2e.spec.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,20 @@ describe('e2e', function() {
124124
client.close();
125125
});
126126

127+
describe('error formatting', () => {
128+
it('throws when a syntax error is encountered', async() => {
129+
await shell.executeLine('<x');
130+
shell.assertContainsError('SyntaxError: Unexpected token');
131+
});
132+
it('throws a runtime error', async() => {
133+
await shell.executeLine('throw new Error(\'a errmsg\')');
134+
shell.assertContainsError('Error: a errmsg');
135+
});
136+
it('recognizes a driver error as error', async() => {
137+
await shell.executeLine('db.coll.initializeOrderedBulkOp().find({}).update({}, {}).execute()');
138+
shell.assertContainsOutput('MongoshInternalError: multi update is not supported for replacement-style update');
139+
});
140+
});
127141
it('throws multiline input with a single line string', async() => {
128142
// this is an unterminated string constant and should throw, since it does
129143
// not pass: https://www.ecma-international.org/ecma-262/#sec-line-terminators
@@ -169,11 +183,6 @@ describe('e2e', function() {
169183
});
170184
});
171185
});
172-
it('throws when a syntax error is encountered', async() => {
173-
await shell.executeLine('<x');
174-
shell.assertContainsError('SyntaxError: Unexpected token');
175-
});
176-
177186
it('runs an unterminated function', async() => {
178187
await shell.writeInputLine('function x () {\nconsole.log(\'y\')\n }');
179188
shell.assertNoErrors();

packages/i18n/src/locales/en_US.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,16 @@ const translations = {
528528
description: 'returns the $latencyStats aggregation for the collection. Takes an options document with an optional boolean \'histograms\' field.',
529529
example: 'db.latencyStats({ histograms: true })'
530530
},
531+
initializeUnorderedBulkOp: {
532+
link: 'https://docs.mongodb.com/manual/reference/method/db.collection.initializeUnorderedBulkOp',
533+
description: 'Initializes an unordered bulk command. Returns an instance of Bulk',
534+
example: 'db.initializeUnorderedBulkOp()'
535+
},
536+
initializeOrderedBulkOp: {
537+
link: 'https://docs.mongodb.com/manual/reference/method/db.collection.initializeOrderedBulkOp',
538+
description: 'Initializes an ordered bulk command. Returns an instance of Bulk',
539+
example: 'db.initializeOrderedBulkOp()'
540+
}
531541
}
532542
}
533543
},
@@ -1222,6 +1232,97 @@ const translations = {
12221232
},
12231233
attributes: {}
12241234
},
1235+
Bulk: {
1236+
help: {
1237+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk',
1238+
description: 'Bulk operations builder used to construct a list of write operations to perform in bulk for a single collection. To instantiate the builder, use either the db.collection.initializeOrderedBulkOp() or the db.collection.initializeUnorderedBulkOp() method.',
1239+
attributes: {
1240+
insert: {
1241+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.insert/',
1242+
description: 'Adds an insert to the bulk operation.',
1243+
example: 'db.insert(<document>)'
1244+
},
1245+
execute: {
1246+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.execute/',
1247+
description: 'Executes the bulk operation.',
1248+
example: 'bulkOp.execute()',
1249+
},
1250+
find: {
1251+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find/',
1252+
description: 'Adds a find to the bulk operation.',
1253+
example: 'bulkOp.find(<filter>)',
1254+
},
1255+
getOperations: {
1256+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.getOperations/',
1257+
description: 'Returns the batches executed by the bulk write.',
1258+
example: 'bulkOp.getOperations()',
1259+
},
1260+
tojson: {
1261+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.tojson/',
1262+
description: 'Returns a JSON document that contains the number of operations and batches in the Bulk() object.',
1263+
example: 'bulkOp.tojson()',
1264+
},
1265+
toString: {
1266+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.toString/',
1267+
description: 'Returns as a string a JSON document that contains the number of operations and batches in the Bulk() object.',
1268+
example: 'bulkOp.toString()',
1269+
}
1270+
}
1271+
}
1272+
},
1273+
BulkFindOp: {
1274+
help: {
1275+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find',
1276+
description: 'Bulk operations builder returned after Bulk.find()',
1277+
attributes: {
1278+
'arrayFilters': {
1279+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find.arrayFilters/',
1280+
description: 'Adds an arrayFilter to the bulk operation.',
1281+
example: 'bulkOp.find(...).arrayFilters(<array of filters)',
1282+
},
1283+
'hint': {
1284+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find.hint/',
1285+
description: 'Adds an hint to the bulk operation.',
1286+
example: 'bulkOp.find(...).hint(<hintd document>)',
1287+
},
1288+
'collation': {
1289+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find.collation/',
1290+
description: 'Not currently implemented, use db.collection.bulkWrite as an alternative',
1291+
example: 'bulkOp.find(...).collation(<collation doc>)',
1292+
},
1293+
'remove': {
1294+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find.remove/',
1295+
description: 'Adds an remove to the bulk operation.',
1296+
example: 'bulkOp.find(...).remove()',
1297+
},
1298+
'removeOne': {
1299+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find.removeOne/',
1300+
description: 'Adds an removeOne to the bulk operation.',
1301+
example: 'bulkOp.find(...).removeOne()',
1302+
},
1303+
'replaceOne': {
1304+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find.replaceOne/',
1305+
description: 'Adds an replaceOne to the bulk operation.',
1306+
example: 'bulkOp.find(...).replaceOne(<document>)',
1307+
},
1308+
'updateOne': {
1309+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find.updateOne/',
1310+
description: 'Adds an updateOne to the bulk operation.',
1311+
example: 'bulkOp.find(...).updateOne(<document>)',
1312+
},
1313+
'update': {
1314+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find.update/',
1315+
description: 'Adds an update to the bulk operation.',
1316+
example: 'bulkOp.find(...).update(<document>)',
1317+
},
1318+
'upsert': {
1319+
link: 'https://docs.mongodb.com/manual/reference/method/Bulk.find.upsert/',
1320+
description: 'Adds an upsert to the bulk operation updates for this find(...).',
1321+
example: 'bulkOp.find(...).upsert()',
1322+
}
1323+
}
1324+
}
1325+
}
12251326
}
12261327
},
12271328
'transport-browser': {
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import Document from './document';
2+
3+
export interface BulkBatch {
4+
originalZeroIndex: number;
5+
batchType: number;
6+
operations: any[];
7+
[key: string]: any;
8+
}
9+
10+
export interface DriverBulkResult {
11+
result: {
12+
ok: boolean;
13+
/**
14+
* The number of documents inserted.
15+
*/
16+
nInserted: number;
17+
18+
/**
19+
* The number of existing documents selected for update or replacement.
20+
*/
21+
nMatched: number;
22+
23+
/**
24+
* The number of existing documents updated or replaced.
25+
*/
26+
nModified: number;
27+
28+
/**
29+
* The number of documents removed.
30+
*/
31+
nRemoved: number;
32+
33+
/**
34+
* The number of upserted documents.
35+
*/
36+
nUpserted: number;
37+
38+
/**
39+
* Ids of upserted documents.
40+
*/
41+
upserted: {[index: number]: any};
42+
43+
/**
44+
* Ids of inserted documents.
45+
*/
46+
insertedIds: {[index: number]: any};
47+
};
48+
}
49+
50+
export interface ServiceProviderBulkFindOp {
51+
/**
52+
* Add a remove operation
53+
*/
54+
remove(): ServiceProviderBulkOp;
55+
56+
/**
57+
* Add a removeOne operation
58+
*/
59+
removeOne(): ServiceProviderBulkOp;
60+
61+
/**
62+
* Add a replaceOne operation
63+
*/
64+
replaceOne(replacement: Document): ServiceProviderBulkOp;
65+
66+
/**
67+
* Add a updateOne operation
68+
*/
69+
updateOne(update: Document): ServiceProviderBulkOp;
70+
71+
/**
72+
* Add a update operation
73+
*/
74+
update(update: Document): ServiceProviderBulkOp;
75+
76+
/**
77+
* Make subsequent update operations upsert: true
78+
*/
79+
upsert(): ServiceProviderBulkFindOp;
80+
}
81+
82+
export default interface ServiceProviderBulkOp {
83+
/**
84+
* Internal state
85+
*/
86+
s: {
87+
batches: BulkBatch[];
88+
currentUpdateBatch: BulkBatch;
89+
currentRemoveBatch: BulkBatch;
90+
currentInsertBatch: BulkBatch;
91+
currentBatch: BulkBatch;
92+
};
93+
94+
/**
95+
* Execute the operation.
96+
*/
97+
execute(): Promise<DriverBulkResult>;
98+
99+
/**
100+
* Find
101+
*/
102+
find(document: Document): ServiceProviderBulkFindOp;
103+
104+
/**
105+
* Insert
106+
*/
107+
insert(document: Document): ServiceProviderBulkOp;
108+
109+
}

packages/service-provider-core/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import CliOptions from './cli-options';
1515
import generateUri, { Scheme } from './uri-generator';
1616
const DEFAULT_DB = 'test';
1717
import bson from 'bson';
18+
import ServiceProviderBulkOp, { ServiceProviderBulkFindOp, BulkBatch } from './bulk';
1819

1920
export {
2021
ServiceProvider,
@@ -37,5 +38,8 @@ export {
3738
Scheme,
3839
DEFAULT_DB,
3940
ServiceProviderCore,
40-
bson
41+
bson,
42+
ServiceProviderBulkFindOp,
43+
ServiceProviderBulkOp,
44+
BulkBatch
4145
};

packages/service-provider-core/src/writable.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,5 +400,22 @@ export default interface Writable {
400400
newName: string,
401401
options?: Document,
402402
dbOptions?: DatabaseOptions): Promise<Result>;
403+
404+
/**
405+
* Initialize a bulk operation.
406+
*
407+
* @param dbName
408+
* @param collName
409+
* @param ordered
410+
* @param options
411+
* @param dbOptions
412+
*/
413+
initializeBulkOp(
414+
dbName: string,
415+
collName: string,
416+
ordered: boolean,
417+
options?: any,
418+
dbOptions?: any
419+
): Promise<any>;
403420
}
404421

packages/service-provider-server/src/cli-service-provider.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,19 @@ class CliServiceProvider extends ServiceProviderCore implements ServiceProvider
10521052
};
10531053
}
10541054
}
1055+
1056+
async initializeBulkOp(
1057+
dbName: string,
1058+
collName: string,
1059+
ordered: boolean,
1060+
options = {},
1061+
dbOptions?: any
1062+
): Promise<any> {
1063+
if (ordered) {
1064+
return await this.db(dbName, dbOptions).collection(collName).initializeOrderedBulkOp(options);
1065+
}
1066+
return await this.db(dbName, dbOptions).collection(collName).initializeUnorderedBulkOp(options);
1067+
}
10551068
}
10561069

10571070
export default CliServiceProvider;

0 commit comments

Comments
 (0)