feat(mongodb): stream legacy agent exports via find cursors

This commit is contained in:
onenewcode authored and GitHub committed 2026-09-16 13:20:08 +08:00
1 parent 9eafac706e
commit 7ab781ce19
26 files changed
+1942 -160

No files matched your search

@@ -16,6 +16,7 @@ import { executeWithProductionContextGuard } from "@/lib/database/productionExec
import { TABLE_IMPORT_ENCODING_OPTIONS } from "@/lib/table/tableImport";
import { importPreviewInput, importSourceDisplayName, importTextDelimiterForName, uploadedImportSourceFromPreview, type UploadedImportSource } from "@/lib/import/importSource";
import { useToast } from "@/composables/useToast";
import { translateBackendError } from "@/i18n/backend-errors";
import * as api from "@/lib/backend/api";
const { t } = useI18n();
@@ -267,7 +268,7 @@ async function startImport() {
running.value = false;
open.value = false;
} catch (error) {
errorMessage.value = error instanceof Error ? error.message : String(error);
errorMessage.value = translateBackendError(t, error);
running.value = false;
} finally {
cancelling.value = false;
+42
View File
@@ -101,6 +101,34 @@ const CASES: { name: string; message: string; key: string; params?: Record<strin
message: "Streaming export needs a result-set session, but this driver returned no session_id.",
key: "exportProgress.agentSessionMissing",
},
{
name: "MongoDB Legacy insertMany unsupported",
message: "MongoDB Legacy Agent does not support insertMany; upgrade or reinstall the MongoDB Legacy driver",
key: "mongo.import.legacyInsertUnsupported",
},
{
// crates/dbx-core/src/mongodb_import_export.rs attributes a batch-level failure to a row.
name: "MongoDB Legacy insertMany unsupported on a located row",
message: "row 1: MongoDB Legacy Agent does not support insertMany; upgrade or reinstall the MongoDB Legacy driver",
key: "mongo.import.legacyInsertUnsupported",
},
{
name: "MongoDB Legacy partial insert",
message: "MongoDB Legacy Agent rejected 2 of 500 documents: E11000 duplicate key error collection: app.users",
key: "mongo.insert.partialFailure",
params: { failed: "2", total: "500", message: "E11000 duplicate key error collection: app.users" },
},
{
name: "MongoDB Legacy export cursor invalid",
message: "MongoDB Legacy Agent returned an invalid find cursor",
key: "mongo.import.legacyCursorInvalid",
},
{
// Agent-raised messages reach the frontend through the "Agent RPC error (<code>): " envelope.
name: "MongoDB Legacy export cursor expired",
message: "Agent RPC error (-1): Find cursor not found",
key: "mongo.import.legacyCursorInvalid",
},
{
name: "DuckDB draining",
message: "The previous DuckDB query is still stopping. Please try again shortly.",
@@ -401,6 +429,17 @@ describe("backend error translation", () => {
expect(translateBackendError(t, error)).toBe(`${t("backendErrors.legacy")}\n\nlegacy backend failure`);
});
// Tauri wraps every backend rejection in a legacy envelope, so a message the catalog knows must
// still be phrased by the catalog rather than surfaced as raw English under a generic summary.
test("phrases a known message that arrived inside a legacy envelope", () => {
const t = translatorFor("zh-CN");
const wrap = (message: string) => new BackendErrorException(message);
expect(translateBackendError(t, wrap("row 1: MongoDB Legacy Agent does not support insertMany; upgrade or reinstall the MongoDB Legacy driver"))).toBe(t("mongo.import.legacyInsertUnsupported"));
expect(translateBackendError(t, wrap("Agent RPC error (-1): Find cursor not found"))).toBe(t("mongo.import.legacyCursorInvalid"));
expect(translateBackendError(t, wrap("MongoDB Legacy Agent rejected 2 of 500 documents: E11000 duplicate key"))).toBe(t("mongo.insert.partialFailure", { failed: "2", total: "500", message: "E11000 duplicate key" }));
});
test("keeps an explicit original detail when a structured legacy error omits detail", () => {
const t = translatorFor("zh-CN");
const error = {
@@ -529,6 +568,9 @@ describe("backend error wording is pinned to the Rust sources", () => {
test.each([
["crates/dbx-core/src/query_result_export.rs", "Streaming export is unsupported for this query. Simplify it or use a supported driver."],
["crates/dbx-core/src/query_result_export.rs", "Streaming export needs a result-set session, but this driver returned no session_id."],
["crates/dbx-core/src/mongodb_import_export.rs", "MongoDB Legacy Agent does not support insertMany; upgrade or reinstall the MongoDB Legacy driver"],
["crates/dbx-core/src/mongodb_import_export.rs", "MongoDB Legacy Agent returned an invalid find cursor"],
["crates/dbx-core/src/mongo_ops.rs", "MongoDB Legacy Agent rejected "],
["crates/dbx-core/src/agent_service.rs", "Failed to remove the old JRE directory: "],
["crates/dbx-core/src/agent_service.rs", "is in use by drivers: "],
["crates/dbx-core/src/agent_service.rs", "agent-registry.json not found in the ZIP; not a valid offline driver package."],
+49 -23
View File
@@ -1,4 +1,4 @@
import { GENERIC_TRANSPORT_FAILURE_MESSAGE, normalizeBackendError, sanitizeBackendErrorMessage, type BackendError } from "@/lib/backend/errorUtils";
import { GENERIC_TRANSPORT_FAILURE_MESSAGE, LEGACY_BACKEND_ERROR_CODE, normalizeBackendError, sanitizeBackendErrorMessage, type BackendError } from "@/lib/backend/errorUtils";
import { PHOENIX_DRIVER_NOT_INSTALLED_ERROR, PHOENIX_JDBC_PLUGIN_NOT_INSTALLED_ERROR } from "@/lib/database/phoenixConnection";
/**
@@ -127,6 +127,17 @@ const patterns: [RegExp, string][] = [
// Query result export limits (crates/dbx-core/src/query_result_export.rs)
[/^Streaming export is unsupported for this query\. Simplify it or use a supported driver\.$/, "exportProgress.streamingUnsupported"],
// MongoDB Legacy agent failures: messages raised by the agent arrive wrapped in "Agent RPC
// error (<code>): ", and the import path prefixes the row a batch-level failure belongs to.
[/^(?:Agent RPC error \(-?\d+\): )?MongoDB Legacy Agent does not support insertMany; upgrade or reinstall the MongoDB Legacy driver$/, "mongo.import.legacyInsertUnsupported"],
[/^(?:row \d+: )?MongoDB Legacy Agent does not support insertMany; upgrade or reinstall the MongoDB Legacy driver$/, "mongo.import.legacyInsertUnsupported"],
[/^MongoDB Legacy Agent rejected (\d+) of (\d+) documents: ([\s\S]+)$/, "mongo.insert.partialFailure"],
[/^(?:Agent RPC error \(-?\d+\): )?MongoDB Legacy Agent returned an invalid find cursor$/, "mongo.import.legacyCursorInvalid"],
[/^(?:Agent RPC error \(-?\d+\): )?MongoDB Legacy Agent returned an invalid find cursor page$/, "mongo.import.legacyCursorInvalid"],
[/^(?:Agent RPC error \(-?\d+\): )?Find cursor not found$/, "mongo.import.legacyCursorInvalid"],
[/^(?:Agent RPC error \(-?\d+\): )?MongoDB Legacy Agent does not support type-preserving export; upgrade or reinstall the MongoDB Legacy driver$/, "mongo.import.legacyExportUnsupported"],
[/^(?:Agent RPC error \(-?\d+\): )?MongoDB Legacy Agent returned the same export page twice; upgrade or reinstall the MongoDB Legacy driver$/, "mongo.import.legacyExportStalled"],
[/^(?:Agent RPC error \(-?\d+\): )?MongoDB Legacy Agent returned a document without _id$/, "mongo.import.legacyExportMissingId"],
[/^Streaming export needs a result-set session, but this driver returned no session_id\.$/, "exportProgress.agentSessionMissing"],
// Legacy bundled DuckDB error kept for compatibility with older backends.
@@ -157,6 +168,7 @@ const paramNames: Record<string, string | string[]> = {
"connection.jreNotInstalled": "jre",
"ai.configNameExists": "name",
"nacos.nacosManagedNamespaceAccessDenied": "detail",
"mongo.insert.partialFailure": ["failed", "total", "message"],
"settings.tunnelsHttpTestSuccess": "code",
"settings.tunnelsProxyTimedOut": "duration",
"settings.tunnelsProxyConnectFailed": "error",
@@ -188,27 +200,11 @@ function usableFallbackDetail(value: unknown): string | undefined {
return detail;
}
function translateStructuredBackendError(t: BackendErrorTranslate, error: BackendError, fallbackDetail?: unknown): string {
const translated = t(error.messageKey, error.messageParams);
const summary = translated !== error.messageKey ? translated : t("backendErrors.unknown");
let detail = error.detail ? sanitizeBackendErrorMessage(error.detail).trim() : usableFallbackDetail(fallbackDetail);
// Callers may pass an already-composited "summary\n\noriginal" cell as the
// fallback (query history re-translation of a failed result grid); strip the
// repeated summary so the message stays singular.
if (detail && detail.startsWith(`${summary}\n\n`)) {
detail = detail.slice(summary.length + 2).trim() || undefined;
}
const rawAdapterCode = error.diagnostics?.adapterCode;
const adapterCode = typeof rawAdapterCode === "string" && /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(rawAdapterCode) ? rawAdapterCode : undefined;
const diagnosticDetail = detail && adapterCode ? `[${adapterCode}] ${detail}` : (detail ?? adapterCode);
return diagnosticDetail && diagnosticDetail !== summary ? `${summary}\n\n${diagnosticDetail}` : summary;
}
export function translateBackendError(t: BackendErrorTranslate, error: unknown, fallbackDetail?: unknown): string {
const structured = normalizeBackendError(error);
if (structured) return translateStructuredBackendError(t, structured, fallbackDetail);
const message = backendErrorMessage(error);
/**
* Resolves a raw backend message through the known-message catalog, or `null` when the message is
* not one the UI knows how to phrase.
*/
function translateKnownMessage(t: BackendErrorTranslate, message: string): string | null {
const exactKey = exactMessageKeys[message];
if (exactKey) return t(exactKey);
@@ -238,5 +234,35 @@ export function translateBackendError(t: BackendErrorTranslate, error: unknown,
return t(key);
}
}
return message;
return null;
}
function translateStructuredBackendError(t: BackendErrorTranslate, error: BackendError, fallbackDetail?: unknown): string {
const translated = t(error.messageKey, error.messageParams);
const summary = translated !== error.messageKey ? translated : t("backendErrors.unknown");
let detail = error.detail ? sanitizeBackendErrorMessage(error.detail).trim() : usableFallbackDetail(fallbackDetail);
// Callers may pass an already-composited "summary\n\noriginal" cell as the
// fallback (query history re-translation of a failed result grid); strip the
// repeated summary so the message stays singular.
if (detail && detail.startsWith(`${summary}\n\n`)) {
detail = detail.slice(summary.length + 2).trim() || undefined;
}
// An unclassified message still goes through the same catalog the raw transports use, so a
// message DBX knows reads the same whether it arrived wrapped or bare.
if (error.code === LEGACY_BACKEND_ERROR_CODE && detail) {
const known = translateKnownMessage(t, detail);
if (known) return known;
}
const rawAdapterCode = error.diagnostics?.adapterCode;
const adapterCode = typeof rawAdapterCode === "string" && /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(rawAdapterCode) ? rawAdapterCode : undefined;
const diagnosticDetail = detail && adapterCode ? `[${adapterCode}] ${detail}` : (detail ?? adapterCode);
return diagnosticDetail && diagnosticDetail !== summary ? `${summary}\n\n${diagnosticDetail}` : summary;
}
export function translateBackendError(t: BackendErrorTranslate, error: unknown, fallbackDetail?: unknown): string {
const structured = normalizeBackendError(error);
if (structured) return translateStructuredBackendError(t, structured, fallbackDetail);
const message = backendErrorMessage(error);
return translateKnownMessage(t, message) ?? message;
}
+8
View File
@@ -5406,6 +5406,11 @@ export default withEnglishFallback({
start: "İdxal et",
success: "{count} sənəd idxal olundu",
stillRunning: "İdxal hələ işləyir. Yeni paketləri dayandırmaq üçün Ləğv et düyməsini istifadə edin.",
legacyInsertUnsupported: "Bu MongoDB Legacy sürücüsü sənədləri toplu daxil edə bilmir. MongoDB Legacy sürücüsünü yeniləyin və ya yenidən quraşdırın.",
legacyCursorInvalid: "MongoDB Legacy ixrac kursoru artıq əlçatan deyil. İxracı yenidən cəhd edin.",
legacyExportUnsupported: "Bu MongoDB Legacy sürücüsü ixrac zamanı BSON tiplərini qorumağı dəstəkləmir. MongoDB Legacy sürücüsünü yeniləyin və ya yenidən quraşdırın.",
legacyExportStalled: "MongoDB Legacy sürücüsü eyni ixrac səhifəsini iki dəfə qaytardı. Sürücünü yeniləyin və ya yenidən quraşdırıb ixracı yenidən cəhd edin.",
legacyExportMissingId: "MongoDB Legacy sürücüsü _id olmayan sənəd qaytardı; ixrac təhlükəsiz şəkildə səhifələnə bilmir.",
rowsRead: "Oxunan sətirlər",
rowsInserted: "Əlavə olunan sətirlər",
rowsFailed: "Uğursuz sətirlər",
@@ -5417,6 +5422,9 @@ export default withEnglishFallback({
done: "Bitdi",
},
},
insert: {
partialFailure: "MongoDB Legacy drayveri {total} sənədin {failed} hissəsini rədd etdi: {message}",
},
},
meilisearch: {
...meilisearchManagementAz,
+8
View File
@@ -5558,6 +5558,11 @@ export default {
start: "Import",
success: "Imported {count} documents",
stillRunning: "Import is still running. Use Cancel to stop new batches.",
legacyInsertUnsupported: "This MongoDB Legacy driver cannot insert documents in bulk. Upgrade or reinstall the MongoDB Legacy driver.",
legacyCursorInvalid: "The MongoDB Legacy export cursor is no longer available. Retry the export.",
legacyExportUnsupported: "This MongoDB Legacy driver cannot preserve BSON types during export. Upgrade or reinstall the MongoDB Legacy driver.",
legacyExportStalled: "The MongoDB Legacy driver returned the same export page twice. Upgrade or reinstall the MongoDB Legacy driver and retry the export.",
legacyExportMissingId: "The MongoDB Legacy driver returned a document without _id, so the export cannot page safely.",
rowsRead: "Rows read",
rowsInserted: "Rows inserted",
rowsFailed: "Rows failed",
@@ -5569,6 +5574,9 @@ export default {
done: "Done",
},
},
insert: {
partialFailure: "The MongoDB Legacy driver rejected {failed} of {total} documents: {message}",
},
},
meilisearch: {
...meilisearchManagementEn,
+8
View File
@@ -5260,6 +5260,11 @@ export default withEnglishFallback({
start: "Importar",
success: "Se importaron {count} documentos",
stillRunning: "La importación sigue en curso. Use Cancelar para detener nuevos lotes.",
legacyInsertUnsupported: "Este controlador MongoDB Legacy no puede insertar documentos en lote. Actualice o reinstale el controlador MongoDB Legacy.",
legacyCursorInvalid: "El cursor de exportación de MongoDB Legacy ya no está disponible. Vuelva a intentar la exportación.",
legacyExportUnsupported: "Este controlador MongoDB Legacy no admite la preservación de tipos BSON al exportar. Actualice o reinstale el controlador MongoDB Legacy.",
legacyExportStalled: "El controlador MongoDB Legacy devolvió dos veces la misma página de exportación. Actualice o reinstale el controlador y vuelva a intentar la exportación.",
legacyExportMissingId: "El controlador MongoDB Legacy devolvió un documento sin _id, por lo que la exportación no puede paginar de forma segura.",
rowsRead: "Filas leídas",
rowsInserted: "Filas insertadas",
rowsFailed: "Filas fallidas",
@@ -5271,6 +5276,9 @@ export default withEnglishFallback({
done: "Hecho",
},
},
insert: {
partialFailure: "El controlador MongoDB Legacy rechazó {failed} de {total} documentos: {message}",
},
},
meilisearch: {
...meilisearchManagementEs,
+8
View File
@@ -5258,6 +5258,11 @@ export default withEnglishFallback({
start: "Importa",
success: "Importati {count} documenti",
stillRunning: "L'importazione è ancora in esecuzione. Usa Annulla per fermare i nuovi batch.",
legacyInsertUnsupported: "Questo driver MongoDB Legacy non può inserire documenti in blocco. Aggiorna o reinstalla il driver MongoDB Legacy.",
legacyCursorInvalid: "Il cursore di esportazione MongoDB Legacy non è più disponibile. Riprova l'esportazione.",
legacyExportUnsupported: "Questo driver MongoDB Legacy non supporta la conservazione dei tipi BSON durante l'esportazione. Aggiorna o reinstalla il driver MongoDB Legacy.",
legacyExportStalled: "Il driver MongoDB Legacy ha restituito due volte la stessa pagina di esportazione. Aggiorna o reinstalla il driver e riprova l'esportazione.",
legacyExportMissingId: "Il driver MongoDB Legacy ha restituito un documento senza _id, quindi l'esportazione non può impaginare in modo sicuro.",
rowsRead: "Righe lette",
rowsInserted: "Righe inserite",
rowsFailed: "Righe non riuscite",
@@ -5269,6 +5274,9 @@ export default withEnglishFallback({
done: "Completato",
},
},
insert: {
partialFailure: "Il driver MongoDB Legacy ha rifiutato {failed} di {total} documenti: {message}",
},
},
meilisearch: {
...meilisearchManagementIt,
+8
View File
@@ -5287,6 +5287,11 @@ export default withEnglishFallback({
start: "インポート",
success: "{count} 件のドキュメントをインポートしました",
stillRunning: "インポートは実行中です。以降のバッチを止めるにはキャンセルしてください。",
legacyInsertUnsupported: "この MongoDB Legacy ドライバーは一括挿入に対応していません。ドライバーをアップグレードまたは再インストールしてください。",
legacyCursorInvalid: "MongoDB Legacy のエクスポートカーソルは利用できなくなりました。エクスポートを再試行してください。",
legacyExportUnsupported: "この MongoDB Legacy ドライバーはエクスポート時の BSON 型保持に対応していません。ドライバーをアップグレードまたは再インストールしてください。",
legacyExportStalled: "MongoDB Legacy ドライバーが同じエクスポートページを 2 回返しました。ドライバーをアップグレードまたは再インストールしてから、エクスポートを再試行してください。",
legacyExportMissingId: "MongoDB Legacy ドライバーが _id のないドキュメントを返したため、エクスポートを安全にページングできません。",
rowsRead: "読み取り行数",
rowsInserted: "挿入行数",
rowsFailed: "失敗行数",
@@ -5298,6 +5303,9 @@ export default withEnglishFallback({
done: "完了",
},
},
insert: {
partialFailure: "MongoDB Legacy ドライバーは {total} 件中 {failed} 件のドキュメントを拒否しました: {message}",
},
},
meilisearch: {
...meilisearchManagementJa,
+8
View File
@@ -4895,6 +4895,11 @@ export default withEnglishFallback({
start: "가져오기",
success: "{count}개 문서를 가져왔습니다",
stillRunning: "가져오기가 계속 실행 중입니다. 이후 배치를 멈추려면 취소를 사용하세요.",
legacyInsertUnsupported: "이 MongoDB Legacy 드라이버는 문서 일괄 삽입을 지원하지 않습니다. MongoDB Legacy 드라이버를 업그레이드하거나 다시 설치하세요.",
legacyCursorInvalid: "MongoDB Legacy 내보내기 커서를 더 이상 사용할 수 없습니다. 내보내기를 다시 시도하세요.",
legacyExportUnsupported: "이 MongoDB Legacy 드라이버는 내보내기 시 BSON 타입 유지를 지원하지 않습니다. MongoDB Legacy 드라이버를 업그레이드하거나 다시 설치하세요.",
legacyExportStalled: "MongoDB Legacy 드라이버가 동일한 내보내기 페이지를 두 번 반환했습니다. 드라이버를 업그레이드하거나 다시 설치한 후 다시 시도하세요.",
legacyExportMissingId: "MongoDB Legacy 드라이버가 _id 없는 문서를 반환해 안전하게 페이지 매김할 수 없습니다.",
rowsRead: "읽은 행",
rowsInserted: "삽입된 행",
rowsFailed: "실패한 행",
@@ -4906,6 +4911,9 @@ export default withEnglishFallback({
done: "완료",
},
},
insert: {
partialFailure: "MongoDB Legacy 드라이버가 {total}개 문서 중 {failed}개를 거부했습니다: {message}",
},
},
meilisearch: {
...meilisearchManagementKo,
+8
View File
@@ -5260,6 +5260,11 @@ export default withEnglishFallback({
start: "Importar",
success: "{count} documentos importados",
stillRunning: "A importação ainda está em execução. Use Cancelar para interromper novos lotes.",
legacyInsertUnsupported: "Este driver MongoDB Legacy não pode inserir documentos em lote. Atualize ou reinstale o driver MongoDB Legacy.",
legacyCursorInvalid: "O cursor de exportação do MongoDB Legacy não está mais disponível. Tente exportar novamente.",
legacyExportUnsupported: "Este driver MongoDB Legacy não é compatível com a preservação de tipos BSON na exportação. Atualize ou reinstale o driver MongoDB Legacy.",
legacyExportStalled: "O driver MongoDB Legacy retornou a mesma página de exportação duas vezes. Atualize ou reinstale o driver e tente exportar novamente.",
legacyExportMissingId: "O driver MongoDB Legacy retornou um documento sem _id, então a exportação não pode paginar com segurança.",
rowsRead: "Linhas lidas",
rowsInserted: "Linhas inseridas",
rowsFailed: "Linhas com falha",
@@ -5271,6 +5276,9 @@ export default withEnglishFallback({
done: "Concluído",
},
},
insert: {
partialFailure: "O driver MongoDB Legacy rejeitou {failed} de {total} documentos: {message}",
},
},
meilisearch: {
...meilisearchManagementPtBR,
+8
View File
@@ -5300,6 +5300,11 @@ export default withEnglishFallback({
start: "İçe aktar",
success: "{count} belge içe aktarıldı",
stillRunning: "İçe aktarma hâlâ çalışıyor. Yeni toplu işleri durdurmak için İptal’i kullanın.",
legacyInsertUnsupported: "Bu MongoDB Legacy sürücüsü belgeleri toplu ekleyemez. MongoDB Legacy sürücüsünü yükseltin veya yeniden yükleyin.",
legacyCursorInvalid: "MongoDB Legacy dışa aktarma imleci artık kullanılamıyor. Dışa aktarmayı yeniden deneyin.",
legacyExportUnsupported: "Bu MongoDB Legacy sürücüsü dışa aktarma sırasında BSON türlerini korumayı desteklemiyor. MongoDB Legacy sürücüsünü yükseltin veya yeniden yükleyin.",
legacyExportStalled: "MongoDB Legacy sürücüsü aynı dışa aktarma sayfasını iki kez döndürdü. Sürücüyü yükseltin veya yeniden yükleyin ve dışa aktarmayı yeniden deneyin.",
legacyExportMissingId: "MongoDB Legacy sürücüsü _id içermeyen bir belge döndürdü; dışa aktarma güvenli şekilde sayfalanamıyor.",
rowsRead: "Okunan satırlar",
rowsInserted: "Eklenen satırlar",
rowsFailed: "Başarısız satırlar",
@@ -5311,6 +5316,9 @@ export default withEnglishFallback({
done: "Bitti",
},
},
insert: {
partialFailure: "MongoDB Legacy sürücüsü {total} belgenin {failed} tanesini reddetti: {message}",
},
},
meilisearch: {
...meilisearchManagementTr,
+8
View File
@@ -5533,6 +5533,11 @@ export default withEnglishFallback({
start: "开始导入",
success: "已导入 {count} 个文档",
stillRunning: "导入仍在运行。如需停止后续批次,请点取消。",
legacyInsertUnsupported: "当前 MongoDB Legacy 驱动不支持批量插入文档。请升级或重新安装 MongoDB Legacy 驱动。",
legacyCursorInvalid: "MongoDB Legacy 导出游标已失效,请重试导出。",
legacyExportUnsupported: "当前 MongoDB Legacy 驱动不支持导出时保留 BSON 类型。请升级或重新安装 MongoDB Legacy 驱动。",
legacyExportStalled: "MongoDB Legacy 驱动返回了重复的导出分页。请升级或重新安装 MongoDB Legacy 驱动后重试导出。",
legacyExportMissingId: "MongoDB Legacy 驱动返回了缺少 _id 的文档,导出无法安全分页。",
rowsRead: "已读取",
rowsInserted: "已插入",
rowsFailed: "失败",
@@ -5544,6 +5549,9 @@ export default withEnglishFallback({
done: "完成",
},
},
insert: {
partialFailure: "MongoDB Legacy 驱动拒绝了 {total} 个文档中的 {failed} 个:{message}",
},
},
meilisearch: {
...meilisearchManagementZhCN,
+8
View File
@@ -4575,6 +4575,11 @@ export default withEnglishFallback({
start: "開始匯入",
success: "已匯入 {count} 個文件",
stillRunning: "匯入仍在執行。如需停止後續批次,請點取消。",
legacyInsertUnsupported: "目前的 MongoDB Legacy 驅動程式不支援批次插入文件。請升級或重新安裝 MongoDB Legacy 驅動程式。",
legacyCursorInvalid: "MongoDB Legacy 匯出游標已失效,請重試匯出。",
legacyExportUnsupported: "目前的 MongoDB Legacy 驅動程式不支援匯出時保留 BSON 類型。請升級或重新安裝 MongoDB Legacy 驅動程式。",
legacyExportStalled: "MongoDB Legacy 驅動程式重複回傳了同一個匯出分頁。請升級或重新安裝 MongoDB Legacy 驅動程式後重試匯出。",
legacyExportMissingId: "MongoDB Legacy 驅動程式回傳了缺少 _id 的文件,匯出無法安全分頁。",
rowsRead: "已讀取",
rowsInserted: "已插入",
rowsFailed: "失敗",
@@ -4591,6 +4596,9 @@ export default withEnglishFallback({
nativeJsonHint: "BSON 值請使用 MongoDB Extended JSON,例如 $oid、$date、$numberLong。",
invalidNativeJson: "原生 JSON 格式無效:{error}",
nativeDocumentRequired: "原生 JSON 的最上層必須是文件物件。",
insert: {
partialFailure: "MongoDB Legacy 驅動程式拒絕了 {total} 個文件中的 {failed} 個:{message}",
},
},
meilisearch: {
...meilisearchManagementZhTW,
+7 -1
View File
@@ -182,6 +182,12 @@ function normalizeBackendErrorAtDepth(error: unknown, seen: WeakSet<object>, dep
export const GENERIC_TRANSPORT_FAILURE_MESSAGE = "Backend request failed";
/**
* Marks a backend message the UI could not classify, so it is carried as raw text inside a
* structured envelope. Callers may still match that text against the known-message catalog.
*/
export const LEGACY_BACKEND_ERROR_CODE = "DBX-LEGACY-0001";
export class BackendErrorException extends Error {
readonly backendError: BackendError;
@@ -193,7 +199,7 @@ export class BackendErrorException extends Error {
this.name = "BackendErrorException";
this.backendError = backendError ?? {
version: 1,
code: "DBX-LEGACY-0001",
code: LEGACY_BACKEND_ERROR_CODE,
messageKey: "backendErrors.legacy",
messageParams: {},
source: "legacyBackend",