fix(mongodb): preserve long ids in filters and updates
This commit is contained in:
9 files changed
+325
-31
No files matched your search
@@ -28,7 +28,7 @@ import {
|
||||
type DocumentFilterMode,
|
||||
type DocumentFilterRule,
|
||||
} from "@/lib/app/documentStoreProvider";
|
||||
import { buildMongoInsertDocument, buildMongoUpdateDocument, formatMongoShellLiteral, parseMongoDocumentInputValue, type MongoInputValue } from "@/lib/mongo/mongoDocumentValues";
|
||||
import { buildMongoInsertDocument, buildMongoUpdateDocument, formatMongoShellLiteral, mongoDocumentIdForGrid, parseMongoDocumentInputValue, serializeMongoDocumentId, type MongoInputValue } from "@/lib/mongo/mongoDocumentValues";
|
||||
import { normalizeResultPageSize } from "@/lib/dataGrid/paginationPageSize";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import JsonEditNode from "./JsonEditNode.vue";
|
||||
@@ -131,8 +131,9 @@ const deleteDetails = computed(() => {
|
||||
if (!pending) return "";
|
||||
if (pending.kind === "document") {
|
||||
const id = documents.value[pending.index]?._id ?? "";
|
||||
if (props.databaseType === "elasticsearch") return `Elasticsearch index: ${props.collection}\nDocument _id: ${String(id)}`;
|
||||
return t("dangerDialog.mongoDocumentDetails", { collection: props.collection, id: String(id) });
|
||||
const displayId = mongoDocumentIdForGrid(id);
|
||||
if (props.databaseType === "elasticsearch") return `Elasticsearch index: ${props.collection}\nDocument _id: ${String(displayId)}`;
|
||||
return t("dangerDialog.mongoDocumentDetails", { collection: props.collection, id: String(displayId) });
|
||||
}
|
||||
return t("dangerDialog.mongoFieldDetails", { field: pending.name || t("mongo.field") });
|
||||
});
|
||||
@@ -162,6 +163,7 @@ const gridResult = computed<QueryResult>(() => {
|
||||
columns.map((col) => {
|
||||
const val = doc[col];
|
||||
if (val === undefined || val === null) return null;
|
||||
if (col === "_id") return mongoDocumentIdForGrid(val);
|
||||
if (typeof val === "object") return JSON.stringify(val);
|
||||
if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") return val;
|
||||
return String(val);
|
||||
@@ -254,6 +256,19 @@ function clearDocumentFilters(clearLocalFilter?: (columnIndex?: number) => void)
|
||||
|
||||
function documentIdFromGridValue(value: MongoInputValue | undefined): string | null {
|
||||
if (value === null || value === undefined) return null;
|
||||
if (typeof value === "string") {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return null;
|
||||
if (trimmed.startsWith('"')) {
|
||||
try {
|
||||
const parsed = JSON.parse(trimmed);
|
||||
return typeof parsed === "string" && parsed.trim() ? parsed : trimmed;
|
||||
} catch {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
const parsed = parseMongoDocumentInputValue(value);
|
||||
if (parsed === null || parsed === undefined) return null;
|
||||
const id = typeof parsed === "object" ? JSON.stringify(parsed) : String(parsed);
|
||||
@@ -307,15 +322,18 @@ async function gridSave(changes: DocumentGridChanges) {
|
||||
|
||||
const updateDoc = buildMongoUpdateDocument(dirtyCols, cols, documents.value[rowIdx]);
|
||||
if (Object.keys(updateDoc).length === 0) continue;
|
||||
await api.documentUpdateDocument(props.connectionId, props.database, props.collection, String(id), JSON.stringify(updateDoc));
|
||||
const documentId = documents.value[rowIdx]?._id ?? id;
|
||||
await api.documentUpdateDocument(props.connectionId, props.database, props.collection, serializeMongoDocumentId(documentId), JSON.stringify(updateDoc));
|
||||
}
|
||||
|
||||
for (const rowIdx of changes.deletedRows) {
|
||||
const row = changes.rows[rowIdx];
|
||||
const id = row?.[idColIdx];
|
||||
if (id == null) continue;
|
||||
const routing = isEs ? documentRoutingFromDocument(documents.value[rowIdx]) : undefined;
|
||||
await api.documentDeleteDocument(props.connectionId, props.database, props.collection, String(id), routing);
|
||||
const document = documents.value[rowIdx];
|
||||
const routing = isEs ? documentRoutingFromDocument(document) : undefined;
|
||||
const documentId = isEs ? id : (document?._id ?? id);
|
||||
await api.documentDeleteDocument(props.connectionId, props.database, props.collection, isEs ? String(documentId) : serializeMongoDocumentId(documentId), routing);
|
||||
}
|
||||
|
||||
for (const newRow of changes.newRows) {
|
||||
@@ -335,17 +353,10 @@ async function gridSave(changes: DocumentGridChanges) {
|
||||
await load();
|
||||
}
|
||||
|
||||
function formatMongoValue(val: unknown): string {
|
||||
if (val === null || val === undefined) return "null";
|
||||
if (typeof val === "number" || typeof val === "boolean") return String(val);
|
||||
if (typeof val === "string") return JSON.stringify(val);
|
||||
return JSON.stringify(val);
|
||||
}
|
||||
|
||||
function mongoIdPreview(val: unknown): string {
|
||||
if (val === null || val === undefined) return "null";
|
||||
if (typeof val === "string" && /^[a-fA-F0-9]{24}$/.test(val)) return `ObjectId("${val}")`;
|
||||
return formatMongoValue(val);
|
||||
return formatMongoShellLiteral(val);
|
||||
}
|
||||
|
||||
function elasticsearchPathIdPreview(id: string): string {
|
||||
@@ -383,7 +394,7 @@ async function previewDocumentChanges(changes: DocumentGridChanges): Promise<str
|
||||
stmts.push(`POST /${coll}/_update/${elasticsearchPathIdPreview(String(id))}${elasticsearchRoutingPreview(routing)}\n${JSON.stringify({ doc: updateDoc.$set ?? updateDoc }, null, 2)}`);
|
||||
} else {
|
||||
const updateDoc = buildMongoUpdateDocument(dirtyCols, columns, documents.value[rowIdx]);
|
||||
stmts.push(`db.${coll}.updateOne({_id: ${mongoIdPreview(id)}}, ${formatMongoShellLiteral(updateDoc)})`);
|
||||
stmts.push(`db.${coll}.updateOne({_id: ${mongoIdPreview(documents.value[rowIdx]?._id ?? id)}}, ${formatMongoShellLiteral(updateDoc)})`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +406,7 @@ async function previewDocumentChanges(changes: DocumentGridChanges): Promise<str
|
||||
const routing = documentRoutingFromGridRow(row, columns);
|
||||
stmts.push(`DELETE /${coll}/_doc/${elasticsearchPathIdPreview(String(id))}${elasticsearchRoutingPreview(routing)}`);
|
||||
} else {
|
||||
stmts.push(`db.${coll}.deleteOne({_id: ${mongoIdPreview(id)}})`);
|
||||
stmts.push(`db.${coll}.deleteOne({_id: ${mongoIdPreview(documents.value[rowIdx]?._id ?? id)}})`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -692,7 +703,7 @@ async function saveDoc() {
|
||||
error.value = "No _id field";
|
||||
return;
|
||||
}
|
||||
await api.documentUpdateDocument(props.connectionId, props.database, props.collection, String(id), JSON.stringify(doc), documentRoutingFromDocument(current));
|
||||
await api.documentUpdateDocument(props.connectionId, props.database, props.collection, serializeMongoDocumentId(id), JSON.stringify(doc), documentRoutingFromDocument(current));
|
||||
}
|
||||
isEditing.value = false;
|
||||
isNew.value = false;
|
||||
@@ -712,7 +723,7 @@ async function applyDeleteDoc(idx: number) {
|
||||
if (!id) return;
|
||||
error.value = "";
|
||||
try {
|
||||
await api.documentDeleteDocument(props.connectionId, props.database, props.collection, String(id), documentRoutingFromDocument(doc));
|
||||
await api.documentDeleteDocument(props.connectionId, props.database, props.collection, serializeMongoDocumentId(id), documentRoutingFromDocument(doc));
|
||||
if (selectedIdx.value === idx) {
|
||||
selectedIdx.value = null;
|
||||
editJson.value = "";
|
||||
|
||||
@@ -75,7 +75,7 @@ import { effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
|
||||
import { chartableColumnIndexes } from "@/lib/dataGrid/chartData";
|
||||
import { elasticsearchJsonResponseForResult } from "@/lib/elasticsearch/elasticsearchJsonResponse";
|
||||
import * as api from "@/lib/backend/api";
|
||||
import { applyMongoGridChangesToDocument, buildMongoUpdateDocument, formatMongoShellLiteral, type MongoInputValue } from "@/lib/mongo/mongoDocumentValues";
|
||||
import { applyMongoGridChangesToDocument, 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";
|
||||
@@ -380,6 +380,11 @@ function mongoIdPreview(val: unknown): string {
|
||||
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;
|
||||
@@ -398,7 +403,7 @@ const mongoQueryResultSaveHandler = computed<CustomSaveHandler | undefined>(() =
|
||||
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(tab.connectionId, tab.database, target.collection, String(id), JSON.stringify(updateDoc));
|
||||
await api.mongoUpdateDocument(tab.connectionId, tab.database, target.collection, serializeMongoDocumentId(mongoQueryResultDocumentId(rowIdx, id)), JSON.stringify(updateDoc));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -412,7 +417,7 @@ const mongoQueryResultSaveHandler = computed<CustomSaveHandler | undefined>(() =
|
||||
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: ${mongoIdPreview(id)}}, ${formatMongoShellLiteral(updateDoc)})`);
|
||||
stmts.push(`${mongoCollectionExpression(target.collection)}.updateOne({_id: ${mongoIdPreview(mongoQueryResultDocumentId(rowIdx, id))}}, ${formatMongoShellLiteral(updateDoc)})`);
|
||||
}
|
||||
return stmts;
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user