Skip to content

Commit 10df3c2

Browse files
authored
feat(shell-api,cli-repl): add versioned API args MONGOSH-351 (#769)
Add CLI args and `Mongo` constructor options matching those added to the legacy shell.
1 parent 573dc4a commit 10df3c2

21 files changed

+221
-28
lines changed

packages/cli-repl/src/arg-mapper.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,24 @@ describe('arg-mapper.mapCliToDriver', () => {
241241
});
242242
});
243243
});
244+
245+
context('when the cli args have all server API options options', () => {
246+
const cliOptions: CliOptions = {
247+
apiStrict: true,
248+
apiDeprecationErrors: true,
249+
apiVersion: '1'
250+
};
251+
252+
it('maps to serverApi', async() => {
253+
expect(await mapCliToDriver(cliOptions)).to.deep.equal({
254+
serverApi: {
255+
strict: true,
256+
deprecationErrors: true,
257+
version: '1'
258+
}
259+
});
260+
});
261+
});
244262
});
245263

246264
describe('arg-mapper.applyTlsCertificateSelector', () => {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import setValue from 'lodash.set';
66
* Mapping fields from the CLI args to Node options.
77
*/
88
const MAPPINGS = {
9+
apiDeprecationErrors: 'serverApi.deprecationErrors',
10+
apiStrict: 'serverApi.strict',
11+
apiVersion: 'serverApi.version',
912
awsAccessKeyId: 'autoEncryption.kmsProviders.aws.accessKeyId',
1013
awsSecretAccessKey: 'autoEncryption.kmsProviders.aws.secretAccessKey',
1114
awsSessionToken: 'autoEncryption.kmsProviders.aws.sessionToken',

packages/cli-repl/src/arg-parser.spec.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,44 @@ describe('arg-parser', () => {
546546
});
547547
});
548548

549+
context('when providing versioned API options', () => {
550+
context('when providing --apiVersion', () => {
551+
const argv = [ ...baseArgv, uri, '--apiVersion', '1' ];
552+
553+
it('returns the URI in the object', () => {
554+
expect(parseCliArgs(argv)._[0]).to.equal(uri);
555+
});
556+
557+
it('sets the apiVersion in the object', () => {
558+
expect(parseCliArgs(argv).apiVersion).to.equal('1');
559+
});
560+
});
561+
562+
context('when providing --apiDeprecationErrors', () => {
563+
const argv = [ ...baseArgv, uri, '--apiDeprecationErrors' ];
564+
565+
it('returns the URI in the object', () => {
566+
expect(parseCliArgs(argv)._[0]).to.equal(uri);
567+
});
568+
569+
it('sets the apiVersion in the object', () => {
570+
expect(parseCliArgs(argv).apiDeprecationErrors).to.equal(true);
571+
});
572+
});
573+
574+
context('when providing --apiStrict', () => {
575+
const argv = [ ...baseArgv, uri, '--apiStrict' ];
576+
577+
it('returns the URI in the object', () => {
578+
expect(parseCliArgs(argv)._[0]).to.equal(uri);
579+
});
580+
581+
it('sets the apiVersion in the object', () => {
582+
expect(parseCliArgs(argv).apiStrict).to.equal(true);
583+
});
584+
});
585+
});
586+
549587
context('when providing filenames', () => {
550588
context('when the filenames end in .js', () => {
551589
const argv = [ ...baseArgv, uri, 'test1.js', 'test2.js' ];

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const START = 'start';
2020
*/
2121
const OPTIONS = {
2222
string: [
23+
'apiVersion',
2324
'authenticationDatabase',
2425
'authenticationMechanism',
2526
'awsAccessKeyId',
@@ -52,7 +53,8 @@ const OPTIONS = {
5253
'username'
5354
],
5455
boolean: [
55-
'async',
56+
'apiDeprecationErrors',
57+
'apiStrict',
5658
'help',
5759
'ipv6',
5860
'nodb',

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

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { expect } from 'chai';
33
import { MongoClient } from 'mongodb';
44
import { eventually } from './helpers';
55
import { TestShell } from './test-shell';
6-
import { startTestServer } from '../../../testing/integration-testing-hooks';
6+
import { startTestServer, skipIfServerVersion } from '../../../testing/integration-testing-hooks';
77
import { promises as fs, createReadStream } from 'fs';
88
import { promisify } from 'util';
99
import rimraf from 'rimraf';
@@ -839,5 +839,63 @@ describe('e2e', function() {
839839
});
840840
});
841841
});
842+
843+
describe('versioned API', () => {
844+
let db;
845+
let dbName;
846+
let client;
847+
848+
beforeEach(async() => {
849+
dbName = `test-${Date.now()}`;
850+
851+
client = await MongoClient.connect(await testServer.connectionString(), {});
852+
db = client.db(dbName);
853+
});
854+
855+
afterEach(async() => {
856+
await db.dropDatabase();
857+
client.close();
858+
});
859+
860+
861+
context('pre-4.4', () => {
862+
skipIfServerVersion(testServer, '> 4.4');
863+
864+
it('errors if an API version is specified', async() => {
865+
const shell = TestShell.start({ args: [
866+
`${await testServer.connectionString()}/${dbName}`, '--apiVersion', '1'
867+
] });
868+
await shell.waitForPrompt();
869+
expect(await shell.executeLine('db.coll.find().toArray()'))
870+
.to.include("Unrecognized field 'apiVersion'");
871+
});
872+
});
873+
874+
context('post-4.4', () => {
875+
skipIfServerVersion(testServer, '<= 4.4');
876+
877+
it('can specify an API version', async() => {
878+
const shell = TestShell.start({ args: [
879+
`${await testServer.connectionString()}/${dbName}`, '--apiVersion', '1'
880+
] });
881+
await shell.waitForPrompt();
882+
expect(await shell.executeLine('db.coll.find().toArray()'))
883+
.to.include('[]');
884+
shell.assertNoErrors();
885+
});
886+
887+
it('can iterate cursors', async() => {
888+
// Make sure SERVER-55593 doesn't happen to us.
889+
const shell = TestShell.start({ args: [
890+
`${await testServer.connectionString()}/${dbName}`, '--apiVersion', '1'
891+
] });
892+
await shell.waitForPrompt();
893+
await shell.executeLine('for (let i = 0; i < 200; i++) db.coll.insert({i})');
894+
await shell.executeLine('const cursor = db.coll.find().limit(100).batchSize(10);');
895+
expect(await shell.executeLine('cursor.toArray()')).to.include('i: 5');
896+
shell.assertNoErrors();
897+
});
898+
});
899+
});
842900
});
843901

packages/service-provider-core/src/all-transport-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,7 @@ export type {
7373
TopologyTypeId,
7474
ServerTypeId,
7575
AutoEncryptionOptions,
76+
ServerApi,
77+
ServerApiVersionId,
7678
MongoClient // mostly for testing
7779
} from 'mongodb';

packages/service-provider-core/src/cli-options.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
*/
44
export default interface CliOptions {
55
_?: string[];
6-
async?: boolean;
6+
apiDeprecationErrors?: boolean;
7+
apiStrict?: boolean;
8+
apiVersion?: string;
79
authenticationDatabase?: string;
810
authenticationMechanism?: string;
911
awsAccessKeyId?: string;

packages/shell-api/src/change-stream-cursor.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ describe('ChangeStreamCursor', () => {
119119
this.timeout(100_000);
120120
serviceProvider = await CliServiceProvider.connect(await srv0.connectionString());
121121
internalState = new ShellInternalState(serviceProvider);
122-
mongo = new Mongo(internalState, undefined, undefined, serviceProvider);
122+
mongo = new Mongo(internalState, undefined, undefined, undefined, serviceProvider);
123123
db = mongo.getDB('testDb');
124124
coll = db.getCollection('testColl');
125125
});

packages/shell-api/src/collection.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ describe('Collection', () => {
118118
serviceProvider.initialDb = 'test';
119119
serviceProvider.bsonLibrary = bson;
120120
internalState = new ShellInternalState(serviceProvider, bus);
121-
mongo = new Mongo(internalState, undefined, undefined, serviceProvider);
121+
mongo = new Mongo(internalState, undefined, undefined, undefined, serviceProvider);
122122
database = new Database(mongo, 'db1');
123123
collection = new Collection(mongo, database, 'coll1');
124124
});
@@ -1807,7 +1807,7 @@ describe('Collection', () => {
18071807
k => serviceProvider[k].resolves({ result: {}, value: {} })
18081808
);
18091809
const internalState = new ShellInternalState(serviceProvider, bus);
1810-
const mongo = new Mongo(internalState, undefined, undefined, serviceProvider);
1810+
const mongo = new Mongo(internalState, undefined, undefined, undefined, serviceProvider);
18111811
const session = mongo.startSession();
18121812
collection = session.getDatabase('db1').getCollection('coll');
18131813
});

packages/shell-api/src/database.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ describe('Database', () => {
126126
serviceProvider.runCommand.resolves({ ok: 1 });
127127
serviceProvider.runCommandWithCheck.resolves({ ok: 1 });
128128
internalState = new ShellInternalState(serviceProvider, bus);
129-
mongo = new Mongo(internalState, undefined, undefined, serviceProvider);
129+
mongo = new Mongo(internalState, undefined, undefined, undefined, serviceProvider);
130130
database = new Database(mongo, 'db1');
131131
});
132132
describe('getCollectionInfos', () => {
@@ -2455,7 +2455,7 @@ describe('Database', () => {
24552455
serviceProvider.runCommand.resolves({ ok: 1 });
24562456
serviceProvider.listCollections.resolves([]);
24572457
const internalState = new ShellInternalState(serviceProvider, bus);
2458-
const mongo = new Mongo(internalState, undefined, undefined, serviceProvider);
2458+
const mongo = new Mongo(internalState, undefined, undefined, undefined, serviceProvider);
24592459
const session = mongo.startSession();
24602460
database = session.getDatabase('db1');
24612461
});

0 commit comments

Comments
 (0)