feat(mongodb): support copying MongoDB documents

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-07-24 15:50:49 +08:00
1 parent b8c488b398
commit 0992c52448
19 files changed
+580 -43

No files matched your search

@@ -84,6 +84,7 @@ type ViewMode = "document" | "table";
const documents = ref<JsonRecord[]>([]);
const copyDocuments = ref<JsonRecord[]>([]);
const mongoCopyDocumentsAvailable = ref(false);
const lastGridColumns = ref<string[]>([]);
const total = ref<number | undefined>(undefined);
const totalIsExact = ref(true);
@@ -112,6 +113,7 @@ const sortInput = ref("");
const filterInputRef = ref<HTMLTextAreaElement>();
const sortInputRef = ref<HTMLTextAreaElement>();
const dataGridRef = ref<InstanceType<typeof DataGrid>>();
const mongoUpdateTarget = computed(() => (props.databaseType === "mongodb" && mongoCopyDocumentsAvailable.value ? { collection: props.collection, idColumn: "_id" as const } : undefined));
const documentViewerRef = ref<HTMLElement>();
const documentSearchInputRef = ref<HTMLInputElement>();
const documentSearchOpen = ref(false);
@@ -822,9 +824,11 @@ async function load() {
}
})
: result.documents.map(asRecord);
const nextCopyDocuments = result.extended_documents?.length === nextDocuments.length ? result.extended_documents.map(asRecord) : nextDocuments;
const hasTypePreservingCopyDocuments = result.extended_documents?.length === nextDocuments.length;
const nextCopyDocuments = hasTypePreservingCopyDocuments ? result.extended_documents!.map(asRecord) : nextDocuments;
documents.value = nextDocuments;
copyDocuments.value = nextCopyDocuments;
mongoCopyDocumentsAvailable.value = hasTypePreservingCopyDocuments;
if (nextDocuments.length > 0) {
const keySet = new Set<string>();
keySet.add("_id");
@@ -1569,6 +1573,7 @@ defineExpose({ focusSearch });
:result="gridResult"
context="results"
:database-type="props.databaseType"
:mongo-update-target="mongoUpdateTarget"
editable
:custom-save-handler="customSaveHandler"
:loading="loading"
@@ -177,7 +177,7 @@ import {
} from "@/lib/dataGrid/dataGridContextMenu";
import { useToast } from "@/composables/useToast";
import { useDataGridExport } from "@/composables/useDataGridExport";
import { useDataGridExport, type MongoCopyUpdateTarget } from "@/composables/useDataGridExport";
import { eventTargetAllowsNativeClipboard, isPlainClipboardShortcut, readTextFromClipboard } from "@/lib/common/clipboard";
import { claimDataGridPaste, clearDataGridClipboardCopy, parseDataGridClipboard, planDataGridPaste } from "@/lib/dataGrid/dataGridClipboard";
import { DATA_GRID_ROW_NUM_WIDTH, useDataGridColumnResize } from "@/composables/useDataGridColumnResize";
@@ -304,6 +304,7 @@ interface DataGridProps {
allExportResults?: Array<{ sheetName: string; result: QueryResult; sql?: string }>;
exportFileBaseName?: string;
customSaveHandler?: import("@/composables/useDataGridEditor").CustomSaveHandler;
mongoUpdateTarget?: MongoCopyUpdateTarget;
queryEditabilityReason?: QueryEditabilityReason;
allowInsertRows?: boolean;
allowDeleteRows?: boolean;
@@ -5103,6 +5104,7 @@ const {
exportSql: computed(() => props.exportSql),
tableMeta: computed(() => (props.tableMeta ? { ...props.tableMeta } : undefined)),
copyInsertTargetLabel: computed(() => props.tableMeta?.tableName ?? props.customSaveHandler?.targetLabel),
mongoUpdateTarget: computed(() => props.mongoUpdateTarget),
databaseType: computed(() => props.databaseType),
connectionId: computed(() => props.connectionId),
database: computed(() => props.executionDatabase ?? props.database),
@@ -77,7 +77,7 @@ import { codeMirrorSqlDialect, codeMirrorSqlDialectForConnection, effectiveDatab
import { chartableColumnIndexes } from "@/lib/dataGrid/chartData";
import { elasticsearchJsonResponseForResult } from "@/lib/elasticsearch/elasticsearchJsonResponse";
import * as api from "@/lib/backend/api";
import { applyMongoGridChangesToDocument, buildMongoUpdateDocument, formatMongoShellLiteral, serializeMongoDocumentId, type MongoInputValue } from "@/lib/mongo/mongoDocumentValues";
import { applyMongoGridChangesToDocument, applyMongoGridChangesToDocumentBaseline, buildMongoUpdateDocument, formatMongoShellLiteral, serializeMongoDocumentId, type MongoInputValue } from "@/lib/mongo/mongoDocumentValues";
import type { SqlExecutionOverride } from "@/lib/sql/sqlExecutionTarget";
import type { DataGridSortMode } from "@/lib/dataGrid/dataGridSort";
import { DATA_GRID_COMPACT_TOPBAR_WIDTH, type DataGridReloadIntent } from "@/lib/dataGrid/dataGridToolbar";
@@ -440,16 +440,22 @@ const mongoQueryResultSaveHandler = computed<CustomSaveHandler | undefined>(() =
// Replace the raw array only after every backend update succeeds, keeping
// the grid and JSON preview atomic when a multi-row save partially fails.
const replacements = new Map<unknown, unknown>();
if (tab.resultLocalSortOriginalMongoDocuments) {
tab.resultLocalSortOriginalMongoDocuments = applyMongoGridChangesToDocumentBaseline(tab.resultLocalSortOriginalMongoDocuments, documents, dirtyRows, columns);
}
tab.result!.mongo_documents = documents.map((document, rowIdx) => {
const changes = dirtyRows.get(rowIdx);
if (!changes) return document;
const updated = applyMongoGridChangesToDocument(document, changes, columns);
replacements.set(document, updated);
return updated;
return changes ? applyMongoGridChangesToDocument(document, changes, columns) : document;
});
if (tab.resultLocalSortOriginalMongoDocuments) {
tab.resultLocalSortOriginalMongoDocuments = tab.resultLocalSortOriginalMongoDocuments.map((document) => replacements.get(document) ?? document);
const copyDocuments = tab.result!.mongo_copy_documents;
if (copyDocuments) {
if (tab.resultLocalSortOriginalMongoCopyDocuments) {
tab.resultLocalSortOriginalMongoCopyDocuments = applyMongoGridChangesToDocumentBaseline(tab.resultLocalSortOriginalMongoCopyDocuments, copyDocuments, dirtyRows, columns);
}
tab.result!.mongo_copy_documents = copyDocuments.map((document, rowIdx) => {
const changes = dirtyRows.get(rowIdx);
return changes ? applyMongoGridChangesToDocument(document, changes, columns) : document;
});
}
};
@@ -1168,6 +1174,7 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
:editable="!!activeTab.queryAnalysis || !!mongoQueryResultSaveHandler"
:source-columns="activeTab.querySourceColumns"
:custom-save-handler="mongoQueryResultSaveHandler"
:mongo-update-target="mongoQueryResultSaveHandler && activeTab.result.mongo_copy_documents?.length === activeTab.result.rows.length ? activeTab.mongoEditTarget : undefined"
:query-editability-reason="activeTab.queryEditabilityReason"
:allow-insert-rows="activeTab.queryAnalysis?.allowInsert !== false && activeTab.queryAnalysis?.allowInsertDelete !== false"
:allow-delete-rows="activeTab.queryAnalysis?.allowInsertDelete !== false"