fix(mongodb): support multi-command execution

* fix mongodb multi-command execution

* fix(connection): 复制连接时保持在同一组内

- 修改 `addConnection` 方法以支持指定目标组 ID
- 更新 `duplicateConnection` 函数以传递目标组 ID
- 添加测试用例以验证复制连接的功能

* fix: add MongoDB data transfer entry

* feat(editor): SQL 编辑器选区大小写转换

Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>

* fix(editor): 修复SQL快捷执行导致执行全量SQL的问题 (#2384)

- 将执行SQL语句的逻辑从直接请求改为通过事件发射
- 增强了代码的可扩展性和可维护性

* fix(sidebar): cache tooltip overflow measurement

* fix(dialog): allow dragging window from modal overlay

* fix(oracle): reuse shared pool for data tabs

* fix(sidebar): reduce comment text repaint cost

* fix(saved-sql): preserve folder on metadata save

* fix(agent): execute transaction control SQL as statements

* feat(vector): add Qdrant/Milvus collection dimension display (#2396)

* fix(oracle): 修复时间字段编辑和表结构修改报错

Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>

* fix(agents): limit common version bumps

---------

Co-authored-by: 二丫讲梵 <eryajf@163.com>
Co-authored-by: zipg <geeky@foxmail.com>
Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>
Co-authored-by: t8y2 <1156263951@qq.com>
Co-authored-by: lexmin0412 <zhangle_dev@outlook.com>
This commit is contained in:
authored and GitHub committed 2026-07-02 12:19:38 +08:00
1 parent b869bcd379
commit 8747df53ef
9 files changed
+861 -272

No files matched your search

+183
View File
@@ -2120,6 +2120,189 @@ test("mongo dropIndexes execution returns dropped index names", async () => {
}
});
test("mongo multi-command execution runs writes sequentially and keeps grouped results", async () => {
const restoreStorage = installMemoryStorage();
setActivePinia(createPinia());
const connectionStore = useConnectionStore();
const store = useQueryStore();
const originalFetch = globalThis.fetch;
const insertBodies: any[] = [];
connectionStore.addEphemeralConnection({
...conn("mongo-1"),
db_type: "mongodb",
port: 27017,
});
globalThis.fetch = withConnectionHealthMock(async (input, init) => {
const url = String(input);
if (url === "/api/mongo/insert-documents") {
insertBodies.push(JSON.parse(String(init?.body ?? "{}")));
return new Response(JSON.stringify({ affected_rows: 1 }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
return new Response("unexpected request", { status: 500 });
});
try {
const tabId = store.createTab("mongo-1", "accounting", "Query", "query", "");
await store.executeTabSql(
tabId,
`
db.users.insertOne({ name: "Ada" });
db.users.insertOne({ name: "Grace" });
`,
);
const tab = store.tabs.find((item) => item.id === tabId);
assert.equal(insertBodies.length, 2);
assert.deepEqual(
insertBodies.map((body) => ({ database: body.database, collection: body.collection, docsJson: body.docsJson })),
[
{ database: "accounting", collection: "users", docsJson: '{ "name": "Ada" }' },
{ database: "accounting", collection: "users", docsJson: '{ "name": "Grace" }' },
],
);
assert.equal(tab?.results?.length, 2);
assert.equal(tab?.activeResultIndex, 0);
assert.equal(tab?.result?.affected_rows, 1);
} finally {
globalThis.fetch = originalFetch;
restoreStorage();
}
});
test("mongo multi-command execution reconnects before running commands", async () => {
const restoreStorage = installMemoryStorage();
setActivePinia(createPinia());
const connectionStore = useConnectionStore();
const store = useQueryStore();
const originalFetch = globalThis.fetch;
const requests: string[] = [];
connectionStore.addEphemeralConnection({
...conn("mongo-1"),
db_type: "mongodb",
port: 27017,
});
connectionStore.connectedIds.delete("mongo-1");
globalThis.fetch = async (input, init) => {
const url = String(input);
if (url === "/api/connection/connect") {
requests.push(url);
return new Response(JSON.stringify("connected"), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
if (url === "/api/mongo/insert-documents") {
requests.push(url);
const body = JSON.parse(String(init?.body ?? "{}"));
assert.equal(body.database, "accounting");
return new Response(JSON.stringify({ affected_rows: 1 }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
return new Response("unexpected request", { status: 500 });
};
try {
const tabId = store.createTab("mongo-1", "accounting", "Query", "query", "");
await store.executeTabSql(tabId, 'db.users.insertOne({ name: "Ada" })');
assert.deepEqual(requests, ["/api/connection/connect", "/api/mongo/insert-documents"]);
} finally {
globalThis.fetch = originalFetch;
restoreStorage();
}
});
test("mongo multi-command execution applies use database before later commands", async () => {
const restoreStorage = installMemoryStorage();
setActivePinia(createPinia());
const connectionStore = useConnectionStore();
const store = useQueryStore();
const originalFetch = globalThis.fetch;
const insertBodies: any[] = [];
connectionStore.addEphemeralConnection({
...conn("mongo-1"),
db_type: "mongodb",
port: 27017,
});
globalThis.fetch = withConnectionHealthMock(async (input, init) => {
const url = String(input);
if (url === "/api/mongo/insert-documents") {
insertBodies.push(JSON.parse(String(init?.body ?? "{}")));
return new Response(JSON.stringify({ affected_rows: 1 }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
return new Response("unexpected request", { status: 500 });
});
try {
const tabId = store.createTab("mongo-1", "accounting", "Query", "query", "");
await store.executeTabSql(
tabId,
`
use archive
db.users.insertOne({ name: "Ada" })
`,
);
const tab = store.tabs.find((item) => item.id === tabId);
assert.equal(insertBodies.length, 1);
assert.equal(insertBodies[0]?.database, "archive");
assert.equal(tab?.database, "archive");
assert.equal(tab?.results?.length, 2);
assert.deepEqual(tab?.results?.[0]?.rows, [["switched to db archive"]]);
} finally {
globalThis.fetch = originalFetch;
restoreStorage();
}
});
test("mongo use-only execution updates the tab without reconnecting", async () => {
const restoreStorage = installMemoryStorage();
setActivePinia(createPinia());
const connectionStore = useConnectionStore();
const store = useQueryStore();
const originalFetch = globalThis.fetch;
const requests: string[] = [];
connectionStore.addEphemeralConnection({
...conn("mongo-1"),
db_type: "mongodb",
port: 27017,
});
connectionStore.connectedIds.delete("mongo-1");
globalThis.fetch = async (input) => {
requests.push(String(input));
return new Response("unexpected request", { status: 500 });
};
try {
const tabId = store.createTab("mongo-1", "accounting", "Query", "query", "");
await store.executeTabSql(tabId, "use archive");
const tab = store.tabs.find((item) => item.id === tabId);
assert.deepEqual(requests, []);
assert.equal(tab?.database, "archive");
assert.deepEqual(tab?.result?.rows, [["switched to db archive"]]);
} finally {
globalThis.fetch = originalFetch;
restoreStorage();
}
});
test("table data export fetches every filtered page", async () => {
const restoreStorage = installMemoryStorage();
setActivePinia(createPinia());