mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-05-31 13:11:45 +08:00
✨ feat(postgres): 新增数据库节点新建模式功能
- 后端新增 CreateSchema 接口,支持在选中 PostgreSQL 数据库下创建 schema - 侧边栏旧版菜单和新版菜单均增加新建模式入口 - 创建成功后刷新对象树,并支持空模式显示 - 补充 Wails 绑定与创建模式相关测试 Refs #480
This commit is contained in:
@@ -114,6 +114,7 @@ vi.mock('../../wailsjs/go/app/App', () => ({
|
||||
ExecuteSQLFile: mocks.noop,
|
||||
CancelSQLFileExecution: mocks.noop,
|
||||
CreateDatabase: mocks.noop,
|
||||
CreateSchema: mocks.noop,
|
||||
RenameDatabase: mocks.noop,
|
||||
DropDatabase: mocks.noop,
|
||||
RenameTable: mocks.noop,
|
||||
@@ -651,6 +652,18 @@ describe('Sidebar locate toolbar', () => {
|
||||
expect(markup).toContain('删除数据库 · DROP');
|
||||
});
|
||||
|
||||
it('renders the v2 database schema action for PostgreSQL-compatible databases', () => {
|
||||
const markup = renderToStaticMarkup(
|
||||
<V2DatabaseContextMenuView
|
||||
dbName="app_db"
|
||||
dialect="postgres"
|
||||
supportsSchemaActions
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(markup).toContain('新建模式');
|
||||
});
|
||||
|
||||
it('renders the v2 connection context menu for host rail actions', () => {
|
||||
const markup = renderToStaticMarkup(
|
||||
<V2ConnectionContextMenuView
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Tree, message, Dropdown, MenuProps, Input, Button, Modal, Form, Badge,
|
||||
FileTextOutlined,
|
||||
CopyOutlined,
|
||||
ExportOutlined,
|
||||
FolderAddOutlined,
|
||||
SaveOutlined,
|
||||
EditOutlined,
|
||||
DownOutlined,
|
||||
@@ -46,7 +47,7 @@ import { buildSidebarTablePinKey, useStore } from '../store';
|
||||
import { buildOverlayWorkbenchTheme } from '../utils/overlayWorkbenchTheme';
|
||||
import { SavedConnection, ConnectionTag, ExternalSQLTreeEntry, JVMCapability, JVMResourceSummary } from '../types';
|
||||
import { getDbIcon } from './DatabaseIcons';
|
||||
import { DBGetDatabases, DBGetTables, DBQuery, DBShowCreateTable, ExportTable, OpenSQLFile, ExecuteSQLFile, CancelSQLFileExecution, CreateDatabase, RenameDatabase, DropDatabase, RenameTable, DropTable, DropView, DropFunction, RenameView, SelectSQLDirectory, ListSQLDirectory, ReadSQLFile, JVMProbeCapabilities, GetDriverStatusList } from '../../wailsjs/go/app/App';
|
||||
import { DBGetDatabases, DBGetTables, DBQuery, DBShowCreateTable, ExportTable, OpenSQLFile, ExecuteSQLFile, CancelSQLFileExecution, CreateDatabase, CreateSchema, RenameDatabase, DropDatabase, RenameTable, DropTable, DropView, DropFunction, RenameView, SelectSQLDirectory, ListSQLDirectory, ReadSQLFile, JVMProbeCapabilities, GetDriverStatusList } from '../../wailsjs/go/app/App';
|
||||
import { getTableDataDangerActionMeta, supportsTableTruncateAction, type TableDataDangerActionKind } from './tableDataDangerActions';
|
||||
import { EventsOn } from '../../wailsjs/runtime/runtime';
|
||||
import { isMacLikePlatform, normalizeOpacityForPlatform, resolveAppearanceValues } from '../utils/appearance';
|
||||
@@ -466,7 +467,7 @@ const DRIVER_STATUS_CACHE_TTL_MS = 30_000;
|
||||
|
||||
const normalizeDriverType = (value: string): string => {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === 'postgresql') return 'postgres';
|
||||
if (normalized === 'postgresql' || normalized === 'pg' || normalized === 'pq' || normalized === 'pgx') return 'postgres';
|
||||
if (normalized === 'doris') return 'diros';
|
||||
if (
|
||||
normalized === 'open_gauss' ||
|
||||
@@ -490,6 +491,10 @@ const resolveSavedConnectionDriverType = (conn: SavedConnection | undefined): st
|
||||
return normalizeDriverType(conn?.config?.driver || '');
|
||||
};
|
||||
|
||||
const isPostgresSchemaDialect = (dialect: string): boolean => (
|
||||
['postgres', 'kingbase', 'highgo', 'vastbase', 'opengauss'].includes(normalizeDriverType(dialect))
|
||||
);
|
||||
|
||||
const SEARCH_SCOPE_OPTIONS: Array<{ value: SearchScope; label: string }> = [
|
||||
{ value: 'smart', label: '智能' },
|
||||
{ value: 'object', label: '表对象' },
|
||||
@@ -748,6 +753,9 @@ const Sidebar: React.FC<{
|
||||
const [isCreateDbModalOpen, setIsCreateDbModalOpen] = useState(false);
|
||||
const [createDbForm] = Form.useForm();
|
||||
const [targetConnection, setTargetConnection] = useState<any>(null);
|
||||
const [isCreateSchemaModalOpen, setIsCreateSchemaModalOpen] = useState(false);
|
||||
const [createSchemaForm] = Form.useForm();
|
||||
const [createSchemaTarget, setCreateSchemaTarget] = useState<any>(null);
|
||||
const [isRenameDbModalOpen, setIsRenameDbModalOpen] = useState(false);
|
||||
const [renameDbForm] = Form.useForm();
|
||||
const [renameDbTarget, setRenameDbTarget] = useState<any>(null);
|
||||
@@ -1109,12 +1117,11 @@ const Sidebar: React.FC<{
|
||||
};
|
||||
|
||||
const getMetadataDialect = (conn: SavedConnection | undefined): string => {
|
||||
const type = String(conn?.config?.type || '').trim().toLowerCase();
|
||||
const type = normalizeDriverType(String(conn?.config?.type || '').trim());
|
||||
if (type === 'custom') {
|
||||
const driver = String(conn?.config?.driver || '').trim().toLowerCase();
|
||||
const driver = normalizeDriverType(String(conn?.config?.driver || '').trim());
|
||||
if (driver === 'diros' || driver === 'doris') return 'mysql';
|
||||
if (driver === 'oceanbase') return normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle' ? 'oracle' : 'mysql';
|
||||
if (driver === 'opengauss' || driver === 'open_gauss' || driver === 'open-gauss') return 'opengauss';
|
||||
return driver;
|
||||
}
|
||||
if (type === 'oceanbase' && normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle') return 'oracle';
|
||||
@@ -1419,6 +1426,15 @@ const Sidebar: React.FC<{
|
||||
}
|
||||
};
|
||||
|
||||
const buildSchemasMetadataQuerySpecs = (dialect: string): MetadataQuerySpec[] => {
|
||||
if (!isPostgresSchemaDialect(dialect)) {
|
||||
return [];
|
||||
}
|
||||
return [{
|
||||
sql: `SELECT nspname AS schema_name FROM pg_namespace WHERE nspname NOT IN ('pg_catalog', 'information_schema') AND nspname NOT LIKE 'pg|_%' ESCAPE '|' ORDER BY nspname`,
|
||||
}];
|
||||
};
|
||||
|
||||
const queryMetadataRowsBySpecs = async (
|
||||
conn: any,
|
||||
dbName: string,
|
||||
@@ -1586,7 +1602,28 @@ const Sidebar: React.FC<{
|
||||
});
|
||||
});
|
||||
return { routines, supported: hasSuccessfulQuery };
|
||||
};
|
||||
};
|
||||
|
||||
const loadSchemas = async (conn: any, dbName: string): Promise<{ schemas: string[]; supported: boolean }> => {
|
||||
const dialect = getMetadataDialect(conn as SavedConnection);
|
||||
const querySpecs = buildSchemasMetadataQuerySpecs(dialect);
|
||||
const { results, hasSuccessfulQuery } = await queryMetadataRowsBySpecs(conn, dbName, querySpecs);
|
||||
const seen = new Set<string>();
|
||||
const schemas: string[] = [];
|
||||
|
||||
results.forEach((queryResult) => {
|
||||
queryResult.rows.forEach((row) => {
|
||||
const schemaName = getCaseInsensitiveValue(row, ['schema_name', 'nspname', 'schemaname']) || getFirstRowValue(row);
|
||||
if (!schemaName) return;
|
||||
const key = schemaName.toLowerCase();
|
||||
if (seen.has(key)) return;
|
||||
seen.add(key);
|
||||
schemas.push(schemaName);
|
||||
});
|
||||
});
|
||||
|
||||
return { schemas, supported: hasSuccessfulQuery };
|
||||
};
|
||||
|
||||
const fetchDriverStatusMap = async (): Promise<Record<string, DriverStatusSnapshot>> => {
|
||||
const cached = driverStatusCacheRef.current;
|
||||
@@ -1894,7 +1931,8 @@ const Sidebar: React.FC<{
|
||||
};
|
||||
});
|
||||
|
||||
const [viewsResult, materializedViewsResult, triggersResult, routinesResult] = await Promise.all([
|
||||
const [schemasResult, viewsResult, materializedViewsResult, triggersResult, routinesResult] = await Promise.all([
|
||||
loadSchemas(conn, conn.dbName),
|
||||
loadViews(conn, conn.dbName),
|
||||
loadStarRocksMaterializedViews(conn, conn.dbName),
|
||||
loadDatabaseTriggers(conn, conn.dbName),
|
||||
@@ -1932,6 +1970,7 @@ const Sidebar: React.FC<{
|
||||
const materializedViewRows: string[] = Array.isArray(materializedViewsResult.views) ? materializedViewsResult.views : [];
|
||||
const triggerRows: any[] = Array.isArray(triggersResult.triggers) ? triggersResult.triggers : [];
|
||||
const routineRows: any[] = Array.isArray(routinesResult.routines) ? routinesResult.routines : [];
|
||||
const schemaRows: string[] = Array.isArray(schemasResult.schemas) ? schemasResult.schemas : [];
|
||||
|
||||
const viewEntries = viewRows.map((viewName: string) => {
|
||||
const parsed = splitQualifiedName(viewName);
|
||||
@@ -2127,6 +2166,7 @@ const Sidebar: React.FC<{
|
||||
return bucket;
|
||||
};
|
||||
|
||||
schemaRows.forEach((schemaName) => getSchemaBucket(schemaName));
|
||||
sortedTableEntries.forEach((entry) => getSchemaBucket(entry.schemaName).tables.push(buildTableNode(entry)));
|
||||
viewEntries.forEach((entry) => getSchemaBucket(entry.schemaName).views.push(buildViewNode(entry)));
|
||||
materializedViewEntries.forEach((entry) => getSchemaBucket(entry.schemaName).materializedViews.push(buildMaterializedViewNode(entry)));
|
||||
@@ -3416,6 +3456,43 @@ const Sidebar: React.FC<{
|
||||
}
|
||||
};
|
||||
|
||||
const openCreateSchemaModal = (node: any) => {
|
||||
const dialect = getMetadataDialect(node?.dataRef as SavedConnection);
|
||||
if (!isPostgresSchemaDialect(dialect)) {
|
||||
message.warning('当前数据源暂不支持通过此入口新建模式');
|
||||
return;
|
||||
}
|
||||
setCreateSchemaTarget(node);
|
||||
createSchemaForm.resetFields();
|
||||
setIsCreateSchemaModalOpen(true);
|
||||
};
|
||||
|
||||
const handleCreateSchema = async () => {
|
||||
try {
|
||||
const values = await createSchemaForm.validateFields();
|
||||
const node = createSchemaTarget;
|
||||
const conn = node?.dataRef;
|
||||
const dbName = String(conn?.dbName || node?.title || '').trim();
|
||||
if (!conn || !dbName) {
|
||||
message.error('未找到目标数据库,无法新建模式');
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await CreateSchema(buildRpcConnectionConfig(conn.config, { database: dbName }) as any, dbName, values.name);
|
||||
if (res.success) {
|
||||
message.success('模式创建成功');
|
||||
setIsCreateSchemaModalOpen(false);
|
||||
setCreateSchemaTarget(null);
|
||||
createSchemaForm.resetFields();
|
||||
await loadTables(node);
|
||||
} else {
|
||||
message.error('创建失败: ' + res.message);
|
||||
}
|
||||
} catch (e) {
|
||||
// Validate failed
|
||||
}
|
||||
};
|
||||
|
||||
const buildRuntimeConfig = (conn: any, overrideDatabase?: string, clearDatabase: boolean = false) => {
|
||||
return buildRpcConnectionConfig(conn.config, {
|
||||
database: resolveSidebarRuntimeDatabase(
|
||||
@@ -4242,6 +4319,9 @@ const Sidebar: React.FC<{
|
||||
case 'new-table':
|
||||
openNewTableDesign(node);
|
||||
return;
|
||||
case 'new-schema':
|
||||
openCreateSchemaModal(node);
|
||||
return;
|
||||
case 'new-materialized-view':
|
||||
openCreateStarRocksMaterializedView(node);
|
||||
return;
|
||||
@@ -5162,6 +5242,7 @@ const Sidebar: React.FC<{
|
||||
<V2DatabaseContextMenuView
|
||||
dbName={String(node.dataRef?.dbName || node.title || '')}
|
||||
dialect={dialect}
|
||||
supportsSchemaActions={isPostgresSchemaDialect(dialect)}
|
||||
supportsStarRocksActions={dialect === 'starrocks'}
|
||||
onAction={(action) => {
|
||||
setContextMenu(null);
|
||||
@@ -5904,6 +5985,7 @@ const Sidebar: React.FC<{
|
||||
];
|
||||
} else if (node.type === 'database') {
|
||||
const isStarRocks = getMetadataDialect(node.dataRef as SavedConnection) === 'starrocks';
|
||||
const supportsSchemaActions = isPostgresSchemaDialect(getMetadataDialect(node.dataRef as SavedConnection));
|
||||
return [
|
||||
{
|
||||
key: 'new-table',
|
||||
@@ -5911,6 +5993,14 @@ const Sidebar: React.FC<{
|
||||
icon: <TableOutlined />,
|
||||
onClick: () => openNewTableDesign(node)
|
||||
},
|
||||
...(supportsSchemaActions ? [
|
||||
{
|
||||
key: 'new-schema',
|
||||
label: '新建模式',
|
||||
icon: <FolderAddOutlined />,
|
||||
onClick: () => handleV2DatabaseContextMenuAction(node, 'new-schema')
|
||||
},
|
||||
] : []),
|
||||
...(isStarRocks ? [
|
||||
{
|
||||
key: 'new-materialized-view',
|
||||
@@ -7032,6 +7122,23 @@ const Sidebar: React.FC<{
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title={`新建模式${createSchemaTarget?.dataRef?.dbName ? ` (${createSchemaTarget.dataRef.dbName})` : ''}`}
|
||||
open={isCreateSchemaModalOpen}
|
||||
onOk={handleCreateSchema}
|
||||
onCancel={() => {
|
||||
setIsCreateSchemaModalOpen(false);
|
||||
setCreateSchemaTarget(null);
|
||||
createSchemaForm.resetFields();
|
||||
}}
|
||||
>
|
||||
<Form form={createSchemaForm} layout="vertical">
|
||||
<Form.Item name="name" label="模式名称" rules={[{ required: true, message: '请输入模式名称' }]}>
|
||||
<Input {...noAutoCapInputProps} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title={`重命名数据库${renameDbTarget?.dataRef?.dbName ? ` (${renameDbTarget.dataRef.dbName})` : ''}`}
|
||||
open={isRenameDbModalOpen}
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
ClearOutlined,
|
||||
DashboardOutlined,
|
||||
FileTextOutlined,
|
||||
FolderAddOutlined,
|
||||
HddOutlined,
|
||||
PushpinOutlined,
|
||||
VerticalAlignBottomOutlined,
|
||||
@@ -282,6 +283,7 @@ export const V2TableGroupContextMenuView: React.FC<{
|
||||
|
||||
export type V2DatabaseContextMenuActionKey =
|
||||
| 'new-table'
|
||||
| 'new-schema'
|
||||
| 'new-materialized-view'
|
||||
| 'new-external-catalog'
|
||||
| 'rename-db'
|
||||
@@ -296,11 +298,13 @@ export type V2DatabaseContextMenuActionKey =
|
||||
export const V2DatabaseContextMenuView: React.FC<{
|
||||
dbName: string;
|
||||
dialect?: string;
|
||||
supportsSchemaActions?: boolean;
|
||||
supportsStarRocksActions?: boolean;
|
||||
onAction?: (action: V2DatabaseContextMenuActionKey) => void;
|
||||
}> = ({
|
||||
dbName,
|
||||
dialect,
|
||||
supportsSchemaActions = false,
|
||||
supportsStarRocksActions = false,
|
||||
onAction,
|
||||
}) => {
|
||||
@@ -321,6 +325,7 @@ export const V2DatabaseContextMenuView: React.FC<{
|
||||
<div className="gn-v2-context-menu-body">
|
||||
{renderItems([
|
||||
{ action: 'new-table', icon: <TableOutlined />, title: '新建表', kbd: '⌘N', featured: true },
|
||||
...(supportsSchemaActions ? [{ action: 'new-schema', icon: <FolderAddOutlined />, title: '新建模式' }] : []),
|
||||
{ action: 'new-query', icon: <ConsoleSqlOutlined />, title: '新建查询' },
|
||||
{ action: 'run-sql', icon: <FileAddOutlined />, title: '运行外部 SQL 文件' },
|
||||
])}
|
||||
|
||||
2
frontend/wailsjs/go/app/App.d.ts
vendored
2
frontend/wailsjs/go/app/App.d.ts
vendored
@@ -28,6 +28,8 @@ export function ConfigureGlobalProxy(arg1:boolean,arg2:connection.ProxyConfig):P
|
||||
|
||||
export function CreateDatabase(arg1:connection.ConnectionConfig,arg2:string):Promise<connection.QueryResult>;
|
||||
|
||||
export function CreateSchema(arg1:connection.ConnectionConfig,arg2:string,arg3:string):Promise<connection.QueryResult>;
|
||||
|
||||
export function DBConnect(arg1:connection.ConnectionConfig):Promise<connection.QueryResult>;
|
||||
|
||||
export function DBGetAllColumns(arg1:connection.ConnectionConfig,arg2:string):Promise<connection.QueryResult>;
|
||||
|
||||
@@ -46,6 +46,10 @@ export function CreateDatabase(arg1, arg2) {
|
||||
return window['go']['app']['App']['CreateDatabase'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function CreateSchema(arg1, arg2, arg3) {
|
||||
return window['go']['app']['App']['CreateSchema'](arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
export function DBConnect(arg1) {
|
||||
return window['go']['app']['App']['DBConnect'](arg1);
|
||||
}
|
||||
|
||||
@@ -149,6 +149,56 @@ func (a *App) CreateDatabase(config connection.ConnectionConfig, dbName string)
|
||||
return connection.QueryResult{Success: true, Message: "数据库创建成功"}
|
||||
}
|
||||
|
||||
func isPostgresSchemaDDLDBType(dbType string) bool {
|
||||
switch resolveDDLDBType(connection.ConnectionConfig{Type: dbType}) {
|
||||
case "postgres", "kingbase", "highgo", "vastbase", "opengauss":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func buildCreateSchemaSQL(dbType string, schemaName string) (string, error) {
|
||||
schemaName = strings.TrimSpace(schemaName)
|
||||
if schemaName == "" {
|
||||
return "", fmt.Errorf("模式名称不能为空")
|
||||
}
|
||||
|
||||
if !isPostgresSchemaDDLDBType(dbType) {
|
||||
return "", fmt.Errorf("当前数据源(%s)暂不支持通过此入口新建模式", dbType)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("CREATE SCHEMA %s", quoteIdentByType(dbType, schemaName)), nil
|
||||
}
|
||||
|
||||
func (a *App) CreateSchema(config connection.ConnectionConfig, dbName string, schemaName string) connection.QueryResult {
|
||||
dbType := resolveDDLDBType(config)
|
||||
targetDbName := strings.TrimSpace(dbName)
|
||||
if targetDbName == "" {
|
||||
targetDbName = strings.TrimSpace(config.Database)
|
||||
}
|
||||
if targetDbName == "" {
|
||||
return connection.QueryResult{Success: false, Message: "目标数据库不能为空"}
|
||||
}
|
||||
|
||||
query, err := buildCreateSchemaSQL(dbType, schemaName)
|
||||
if err != nil {
|
||||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||||
}
|
||||
|
||||
runConfig := buildRunConfigForDDL(config, dbType, targetDbName)
|
||||
dbInst, err := a.getDatabase(runConfig)
|
||||
if err != nil {
|
||||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||||
}
|
||||
|
||||
if _, err := dbInst.Exec(query); err != nil {
|
||||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||||
}
|
||||
|
||||
return connection.QueryResult{Success: true, Message: "模式创建成功"}
|
||||
}
|
||||
|
||||
func resolveDDLDBType(config connection.ConnectionConfig) string {
|
||||
dbType := strings.ToLower(strings.TrimSpace(config.Type))
|
||||
if dbType == "doris" {
|
||||
|
||||
@@ -115,3 +115,58 @@ func TestCreateDatabase_SQLServerUsesBracketIdentifiers(t *testing.T) {
|
||||
t.Fatalf("unexpected SQL Server create database SQL, want %q got %q", want, fakeDB.execQueries[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCreateSchemaSQL_PostgresQuotesSchemaName(t *testing.T) {
|
||||
got, err := buildCreateSchemaSQL("postgresql", `sales"Ops`)
|
||||
if err != nil {
|
||||
t.Fatalf("expected postgres create schema SQL, got error: %v", err)
|
||||
}
|
||||
const want = `CREATE SCHEMA "sales""Ops"`
|
||||
if got != want {
|
||||
t.Fatalf("unexpected create schema SQL, want %q got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCreateSchemaSQL_RejectsUnsupportedDatabaseType(t *testing.T) {
|
||||
if _, err := buildCreateSchemaSQL("mysql", "sales"); err == nil {
|
||||
t.Fatalf("expected unsupported database type error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateSchema_CustomPostgresUsesSelectedDatabase(t *testing.T) {
|
||||
originalNewDatabaseFunc := newDatabaseFunc
|
||||
originalResolveDialConfigWithProxyFunc := resolveDialConfigWithProxyFunc
|
||||
t.Cleanup(func() {
|
||||
newDatabaseFunc = originalNewDatabaseFunc
|
||||
resolveDialConfigWithProxyFunc = originalResolveDialConfigWithProxyFunc
|
||||
})
|
||||
|
||||
fakeDB := &fakeCreateDatabaseDB{}
|
||||
newDatabaseFunc = func(dbType string) (db.Database, error) {
|
||||
return fakeDB, nil
|
||||
}
|
||||
resolveDialConfigWithProxyFunc = func(raw connection.ConnectionConfig) (connection.ConnectionConfig, error) {
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
app := NewAppWithSecretStore(secretstore.NewUnavailableStore("test"))
|
||||
result := app.CreateSchema(connection.ConnectionConfig{
|
||||
Type: "custom",
|
||||
Driver: "pgx",
|
||||
Database: "postgres",
|
||||
}, "tenant_db", `tenant"schema`)
|
||||
|
||||
if !result.Success {
|
||||
t.Fatalf("expected create schema success, got failure: %s", result.Message)
|
||||
}
|
||||
if fakeDB.connectConfig.Database != "tenant_db" {
|
||||
t.Fatalf("expected create schema connection to use selected database tenant_db, got %q", fakeDB.connectConfig.Database)
|
||||
}
|
||||
if len(fakeDB.execQueries) != 1 {
|
||||
t.Fatalf("expected one create schema statement, got %d: %#v", len(fakeDB.execQueries), fakeDB.execQueries)
|
||||
}
|
||||
const want = `CREATE SCHEMA "tenant""schema"`
|
||||
if fakeDB.execQueries[0] != want {
|
||||
t.Fatalf("unexpected create schema SQL, want %q got %q", want, fakeDB.execQueries[0])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user