feat(export): add SQL INSERT export crash diagnostics
This commit is contained in:
10 files changed
+298
-5
No files matched your search
@@ -16,6 +16,8 @@ import { clearDataGridClipboardCopy, rememberDataGridClipboardCopy } from "@/lib
|
||||
import { buildDataGridCopyInsertStatement, type DataGridCopyInsertMode, type DataGridTableMeta } from "@/lib/dataGrid/dataGridSql";
|
||||
import { formatSqlInsert, formatTsv } from "@/lib/export/exportFormats";
|
||||
import { showSqlInsertModeDialog, type SqlInsertMode } from "@/lib/export/sqlInsertMode";
|
||||
import { summarizeExportRows } from "@/lib/export/exportDiagnostics";
|
||||
import { appendDebugLog, appendNativeProcessMemoryLog, getBrowserMemorySnapshot, isDebugLoggingEnabled } from "@/lib/backend/debugLog";
|
||||
import { uuid } from "@/lib/common/utils";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { expandNestedJsonStringsForCopy } from "@/lib/common/jsonCopyValue";
|
||||
@@ -1334,18 +1336,76 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
|
||||
async function exportSql(rowIds?: number[]) {
|
||||
await runExclusiveExport(async () => {
|
||||
const exportId = uuid();
|
||||
const exportStartedAt = performance.now();
|
||||
const logExportStage = (stage: string, details: Record<string, unknown> = {}, sampleNativeMemory = false) => {
|
||||
if (!isDebugLoggingEnabled()) return;
|
||||
appendDebugLog("info", `[DBX][export:sql:${stage}]`, {
|
||||
exportId,
|
||||
elapsedMs: Math.round(performance.now() - exportStartedAt),
|
||||
...details,
|
||||
browserMemory: getBrowserMemorySnapshot(),
|
||||
});
|
||||
if (sampleNativeMemory) void appendNativeProcessMemoryLog(`export-sql-${stage}`, { exportId });
|
||||
};
|
||||
|
||||
logExportStage(
|
||||
"start",
|
||||
{
|
||||
context: context.value,
|
||||
databaseType: databaseType.value,
|
||||
exportAllRows: rowIds === undefined,
|
||||
requestedRowCount: rowIds?.length ?? null,
|
||||
hasCompleteLocalResult: hasCompleteLocalResult?.value ?? null,
|
||||
},
|
||||
true,
|
||||
);
|
||||
const insertMode = await showSqlInsertModeDialog();
|
||||
if (insertMode === null) return;
|
||||
if (insertMode === null) {
|
||||
logExportStage("cancelled", { stage: "insert-mode-dialog" });
|
||||
return;
|
||||
}
|
||||
logExportStage("mode-selected", { insertMode });
|
||||
try {
|
||||
// Step 1: table-data context — existing backend table export
|
||||
if (await exportFullTableDataViaBackend("sql", rowIds, "name", true, insertMode)) return;
|
||||
logExportStage("backend-export-start");
|
||||
const handledByBackend = await exportFullTableDataViaBackend("sql", rowIds, "name", true, insertMode);
|
||||
logExportStage("backend-export-finished", { handledByBackend });
|
||||
if (handledByBackend) {
|
||||
logExportStage("done", { path: "backend" });
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: query-result context — NEW backend streaming with background task
|
||||
if (await exportQueryResultSqlViaBackend(rowIds, insertMode)) return;
|
||||
logExportStage("query-backend-export-start");
|
||||
const handledQueryByBackend = await exportQueryResultSqlViaBackend(rowIds, insertMode);
|
||||
logExportStage("query-backend-export-finished", { handledByBackend: handledQueryByBackend });
|
||||
if (handledQueryByBackend) {
|
||||
logExportStage("done", { path: "query-backend" });
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 3: fallback — local export (Web and edge-case scenarios)
|
||||
const result = await resultToExport(rowIds, undefined, true, false);
|
||||
logExportStage(
|
||||
"result-ready",
|
||||
{
|
||||
columns: result.columns.length,
|
||||
rows: result.rows.length,
|
||||
values: isDebugLoggingEnabled() ? summarizeExportRows(result.rows) : undefined,
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
logExportStage("row-remap-start");
|
||||
const exportData = sqlInsertExportData(result);
|
||||
logExportStage("row-remap-done", {
|
||||
columns: exportData.columns.length,
|
||||
rows: exportData.rows.length,
|
||||
values: isDebugLoggingEnabled() ? summarizeExportRows(exportData.rows) : undefined,
|
||||
});
|
||||
|
||||
logExportStage("sql-build-start");
|
||||
const content = await formatSqlInsert({
|
||||
databaseType: databaseType.value,
|
||||
identifierQuote: options.identifierQuote?.value,
|
||||
@@ -1358,10 +1418,23 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
rows: exportData.rows,
|
||||
insertMode,
|
||||
});
|
||||
await saveTextFile(content, exportFileName(tableMeta.value?.tableName || "export", "sql", { preferFallback: true }), "SQL", "sql");
|
||||
logExportStage(
|
||||
"sql-build-done",
|
||||
{
|
||||
sqlChars: content.length,
|
||||
},
|
||||
true,
|
||||
);
|
||||
logExportStage("save-start", { contentChars: content.length }, true);
|
||||
await saveTextFile(content, exportFileName(tableMeta.value?.tableName || "export", "sql", { preferFallback: true }), "SQL", "sql", { exportId, operation: "sql-insert-all" });
|
||||
logExportStage("done", { contentChars: content.length });
|
||||
toast(t("grid.exported"));
|
||||
} catch (e: any) {
|
||||
toast(t("grid.exportFailed", { message: translateBackendError(t, e) }), 5000);
|
||||
logExportStage("error", {
|
||||
errorName: e?.name || typeof e,
|
||||
errorMessage: e?.message || String(e),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user