console: fix console crash on adding pg sources with connection params

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4485
GitOrigin-RevId: 00230fd2563fae9dcbdc03af5927dfeb1a82b965
This commit is contained in:
Abhijeet Khangarot 2022-05-12 17:44:40 +05:30 committed by hasura-bot
parent 43622f3011
commit 936ee990c2
9 changed files with 130 additions and 14 deletions

View File

@ -20,6 +20,7 @@
- console: bug fixes for RS-to-RS relationships
- console: allow users to remove prefix / suffix / root field namespace from a remote schema
- console: new "add remote schema" page (with GQL customization)
- console: fix console crash on adding pg sources with connection params through api
- cli: avoid exporting hasura-specific schemas during hasura init (#8352)
- cli: fix performance regression in `migrate status` command (fix #8398)

View File

@ -24,6 +24,7 @@ import {
ExtendedConnectDBState,
} from './state';
import {
getDatasourceConnectionParams,
getDatasourceURL,
getErrorMessageFromMissingFields,
getReadReplicaDBUrlInfo,
@ -84,8 +85,10 @@ const ConnectDatabase: React.FC<ConnectDatabaseProps> = props => {
name: currentSourceInfo.name,
driver: currentSourceInfo.kind ?? 'postgres',
databaseUrl: getDatasourceURL(
currentSourceInfo.kind,
databaseUrl ?? connectionInfo?.connection_string
),
connectionParamState: getDatasourceConnectionParams(databaseUrl),
connectionSettings: connectionInfo?.pool_settings,
preparedStatements: connectionInfo?.use_prepared_statements ?? false,
isolationLevel: connectionInfo?.isolation_level ?? 'read-committed',
@ -147,7 +150,12 @@ const ConnectDatabase: React.FC<ConnectDatabaseProps> = props => {
});
}
if (typeof databaseUrl !== 'string' && databaseUrl?.from_env) {
if (
databaseUrl &&
typeof databaseUrl !== 'string' &&
'from_env' in databaseUrl &&
databaseUrl?.from_env
) {
changeConnectionType(connectionTypes.ENV_VAR);
connectDBDispatch({
type: 'UPDATE_DB_URL_ENV_VAR',

View File

@ -44,16 +44,18 @@ export type ConnectDBState = {
preparedStatements?: boolean;
};
const defaultConnectionParamState = {
host: '',
port: '',
username: '',
password: '',
database: '',
};
export const defaultState: ConnectDBState = {
displayName: '',
dbType: 'postgres',
connectionParamState: {
host: '',
port: '',
username: '',
password: '',
database: '',
},
connectionParamState: defaultConnectionParamState,
databaseURLState: {
dbURL: '',
serviceAccount: '',
@ -124,6 +126,7 @@ export const connectDataSource = (
isRenameSource = false,
currentName = ''
) => {
let connectionParams: ConnectionParams | undefined;
let databaseURL: string | { from_env: string } =
currentState.dbType === 'bigquery'
? currentState.databaseURLState.serviceAccount.trim()
@ -142,6 +145,9 @@ export const connectDataSource = (
currentState.dbType
)
) {
if (currentState.dbType === 'postgres' || currentState.dbType === 'citus') {
connectionParams = currentState.connectionParamState;
}
databaseURL = makeConnectionStringFromConnectionParams({
dbType: currentState.dbType,
...currentState.connectionParamState,
@ -153,6 +159,12 @@ export const connectDataSource = (
payload: {
name: currentState.displayName.trim(),
dbUrl: databaseURL,
connection_parameters: connectionParams
? {
...connectionParams,
port: Number(connectionParams?.port),
}
: undefined,
replace_configuration: isEditState,
bigQuery: {
projectId: currentState.databaseURLState.projectId,
@ -190,6 +202,7 @@ export type ConnectDBActions =
name: string;
driver: Driver;
databaseUrl: string;
connectionParamState?: ConnectionParams;
connectionSettings?: ConnectionPoolSettings;
preparedStatements: boolean;
isolationLevel: IsolationLevelOptions;
@ -239,6 +252,8 @@ export const connectDBReducer = (
...state.databaseURLState,
dbURL: action.data.databaseUrl,
},
connectionParamState:
action.data.connectionParamState || defaultConnectionParamState,
connectionSettings: action.data.connectionSettings,
preparedStatements: action.data.preparedStatements,
isolationLevel: action.data.isolationLevel,

View File

@ -1,11 +1,14 @@
import { Driver } from '@/dataSources';
import { addSource } from './../../../../metadata/sourcesUtils';
import { isObject, isEqual } from './../../../Common/utils/jsUtils';
import { Table } from '../../../../dataSources/types';
import {
ConnectionParams,
MetadataDataSource,
SourceConnectionInfo,
} from '../../../../metadata/types';
import { connectionTypes } from './state';
import { makeConnectionStringFromConnectionParams } from './ManageDBUtils';
export const getErrorMessageFromMissingFields = (
host: string,
@ -33,7 +36,12 @@ export const getErrorMessageFromMissingFields = (
};
export const getDatasourceURL = (
link: string | { from_env: string } | undefined
kind: Driver,
link:
| string
| { from_env: string }
| { connection_parameters: ConnectionParams }
| undefined
) => {
if (!link) {
return '';
@ -41,9 +49,38 @@ export const getDatasourceURL = (
if (typeof link === 'string') {
return link.toString();
}
if ('connection_parameters' in link) {
return makeConnectionStringFromConnectionParams({
dbType: kind,
host: link.connection_parameters.host,
port: link.connection_parameters.port.toString(),
username: link.connection_parameters.username,
database: link.connection_parameters.database,
password: link.connection_parameters.password,
});
}
return link.from_env.toString();
};
export const getDatasourceConnectionParams = (
link:
| string
| { from_env: string }
| { connection_parameters: ConnectionParams }
| undefined
) => {
if (link && typeof link !== 'string' && 'connection_parameters' in link) {
return {
host: link.connection_parameters.host,
port: link.connection_parameters.port.toString(),
username: link.connection_parameters.username,
database: link.connection_parameters.database,
password: link.connection_parameters.password ?? '',
};
}
return undefined;
};
export function parsePgUrl(
url: string
): Partial<Omit<URL, 'searchParams' | 'toJSON'>> {
@ -160,7 +197,10 @@ export const getReadReplicaDBUrlInfo = (
return {
connectionType: connectionTypes.ENV_VAR,
envVarState: {
envVar: replica?.database_url?.from_env ?? '',
envVar:
replica?.database_url && 'from_env' in replica?.database_url
? replica?.database_url?.from_env
: '',
},
};
}

View File

@ -2,6 +2,7 @@ import { MetadataResponse } from '@/features/MetadataAPI';
import requestAction from '../utils/requestAction';
import Endpoints, { globalCookiePolicy } from '../Endpoints';
import {
ConnectionParams,
ConnectionPoolSettings,
HasuraMetadataV2,
HasuraMetadataV3,
@ -141,6 +142,7 @@ export interface AddDataSourceRequest {
datasets: string;
global_select_limit: number;
};
connection_parameters?: ConnectionParams;
sslConfiguration?: SSLConfigOptions;
preparedStatements?: boolean;
isolationLevel?: IsolationLevelOptions;

View File

@ -6,6 +6,7 @@ import { filterInconsistentMetadataObjects } from '../components/Services/Settin
import { parseCustomTypes } from '../shared/utils/hasuraCustomTypeUtils';
import { Driver, drivers } from '../dataSources';
import { EventTrigger } from '../components/Services/Events/types';
import { getDatabaseUrlFromSource } from './utils';
export const getDataSourceMetadata = (state: ReduxState) => {
const currentDataSource = state.tables?.currentDataSource;
@ -372,7 +373,10 @@ export const getDataSources = createSelector(getMetadata, metadata => {
} else {
url = source.configuration?.connection_info?.connection_string
? source.configuration?.connection_info.connection_string
: source.configuration?.connection_info?.database_url || '';
: getDatabaseUrlFromSource(
source.kind,
source.configuration?.connection_info?.database_url
);
}
sources.push({
name: source.name,

View File

@ -1,5 +1,6 @@
import { Driver, sourceNames } from '../dataSources';
import {
ConnectionParams,
ConnectionPoolSettings,
IsolationLevelOptions,
SourceConnectionInfo,
@ -11,6 +12,7 @@ export const addSource = (
payload: {
name: string;
dbUrl: string | { from_env: string };
connection_parameters?: ConnectionParams;
connection_pool_settings?: ConnectionPoolSettings;
replace_configuration?: boolean;
bigQuery: {
@ -75,7 +77,9 @@ export const addSource = (
name: payload.name,
configuration: {
connection_info: {
database_url: payload.dbUrl,
database_url: payload.connection_parameters
? { connection_parameters: payload.connection_parameters }
: payload.dbUrl,
use_prepared_statements: payload.preparedStatements,
isolation_level: payload.isolationLevel,
pool_settings: payload.connection_pool_settings,

View File

@ -1022,11 +1022,22 @@ export interface ConnectionPoolSettings {
connection_lifetime?: number;
}
export type ConnectionParams = {
username: string;
password?: string;
database: string;
host: string;
port: number;
};
export interface SourceConnectionInfo {
// used for SQL Server
connection_string?: string | { from_env: string };
// used for Postgres
database_url?: string | { from_env: string };
database_url?:
| string
| { from_env: string }
| { connection_parameters: ConnectionParams };
use_prepared_statements?: boolean;
isolation_level?: IsolationLevelOptions;
pool_settings?: ConnectionPoolSettings;

View File

@ -1,10 +1,17 @@
import { makeConnectionStringFromConnectionParams } from '@/components/Services/Data/DataSources/ManageDBUtils';
import { Driver } from '@/dataSources';
import { Nullable } from './../components/Common/utils/tsUtils';
import {
inconsistentObjectsQuery,
getReloadMetadataQuery,
getReloadRemoteSchemaCacheQuery,
} from './queryUtils';
import { AllowList, QueryCollectionEntry, HasuraMetadataV3 } from './types';
import {
AllowList,
QueryCollectionEntry,
HasuraMetadataV3,
ConnectionParams,
} from './types';
import { AllowedQueriesCollection } from './reducer';
export const allowedQueriesCollection = 'allowed-queries';
@ -395,3 +402,27 @@ export const getRemoteSchemaNameFromInconsistentObjects = (
}
return rsNameList;
}, []);
export const getDatabaseUrlFromSource = (
kind: Driver,
dbUrl:
| string
| { from_env: string }
| {
connection_parameters: ConnectionParams;
}
| undefined
) => {
if (!dbUrl) return '';
if (typeof dbUrl !== 'string' && 'connection_parameters' in dbUrl) {
return makeConnectionStringFromConnectionParams({
dbType: kind,
host: dbUrl.connection_parameters.host,
port: dbUrl.connection_parameters.port.toString(),
username: dbUrl.connection_parameters.username,
database: dbUrl.connection_parameters.database,
password: dbUrl.connection_parameters.password,
});
}
return dbUrl;
};