fix(mongodb): support show databases shell commands

Closes #6226
This commit is contained in:
t8y2 committed 2026-08-14 07:49:07 +00:00
1 parent 462f8e1fb2
commit 65792128e4
7 files changed
+515 -1

No files matched your search

@@ -62,6 +62,10 @@ export interface MongoVersionCommand {
kind: "version";
}
export interface MongoShowDatabasesCommand {
kind: "showDatabases";
}
export interface MongoCreateUserCommand {
userJson: string;
writeConcernJson?: string;
@@ -91,6 +95,7 @@ export type MongoCommand =
| ({ kind: "find" } & MongoFindCommand)
| ({ kind: "findOne" } & MongoFindOneCommand)
| MongoVersionCommand
| MongoShowDatabasesCommand
| ({ kind: "countDocuments" } & MongoCountDocumentsCommand)
| ({ kind: "aggregate" } & MongoAggregateCommand)
| ({ kind: "distinct" } & MongoDistinctCommand)
@@ -619,6 +624,7 @@ export function parseMongoCommand(input: string): ParsedMongoCommand | null {
// Keep the more specific readers ahead of generic write parsing so the
// returned kind matches the result renderer we want to use downstream.
const parsers: Array<(source: string) => MongoCommand | null> = [
parseMongoShowDatabasesCommand,
(source) => {
const version = parseMongoVersionCommand(source);
return version ?? null;
@@ -691,6 +697,11 @@ export function parseMongoCommand(input: string): ParsedMongoCommand | null {
return null;
}
export function parseMongoShowDatabasesCommand(input: string): MongoShowDatabasesCommand | null {
const source = input.trim().replace(/;$/, "").trim();
return /^show\s+(?:dbs|databases)$/i.test(source) ? { kind: "showDatabases" } : null;
}
export function splitMongoCommands(input: string): ParsedMongoCommand[] {
return splitMongoCommandRanges(input).map(({ from: _from, to: _to, ...command }) => command);
}
@@ -786,6 +797,27 @@ export function mongoDocumentsToQueryResult(documents: unknown[], executionTimeM
};
}
export function mongoDatabasesToQueryResult(documents: unknown[], executionTimeMs: number, maxRows: number): QueryResult {
const response = documents[0];
const databases = isRecord(response) ? response.databases : undefined;
if (!Array.isArray(databases)) throw new Error("MongoDB listDatabases response is missing the databases array.");
if (!databases.every(isRecord)) {
throw new Error("MongoDB listDatabases response contains an invalid database entry.");
}
const rowLimit = Number.isFinite(maxRows) ? Math.max(1, Math.trunc(maxRows)) : databases.length;
const rows = databases.slice(0, rowLimit).map((database) => [toCellValue(database.name), toCellValue(database.sizeOnDisk), toCellValue(database.empty)]);
const truncated = rows.length < databases.length;
return {
columns: ["name", "sizeOnDisk", "empty"],
rows,
affected_rows: databases.length,
execution_time_ms: Math.max(0, Math.round(executionTimeMs)),
truncated,
has_more: truncated,
};
}
export function mongoDistinctToQueryResult(field: string, values: unknown[], executionTimeMs: number): QueryResult {
return {
columns: [field],
@@ -1110,7 +1142,7 @@ function mongoTopLevelCommandLineStarts(segment: string): number[] {
function isMongoCommandLineStart(segment: string, index: number): boolean {
const rest = segment.slice(index);
return /^use\b/i.test(rest) || /^db(?:\s*\.|\b)/i.test(rest);
return /^use\b/i.test(rest) || /^show\s+(?:dbs|databases)\b/i.test(rest) || /^db(?:\s*\.|\b)/i.test(rest);
}
function pushMongoSegment(segments: MongoTextRange[], source: string, from: number, to: number) {
+15
View File
@@ -15,6 +15,7 @@ import {
evaluateMongoWriteSafety,
mongoCollectionStatsToQueryResult,
mongoCountToQueryResult,
mongoDatabasesToQueryResult,
mongoDistinctToQueryResult,
mongoCreateIndexToQueryResult,
mongoDocumentsToQueryResult,
@@ -4092,6 +4093,7 @@ export const useQueryStore = defineStore("query", () => {
queryExecutionLog("info", "mongo:start", { traceId, commandCount: mongoCommands.length, sqlLength: sql.length });
const allResults: QueryResult[] = [];
const mongoResultMaxRows = effectiveQueryResultMaxRows(settingsStore.editorSettings.queryResultMaxRowsEnabled, settingsStore.editorSettings.queryResultMaxRows);
// Track the effective db as we walk the batch so later commands observe
// earlier `use ...` statements in the same editor selection.
let currentDatabase = executionTarget?.database ?? tab.database;
@@ -4175,6 +4177,19 @@ export const useQueryStore = defineStore("query", () => {
});
break;
}
case "showDatabases": {
queryExecutionLog("info", "mongo-show-databases:start", { traceId });
const result = await api.mongoRunCommand(executionConnectionId, "admin", '{"listDatabases":1}', executionId);
const queryResult = mongoDatabasesToQueryResult(result.documents, performance.now() - commandStartedAt, agentProtocolQueryResultMaxRows(mongoResultMaxRows));
allResults.push(markQueryResultRowsRaw(annotateMongoResult(queryResult)));
mongoEditTarget = undefined;
queryExecutionLog("info", "mongo-show-databases:done", {
traceId,
databaseCount: queryResult.affected_rows,
elapsed: elapsed(),
});
break;
}
case "countDocuments": {
queryExecutionLog("info", "mongo-count:start", { traceId, collection: mongoCommand.collection, database: currentDatabase });
const total = await api.mongoCountDocuments(executionConnectionId, currentDatabase, mongoCommand.collection, mongoCommand.filter, mongoCommand.mode, executionId);