feat(schema): add object rename actions
This commit is contained in:
parent
307f773387
commit
f80b1e8bc9
|
|
@ -7,6 +7,7 @@ import {
|
|||
Copy,
|
||||
Eye,
|
||||
Loader2,
|
||||
Pencil,
|
||||
PencilLine,
|
||||
RefreshCw,
|
||||
Search,
|
||||
|
|
@ -34,11 +35,13 @@ import { isSchemaAware } from "@/lib/databaseCapabilities";
|
|||
import { buildTableSelectSql, qualifiedTableName } from "@/lib/tableSelectSql";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { buildExecutableObjectSourceSql, objectSourceSaveExecutionMode } from "@/lib/objectSourceEditor";
|
||||
import { buildRenameObjectSql, supportsObjectRename } from "@/lib/objectRenameSql";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { useQueryStore } from "@/stores/queryStore";
|
||||
import QueryEditor from "@/components/editor/QueryEditor.vue";
|
||||
import type { SqlFormatDialect } from "@/lib/sqlFormatter";
|
||||
import { isCancelSearchShortcut } from "@/lib/keyboardShortcuts";
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
|
||||
type ObjectRow = {
|
||||
id: string;
|
||||
|
|
@ -85,6 +88,10 @@ const sourceSaveError = ref("");
|
|||
const error = ref("");
|
||||
const showDropConfirm = ref(false);
|
||||
const dropTarget = ref<ObjectRow | null>(null);
|
||||
const showRenameDialog = ref(false);
|
||||
const renameTarget = ref<ObjectRow | null>(null);
|
||||
const renameInput = ref("");
|
||||
const renameError = ref("");
|
||||
let loadId = 0;
|
||||
|
||||
const needsSchema = computed(() => isSchemaAware(props.connection.db_type));
|
||||
|
|
@ -176,6 +183,10 @@ function canOpenSource(row: ObjectRow) {
|
|||
return row.type === "VIEW" || row.type === "PROCEDURE" || row.type === "FUNCTION";
|
||||
}
|
||||
|
||||
function canRename(row: ObjectRow) {
|
||||
return supportsObjectRename(props.connection.db_type, row.type);
|
||||
}
|
||||
|
||||
function sourceTitle(row: ObjectRow | null) {
|
||||
if (!row) return t("objects.source");
|
||||
return `${row.name} ${t("objects.source")}`;
|
||||
|
|
@ -241,6 +252,59 @@ function requestDrop(row: ObjectRow) {
|
|||
showDropConfirm.value = true;
|
||||
}
|
||||
|
||||
function requestRename(row: ObjectRow) {
|
||||
renameTarget.value = row;
|
||||
renameInput.value = row.name;
|
||||
renameError.value = "";
|
||||
showRenameDialog.value = true;
|
||||
}
|
||||
|
||||
function renamePreviewSql() {
|
||||
const row = renameTarget.value;
|
||||
const newName = renameInput.value.trim();
|
||||
if (!row || !newName || newName === row.name) return "";
|
||||
try {
|
||||
return buildRenameObjectSql({
|
||||
databaseType: props.connection.db_type,
|
||||
objectType: row.type,
|
||||
schema: row.schema || selectedSchema.value,
|
||||
oldName: row.name,
|
||||
newName,
|
||||
});
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmRename() {
|
||||
const row = renameTarget.value;
|
||||
const newName = renameInput.value.trim();
|
||||
if (!row || !newName || newName === row.name) return;
|
||||
renameError.value = "";
|
||||
try {
|
||||
const schema = row.schema || selectedSchema.value || props.database;
|
||||
const sql = buildRenameObjectSql({
|
||||
databaseType: props.connection.db_type,
|
||||
objectType: row.type,
|
||||
schema,
|
||||
oldName: row.name,
|
||||
newName,
|
||||
});
|
||||
await api.executeQuery(props.connection.id, props.database, sql, schema);
|
||||
toast(t("contextMenu.renameObjectSuccess", { oldName: row.name, newName }));
|
||||
showRenameDialog.value = false;
|
||||
if (sourceRow.value?.id === row.id) closeSource();
|
||||
await reload();
|
||||
await connectionStore.refreshObjectListTreeNode(
|
||||
props.connection.id,
|
||||
props.database,
|
||||
row.schema || selectedSchema.value,
|
||||
);
|
||||
} catch (e: any) {
|
||||
renameError.value = e?.message || String(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmDrop() {
|
||||
if (!dropTarget.value) return;
|
||||
const row = dropTarget.value;
|
||||
|
|
@ -570,6 +634,9 @@ watch(
|
|||
<ContextMenuItem @click="openNewQuery(item)">
|
||||
<TerminalSquare class="w-4 h-4 mr-2" /> {{ t("contextMenu.newQuery") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem v-if="canRename(item)" @click="requestRename(item)">
|
||||
<Pencil class="w-4 h-4 mr-2" /> {{ t("contextMenu.renameObject") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem class="text-destructive" @click="requestDrop(item)">
|
||||
<Trash2 class="w-4 h-4 mr-2" /> {{ t("contextMenu.dropTable") }}
|
||||
|
|
@ -580,6 +647,9 @@ watch(
|
|||
<ContextMenuItem @click="openSource(item)">
|
||||
<Code2 class="w-4 h-4 mr-2" /> {{ t("contextMenu.viewSource") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem v-if="canRename(item)" @click="requestRename(item)">
|
||||
<Pencil class="w-4 h-4 mr-2" /> {{ t("contextMenu.renameObject") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem class="text-destructive" @click="requestDrop(item)">
|
||||
<Trash2 class="w-4 h-4 mr-2" /> {{ t("contextMenu.dropView") }}
|
||||
|
|
@ -590,6 +660,9 @@ watch(
|
|||
<ContextMenuItem @click="openSource(item)">
|
||||
<Code2 class="w-4 h-4 mr-2" /> {{ t("contextMenu.viewSource") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem v-if="canRename(item)" @click="requestRename(item)">
|
||||
<Pencil class="w-4 h-4 mr-2" /> {{ t("contextMenu.renameObject") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem class="text-destructive" @click="requestDrop(item)">
|
||||
<Trash2 class="w-4 h-4 mr-2" />
|
||||
|
|
@ -694,6 +767,33 @@ watch(
|
|||
:confirm-label="t('dangerDialog.deleteConfirm')"
|
||||
@confirm="confirmDrop"
|
||||
/>
|
||||
|
||||
<Dialog v-model:open="showRenameDialog">
|
||||
<DialogContent class="sm:max-w-[420px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t("contextMenu.renameObjectTitle") }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div class="grid gap-3">
|
||||
<Input
|
||||
v-model="renameInput"
|
||||
:placeholder="t('contextMenu.renameObjectNamePlaceholder')"
|
||||
@keydown.enter.prevent="confirmRename"
|
||||
/>
|
||||
<pre
|
||||
v-if="renamePreviewSql()"
|
||||
class="max-h-32 overflow-auto rounded bg-muted p-3 text-xs whitespace-pre-wrap"
|
||||
>{{ renamePreviewSql() }}</pre
|
||||
>
|
||||
<p v-if="renameError" class="text-sm text-destructive">{{ renameError }}</p>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="showRenameDialog = false">{{ t("dangerDialog.cancel") }}</Button>
|
||||
<Button :disabled="!renameInput.trim() || renameInput.trim() === renameTarget?.name" @click="confirmRename">
|
||||
{{ t("contextMenu.renameObject") }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ import {
|
|||
import { sidebarSelectionCopyAction, treeNodeRowAction, treeNodeRowDoubleClickAction } from "@/lib/treeNodeClick";
|
||||
import { formatCsv, formatJson, formatSqlInsert } from "@/lib/exportFormats";
|
||||
import { buildCreateDatabaseSql, supportsCreateDatabaseCharset } from "@/lib/createDatabaseSql";
|
||||
import { buildRenameObjectSql, supportsObjectRename, type RenameableObjectType } from "@/lib/objectRenameSql";
|
||||
import { hexToRgba } from "@/lib/color";
|
||||
import DangerConfirmDialog from "@/components/editor/DangerConfirmDialog.vue";
|
||||
import { isTauriRuntime } from "@/lib/tauriRuntime";
|
||||
|
|
@ -602,6 +603,9 @@ async function duplicateConnection() {
|
|||
const showDropTableConfirm = ref(false);
|
||||
const showEmptyTableConfirm = ref(false);
|
||||
const showTruncateTableConfirm = ref(false);
|
||||
const showRenameObjectDialog = ref(false);
|
||||
const renameObjectName = ref("");
|
||||
const renameObjectError = ref("");
|
||||
const showDuplicateDialog = ref(false);
|
||||
const duplicateTableName = ref("");
|
||||
|
||||
|
|
@ -653,6 +657,66 @@ function requestDropObject() {
|
|||
showDropObjectConfirm.value = true;
|
||||
}
|
||||
|
||||
function nodeRenameObjectType(): RenameableObjectType | null {
|
||||
if (props.node.type === "table") return "TABLE";
|
||||
if (props.node.type === "view") return "VIEW";
|
||||
if (props.node.type === "procedure") return "PROCEDURE";
|
||||
if (props.node.type === "function") return "FUNCTION";
|
||||
return null;
|
||||
}
|
||||
|
||||
const canRenameObject = computed(() => {
|
||||
const objectType = nodeRenameObjectType();
|
||||
return !!objectType && supportsObjectRename(currentDatabaseType(), objectType);
|
||||
});
|
||||
|
||||
function openRenameObjectDialog() {
|
||||
renameObjectName.value = props.node.label;
|
||||
renameObjectError.value = "";
|
||||
showRenameObjectDialog.value = true;
|
||||
}
|
||||
|
||||
function buildRenameObjectPreviewSql(): string {
|
||||
const objectType = nodeRenameObjectType();
|
||||
const newName = renameObjectName.value.trim();
|
||||
if (!objectType || !newName || newName === props.node.label) return "";
|
||||
try {
|
||||
return buildRenameObjectSql({
|
||||
databaseType: currentDatabaseType(),
|
||||
objectType,
|
||||
schema: props.node.schema,
|
||||
oldName: props.node.label,
|
||||
newName,
|
||||
});
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmRenameObject() {
|
||||
const node = props.node;
|
||||
const objectType = nodeRenameObjectType();
|
||||
const newName = renameObjectName.value.trim();
|
||||
if (!objectType || !newName || newName === node.label || !node.connectionId || !node.database) return;
|
||||
renameObjectError.value = "";
|
||||
try {
|
||||
const sql = buildRenameObjectSql({
|
||||
databaseType: currentDatabaseType(),
|
||||
objectType,
|
||||
schema: node.schema,
|
||||
oldName: node.label,
|
||||
newName,
|
||||
});
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
await api.executeQuery(node.connectionId, node.database, sql, node.schema);
|
||||
toast(t("contextMenu.renameObjectSuccess", { oldName: node.label, newName }), 3000);
|
||||
showRenameObjectDialog.value = false;
|
||||
await refreshTableList(node);
|
||||
} catch (e: any) {
|
||||
renameObjectError.value = e?.message || String(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmDropObject() {
|
||||
const node = props.node;
|
||||
if (!node.connectionId || !node.database) return;
|
||||
|
|
@ -1758,6 +1822,9 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr
|
|||
<ContextMenuItem v-if="canOpenStructureEditor" @click="openStructureEditor">
|
||||
<PencilRuler class="w-4 h-4" /> {{ t("contextMenu.editStructure") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem v-if="canRenameObject" @click="openRenameObjectDialog">
|
||||
<Pencil class="w-4 h-4" /> {{ t("contextMenu.renameObject") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem @click="newQuery">
|
||||
<TerminalSquare class="w-4 h-4" /> {{ t("contextMenu.newQuery") }}
|
||||
</ContextMenuItem>
|
||||
|
|
@ -1822,6 +1889,10 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr
|
|||
<Code2 class="w-4 h-4 mr-2" />
|
||||
{{ t("contextMenu.viewSource") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem v-if="canRenameObject" @click="openRenameObjectDialog">
|
||||
<Pencil class="w-4 h-4 mr-2" />
|
||||
{{ t("contextMenu.renameObject") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem class="text-destructive" @click="requestDropObject">
|
||||
<Trash2 class="w-4 h-4 mr-2" />
|
||||
|
|
@ -1953,6 +2024,36 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr
|
|||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<Dialog v-model:open="showRenameObjectDialog">
|
||||
<DialogContent class="sm:max-w-[420px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t("contextMenu.renameObjectTitle") }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div class="grid gap-3">
|
||||
<Input
|
||||
v-model="renameObjectName"
|
||||
:placeholder="t('contextMenu.renameObjectNamePlaceholder')"
|
||||
@keydown.enter.prevent="confirmRenameObject"
|
||||
/>
|
||||
<pre
|
||||
v-if="buildRenameObjectPreviewSql()"
|
||||
class="max-h-32 overflow-auto rounded bg-muted p-3 text-xs whitespace-pre-wrap"
|
||||
>{{ buildRenameObjectPreviewSql() }}</pre
|
||||
>
|
||||
<p v-if="renameObjectError" class="text-sm text-destructive">{{ renameObjectError }}</p>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="showRenameObjectDialog = false">{{ t("dangerDialog.cancel") }}</Button>
|
||||
<Button
|
||||
:disabled="!renameObjectName.trim() || renameObjectName.trim() === node.label"
|
||||
@click="confirmRenameObject"
|
||||
>
|
||||
{{ t("contextMenu.renameObject") }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<Dialog v-model:open="showDeleteSavedSqlFileConfirm">
|
||||
<DialogContent class="sm:max-w-[400px]">
|
||||
<DialogHeader>
|
||||
|
|
|
|||
|
|
@ -645,6 +645,10 @@ export default {
|
|||
emptyTable: "Empty Table",
|
||||
truncateTable: "Truncate Table",
|
||||
duplicateStructure: "Duplicate Structure",
|
||||
renameObject: "Rename",
|
||||
renameObjectTitle: "Rename Object",
|
||||
renameObjectNamePlaceholder: "New name",
|
||||
renameObjectSuccess: '"{oldName}" renamed to "{newName}"',
|
||||
confirmDropTableTitle: "Drop Table",
|
||||
confirmDropTableMessage:
|
||||
'Are you sure you want to drop "{name}"? This will permanently delete the table and all its data.',
|
||||
|
|
|
|||
|
|
@ -630,6 +630,10 @@ export default {
|
|||
emptyTable: "清空数据",
|
||||
truncateTable: "截断表",
|
||||
duplicateStructure: "复制表结构",
|
||||
renameObject: "重命名",
|
||||
renameObjectTitle: "重命名对象",
|
||||
renameObjectNamePlaceholder: "新名称",
|
||||
renameObjectSuccess: "已将「{oldName}」重命名为「{newName}」",
|
||||
confirmDropTableTitle: "删除表",
|
||||
confirmDropTableMessage: "确定要删除「{name}」吗?这将永久删除表及其所有数据。",
|
||||
confirmEmptyTableTitle: "清空数据",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
import type { DatabaseObjectType, DatabaseType } from "@/types/database";
|
||||
import { isSchemaAware } from "@/lib/databaseCapabilities";
|
||||
import { quoteTableIdentifier } from "@/lib/tableSelectSql";
|
||||
|
||||
export type RenameableObjectType = DatabaseObjectType;
|
||||
|
||||
export interface BuildRenameObjectSqlOptions {
|
||||
databaseType?: DatabaseType;
|
||||
objectType: RenameableObjectType;
|
||||
schema?: string | null;
|
||||
oldName: string;
|
||||
newName: string;
|
||||
}
|
||||
|
||||
const postgresLikeRenameTypes = new Set<DatabaseType>([
|
||||
"postgres",
|
||||
"redshift",
|
||||
"gaussdb",
|
||||
"kingbase",
|
||||
"highgo",
|
||||
"vastbase",
|
||||
]);
|
||||
|
||||
const oracleLikeRenameTypes = new Set<DatabaseType>(["oracle", "dameng"]);
|
||||
|
||||
function sqlServerString(value: string): string {
|
||||
return `N'${value.replaceAll("'", "''")}'`;
|
||||
}
|
||||
|
||||
function quoteRenameIdentifier(databaseType: DatabaseType | undefined, name: string): string {
|
||||
if (databaseType === "mysql" || databaseType === "goldendb") return `\`${name.replaceAll("`", "``")}\``;
|
||||
return quoteTableIdentifier(databaseType, name);
|
||||
}
|
||||
|
||||
function qualifiedName(databaseType: DatabaseType | undefined, schema: string | null | undefined, name: string) {
|
||||
if (isSchemaAware(databaseType) && schema) {
|
||||
return `${quoteRenameIdentifier(databaseType, schema)}.${quoteRenameIdentifier(databaseType, name)}`;
|
||||
}
|
||||
return quoteRenameIdentifier(databaseType, name);
|
||||
}
|
||||
|
||||
function sqlServerObjectName(schema: string | null | undefined, name: string) {
|
||||
return schema ? `${schema}.${name}` : name;
|
||||
}
|
||||
|
||||
export function supportsObjectRename(
|
||||
databaseType: DatabaseType | undefined,
|
||||
objectType: RenameableObjectType,
|
||||
): boolean {
|
||||
if (!databaseType) return false;
|
||||
if (databaseType === "sqlserver") return true;
|
||||
if (objectType === "PROCEDURE" || objectType === "FUNCTION") return false;
|
||||
if (databaseType === "sqlite") return objectType === "TABLE";
|
||||
if (databaseType === "mysql" || databaseType === "goldendb") return objectType === "TABLE" || objectType === "VIEW";
|
||||
if (postgresLikeRenameTypes.has(databaseType)) return objectType === "TABLE" || objectType === "VIEW";
|
||||
if (oracleLikeRenameTypes.has(databaseType)) return objectType === "TABLE" || objectType === "VIEW";
|
||||
return false;
|
||||
}
|
||||
|
||||
export function buildRenameObjectSql(options: BuildRenameObjectSqlOptions): string {
|
||||
const { databaseType, objectType, schema, oldName, newName } = options;
|
||||
if (!supportsObjectRename(databaseType, objectType)) {
|
||||
throw new Error(`Renaming ${objectType} is not supported for ${databaseType ?? "this database"}.`);
|
||||
}
|
||||
|
||||
if (databaseType === "sqlserver") {
|
||||
return `EXEC sp_rename ${sqlServerString(sqlServerObjectName(schema, oldName))}, ${sqlServerString(newName)}, N'OBJECT';`;
|
||||
}
|
||||
|
||||
if (databaseType === "mysql" || databaseType === "goldendb") {
|
||||
return `RENAME TABLE ${qualifiedName(databaseType, schema, oldName)} TO ${qualifiedName(databaseType, schema, newName)};`;
|
||||
}
|
||||
|
||||
if (databaseType === "sqlite") {
|
||||
return `ALTER TABLE ${qualifiedName(databaseType, schema, oldName)} RENAME TO ${quoteRenameIdentifier(databaseType, newName)};`;
|
||||
}
|
||||
|
||||
if (
|
||||
postgresLikeRenameTypes.has(databaseType as DatabaseType) ||
|
||||
oracleLikeRenameTypes.has(databaseType as DatabaseType)
|
||||
) {
|
||||
const keyword = objectType === "VIEW" ? "VIEW" : "TABLE";
|
||||
return `ALTER ${keyword} ${qualifiedName(databaseType, schema, oldName)} RENAME TO ${quoteRenameIdentifier(databaseType, newName)};`;
|
||||
}
|
||||
|
||||
throw new Error(`Renaming ${objectType} is not supported for ${databaseType ?? "this database"}.`);
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
import { strict as assert } from "node:assert";
|
||||
import test from "node:test";
|
||||
import { buildRenameObjectSql, supportsObjectRename } from "../src/lib/objectRenameSql.ts";
|
||||
|
||||
test("builds MySQL table and view rename statements", () => {
|
||||
assert.equal(
|
||||
buildRenameObjectSql({
|
||||
databaseType: "mysql",
|
||||
objectType: "TABLE",
|
||||
oldName: "users",
|
||||
newName: "app users",
|
||||
}),
|
||||
"RENAME TABLE `users` TO `app users`;",
|
||||
);
|
||||
assert.equal(
|
||||
buildRenameObjectSql({
|
||||
databaseType: "goldendb",
|
||||
objectType: "VIEW",
|
||||
oldName: "active_users",
|
||||
newName: "enabled_users",
|
||||
}),
|
||||
"RENAME TABLE `active_users` TO `enabled_users`;",
|
||||
);
|
||||
});
|
||||
|
||||
test("builds PostgreSQL table and view rename statements", () => {
|
||||
assert.equal(
|
||||
buildRenameObjectSql({
|
||||
databaseType: "postgres",
|
||||
objectType: "TABLE",
|
||||
schema: "public",
|
||||
oldName: "orders",
|
||||
newName: "archived orders",
|
||||
}),
|
||||
'ALTER TABLE "public"."orders" RENAME TO "archived orders";',
|
||||
);
|
||||
assert.equal(
|
||||
buildRenameObjectSql({
|
||||
databaseType: "postgres",
|
||||
objectType: "VIEW",
|
||||
schema: "public",
|
||||
oldName: "active_users",
|
||||
newName: "enabled_users",
|
||||
}),
|
||||
'ALTER VIEW "public"."active_users" RENAME TO "enabled_users";',
|
||||
);
|
||||
});
|
||||
|
||||
test("builds SQL Server rename statements for all object kinds", () => {
|
||||
assert.equal(
|
||||
buildRenameObjectSql({
|
||||
databaseType: "sqlserver",
|
||||
objectType: "FUNCTION",
|
||||
schema: "dbo",
|
||||
oldName: "fn_total",
|
||||
newName: "fn_order_total",
|
||||
}),
|
||||
"EXEC sp_rename N'dbo.fn_total', N'fn_order_total', N'OBJECT';",
|
||||
);
|
||||
assert.equal(supportsObjectRename("sqlserver", "PROCEDURE"), true);
|
||||
});
|
||||
|
||||
test("builds Oracle-family table and view rename statements", () => {
|
||||
assert.equal(
|
||||
buildRenameObjectSql({
|
||||
databaseType: "oracle",
|
||||
objectType: "TABLE",
|
||||
schema: "HR",
|
||||
oldName: "EMPLOYEES",
|
||||
newName: "STAFF",
|
||||
}),
|
||||
'ALTER TABLE "HR"."EMPLOYEES" RENAME TO "STAFF";',
|
||||
);
|
||||
assert.equal(
|
||||
buildRenameObjectSql({
|
||||
databaseType: "dameng",
|
||||
objectType: "VIEW",
|
||||
schema: "SYSDBA",
|
||||
oldName: "ACTIVE_USERS",
|
||||
newName: "ENABLED_USERS",
|
||||
}),
|
||||
'ALTER VIEW "SYSDBA"."ACTIVE_USERS" RENAME TO "ENABLED_USERS";',
|
||||
);
|
||||
});
|
||||
|
||||
test("reports unsupported routine rename cases", () => {
|
||||
assert.equal(supportsObjectRename("mysql", "PROCEDURE"), false);
|
||||
assert.equal(supportsObjectRename("postgres", "FUNCTION"), false);
|
||||
assert.throws(
|
||||
() =>
|
||||
buildRenameObjectSql({
|
||||
databaseType: "mysql",
|
||||
objectType: "PROCEDURE",
|
||||
oldName: "refresh_cache",
|
||||
newName: "refresh_cache_v2",
|
||||
}),
|
||||
/Renaming PROCEDURE is not supported/,
|
||||
);
|
||||
});
|
||||
Loading…
Reference in New Issue