10 files changed
+745
-65
No files matched your search
@@ -67,12 +67,10 @@ import { buildTableSelectSql } from "@/lib/table/tableSelectSql";
|
||||
import {
|
||||
buildDropObjectSql,
|
||||
buildDropTableSql,
|
||||
buildDuplicateTableStructureSql,
|
||||
buildDuplicateTableStructurePlan as buildSharedDuplicateTableStructurePlan,
|
||||
buildCopyTableDataSql,
|
||||
buildEmptyTableSql,
|
||||
buildTruncateTableSql,
|
||||
collectDuplicateTableColumnComments,
|
||||
duplicateTableStructureRequiresScript,
|
||||
supportsDropTableCascade,
|
||||
supportsTruncateTableCascade,
|
||||
type TableAdminSqlOptions,
|
||||
@@ -1933,24 +1931,17 @@ function requestDuplicateStructure(row: ObjectBrowserRow) {
|
||||
}
|
||||
|
||||
async function buildDuplicateStructurePlan(sourceName: string, targetName: string, schema: string | undefined, tableComment?: string | null, sourceColumns?: ColumnInfo[]) {
|
||||
let columns = sourceColumns;
|
||||
if (effectiveDatabaseType.value === "dameng" && !columns) {
|
||||
try {
|
||||
columns = await api.getColumns(props.connection.id, props.database, schema || "", sourceName, props.catalog);
|
||||
} catch (error) {
|
||||
console.warn(`Failed to load Dameng column comments for table clone: ${sourceName}`, error);
|
||||
}
|
||||
}
|
||||
const columnComments = effectiveDatabaseType.value === "dameng" ? collectDuplicateTableColumnComments(columns ?? []) : [];
|
||||
const sql = await buildDuplicateTableStructureSql({
|
||||
return buildSharedDuplicateTableStructurePlan({
|
||||
connectionId: props.connection.id,
|
||||
database: props.database,
|
||||
catalog: props.catalog,
|
||||
databaseType: effectiveDatabaseType.value,
|
||||
schema,
|
||||
sourceName,
|
||||
targetName,
|
||||
tableComment,
|
||||
columnComments,
|
||||
sourceColumns,
|
||||
});
|
||||
return { sql, sourceColumns: columns, executeAsScript: duplicateTableStructureRequiresScript(sql) };
|
||||
}
|
||||
|
||||
function executeDuplicateStructurePlan(plan: { sql: string; executeAsScript: boolean }, schema: string | undefined) {
|
||||
|
||||
@@ -114,12 +114,10 @@ import {
|
||||
buildUpdateDatabasePropertiesSql,
|
||||
buildDropTableSql,
|
||||
buildDropTableChildObjectSql,
|
||||
buildDuplicateTableStructureSql,
|
||||
buildDuplicateTableStructurePlan,
|
||||
buildCopyTableDataSql,
|
||||
buildEmptyTableSql,
|
||||
buildTruncateTableSql,
|
||||
collectDuplicateTableColumnComments,
|
||||
duplicateTableStructureRequiresScript,
|
||||
supportsDropTableCascade,
|
||||
supportsTruncateTableCascade,
|
||||
supportsSchemaComment,
|
||||
@@ -3126,19 +3124,6 @@ function isDuplicateStructureSource(node: TreeNode): node is DuplicateStructureS
|
||||
return node.type === "table" && !!node.connectionId && !!node.database;
|
||||
}
|
||||
|
||||
/** Dameng CTAS does not copy comments; load column comments for COMMENT ON COLUMN. */
|
||||
async function loadDamengDuplicateColumnComments(connectionId: string, database: string, schema: string | undefined, sourceName: string, catalog?: string, sourceColumns?: ColumnInfo[]): Promise<{ columns?: ColumnInfo[]; columnComments: Array<{ name: string; comment: string }> }> {
|
||||
let columns = sourceColumns;
|
||||
if (!columns) {
|
||||
try {
|
||||
columns = await api.getColumns(connectionId, database, schema || "", sourceName, catalog);
|
||||
} catch (error) {
|
||||
console.warn(`Failed to load Dameng column comments for table clone: ${sourceName}`, error);
|
||||
}
|
||||
}
|
||||
return { columns, columnComments: collectDuplicateTableColumnComments(columns ?? []) };
|
||||
}
|
||||
|
||||
async function confirmDuplicateStructure() {
|
||||
const node = duplicateStructureSource.value || (isDuplicateStructureSource(activeNode.value) ? activeNode.value : null);
|
||||
const newName = duplicateTableName.value.trim();
|
||||
@@ -3148,19 +3133,20 @@ async function confirmDuplicateStructure() {
|
||||
try {
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
const databaseType = databaseTypeForNode(node);
|
||||
const columnComments = databaseType === "dameng" ? (await loadDamengDuplicateColumnComments(node.connectionId, node.database, node.schema, node.label, node.catalog)).columnComments : [];
|
||||
const sql = await buildDuplicateTableStructureSql({
|
||||
const plan = await buildDuplicateTableStructurePlan({
|
||||
connectionId: node.connectionId,
|
||||
database: node.database,
|
||||
catalog: node.catalog,
|
||||
databaseType,
|
||||
schema: node.schema,
|
||||
sourceName: node.label,
|
||||
targetName: newName,
|
||||
tableComment: node.comment,
|
||||
columnComments,
|
||||
});
|
||||
await executeTreeNodeSqlWithProductionGuard(node, sql, {
|
||||
await executeTreeNodeSqlWithProductionGuard(node, plan.sql, {
|
||||
database: node.database,
|
||||
schema: node.schema,
|
||||
executeAsScript: duplicateTableStructureRequiresScript(sql),
|
||||
executeAsScript: plan.executeAsScript,
|
||||
});
|
||||
toast(t("contextMenu.duplicateStructureSuccess", { name: newName }), 3000);
|
||||
await refreshTableList(node);
|
||||
@@ -3198,24 +3184,20 @@ async function confirmPasteTable() {
|
||||
const databaseType = entry.connectionId ? effectiveDatabaseTypeForConnection(connectionStore.getConfig(entry.connectionId)) : undefined;
|
||||
let sourceColumns: ColumnInfo[] | undefined;
|
||||
if (mode === "structure-and-data" || mode === "structure-only") {
|
||||
let columnComments: Array<{ name: string; comment: string }> = [];
|
||||
if (databaseType === "dameng") {
|
||||
const loaded = await loadDamengDuplicateColumnComments(entry.connectionId, entry.database, entry.schema, entry.sourceName);
|
||||
sourceColumns = loaded.columns;
|
||||
columnComments = loaded.columnComments;
|
||||
}
|
||||
const structureSql = await buildDuplicateTableStructureSql({
|
||||
const plan = await buildDuplicateTableStructurePlan({
|
||||
connectionId: entry.connectionId,
|
||||
database: entry.database,
|
||||
databaseType,
|
||||
schema: entry.schema,
|
||||
sourceName: entry.sourceName,
|
||||
targetName,
|
||||
tableComment: entry.tableComment,
|
||||
columnComments,
|
||||
});
|
||||
const structureExecuted = await executeTreeNodeSqlWithProductionGuard(entry, structureSql, {
|
||||
sourceColumns = plan.sourceColumns;
|
||||
const structureExecuted = await executeTreeNodeSqlWithProductionGuard(entry, plan.sql, {
|
||||
database: entry.database,
|
||||
schema: entry.schema,
|
||||
executeAsScript: duplicateTableStructureRequiresScript(structureSql),
|
||||
executeAsScript: plan.executeAsScript,
|
||||
});
|
||||
if (!structureExecuted) {
|
||||
pasteCancelled = true;
|
||||
|
||||
+6
-8
@@ -32,15 +32,13 @@ describe("cross-database table paste", () => {
|
||||
expect(runtimeSource).toMatch(/tableName: node\.label,\s*tableComment: node\.comment/);
|
||||
expect(runtimeSource).toMatch(/targetName: `\$\{entry\.tableName\}_copy`,[\s\S]*?tableComment: entry\.tableComment/);
|
||||
expect(runtimeSource).toMatch(/targetName,\s*tableComment: entry\.tableComment/);
|
||||
expect(runtimeSource).toContain("executeAsScript: duplicateTableStructureRequiresScript(structureSql)");
|
||||
expect(runtimeSource).toContain("executeAsScript: plan.executeAsScript");
|
||||
});
|
||||
|
||||
it("loads Dameng column comments for sidebar duplicate and paste structure clone", () => {
|
||||
expect(runtimeSource).toContain("collectDuplicateTableColumnComments");
|
||||
expect(runtimeSource).toContain("async function loadDamengDuplicateColumnComments(");
|
||||
expect(runtimeSource).toMatch(/databaseType === "dameng"[\s\S]*?loadDamengDuplicateColumnComments\([\s\S]*?node\.connectionId[\s\S]*?columnComments/);
|
||||
expect(runtimeSource).toMatch(/if \(databaseType === "dameng"\) \{[\s\S]*?loadDamengDuplicateColumnComments\([\s\S]*?entry\.connectionId[\s\S]*?columnComments = loaded\.columnComments/);
|
||||
expect(runtimeSource).toMatch(/tableComment: node\.comment,\s*columnComments,/);
|
||||
expect(runtimeSource).toMatch(/tableComment: entry\.tableComment,\s*columnComments,/);
|
||||
it("uses the shared metadata-aware structure plan for duplicate and paste", () => {
|
||||
expect(runtimeSource).toContain("buildDuplicateTableStructurePlan");
|
||||
expect(runtimeSource).toMatch(/buildDuplicateTableStructurePlan\(\{[\s\S]*?connectionId: node\.connectionId[\s\S]*?sourceName: node\.label[\s\S]*?tableComment: node\.comment/);
|
||||
expect(runtimeSource).toMatch(/buildDuplicateTableStructurePlan\(\{[\s\S]*?connectionId: entry\.connectionId[\s\S]*?sourceName: entry\.sourceName[\s\S]*?tableComment: entry\.tableComment/);
|
||||
expect(runtimeSource).toContain("sourceColumns = plan.sourceColumns");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user