Skip to content

Commit d5a9345

Browse files
authored
feat(chat): show errors if there are issues when getting databases & collections to pick VSCODE-610 (#864)
1 parent 9acf251 commit d5a9345

File tree

2 files changed

+107
-20
lines changed

2 files changed

+107
-20
lines changed

src/participant/participant.ts

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -793,11 +793,10 @@ export default class ParticipantController {
793793
_id: string;
794794
name: string;
795795
}[]
796-
| undefined
797796
> {
798797
const dataService = this._connectionController.getActiveDataService();
799798
if (!dataService) {
800-
return undefined;
799+
throw new Error(vscode.l10n.t('Failed to get the data service'));
801800
}
802801

803802
stream.push(
@@ -811,7 +810,11 @@ export default class ParticipantController {
811810
} catch (error) {
812811
log.error('Unable to fetch databases:', error);
813812

814-
return undefined;
813+
throw new Error(
814+
vscode.l10n.t(
815+
`Unable to fetch database names: ${formatError(error).message}.`
816+
)
817+
);
815818
}
816819
}
817820

@@ -821,11 +824,11 @@ export default class ParticipantController {
821824
}: {
822825
stream: vscode.ChatResponseStream;
823826
databaseName: string;
824-
}): Promise<ReturnType<DataService['listCollections']> | undefined> {
827+
}): Promise<ReturnType<DataService['listCollections']>> {
825828
const dataService = this._connectionController.getActiveDataService();
826829

827830
if (!dataService) {
828-
return undefined;
831+
throw new Error(vscode.l10n.t('Failed to get the data service'));
829832
}
830833

831834
stream.push(
@@ -835,9 +838,15 @@ export default class ParticipantController {
835838
try {
836839
return await dataService.listCollections(databaseName);
837840
} catch (error) {
838-
log.error('Unable to fetch collections:', error);
841+
log.error('Unable to fetch collection names:', error);
839842

840-
return undefined;
843+
throw new Error(
844+
vscode.l10n.t(
845+
`Unable to fetch collection names from ${databaseName}: ${
846+
formatError(error).message
847+
}.`
848+
)
849+
);
841850
}
842851
}
843852

@@ -856,9 +865,12 @@ export default class ParticipantController {
856865
}): Promise<string | undefined> {
857866
const collections = await this._getCollections({ stream, databaseName });
858867

859-
if (collections === undefined) {
860-
log.error('No collections found');
861-
return undefined;
868+
if (collections.length === 0) {
869+
throw new Error(
870+
vscode.l10n.t(
871+
`No collections were found in the database ${databaseName}.`
872+
)
873+
);
862874
}
863875
if (collections.length === 1) {
864876
return collections[0].name;
@@ -894,9 +906,8 @@ export default class ParticipantController {
894906
}): Promise<string | undefined> {
895907
const databases = await this._getDatabases({ stream });
896908

897-
if (databases === undefined || databases.length === 0) {
898-
log.error('No databases found');
899-
return undefined;
909+
if (databases.length === 0) {
910+
throw new Error(vscode.l10n.t('No databases were found.'));
900911
}
901912

902913
if (databases.length === 1) {
@@ -908,9 +919,11 @@ export default class ParticipantController {
908919
// Users can then select a value by clicking on an item in the list
909920
// or typing the name manually.
910921
stream.markdown(
911-
`Which database would you like ${
912-
command === '/query' ? 'this query to run against' : 'to use'
913-
}? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n`
922+
vscode.l10n.t(
923+
`Which database would you like ${
924+
command === '/query' ? 'this query to run against' : 'to use'
925+
}? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n`
926+
)
914927
);
915928

916929
this.renderDatabasesTree({

src/test/suite/participant/participant.test.ts

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as vscode from 'vscode';
22
import { beforeEach, afterEach } from 'mocha';
33
import { expect } from 'chai';
4-
import type { SinonSpy } from 'sinon';
4+
import type { SinonSpy, SinonStub } from 'sinon';
55
import sinon from 'sinon';
66
import type { DataService } from 'mongodb-data-service';
77
import { ObjectId, Int32 } from 'bson';
@@ -404,9 +404,9 @@ suite('Participant Controller Test Suite', function () {
404404
});
405405

406406
suite('when connected', function () {
407-
let sampleStub;
408-
let listCollectionsStub;
409-
let listDatabasesStub;
407+
let sampleStub: SinonStub;
408+
let listCollectionsStub: SinonStub;
409+
let listDatabasesStub: SinonStub;
410410

411411
beforeEach(function () {
412412
sampleStub = sinon.stub();
@@ -1790,6 +1790,43 @@ Schema:
17901790
sinon.restore();
17911791
});
17921792

1793+
test('shows an error if something goes wrong with getting databases', async function () {
1794+
listDatabasesStub.rejects(new Error('Something went wrong'));
1795+
1796+
let caughtError: Error | undefined;
1797+
try {
1798+
await invokeChatHandler({
1799+
prompt: 'find all docs by a name example',
1800+
command,
1801+
references: [],
1802+
});
1803+
} catch (error) {
1804+
caughtError = error as Error;
1805+
}
1806+
1807+
expect(caughtError?.message).equals(
1808+
'Unable to fetch database names: Something went wrong.'
1809+
);
1810+
});
1811+
1812+
test('shows an error if there are no databases found', async function () {
1813+
// No databases
1814+
listDatabasesStub.resolves([]);
1815+
1816+
let caughtError: Error | undefined;
1817+
try {
1818+
await invokeChatHandler({
1819+
prompt: 'find all docs by a name example',
1820+
command,
1821+
references: [],
1822+
});
1823+
} catch (error) {
1824+
caughtError = error as Error;
1825+
}
1826+
1827+
expect(caughtError?.message).equals('No databases were found.');
1828+
});
1829+
17931830
test('database name gets picked automatically if there is only 1', async function () {
17941831
listDatabasesStub.resolves([{ name: 'onlyOneDb' }]);
17951832

@@ -1859,6 +1896,43 @@ Schema:
18591896
);
18601897
});
18611898

1899+
test('shows an error if something goes wrong with getting collections', async function () {
1900+
listCollectionsStub.rejects(new Error('Something went wrong'));
1901+
1902+
let caughtError: Error | undefined;
1903+
try {
1904+
await invokeChatHandler({
1905+
prompt: 'find all docs by a name example',
1906+
command,
1907+
references: [],
1908+
});
1909+
} catch (error) {
1910+
caughtError = error as Error;
1911+
}
1912+
1913+
expect(caughtError?.message).equals(
1914+
'Unable to fetch collection names from dbOne: Something went wrong.'
1915+
);
1916+
});
1917+
1918+
test('shows an error if there are no collections found', async function () {
1919+
listCollectionsStub.resolves([]);
1920+
let caughtError: Error | undefined;
1921+
try {
1922+
await invokeChatHandler({
1923+
prompt: 'find all docs by a name example',
1924+
command,
1925+
references: [],
1926+
});
1927+
} catch (error) {
1928+
caughtError = error as Error;
1929+
}
1930+
1931+
expect(caughtError?.message).equals(
1932+
'No collections were found in the database dbOne.'
1933+
);
1934+
});
1935+
18621936
test('collection name gets picked automatically if there is only 1', async function () {
18631937
listCollectionsStub.resolves([{ name: 'onlyOneColl' }]);
18641938
const renderCollectionsTreeSpy = sinon.spy(

0 commit comments

Comments
 (0)