Skip to content

Commit 998bf19

Browse files
committed
nodb
1 parent 77867aa commit 998bf19

File tree

9 files changed

+122
-17
lines changed

9 files changed

+122
-17
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class CliRepl {
8181
*/
8282
async setupRepl(driverUri: string, driverOptions: NodeOptions): Promise<void> {
8383
const initialServiceProvider = await this.connect(driverUri, driverOptions);
84-
this.internalState = new ShellInternalState(initialServiceProvider, this.bus);
84+
this.internalState = new ShellInternalState(initialServiceProvider, this.bus, this.options);
8585
this.shellEvaluator = new ShellEvaluator(this.internalState, this);
8686
await this.internalState.fetchConnectionInfo();
8787
this.start();
@@ -94,8 +94,10 @@ class CliRepl {
9494
* @param {NodeOptions} driverOptions - The driver options.
9595
*/
9696
async connect(driverUri: string, driverOptions: NodeOptions): Promise<any> {
97-
console.log(i18n.__(CONNECTING), ' ', clr(retractPassword(driverUri), ['bold', 'green']));
98-
return await CliServiceProvider.connect(driverUri, driverOptions);
97+
if (!this.options.nodb) {
98+
console.log(i18n.__(CONNECTING), ' ', clr(retractPassword(driverUri), ['bold', 'green']));
99+
}
100+
return await CliServiceProvider.connect(driverUri, driverOptions, this.options);
99101
}
100102

101103
/**

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,27 @@ describe('e2e', function() {
2121
});
2222
});
2323

24+
describe('--nodb', () => {
25+
let shell;
26+
beforeEach(async() => {
27+
shell = TestShell.start({ args: [ '--nodb' ] });
28+
await shell.waitForPrompt();
29+
shell.assertNoErrors();
30+
});
31+
it('db throws', async() => {
32+
await shell.executeLine('db');
33+
shell.assertContainsError('MongoshInvalidInputError: No connected database');
34+
});
35+
it('show dbs throws InvalidInput', async() => {
36+
await shell.executeLine('show dbs');
37+
shell.assertContainsError('MongoshInvalidInputError: No connected database');
38+
});
39+
it('db.coll.find() throws InvalidInput', async() => {
40+
await shell.executeLine('db.coll.find()');
41+
shell.assertContainsError('MongoshInvalidInputError: No connected database');
42+
});
43+
});
44+
2445
describe('with connection string', () => {
2546
let db;
2647
let client;

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,26 @@ class CliServiceProvider implements ServiceProvider {
4242
*
4343
* @param {String} uri - The URI.
4444
* @param {NodeOptions} options - The options.
45+
* @param {Object} cliOptions - Options passed through CLI. Right now only being used for nodb.
4546
*
4647
* @returns {Promise} The promise with cli service provider.
4748
*/
4849
static async connect(
4950
uri: string,
50-
options: NodeOptions = {}
51+
options: NodeOptions = {},
52+
cliOptions: any = {}
5153
): Promise<CliServiceProvider> {
5254
const clientOptions: any = {
5355
...DEFAULT_OPTIONS,
5456
...options
5557
};
5658

57-
const mongoClient = await MongoClient.connect(
58-
uri,
59-
clientOptions
60-
);
59+
const mongoClient = !cliOptions.nodb ?
60+
await MongoClient.connect(
61+
uri,
62+
clientOptions
63+
) :
64+
new MongoClient(uri, clientOptions);
6165

6266
return new CliServiceProvider(mongoClient, uri);
6367
}

packages/shell-api/src/helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,6 @@ export function validateExplainableVerbosity(verbosity: string): void {
5151

5252
export function checkUndefinedUpdate(...args: any): void {
5353
if (args.some(a => a === undefined)) {
54-
throw new MongoshInvalidInputError('Cannot pass an undefined argument to a write command');
54+
throw new MongoshInvalidInputError('Cannot pass an undefined argument to a command');
5555
}
5656
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { expect } from 'chai';
2+
import NoDatabase from './no-db';
3+
describe('NoDatabase', () => {
4+
let nomongo;
5+
let nodb;
6+
beforeEach(() => {
7+
nodb = new NoDatabase();
8+
nomongo = nodb.mongo;
9+
});
10+
it('throws for show', () => {
11+
try {
12+
nodb.mongo.show('dbs');
13+
} catch (e) {
14+
return expect(e.name).to.equal('MongoshInvalidInputError');
15+
}
16+
expect.fail('no error thrown for NoDb.mongo.use');
17+
});
18+
it('throws for nomongo.use', () => {
19+
try {
20+
nomongo.use('test');
21+
} catch (e) {
22+
return expect(e.name).to.equal('MongoshInvalidInputError');
23+
}
24+
expect.fail('no error thrown for NoDb');
25+
});
26+
});

packages/shell-api/src/no-db.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { MongoshInvalidInputError } from '@mongosh/errors';
2+
import Mongo from './mongo';
3+
4+
export default class NoDatabase {
5+
mongo: Mongo;
6+
constructor() {
7+
this.mongo = new NoMongo() as Mongo;
8+
const proxy = new Proxy(this, {
9+
get: (target, prop): any => {
10+
if (prop === 'mongo') return this.mongo; // so we can create rs/sh without erroring
11+
throw new MongoshInvalidInputError('No connected database');
12+
}
13+
});
14+
return proxy;
15+
}
16+
}
17+
18+
class NoMongo {
19+
constructor() {
20+
const proxy = new Proxy(this, {
21+
get: (): any => {
22+
throw new MongoshInvalidInputError('No connected database');
23+
}
24+
});
25+
return proxy;
26+
}
27+
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,17 @@ describe('ShellApi', () => {
141141
expect(db.shellApiType()).to.equal('Database');
142142
expect(db.getMongo().uri).to.equal('uri');
143143
});
144+
it('fails with no arg', async() => {
145+
serviceProvider.platform = ReplPlatform.CLI;
146+
try {
147+
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
148+
// @ts-ignore
149+
await internalState.shellApi.connect();
150+
} catch (e) {
151+
return expect(e.name).to.equal('MongoshInvalidInputError');
152+
}
153+
expect.fail('MongoshInvalidInputError not thrown for connect');
154+
});
144155
});
145156
});
146157
describe('from context', () => {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Mongo from './mongo';
1212
import Database from './database';
1313
import { CommandResult } from './result';
1414
import ShellInternalState from './shell-internal-state';
15+
import { checkUndefinedUpdate } from './helpers';
1516
import { ReplPlatform } from '@mongosh/service-provider-core';
1617
import { MongoshUnimplementedError } from '@mongosh/errors';
1718

@@ -68,11 +69,12 @@ export default class ShellApi extends ShellApiClass {
6869
@returnsPromise
6970
@returnType('Database')
7071
@platforms([ ReplPlatform.CLI ] )
71-
async connect(uri?, user?, pwd?): Promise<Database> {
72+
async connect(uri, user?, pwd?): Promise<Database> {
73+
checkUndefinedUpdate(uri);
7274
const options = {} as any;
7375
if (user) options.username = user;
7476
if (pwd) options.password = pwd;
75-
const mongo = await this.Mongo(uri, { auth: options });
77+
const mongo = await this.Mongo(uri, Object.keys(options).length ? { auth: options } : {});
7678
return mongo.getDB('test');
7779
}
7880

packages/shell-api/src/shell-internal-state.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Document, ServiceProvider } from '@mongosh/service-provider-core';
1515
import { MongoshInvalidInputError } from '@mongosh/errors';
1616
import AsyncWriter from '@mongosh/async-rewriter';
1717
import { toIgnore } from './decorators';
18+
import NoDatabase from './no-db';
1819

1920
/**
2021
* Anything to do with the internal shell state is stored here.
@@ -30,21 +31,31 @@ export default class ShellInternalState {
3031
public context: any;
3132
public mongos: Mongo[];
3233
public shellApi: ShellApi;
33-
constructor(initialServiceProvider: ServiceProvider, messageBus: any = new EventEmitter()) {
34+
public cliOptions: any;
35+
constructor(initialServiceProvider: ServiceProvider, messageBus: any = new EventEmitter(), cliOptions: any = {}) {
3436
this.initialServiceProvider = initialServiceProvider;
3537
this.messageBus = messageBus;
3638
this.asyncWriter = new AsyncWriter(signatures);
3739
this.shellApi = new ShellApi(this);
38-
const mongo = new Mongo(this);
40+
this.mongos = [];
41+
this.connectionInfo = { buildInfo: {} };
42+
if (!cliOptions.nodb) {
43+
const mongo = new Mongo(this);
44+
this.mongos.push(mongo);
45+
this.currentDb = mongo.getDB('test'); // TODO: set to CLI arg
46+
} else {
47+
this.currentDb = new NoDatabase() as Database;
48+
}
3949
this.currentCursor = null;
40-
this.currentDb = mongo.getDB('test'); // TODO: set to CLI arg
4150
this.context = {};
42-
this.mongos = [ mongo ];
51+
this.cliOptions = cliOptions;
4352
}
4453

4554
async fetchConnectionInfo(): Promise<void> {
46-
this.connectionInfo = await this.currentDb.mongo.serviceProvider.getConnectionInfo();
47-
this.messageBus.emit('mongosh:connect', this.connectionInfo.extraInfo);
55+
if (!this.cliOptions.nodb) {
56+
this.connectionInfo = await this.currentDb.mongo.serviceProvider.getConnectionInfo();
57+
this.messageBus.emit('mongosh:connect', this.connectionInfo.extraInfo);
58+
}
4859
}
4960

5061
async close(p): Promise<void> {
@@ -95,6 +106,7 @@ export default class ShellInternalState {
95106
contextObject.help = this.shellApi.help;
96107
contextObject.printjson = contextObject.print;
97108
Object.assign(contextObject, ShellBson);
109+
98110
contextObject.rs = new ReplicaSet(this.currentDb.mongo);
99111
contextObject.sh = new Shard(this.currentDb.mongo);
100112

0 commit comments

Comments
 (0)