feat(mongodb): bson dumps and database backup/restore
This commit is contained in:
1 parent
ecc1135de3
commit
f5673ca0a1
54 files changed
+6355
-106
No files matched your search
@@ -158,6 +158,39 @@ describe("useSidebarTreeExportRuntime", () => {
|
||||
expect(toastMock).toHaveBeenCalledWith("grid.exported");
|
||||
});
|
||||
|
||||
it.each(["bson", "bsonGzip"] as const)("exports an official-compatible %s collection dump", async (mode) => {
|
||||
apiMock.exportMongodbQuery.mockImplementation(async (_request, onProgress) => {
|
||||
onProgress({ exportId: "export-1", status: "done", documentsRead: 2, bytesWritten: 64, elapsedMs: 4 });
|
||||
return { exportId: "export-1", documentsExported: 2, filePath: "orders.bson.gz", elapsedMs: 4 };
|
||||
});
|
||||
const activeNode = shallowRef({ id: "col-1", type: "mongo-collection", label: "orders", connectionId: "conn-1", database: "shop", children: [] } as TreeNode);
|
||||
const connectionStore = {
|
||||
ensureConnected: vi.fn(),
|
||||
getConfig: vi.fn(() => ({ db_type: "mongodb" })),
|
||||
treeNodes: [],
|
||||
selectedTreeNodeIds: [],
|
||||
};
|
||||
const runtime = useSidebarTreeExportRuntime({
|
||||
activeNode,
|
||||
connectionStore: connectionStore as never,
|
||||
settingsStore: exportSettings() as never,
|
||||
acceptedSelectionIds: () => null,
|
||||
});
|
||||
|
||||
await runtime.exportMongoCollection(mode);
|
||||
|
||||
expect(apiMock.exportMongodbQuery).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
database: "shop",
|
||||
collection: "orders",
|
||||
format: "bson",
|
||||
gzip: mode === "bsonGzip",
|
||||
filePath: mode === "bsonGzip" ? "orders.bson.gz" : "orders.bson",
|
||||
}),
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it("loads and joins every selected DDL in tree order", async () => {
|
||||
apiMock.getTableDdl.mockResolvedValueOnce("CREATE TABLE one (id INT)").mockResolvedValueOnce("CREATE VIEW two AS SELECT 1;");
|
||||
const first = { id: "table-1", type: "table", label: "one", connectionId: "conn-1", database: "db", schema: "main" } as TreeNode;
|
||||
|
||||
+24
@@ -11,6 +11,7 @@ function setup(node: Partial<TreeNode>, options: { treeNodes?: TreeNode[]; selec
|
||||
diagramSource: null as unknown,
|
||||
databaseExportSource: null as unknown,
|
||||
mongoImportSource: undefined as unknown,
|
||||
mongoDatabaseDumpSource: null as unknown,
|
||||
schemaDiffSource: null as unknown,
|
||||
treeNodes: options.treeNodes ?? [],
|
||||
selectedTreeNodeIds: options.selectedTreeNodeIds ?? [],
|
||||
@@ -129,6 +130,29 @@ describe("useSidebarTreeToolRuntime mongo import", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("useSidebarTreeToolRuntime MongoDB dump and restore", () => {
|
||||
it.each(["dump", "restore"] as const)("opens %s for the selected MongoDB database", (mode) => {
|
||||
const { connectionStore, runtime } = setup({ type: "mongo-db", connectionId: "conn-1", database: "shop" });
|
||||
|
||||
runtime.openMongoDatabaseDump(mode);
|
||||
|
||||
expect(connectionStore.mongoDatabaseDumpSource).toEqual({ connectionId: "conn-1", database: "shop", mode });
|
||||
});
|
||||
|
||||
it.each<Partial<TreeNode>>([
|
||||
{ type: "table", connectionId: "conn-1", database: "shop" },
|
||||
{ type: "mongo-collection", connectionId: "conn-1", database: "shop" },
|
||||
{ type: "mongo-db", database: "shop" },
|
||||
{ type: "mongo-db", connectionId: "conn-1" },
|
||||
])("does not open a database restore from an invalid context: %j", (node) => {
|
||||
const { connectionStore, runtime } = setup(node);
|
||||
|
||||
runtime.openMongoDatabaseDump("restore");
|
||||
|
||||
expect(connectionStore.mongoDatabaseDumpSource).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("useSidebarTreeToolRuntime openSchemaDiffForRoutine", () => {
|
||||
it("prefills schema diff with a signature-aware routine key", () => {
|
||||
const { connectionStore, runtime } = setup({
|
||||
|
||||
@@ -15,6 +15,10 @@ const showDiagramDialog = ref(false);
|
||||
const showDocsDialog = ref(false);
|
||||
const showTableImportDialog = ref(false);
|
||||
const showMongoImportDialog = ref(false);
|
||||
const showMongoDatabaseDumpDialog = ref(false);
|
||||
const mongoDatabaseDumpPrefillConnectionId = ref("");
|
||||
const mongoDatabaseDumpPrefillDatabase = ref("");
|
||||
const mongoDatabaseDumpMode = ref<"dump" | "restore">("dump");
|
||||
const showTableDataGenerateDialog = ref(false);
|
||||
const showFieldLineageDialog = ref(false);
|
||||
const showDatabaseSearchDialog = ref(false);
|
||||
@@ -263,6 +267,18 @@ export function useDialogSources() {
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => connectionStore.mongoDatabaseDumpSource,
|
||||
(source) => {
|
||||
if (!source) return;
|
||||
mongoDatabaseDumpPrefillConnectionId.value = source.connectionId;
|
||||
mongoDatabaseDumpPrefillDatabase.value = source.database;
|
||||
mongoDatabaseDumpMode.value = source.mode;
|
||||
showMongoDatabaseDumpDialog.value = true;
|
||||
connectionStore.mongoDatabaseDumpSource = null;
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => connectionStore.tableDataGenerateSource,
|
||||
(v) => {
|
||||
@@ -519,6 +535,10 @@ export function useDialogSources() {
|
||||
showDocsDialog,
|
||||
showTableImportDialog,
|
||||
showMongoImportDialog,
|
||||
showMongoDatabaseDumpDialog,
|
||||
mongoDatabaseDumpPrefillConnectionId,
|
||||
mongoDatabaseDumpPrefillDatabase,
|
||||
mongoDatabaseDumpMode,
|
||||
showTableDataGenerateDialog,
|
||||
showFieldLineageDialog,
|
||||
showDatabaseSearchDialog,
|
||||
|
||||
@@ -274,6 +274,7 @@ export function useSidebarTreeExportRuntime(options: SidebarTreeExportRuntimeOpt
|
||||
if (format === "csv") return "CSV";
|
||||
if (format === "json") return "JSON";
|
||||
if (format === "ndjson") return "NDJSON";
|
||||
if (format === "bson" || format === "bson.gz") return "MongoDB BSON dump";
|
||||
if (format === "xlsx") return "Excel";
|
||||
return "SQL";
|
||||
}
|
||||
@@ -287,7 +288,7 @@ export function useSidebarTreeExportRuntime(options: SidebarTreeExportRuntimeOpt
|
||||
const { save } = await import("@tauri-apps/plugin-dialog");
|
||||
const path = await save({
|
||||
defaultPath: fileName,
|
||||
filters: [{ name: exportFilterName(format), extensions: [format] }],
|
||||
filters: [{ name: exportFilterName(format), extensions: [format === "bson.gz" ? "gz" : format] }],
|
||||
});
|
||||
return path ? String(path) : null;
|
||||
}
|
||||
@@ -472,10 +473,12 @@ export function useSidebarTreeExportRuntime(options: SidebarTreeExportRuntimeOpt
|
||||
return pickTableExportDirectory();
|
||||
}
|
||||
|
||||
async function exportMongoCollection(format: "csv" | "ndjson") {
|
||||
async function exportMongoCollection(outputFormat: "csv" | "ndjson" | "bson" | "bsonGzip") {
|
||||
const node = activeNode.value;
|
||||
if (node.type !== "mongo-collection" || !node.connectionId || !node.database) return;
|
||||
const outputPath = await resolveExportOutputPath(node.label, format);
|
||||
const format: api.MongoExportFormat = outputFormat === "bsonGzip" ? "bson" : outputFormat;
|
||||
const fileExtension = outputFormat === "bsonGzip" ? "bson.gz" : outputFormat;
|
||||
const outputPath = await resolveExportOutputPath(node.label, fileExtension);
|
||||
if (!outputPath) return;
|
||||
let task: ExportTask | null = null;
|
||||
try {
|
||||
@@ -490,6 +493,7 @@ export function useSidebarTreeExportRuntime(options: SidebarTreeExportRuntimeOpt
|
||||
collection: node.label,
|
||||
format,
|
||||
includeHeader: true,
|
||||
gzip: outputFormat === "bsonGzip",
|
||||
filePath: outputPath,
|
||||
},
|
||||
(progress) => {
|
||||
|
||||
@@ -149,6 +149,12 @@ export function useSidebarTreeToolRuntime(options: SidebarTreeToolRuntimeOptions
|
||||
};
|
||||
}
|
||||
|
||||
function openMongoDatabaseDump(mode: "dump" | "restore") {
|
||||
const node = activeNode.value;
|
||||
if (node.type !== "mongo-db" || !node.connectionId || !node.database) return;
|
||||
connectionStore.mongoDatabaseDumpSource = { connectionId: node.connectionId, database: node.database, mode };
|
||||
}
|
||||
|
||||
function openStructureEditor() {
|
||||
const node = activeNode.value;
|
||||
if (!node.connectionId || !node.database) return;
|
||||
@@ -191,6 +197,7 @@ export function useSidebarTreeToolRuntime(options: SidebarTreeToolRuntimeOptions
|
||||
openDocs,
|
||||
openFieldLineage,
|
||||
openMongoImport,
|
||||
openMongoDatabaseDump,
|
||||
openScheduledBackups,
|
||||
openSchemaDiff,
|
||||
openSchemaDiffForRoutine,
|
||||
|
||||
Reference in new issue
Block a user