fix(export): allow routine-only database exports

Closes #6888
This commit is contained in:
t8y2 committed 2026-08-23 22:00:42 +08:00
1 parent e15ade130d
commit b4b04d30b8
3 files changed
+58 -3

No files matched your search

@@ -13,7 +13,7 @@ import type { ExportProgress } from "@/lib/backend/api";
import { isSchemaAware, isSingleDatabase } from "@/lib/database/databaseFeatureSupport"; import { isSchemaAware, isSingleDatabase } from "@/lib/database/databaseFeatureSupport";
import { databaseOptionsForConnection, fetchNamespaceOptionsForConnection } from "@/composables/useDatabaseOptions"; import { databaseOptionsForConnection, fetchNamespaceOptionsForConnection } from "@/composables/useDatabaseOptions";
import { buildAllDatabaseExportPlan, generateDatabaseExportId, runDatabaseExportUntilTerminal, runWithDatabaseBackupSnapshot, shouldUseDatabaseBackupSnapshot, type AllDatabaseExportPlanItem } from "@/lib/export/databaseExport"; import { buildAllDatabaseExportPlan, generateDatabaseExportId, runDatabaseExportUntilTerminal, runWithDatabaseBackupSnapshot, shouldUseDatabaseBackupSnapshot, type AllDatabaseExportPlanItem } from "@/lib/export/databaseExport";
import { buildSelectedTablesPayload } from "@/lib/export/databaseExportSelection"; import { buildSelectedTablesPayload, isDatabaseExportTableSelectionValid } from "@/lib/export/databaseExportSelection";
import { isTauriRuntime } from "@/lib/backend/tauriRuntime"; import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
import { useToast } from "@/composables/useToast"; import { useToast } from "@/composables/useToast";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
@@ -109,7 +109,18 @@ const canExport = computed(() => {
const hasContent = includeStructure.value || includeData.value || includeObjects.value; const hasContent = includeStructure.value || includeData.value || includeObjects.value;
if (!connectionId.value || !hasContent || isExporting.value) return false; if (!connectionId.value || !hasContent || isExporting.value) return false;
if (exportAllDatabases.value) return selectedDatabases.value.length > 0 && !loadingMeta.value; if (exportAllDatabases.value) return selectedDatabases.value.length > 0 && !loadingMeta.value;
return database.value && schema.value && !loadingTables.value && !tableError.value && (tables.value.length === 0 || selectedTables.value.length > 0); return (
database.value &&
schema.value &&
!loadingTables.value &&
!tableError.value &&
isDatabaseExportTableSelectionValid({
allTableCount: tables.value.length,
selectedTableCount: selectedTables.value.length,
includeStructure: includeStructure.value,
includeData: includeData.value,
})
);
}); });
const selectedTableSet = computed(() => new Set(selectedTables.value)); const selectedTableSet = computed(() => new Set(selectedTables.value));
@@ -340,7 +351,7 @@ async function startExport() {
database: database.value, database: database.value,
schema: schema.value, schema: schema.value,
filePath, filePath,
selectedTables: buildSelectedTablesPayload(tables.value, selectedTables.value), selectedTables: includeStructure.value || includeData.value ? buildSelectedTablesPayload(tables.value, selectedTables.value) : undefined,
includeStructure: includeStructure.value, includeStructure: includeStructure.value,
includeData: includeData.value, includeData: includeData.value,
includeObjects: includeObjects.value, includeObjects: includeObjects.value,
@@ -6,3 +6,13 @@ export function buildSelectedTablesPayload(allTables: string[], selectedTables:
const selected = new Set(selectedTables); const selected = new Set(selectedTables);
return allTables.filter((table) => selected.has(table)); return allTables.filter((table) => selected.has(table));
} }
export function isDatabaseExportTableSelectionValid(options: {
allTableCount: number;
selectedTableCount: number;
includeStructure: boolean;
includeData: boolean;
}): boolean {
if (!options.includeStructure && !options.includeData) return true;
return options.allTableCount === 0 || options.selectedTableCount > 0;
}
+34
View File
@@ -1,6 +1,40 @@
import assert from "node:assert/strict"; import assert from "node:assert/strict";
import { test } from "vitest"; import { test } from "vitest";
import { buildAllDatabaseExportPlan } from "../../apps/desktop/src/lib/export/databaseExport.ts"; import { buildAllDatabaseExportPlan } from "../../apps/desktop/src/lib/export/databaseExport.ts";
import { isDatabaseExportTableSelectionValid } from "../../apps/desktop/src/lib/export/databaseExportSelection.ts";
test("database export allows object-only exports without selecting tables", () => {
assert.equal(
isDatabaseExportTableSelectionValid({
allTableCount: 982,
selectedTableCount: 0,
includeStructure: false,
includeData: false,
}),
true,
);
});
test("database export still requires a table when exporting structure or data", () => {
assert.equal(
isDatabaseExportTableSelectionValid({
allTableCount: 982,
selectedTableCount: 0,
includeStructure: true,
includeData: false,
}),
false,
);
assert.equal(
isDatabaseExportTableSelectionValid({
allTableCount: 982,
selectedTableCount: 1,
includeStructure: false,
includeData: true,
}),
true,
);
});
test("all-database export includes every schema for schema-aware databases", () => { test("all-database export includes every schema for schema-aware databases", () => {
const plan = buildAllDatabaseExportPlan({ const plan = buildAllDatabaseExportPlan({