feat(mongodb): delete rows from the query result grid

This commit is contained in:
onenewcode authored and GitHub committed 2026-09-22 11:03:43 +08:00
1 parent d1bd67b828
commit 9fa61d53b6
5 files changed
+183 -35

No files matched your search

@@ -172,7 +172,8 @@ import { elasticsearchProfileBodyForResult, parseElasticsearchProfile } from "@/
import * as api from "@/lib/backend/api";
import type { SqlInsertMode } from "@/lib/export/sqlInsertMode";
import { queryResultExportBaseName } from "@/lib/export/saveTextFile";
import { applyMongoGridChangesToDocument, applyMongoGridChangesToDocumentBaseline, buildMongoUpdateDocument, formatMongoShellLiteral, serializeMongoDocumentId, type MongoInputValue } from "@/lib/mongo/mongoDocumentValues";
import { applyMongoGridChangesToDocument, applyMongoGridChangesToDocumentBaseline, serializeMongoDocumentId, type MongoInputValue } from "@/lib/mongo/mongoDocumentValues";
import { buildMongoQueryResultOperations, formatMongoQueryResultOperationPreview } from "@/lib/mongo/mongoQueryResultEditing";
import type { DataGridSortMode } from "@/lib/dataGrid/dataGridSort";
import { isDataGridToolbarCompact, type DataGridReloadIntent } from "@/lib/dataGrid/dataGridToolbar";
import { useTabScroll } from "@/composables/useTabScroll";
@@ -632,50 +633,30 @@ type MongoQueryGridChanges = {
columns: string[];
rows: MongoInputValue[][];
};
function mongoCollectionExpression(collection: string): string {
return `db.getCollection(${JSON.stringify(collection)})`;
}
function mongoQueryResultDocumentId(rowIdx: number, fallback: unknown): unknown {
const document = props.activeTab.result?.mongo_documents?.[rowIdx];
if (!document || typeof document !== "object" || Array.isArray(document)) return fallback;
return (document as Record<string, unknown>)._id ?? fallback;
}
const mongoQueryResultSaveHandler = computed<CustomSaveHandler | undefined>(() => {
const tab = props.activeTab;
const target = tab.mongoEditTarget;
if (tab.mode !== "query" || activeEffectiveDatabaseType.value !== "mongodb" || !target || !activeResultConnectionId.value || !activeResultDatabase.value || !tab.result) return undefined;
if (!tab.result.columns.includes(target.idColumn)) return undefined;
const editTarget = { idColumn: target.idColumn, documentAt: (rowIdx: number) => tab.result?.mongo_documents?.[rowIdx] };
const save: CustomSaveHandler["save"] = async (changes: MongoQueryGridChanges) => {
if (changes.newRows.length > 0 || changes.deletedRows.size > 0) {
throw new Error("MongoDB query result editing only supports updating existing rows.");
if (changes.newRows.length > 0) {
throw new Error("MongoDB query result editing does not support inserting rows.");
}
const idColIdx = changes.columns.indexOf(target.idColumn);
if (idColIdx < 0) throw new Error("No _id column");
for (const [rowIdx, dirtyCols] of changes.dirtyRows) {
const row = changes.rows[rowIdx];
const id = row?.[idColIdx];
if (id === null || id === undefined || String(id).trim() === "") continue;
const updateDoc = buildMongoUpdateDocument(dirtyCols, changes.columns, tab.result?.mongo_documents?.[rowIdx]);
if (Object.keys(updateDoc).length === 0) continue;
await api.mongoUpdateDocument(activeResultConnectionId.value, activeResultDatabase.value, target.collection, serializeMongoDocumentId(mongoQueryResultDocumentId(rowIdx, id)), JSON.stringify(updateDoc));
if (!changes.columns.includes(target.idColumn)) throw new Error("No _id column");
for (const operation of buildMongoQueryResultOperations(changes, editTarget)) {
const id = serializeMongoDocumentId(operation.id);
if (operation.kind === "delete") {
await api.mongoDeleteDocument(activeResultConnectionId.value, activeResultDatabase.value, target.collection, id);
} else {
await api.mongoUpdateDocument(activeResultConnectionId.value, activeResultDatabase.value, target.collection, id, JSON.stringify(operation.update));
}
}
};
const preview: CustomSaveHandler["preview"] = async (changes: MongoQueryGridChanges) => {
const idColIdx = changes.columns.indexOf(target.idColumn);
if (idColIdx < 0) return [];
const stmts: string[] = [];
for (const [rowIdx, dirtyCols] of changes.dirtyRows) {
const row = changes.rows[rowIdx];
const id = row?.[idColIdx];
if (id === null || id === undefined || String(id).trim() === "") continue;
const updateDoc = buildMongoUpdateDocument(dirtyCols, changes.columns, tab.result?.mongo_documents?.[rowIdx]);
if (Object.keys(updateDoc).length === 0) continue;
stmts.push(`${mongoCollectionExpression(target.collection)}.updateOne({_id: ${formatMongoShellLiteral(mongoQueryResultDocumentId(rowIdx, id))}}, ${formatMongoShellLiteral(updateDoc)})`);
}
return stmts;
};
const preview: CustomSaveHandler["preview"] = async (changes: MongoQueryGridChanges) => buildMongoQueryResultOperations(changes, editTarget).map((operation) => formatMongoQueryResultOperationPreview(target.collection, operation));
const applySavedChanges: NonNullable<CustomSaveHandler["applySavedChanges"]> = ({ dirtyRows, columns }) => {
const documents = tab.result?.mongo_documents;
@@ -702,7 +683,7 @@ const mongoQueryResultSaveHandler = computed<CustomSaveHandler | undefined>(() =
}
};
return { save, preview, applySavedChanges, canInsert: false, canDelete: false, supportsInsert: false, readonlyColumns: [target.idColumn], targetLabel: target.collection };
return { save, preview, applySavedChanges, canInsert: false, canDelete: true, supportsInsert: false, readonlyColumns: [target.idColumn], targetLabel: target.collection };
});
const resultsPaneOpen = ref(false);
const resultsPaneSize = ref(Number(safeLocalStorageGet("dbx-results-pane-size")) || DEFAULT_QUERY_RESULTS_PANE_SIZE);