fix(mongodb): support collection drop shell command

This commit is contained in:
Guoyu Su 2026-07-09 14:16:32 +08:00 committed by GitHub
parent 315c6e235b
commit ca9e11217e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 206 additions and 14 deletions

View File

@ -46,6 +46,7 @@ public final class AgentProtocol {
public static final String MONGO_METHOD_SERVER_VERSION = "server_version";
public static final String MONGO_METHOD_CREATE_INDEX = "create_index";
public static final String MONGO_METHOD_DROP_INDEXES = "drop_indexes";
public static final String MONGO_METHOD_DROP_COLLECTION = "drop_collection";
public static final String MONGO_METHOD_INSERT_DOCUMENT = "insert_document";
public static final String MONGO_METHOD_UPDATE_DOCUMENT = "update_document";
public static final String MONGO_METHOD_UPDATE_DOCUMENTS = "update_documents";
@ -126,6 +127,7 @@ public final class AgentProtocol {
MONGO_METHOD_SERVER_VERSION,
MONGO_METHOD_CREATE_INDEX,
MONGO_METHOD_DROP_INDEXES,
MONGO_METHOD_DROP_COLLECTION,
MONGO_METHOD_INSERT_DOCUMENT,
MONGO_METHOD_UPDATE_DOCUMENT,
MONGO_METHOD_UPDATE_DOCUMENTS,

View File

@ -72,6 +72,7 @@
"server_version",
"create_index",
"drop_indexes",
"drop_collection",
"insert_document",
"update_document",
"update_documents",

View File

@ -504,6 +504,14 @@ public final class MongoAgent {
return result;
}
private static Object dropCollection(JsonObject params) {
MongoClient c = requireClient();
String database = params.get("database").getAsString();
String collection = params.get("collection").getAsString();
c.getDatabase(database).getCollection(collection).drop();
return Collections.singletonMap("ok", true);
}
private static Object parseDropIndexesValue(String indexesJson, boolean single) {
if (indexesJson == null || indexesJson.isBlank()) {
if (single) {
@ -808,6 +816,7 @@ public final class MongoAgent {
case AgentProtocol.MONGO_METHOD_SERVER_VERSION -> serverVersion(params);
case AgentProtocol.MONGO_METHOD_CREATE_INDEX -> createIndex(params);
case AgentProtocol.MONGO_METHOD_DROP_INDEXES -> dropIndexes(params);
case AgentProtocol.MONGO_METHOD_DROP_COLLECTION -> dropCollection(params);
case AgentProtocol.MONGO_METHOD_INSERT_DOCUMENT -> insertDocument(params);
case AgentProtocol.MONGO_METHOD_UPDATE_DOCUMENT -> updateDocument(params);
case AgentProtocol.MONGO_METHOD_UPDATE_DOCUMENTS -> updateDocuments(params);

View File

@ -176,6 +176,19 @@ class MongoAgentTest {
assertTrue(AgentProtocol.MONGO_LEGACY_METHODS.contains(AgentProtocol.MONGO_METHOD_DROP_INDEXES));
}
@Test
void dropCollectionMethodIsRecognizedOverJsonRpc() {
String response = MongoAgent.handleRequest(
"{\"jsonrpc\":\"2.0\",\"id\":14,\"method\":\"drop_collection\","
+ "\"params\":{\"database\":\"app\",\"collection\":\"orders\"}}");
JsonObject json = JsonParser.parseString(response).getAsJsonObject();
assertEquals(14, json.get("id").getAsInt());
assertEquals("Not connected", json.getAsJsonObject("error").get("message").getAsString());
assertFalse(json.getAsJsonObject("error").get("message").getAsString().contains("Unknown method"));
assertTrue(AgentProtocol.MONGO_LEGACY_METHODS.contains(AgentProtocol.MONGO_METHOD_DROP_COLLECTION));
}
@Test
void updateDocumentsMethodIsRecognizedOverJsonRpc() {
String response = MongoAgent.handleRequest(

View File

@ -39,7 +39,7 @@ export interface MongoCollectionStatsCommand {
scale?: number;
}
type MongoWriteKind = "insert" | "update" | "delete" | "createIndex" | "dropIndex" | "dropIndexes";
type MongoWriteKind = "insert" | "update" | "delete" | "createIndex" | "dropIndex" | "dropIndexes" | "dropCollection";
export type MongoCommand =
| ({ kind: "find" } & MongoFindCommand)
@ -54,7 +54,8 @@ export type MongoCommand =
| { kind: "delete"; collection: string; filter: string; many: boolean }
| { kind: "createIndex"; collection: string; keys: string; options?: string }
| { kind: "dropIndex"; collection: string; index: string }
| { kind: "dropIndexes"; collection: string; indexes?: string };
| { kind: "dropIndexes"; collection: string; indexes?: string }
| { kind: "dropCollection"; collection: string };
export type MongoWriteCommand = Extract<MongoCommand, { kind: MongoWriteKind }>;
@ -340,6 +341,13 @@ export function parseMongoWriteCommand(input: string): MongoWriteCommand | null
return indexes !== null ? { kind: "dropIndexes", collection: dropIndexes.collection, ...(indexes ? { indexes } : {}) } : null;
}
const dropCollection = parseCollectionMethodTarget(source, "drop");
if (dropCollection) {
const args = parseMethodArgs(source, dropCollection.methodCallIndex);
if (!args || args.some((arg) => arg.trim())) return null;
return { kind: "dropCollection", collection: dropCollection.collection };
}
return null;
}
@ -427,6 +435,12 @@ export function evaluateMongoWriteSafety(command: MongoWriteCommand, options: Mo
reason: "MongoDB dropIndexes() without a specific single index requires DBX_MCP_ALLOW_DANGEROUS_SQL=1.",
};
}
if (!options.allowDangerous && command.kind === "dropCollection") {
return {
allowed: false,
reason: "MongoDB drop() requires DBX_MCP_ALLOW_DANGEROUS_SQL=1.",
};
}
return { allowed: true };
}

View File

@ -2246,7 +2246,8 @@ export const useQueryStore = defineStore("query", () => {
case "delete":
case "createIndex":
case "dropIndex":
case "dropIndexes": {
case "dropIndexes":
case "dropCollection": {
if (options?.mongoSafety) {
const safety = evaluateMongoWriteSafety(mongoCommand, options.mongoSafety);
if (!safety.allowed) throw new Error(safety.reason);
@ -2270,6 +2271,9 @@ export const useQueryStore = defineStore("query", () => {
} else if (mongoCommand.kind === "dropIndex" || mongoCommand.kind === "dropIndexes") {
const result = await api.mongoDropIndexes(tab.connectionId, currentDatabase, mongoCommand.collection, mongoCommand.kind === "dropIndex" ? mongoCommand.index : mongoCommand.indexes, mongoCommand.kind === "dropIndex");
allResults.push(markQueryResultRowsRaw(annotateQueryResultSource(mongoDroppedIndexesToQueryResult(result.dropped_names, performance.now() - commandStartedAt), sourceStatement)));
} else if (mongoCommand.kind === "dropCollection") {
await api.mongoDropCollection(tab.connectionId, currentDatabase, mongoCommand.collection);
allResults.push(markQueryResultRowsRaw(annotateQueryResultSource(mongoWriteToQueryResult(1, performance.now() - commandStartedAt), sourceStatement)));
} else {
const result = await api.mongoDeleteDocuments(tab.connectionId, currentDatabase, mongoCommand.collection, mongoCommand.filter, mongoCommand.many);
allResults.push(markQueryResultRowsRaw(annotateQueryResultSource(mongoWriteToQueryResult(result.affected_rows, performance.now() - commandStartedAt), sourceStatement)));

View File

@ -72,6 +72,7 @@
"server_version",
"create_index",
"drop_indexes",
"drop_collection",
"insert_document",
"update_document",
"update_documents",

View File

@ -256,6 +256,7 @@ pub enum MongoAgentMethod {
ServerVersion,
CreateIndex,
DropIndexes,
DropCollection,
InsertDocument,
UpdateDocument,
UpdateDocuments,
@ -264,7 +265,7 @@ pub enum MongoAgentMethod {
}
impl MongoAgentMethod {
pub const ALL: [Self; 12] = [
pub const ALL: [Self; 13] = [
Self::ListDatabases,
Self::ListCollections,
Self::FindDocuments,
@ -272,6 +273,7 @@ impl MongoAgentMethod {
Self::ServerVersion,
Self::CreateIndex,
Self::DropIndexes,
Self::DropCollection,
Self::InsertDocument,
Self::UpdateDocument,
Self::UpdateDocuments,
@ -288,6 +290,7 @@ impl MongoAgentMethod {
Self::ServerVersion => "server_version",
Self::CreateIndex => "create_index",
Self::DropIndexes => "drop_indexes",
Self::DropCollection => "drop_collection",
Self::InsertDocument => "insert_document",
Self::UpdateDocument => "update_document",
Self::UpdateDocuments => "update_documents",
@ -1024,6 +1027,13 @@ impl AgentDriverClient {
self.call_mongo_method(MongoAgentMethod::DropIndexes, params).await
}
pub async fn mongo_drop_collection<T: DeserializeOwned + Send + 'static>(
&mut self,
params: Value,
) -> Result<T, String> {
self.call_mongo_method(MongoAgentMethod::DropCollection, params).await
}
pub async fn mongo_insert_document<T: DeserializeOwned + Send + 'static>(
&mut self,
params: Value,
@ -1698,6 +1708,7 @@ mod tests {
assert_eq!(MongoAgentMethod::ServerVersion.as_str(), "server_version");
assert_eq!(MongoAgentMethod::CreateIndex.as_str(), "create_index");
assert_eq!(MongoAgentMethod::DropIndexes.as_str(), "drop_indexes");
assert_eq!(MongoAgentMethod::DropCollection.as_str(), "drop_collection");
assert_eq!(MongoAgentMethod::InsertDocument.as_str(), "insert_document");
assert_eq!(MongoAgentMethod::UpdateDocument.as_str(), "update_document");
assert_eq!(MongoAgentMethod::UpdateDocuments.as_str(), "update_documents");
@ -1744,6 +1755,7 @@ mod tests {
let _mongo_server_version = AgentDriverClient::mongo_server_version::<serde_json::Value>;
let _mongo_create_index = AgentDriverClient::mongo_create_index::<serde_json::Value>;
let _mongo_drop_indexes = AgentDriverClient::mongo_drop_indexes::<serde_json::Value>;
let _mongo_drop_collection = AgentDriverClient::mongo_drop_collection::<serde_json::Value>;
let _mongo_insert_document = AgentDriverClient::mongo_insert_document::<serde_json::Value>;
let _mongo_update_document = AgentDriverClient::mongo_update_document::<serde_json::Value>;
let _mongo_update_documents = AgentDriverClient::mongo_update_documents::<serde_json::Value>;

View File

@ -48,7 +48,16 @@ pub async fn mongo_drop_collection_core(
let connections = state.connections.read().await;
match connections.get(connection_id).ok_or("Not found")? {
PoolKind::MongoDb(client) => mongo_driver::drop_collection(client, database, collection).await,
PoolKind::Agent(_) => Err("MongoDB legacy agent does not support drop collection".to_string()),
PoolKind::Agent(client) => {
let mut client = client.lock().await;
let _: serde_json::Value = client
.mongo_drop_collection(serde_json::json!({
"database": database,
"collection": collection,
}))
.await?;
Ok(())
}
_ => Err("Not a MongoDB connection".to_string()),
}
}

View File

@ -184,6 +184,25 @@ test("parseMongoWriteCommand parses dropIndex and dropIndexes variants", () => {
});
});
test("parseMongoWriteCommand parses collection drop commands", () => {
assert.deepEqual(parseMongoWriteCommand("db.users.drop()"), {
kind: "dropCollection",
collection: "users",
});
assert.deepEqual(parseMongoWriteCommand('db.getCollection("audit.logs").drop();'), {
kind: "dropCollection",
collection: "audit.logs",
});
assert.deepEqual(parseMongoCommand("db.users.drop()")?.command, {
kind: "dropCollection",
collection: "users",
});
});
test("parseMongoWriteCommand rejects collection drop arguments", () => {
assert.equal(parseMongoWriteCommand("db.users.drop({ writeConcern: 1 })"), null);
});
test("parseMongoWriteCommand rejects invalid dropIndex/dropIndexes variants", () => {
assert.equal(parseMongoWriteCommand("db.users.dropIndex()"), null);
assert.equal(parseMongoWriteCommand('db.users.dropIndex("*")'), null);
@ -191,6 +210,13 @@ test("parseMongoWriteCommand rejects invalid dropIndex/dropIndexes variants", ()
assert.equal(parseMongoWriteCommand('db.users.dropIndexes([{"a":1}])'), null);
});
test("evaluateMongoWriteSafety blocks collection drop unless dangerous writes are enabled", () => {
const dropCollection = parseMongoWriteCommand("db.users.drop()");
assert.ok(dropCollection);
assert.match(evaluateMongoWriteSafety(dropCollection, { allowWrites: true }).reason || "", /DBX_MCP_ALLOW_DANGEROUS_SQL=1/);
assert.equal(evaluateMongoWriteSafety(dropCollection, { allowWrites: true, allowDangerous: true }).allowed, true);
});
test("evaluateMongoWriteSafety blocks dangerous dropIndexes shapes unless enabled", () => {
const dropAll = parseMongoWriteCommand("db.users.dropIndexes()");
assert.ok(dropAll);

View File

@ -919,7 +919,7 @@ export async function executeQuery(config: ConnectionConfig, sql: string, option
return { columns: [], rows: [], row_count: result.affectedRows };
}
throw new Error(
'Use MongoDB shell-style commands, for example: db.projects.find({}).limit(100), db.version(), db.projects.countDocuments({}), db.projects.count({}), db.projects.getIndexes(), db.projects.dataSize(), db.projects.storageSize(1024), db.projects.totalIndexSize(), db.projects.stats(), db.projects.createIndex({...}), db.projects.dropIndex("name"), db.projects.dropIndexes(), db.projects.insertOne({...}), db.projects.updateOne({...}, {$set: {...}}), or db.projects.deleteOne({...})',
'Use MongoDB shell-style commands, for example: db.projects.find({}).limit(100), db.version(), db.projects.countDocuments({}), db.projects.count({}), db.projects.getIndexes(), db.projects.dataSize(), db.projects.storageSize(1024), db.projects.totalIndexSize(), db.projects.stats(), db.projects.createIndex({...}), db.projects.dropIndex("name"), db.projects.dropIndexes(), db.projects.drop(), db.projects.insertOne({...}), db.projects.updateOne({...}, {$set: {...}}), or db.projects.deleteOne({...})',
);
}
if (isDirectQueryType(config.db_type)) {
@ -1167,6 +1167,14 @@ async function executeMongoWrite(config: ConnectionConfig, command: MongoWriteCo
});
return { affectedRows: result.affected_rows, droppedNames: result.dropped_names };
}
if (command.kind === "dropCollection") {
await bridgeDataRequest<{ ok: boolean }>("/data/mongo/drop-collection", {
connection_name: config.name,
database: config.database || "",
collection: command.collection,
});
return { affectedRows: 1 };
}
const result = await bridgeDataRequest<{ affected_rows: number }>("/data/mongo/delete-documents", {
connection_name: config.name,
database: config.database || "",
@ -1288,7 +1296,8 @@ export type MongoWriteCommand =
| { kind: "delete"; collection: string; filter: string; many: boolean }
| { kind: "createIndex"; collection: string; keys: string; options?: string }
| { kind: "dropIndex"; collection: string; index: string }
| { kind: "dropIndexes"; collection: string; indexes?: string };
| { kind: "dropIndexes"; collection: string; indexes?: string }
| { kind: "dropCollection"; collection: string };
export function parseMongoFindCommand(input: string): MongoFindCommand | null {
const source = input.trim().replace(/;$/, "").trim();
@ -1480,6 +1489,13 @@ export function parseMongoWriteCommand(input: string): MongoWriteCommand | null
return indexes !== null ? { kind: "dropIndexes", collection: dropIndexes.collection, ...(indexes ? { indexes } : {}) } : null;
}
const dropCollection = parseCollectionMethodTarget(source, "drop");
if (dropCollection) {
const args = parseMethodArgs(source, dropCollection.methodCallIndex);
if (!args || args.some((arg) => arg.trim())) return null;
return { kind: "dropCollection", collection: dropCollection.collection };
}
return null;
}
@ -1502,6 +1518,12 @@ export function evaluateMongoWriteSafety(command: MongoWriteCommand, options: {
reason: "MongoDB dropIndexes() without a specific single index requires DBX_MCP_ALLOW_DANGEROUS_SQL=1.",
};
}
if (!options.allowDangerous && command.kind === "dropCollection") {
return {
allowed: false,
reason: "MongoDB drop() requires DBX_MCP_ALLOW_DANGEROUS_SQL=1.",
};
}
return { allowed: true };
}

View File

@ -1,6 +1,22 @@
import type { ConnectionConfig } from "./connections.js";
import type { TableInfo, ColumnInfo, QueryOptions, QueryResult } from "./database.js";
import { collectionListToTableInfos, evaluateMongoAggregateSafety, evaluateMongoWriteSafety, inferMongoColumns, mongoCollectionStatsToQueryResult, mongoDocumentsToQueryResult, parseMongoAggregateCommand, parseMongoCollectionStatsCommand, parseMongoCountDocumentsCommand, parseMongoFindCommand, parseMongoGetIndexesCommand, parseMongoVersionCommand, parseMongoWriteCommand, type CollectionInfo, type MongoWriteCommand } from "./database.js";
import {
collectionListToTableInfos,
evaluateMongoAggregateSafety,
evaluateMongoWriteSafety,
inferMongoColumns,
mongoCollectionStatsToQueryResult,
mongoDocumentsToQueryResult,
parseMongoAggregateCommand,
parseMongoCollectionStatsCommand,
parseMongoCountDocumentsCommand,
parseMongoFindCommand,
parseMongoGetIndexesCommand,
parseMongoVersionCommand,
parseMongoWriteCommand,
type CollectionInfo,
type MongoWriteCommand,
} from "./database.js";
import type { RedisCommandOptions, RedisCommandResult } from "./redis-command.js";
import { sqlSafetyFromEnv } from "./sql-safety.js";
@ -288,7 +304,7 @@ export async function executeQuery(config: ConnectionConfig, sql: string, option
return { columns: [], rows: [], row_count: result.affectedRows };
}
throw new Error(
"Use MongoDB shell-style commands, for example: db.projects.find({}).limit(100), db.version(), db.projects.countDocuments({}), db.projects.count({}), db.projects.getIndexes(), db.projects.dataSize(), db.projects.storageSize(1024), db.projects.totalIndexSize(), db.projects.stats(), db.projects.createIndex({...}), db.projects.dropIndex(\"name\"), db.projects.dropIndexes(), db.projects.insertOne({...}), db.projects.updateOne({...}, {$set: {...}}), or db.projects.deleteOne({...})",
'Use MongoDB shell-style commands, for example: db.projects.find({}).limit(100), db.version(), db.projects.countDocuments({}), db.projects.count({}), db.projects.getIndexes(), db.projects.dataSize(), db.projects.storageSize(1024), db.projects.totalIndexSize(), db.projects.stats(), db.projects.createIndex({...}), db.projects.dropIndex("name"), db.projects.dropIndexes(), db.projects.drop(), db.projects.insertOne({...}), db.projects.updateOne({...}, {$set: {...}}), or db.projects.deleteOne({...})',
);
}
const res = await apiFetch("/api/query/execute", {
@ -328,10 +344,7 @@ export async function executeRedisCommand(config: ConnectionConfig, db: number,
return (await res.json()) as RedisCommandResult;
}
async function executeMongoWrite(
config: ConnectionConfig,
command: MongoWriteCommand,
): Promise<{ affectedRows: number; indexName?: string; droppedNames?: string[] }> {
async function executeMongoWrite(config: ConnectionConfig, command: MongoWriteCommand): Promise<{ affectedRows: number; indexName?: string; droppedNames?: string[] }> {
if (command.kind === "insert") {
const res = await apiFetch("/api/mongo/insert-documents", {
method: "POST",
@ -388,6 +401,17 @@ async function executeMongoWrite(
const result = (await res.json()) as { dropped_names: string[]; affected_rows: number };
return { affectedRows: result.affected_rows, droppedNames: result.dropped_names };
}
if (command.kind === "dropCollection") {
await apiFetch("/api/mongo/drop-collection", {
method: "POST",
body: JSON.stringify({
connectionId: config.id,
database: config.database || "",
collection: command.collection,
}),
});
return { affectedRows: 1 };
}
const res = await apiFetch("/api/mongo/delete-documents", {
method: "POST",
body: JSON.stringify({

View File

@ -1,6 +1,19 @@
import assert from "node:assert/strict";
import { test } from "vitest";
import { executeQuery, inferMongoColumns, mongoAggregateWriteStage, mongoCollectionStatsToQueryResult, mongoDocumentsToQueryResult, parseMongoAggregateCommand, parseMongoCollectionStatsCommand, parseMongoCountDocumentsCommand, parseMongoFindCommand, parseMongoGetIndexesCommand, parseMongoVersionCommand, parseMongoWriteCommand } from "../src/database.js";
import {
executeQuery,
inferMongoColumns,
mongoAggregateWriteStage,
mongoCollectionStatsToQueryResult,
mongoDocumentsToQueryResult,
parseMongoAggregateCommand,
parseMongoCollectionStatsCommand,
parseMongoCountDocumentsCommand,
parseMongoFindCommand,
parseMongoGetIndexesCommand,
parseMongoVersionCommand,
parseMongoWriteCommand,
} from "../src/database.js";
test("parseMongoFindCommand accepts shell-style find commands", () => {
assert.deepEqual(parseMongoFindCommand('db.getCollection("operation_logs").find({"level":"info"}).sort({"ts":-1}).skip(5).limit(10)'), {
@ -233,6 +246,14 @@ test("parseMongoWriteCommand accepts supported write commands", () => {
collection: "projects",
indexes: '["a_1","b_1"]',
});
assert.deepEqual(parseMongoWriteCommand("db.projects.drop()"), {
kind: "dropCollection",
collection: "projects",
});
assert.deepEqual(parseMongoWriteCommand('db.getCollection("audit.logs").drop();'), {
kind: "dropCollection",
collection: "audit.logs",
});
});
test("parseMongoWriteCommand rejects invalid dropIndex and dropIndexes commands", () => {
@ -240,6 +261,7 @@ test("parseMongoWriteCommand rejects invalid dropIndex and dropIndexes commands"
assert.equal(parseMongoWriteCommand('db.projects.dropIndex("*")'), null);
assert.equal(parseMongoWriteCommand('db.projects.dropIndex(["a_1"])'), null);
assert.equal(parseMongoWriteCommand('db.projects.dropIndexes([{"email":1}])'), null);
assert.equal(parseMongoWriteCommand("db.projects.drop({ writeConcern: 1 })"), null);
});
test("mongodb executeQuery blocks writes when writes are explicitly disabled", async () => {
@ -339,6 +361,7 @@ test("mongodb executeQuery blocks dangerous dropIndexes shapes until dangerous S
await assert.rejects(executeQuery(config, "db.projects.dropIndexes()"), /DBX_MCP_ALLOW_DANGEROUS_SQL=1/);
await assert.rejects(executeQuery(config, 'db.projects.dropIndexes("*")'), /DBX_MCP_ALLOW_DANGEROUS_SQL=1/);
await assert.rejects(executeQuery(config, 'db.projects.dropIndexes(["a_1","b_1"])'), /DBX_MCP_ALLOW_DANGEROUS_SQL=1/);
await assert.rejects(executeQuery(config, "db.projects.drop()"), /DBX_MCP_ALLOW_DANGEROUS_SQL=1/);
if (oldAllowWrites === undefined) delete process.env.DBX_MCP_ALLOW_WRITES;
else process.env.DBX_MCP_ALLOW_WRITES = oldAllowWrites;

View File

@ -98,6 +98,13 @@ struct MongoDropIndexesRequest {
single: bool,
}
#[derive(Deserialize)]
struct MongoDropCollectionRequest {
connection_name: String,
database: Option<String>,
collection: String,
}
#[derive(Deserialize)]
struct MongoInsertDocumentsRequest {
connection_name: String,
@ -203,6 +210,8 @@ pub fn start(app_handle: AppHandle, state: Arc<AppState>, data_dir: PathBuf) {
handle_mongo_create_index_data(&st, body, &mut stream).await;
} else if first_line.starts_with("POST /data/mongo/drop-indexes") {
handle_mongo_drop_indexes_data(&st, body, &mut stream).await;
} else if first_line.starts_with("POST /data/mongo/drop-collection") {
handle_mongo_drop_collection_data(&st, body, &mut stream).await;
} else if first_line.starts_with("POST /data/mongo/insert-documents") {
handle_mongo_insert_documents_data(&st, body, &mut stream).await;
} else if first_line.starts_with("POST /data/mongo/update-documents") {
@ -628,6 +637,29 @@ async fn handle_mongo_drop_indexes_data(state: &Arc<AppState>, body: &str, strea
}
}
async fn handle_mongo_drop_collection_data(state: &Arc<AppState>, body: &str, stream: &mut tokio::net::TcpStream) {
let req: MongoDropCollectionRequest = match serde_json::from_str(body) {
Ok(r) => r,
Err(_) => {
respond_error(stream, "400 Bad Request", "Invalid JSON").await;
return;
}
};
let Some((pool_key, database, connection_id)) =
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
else {
return;
};
if let Err(e) = ensure_connection_writable(state, &connection_id, "Drop collection").await {
respond_error(stream, "403 Forbidden", &e).await;
return;
}
match dbx_core::mongo_ops::mongo_drop_collection_core(state, &pool_key, &database, &req.collection).await {
Ok(()) => respond_json(stream, &serde_json::json!({ "ok": true })).await,
Err(e) => respond_error(stream, "500 Internal Server Error", &e).await,
}
}
async fn handle_mongo_insert_documents_data(state: &Arc<AppState>, body: &str, stream: &mut tokio::net::TcpStream) {
let req: MongoInsertDocumentsRequest = match serde_json::from_str(body) {
Ok(r) => r,