mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 08:02:15 +03:00
console: add new connection params to connect database form
GitOrigin-RevId: 073d30e50a196e265cd8dfb7cfb3c9af00c3fc0e
This commit is contained in:
parent
3bcf758e14
commit
d0a66e5172
@ -6,6 +6,8 @@
|
||||
### Bug fixes and improvements
|
||||
(Add entries below in the order of server, console, cli, docs, others)
|
||||
|
||||
- console: add `pool_timeout`, `connection_lifetime` and `isolation_level` connection params to connect database form
|
||||
|
||||
## v2.0.0-alpha.11
|
||||
|
||||
### Breaking Changes
|
||||
|
@ -1,15 +1,18 @@
|
||||
import React, { InputHTMLAttributes } from 'react';
|
||||
import styles from '../../Common/Common.scss';
|
||||
import Tooltip from '../Tooltip/Tooltip';
|
||||
|
||||
interface LabeledInputProps extends InputHTMLAttributes<HTMLInputElement> {
|
||||
label: string;
|
||||
boldlabel?: boolean;
|
||||
tooltipText?: string;
|
||||
}
|
||||
|
||||
export const LabeledInput: React.FC<LabeledInputProps> = props => (
|
||||
<>
|
||||
<label className={props.boldlabel ? '' : styles.connect_db_input_label}>
|
||||
{props?.boldlabel ? <b>{props.label}</b> : props.label}
|
||||
{props.tooltipText && <Tooltip message={props.tooltipText} />}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
|
@ -86,6 +86,7 @@ const ConnectDatabase: React.FC<ConnectDatabaseProps> = props => {
|
||||
),
|
||||
connectionSettings: connectionInfo?.pool_settings ?? {},
|
||||
preparedStatements: connectionInfo?.use_prepared_statements ?? false,
|
||||
isolationLevel: connectionInfo?.isolation_level ?? 'read-committed',
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -6,6 +6,7 @@ import Tooltip from '../../../Common/Tooltip/Tooltip';
|
||||
import { getSupportedDrivers } from '../../../../dataSources';
|
||||
|
||||
import styles from './DataSources.scss';
|
||||
import { IsolationLevelOptions } from '../../../../metadata/types';
|
||||
|
||||
export interface ConnectionSettingsFormProps {
|
||||
// Connect DB State Props
|
||||
@ -50,6 +51,7 @@ const ConnectionSettingsForm: React.FC<ConnectionSettingsFormProps> = ({
|
||||
<div className={styles.connection_settings_input_layout}>
|
||||
<LabeledInput
|
||||
label="Max Connections"
|
||||
tooltipText="Maximum number of connections to be kept in the pool"
|
||||
type="number"
|
||||
className={`form-control ${styles.connnection_settings_form_input}`}
|
||||
placeholder="50"
|
||||
@ -71,6 +73,7 @@ const ConnectionSettingsForm: React.FC<ConnectionSettingsFormProps> = ({
|
||||
<div className={styles.connection_settings_input_layout}>
|
||||
<LabeledInput
|
||||
label="Idle Timeout"
|
||||
tooltipText="The idle timeout (in seconds) per connection"
|
||||
type="number"
|
||||
className={`form-control ${styles.connnection_settings_form_input}`}
|
||||
placeholder="180"
|
||||
@ -95,6 +98,7 @@ const ConnectionSettingsForm: React.FC<ConnectionSettingsFormProps> = ({
|
||||
<div className={styles.connection_settings_input_layout}>
|
||||
<LabeledInput
|
||||
label="Retries"
|
||||
tooltipText="Number of retries to perform"
|
||||
type="number"
|
||||
className={`form-control ${styles.connnection_settings_form_input}`}
|
||||
placeholder="1"
|
||||
@ -113,6 +117,82 @@ const ConnectionSettingsForm: React.FC<ConnectionSettingsFormProps> = ({
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{getSupportedDrivers('connectDbForm.pool_timeout').includes(
|
||||
connectionDBState.dbType
|
||||
) ? (
|
||||
<div className={styles.connection_settings_input_layout}>
|
||||
<LabeledInput
|
||||
label="Pool Timeout"
|
||||
tooltipText="Maximum time (in seconds) to wait while acquiring a Postgres connection from the pool"
|
||||
type="number"
|
||||
className={`form-control ${styles.connnection_settings_form_input}`}
|
||||
placeholder="360"
|
||||
value={
|
||||
connectionDBState.connectionSettings?.pool_timeout ??
|
||||
undefined
|
||||
}
|
||||
onChange={e =>
|
||||
connectionDBStateDispatch({
|
||||
type: 'UPDATE_POOL_TIMEOUT',
|
||||
data: e.target.value,
|
||||
})
|
||||
}
|
||||
min="0"
|
||||
boldlabel
|
||||
data-test="pool-timeout"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{getSupportedDrivers(
|
||||
'connectDbForm.connection_lifetime'
|
||||
).includes(connectionDBState.dbType) ? (
|
||||
<div className={styles.connection_settings_input_layout}>
|
||||
<LabeledInput
|
||||
label="Connection Lifetime"
|
||||
tooltipText="Time (in seconds) from connection creation after which the connection should be destroyed and a new one created. A value of 0 indicates we should never destroy an active connection. If 0 is passed, memory from large query results may not be reclaimed."
|
||||
type="number"
|
||||
className={`form-control ${styles.connnection_settings_form_input}`}
|
||||
placeholder="600"
|
||||
value={
|
||||
connectionDBState.connectionSettings
|
||||
?.connection_lifetime ?? undefined
|
||||
}
|
||||
onChange={e =>
|
||||
connectionDBStateDispatch({
|
||||
type: 'UPDATE_CONNECTION_LIFETIME',
|
||||
data: e.target.value,
|
||||
})
|
||||
}
|
||||
min="0"
|
||||
boldlabel
|
||||
data-test="connection-lifetime"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{getSupportedDrivers('connectDbForm.isolation_level').includes(
|
||||
connectionDBState.dbType
|
||||
) && (
|
||||
<div className={styles.connection_settings_input_layout}>
|
||||
<label>
|
||||
<b>Isolation Level</b>
|
||||
<Tooltip message="The transaction isolation level in which the queries made to the source will be run" />
|
||||
</label>
|
||||
<select
|
||||
className={`form-control ${styles.connnection_settings_form_input}`}
|
||||
onChange={e =>
|
||||
connectionDBStateDispatch({
|
||||
type: 'UPDATE_ISOLATION_LEVEL',
|
||||
data: e.target.value as IsolationLevelOptions,
|
||||
})
|
||||
}
|
||||
value={connectionDBState.isolationLevel}
|
||||
>
|
||||
<option value="read-committed">read-committed</option>
|
||||
<option value="repeatable-read">repeatable-read</option>
|
||||
<option value="serializable">serializable</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
{getSupportedDrivers(
|
||||
'connectDbForm.prepared_statements'
|
||||
).includes(connectionDBState.dbType) ? (
|
||||
|
@ -2,7 +2,11 @@ import { Driver, getSupportedDrivers } from '../../../../dataSources';
|
||||
import { makeConnectionStringFromConnectionParams } from './ManageDBUtils';
|
||||
import { addDataSource } from '../../../../metadata/actions';
|
||||
import { Dispatch } from '../../../../types';
|
||||
import { SourceConnectionInfo } from '../../../../metadata/types';
|
||||
import {
|
||||
ConnectionPoolSettings,
|
||||
IsolationLevelOptions,
|
||||
SourceConnectionInfo,
|
||||
} from '../../../../metadata/types';
|
||||
|
||||
export const connectionTypes = {
|
||||
DATABASE_URL: 'DATABASE_URL',
|
||||
@ -10,12 +14,6 @@ export const connectionTypes = {
|
||||
ENV_VAR: 'ENVIRONMENT_VARIABLES',
|
||||
};
|
||||
|
||||
type ConnectionSettings = {
|
||||
max_connections?: number;
|
||||
idle_timeout?: number;
|
||||
retries?: number;
|
||||
};
|
||||
|
||||
type ConnectionParams = {
|
||||
host: string;
|
||||
port: string;
|
||||
@ -37,7 +35,8 @@ export type ConnectDBState = {
|
||||
envVarState: {
|
||||
envVar: string;
|
||||
};
|
||||
connectionSettings: ConnectionSettings;
|
||||
connectionSettings: ConnectionPoolSettings;
|
||||
isolationLevel?: IsolationLevelOptions;
|
||||
preparedStatements?: boolean;
|
||||
};
|
||||
|
||||
@ -62,6 +61,7 @@ export const defaultState: ConnectDBState = {
|
||||
},
|
||||
connectionSettings: {},
|
||||
preparedStatements: false,
|
||||
isolationLevel: 'read-committed',
|
||||
};
|
||||
|
||||
type DefaultStateProps = {
|
||||
@ -97,7 +97,7 @@ export const connectDataSource = (
|
||||
cb: () => void,
|
||||
replicas?: Omit<
|
||||
SourceConnectionInfo,
|
||||
'connection_string' | 'use_prepared_statements'
|
||||
'connection_string' | 'use_prepared_statements' | 'isolation_level'
|
||||
>[],
|
||||
isEditState = false
|
||||
) => {
|
||||
@ -139,6 +139,7 @@ export const connectDataSource = (
|
||||
datasets: currentState.databaseURLState.datasets,
|
||||
},
|
||||
preparedStatements: currentState.preparedStatements,
|
||||
isolationLevel: currentState.isolationLevel,
|
||||
},
|
||||
},
|
||||
cb,
|
||||
@ -154,8 +155,9 @@ export type ConnectDBActions =
|
||||
name: string;
|
||||
driver: Driver;
|
||||
databaseUrl: string;
|
||||
connectionSettings: ConnectionSettings;
|
||||
connectionSettings: ConnectionPoolSettings;
|
||||
preparedStatements: boolean;
|
||||
isolationLevel: IsolationLevelOptions;
|
||||
};
|
||||
}
|
||||
| { type: 'UPDATE_PARAM_STATE'; data: ConnectionParams }
|
||||
@ -173,9 +175,12 @@ export type ConnectDBActions =
|
||||
| { type: 'UPDATE_MAX_CONNECTIONS'; data: string }
|
||||
| { type: 'UPDATE_RETRIES'; data: string }
|
||||
| { type: 'UPDATE_IDLE_TIMEOUT'; data: string }
|
||||
| { type: 'UPDATE_POOL_TIMEOUT'; data: string }
|
||||
| { type: 'UPDATE_CONNECTION_LIFETIME'; data: string }
|
||||
| { type: 'UPDATE_DB_DRIVER'; data: Driver }
|
||||
| { type: 'UPDATE_CONNECTION_SETTINGS'; data: ConnectionSettings }
|
||||
| { type: 'UPDATE_CONNECTION_SETTINGS'; data: ConnectionPoolSettings }
|
||||
| { type: 'UPDATE_PREPARED_STATEMENTS'; data: boolean }
|
||||
| { type: 'UPDATE_ISOLATION_LEVEL'; data: IsolationLevelOptions }
|
||||
| { type: 'RESET_INPUT_STATE' };
|
||||
|
||||
export const connectDBReducer = (
|
||||
@ -194,6 +199,7 @@ export const connectDBReducer = (
|
||||
},
|
||||
connectionSettings: action.data.connectionSettings,
|
||||
preparedStatements: action.data.preparedStatements,
|
||||
isolationLevel: action.data.isolationLevel,
|
||||
};
|
||||
case 'UPDATE_PARAM_STATE':
|
||||
return {
|
||||
@ -293,11 +299,32 @@ export const connectDBReducer = (
|
||||
idle_timeout: setNumberFromString(action.data),
|
||||
},
|
||||
};
|
||||
case 'UPDATE_POOL_TIMEOUT':
|
||||
return {
|
||||
...state,
|
||||
connectionSettings: {
|
||||
...state.connectionSettings,
|
||||
pool_timeout: setNumberFromString(action.data),
|
||||
},
|
||||
};
|
||||
case 'UPDATE_CONNECTION_LIFETIME':
|
||||
return {
|
||||
...state,
|
||||
connectionSettings: {
|
||||
...state.connectionSettings,
|
||||
connection_lifetime: setNumberFromString(action.data),
|
||||
},
|
||||
};
|
||||
case 'UPDATE_CONNECTION_SETTINGS':
|
||||
return {
|
||||
...state,
|
||||
connectionSettings: action.data,
|
||||
};
|
||||
case 'UPDATE_ISOLATION_LEVEL':
|
||||
return {
|
||||
...state,
|
||||
isolationLevel: action.data,
|
||||
};
|
||||
case 'UPDATE_PREPARED_STATEMENTS':
|
||||
return {
|
||||
...state,
|
||||
|
@ -69,11 +69,25 @@ const CollapsibleToggle: React.FC<CollapsibleToggleProps> = ({
|
||||
</div>
|
||||
) : null}
|
||||
{dataSource.connection_pool_settings?.retries ? (
|
||||
<div>
|
||||
<div className={styles.add_mar_bottom_mid}>
|
||||
<span className={styles.dataSource_label}>Retries</span>
|
||||
{dataSource.connection_pool_settings?.retries}
|
||||
</div>
|
||||
) : null}
|
||||
{dataSource.connection_pool_settings?.pool_timeout ? (
|
||||
<div className={styles.add_mar_bottom_mid}>
|
||||
<span className={styles.dataSource_label}>Pool Timeout</span>
|
||||
{dataSource.connection_pool_settings?.pool_timeout}
|
||||
</div>
|
||||
) : null}
|
||||
{dataSource.connection_pool_settings?.connection_lifetime ? (
|
||||
<div>
|
||||
<span className={styles.dataSource_label}>
|
||||
Connection Lifetime
|
||||
</span>
|
||||
{dataSource.connection_pool_settings?.connection_lifetime}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
|
@ -158,8 +158,11 @@ export const supportedFeatures: SupportedFeaturesType = {
|
||||
environmentVariable: true,
|
||||
read_replicas: false,
|
||||
prepared_statements: false,
|
||||
isolation_level: false,
|
||||
connectionSettings: false,
|
||||
retries: false,
|
||||
pool_timeout: false,
|
||||
connection_lifetime: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -164,8 +164,11 @@ export const supportedFeatures: SupportedFeaturesType = {
|
||||
environmentVariable: true,
|
||||
read_replicas: false,
|
||||
prepared_statements: false,
|
||||
isolation_level: false,
|
||||
connectionSettings: true,
|
||||
retries: false,
|
||||
pool_timeout: false,
|
||||
connection_lifetime: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -587,8 +587,11 @@ export const supportedFeatures: SupportedFeaturesType = {
|
||||
environmentVariable: true,
|
||||
read_replicas: true,
|
||||
prepared_statements: true,
|
||||
isolation_level: true,
|
||||
connectionSettings: true,
|
||||
retries: true,
|
||||
pool_timeout: true,
|
||||
connection_lifetime: true,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -295,8 +295,11 @@ export type SupportedFeaturesType = {
|
||||
environmentVariable: boolean;
|
||||
read_replicas: boolean;
|
||||
prepared_statements: boolean;
|
||||
isolation_level: boolean;
|
||||
connectionSettings: boolean;
|
||||
retries: boolean;
|
||||
pool_timeout: boolean;
|
||||
connection_lifetime: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import requestAction from '../utils/requestAction';
|
||||
import Endpoints, { globalCookiePolicy } from '../Endpoints';
|
||||
import {
|
||||
ConnectionPoolSettings,
|
||||
HasuraMetadataV3,
|
||||
IsolationLevelOptions,
|
||||
RestEndpointEntry,
|
||||
SourceConnectionInfo,
|
||||
} from './types';
|
||||
@ -118,17 +120,14 @@ export interface AddDataSourceRequest {
|
||||
payload: {
|
||||
name: string;
|
||||
dbUrl: string | { from_env: string };
|
||||
connection_pool_settings: {
|
||||
max_connections?: number;
|
||||
idle_timeout?: number; // in seconds
|
||||
retries?: number;
|
||||
};
|
||||
connection_pool_settings: ConnectionPoolSettings;
|
||||
replace_configuration?: boolean;
|
||||
bigQuery: {
|
||||
projectId: string;
|
||||
datasets: string;
|
||||
};
|
||||
preparedStatements?: boolean;
|
||||
isolationLevel?: IsolationLevelOptions;
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -244,7 +243,7 @@ export const addDataSource = (
|
||||
successCb: () => void,
|
||||
replicas?: Omit<
|
||||
SourceConnectionInfo,
|
||||
'connection_string' | 'use_prepared_statements'
|
||||
'connection_string' | 'use_prepared_statements' | 'isolation_level'
|
||||
>[],
|
||||
skipNotification = false
|
||||
): Thunk<Promise<void | ReduxState>, MetadataActions> => (
|
||||
|
@ -1,27 +1,28 @@
|
||||
import { Driver } from '../dataSources';
|
||||
import { SourceConnectionInfo } from './types';
|
||||
import {
|
||||
ConnectionPoolSettings,
|
||||
IsolationLevelOptions,
|
||||
SourceConnectionInfo,
|
||||
} from './types';
|
||||
|
||||
export const addSource = (
|
||||
driver: Driver,
|
||||
payload: {
|
||||
name: string;
|
||||
dbUrl: string | { from_env: string };
|
||||
connection_pool_settings?: {
|
||||
max_connections?: number;
|
||||
idle_timeout?: number;
|
||||
retries?: number;
|
||||
};
|
||||
connection_pool_settings?: ConnectionPoolSettings;
|
||||
replace_configuration?: boolean;
|
||||
bigQuery: {
|
||||
projectId: string;
|
||||
datasets: string;
|
||||
};
|
||||
preparedStatements?: boolean;
|
||||
isolationLevel?: IsolationLevelOptions;
|
||||
},
|
||||
// supported only for PG sources at the moment
|
||||
replicas?: Omit<
|
||||
SourceConnectionInfo,
|
||||
'connection_string' | 'use_prepared_statements'
|
||||
'connection_string' | 'use_prepared_statements' | 'isolation_level'
|
||||
>[]
|
||||
) => {
|
||||
const replace_configuration = payload.replace_configuration ?? false;
|
||||
@ -69,6 +70,7 @@ export const addSource = (
|
||||
database_url: payload.dbUrl,
|
||||
pool_settings: payload.connection_pool_settings,
|
||||
use_prepared_statements: payload.preparedStatements,
|
||||
isolation_level: payload.isolationLevel,
|
||||
},
|
||||
read_replicas: replicas?.length ? replicas : null,
|
||||
},
|
||||
|
@ -5,11 +5,7 @@ export type DataSource = {
|
||||
name: string;
|
||||
url: string | { from_env: string };
|
||||
driver: Driver;
|
||||
connection_pool_settings?: {
|
||||
max_connections?: number;
|
||||
idle_timeout?: number;
|
||||
retries?: number;
|
||||
};
|
||||
connection_pool_settings?: ConnectionPoolSettings;
|
||||
read_replicas?: Omit<SourceConnectionInfo, 'connection_string'>[];
|
||||
};
|
||||
|
||||
@ -882,17 +878,27 @@ export interface RestEndpointEntry {
|
||||
* Docs for type: https://hasura.io/docs/latest/graphql/core/api-reference/syntax-defs.html#pgsourceconnectioninfo
|
||||
*/
|
||||
|
||||
export interface ConnectionPoolSettings {
|
||||
max_connections?: number;
|
||||
idle_timeout?: number;
|
||||
retries?: number;
|
||||
pool_timeout?: number;
|
||||
connection_lifetime?: number;
|
||||
}
|
||||
|
||||
export type IsolationLevelOptions =
|
||||
| 'read-committed'
|
||||
| 'repeatable-read'
|
||||
| 'serializable';
|
||||
|
||||
export interface SourceConnectionInfo {
|
||||
// used for SQL Server
|
||||
connection_string: string | { from_env: string };
|
||||
// used for Postgres
|
||||
database_url: string | { from_env: string };
|
||||
pool_settings: {
|
||||
max_connections: number;
|
||||
idle_timeout: number;
|
||||
retries: number;
|
||||
};
|
||||
pool_settings: ConnectionPoolSettings;
|
||||
use_prepared_statements: boolean;
|
||||
isolation_level: IsolationLevelOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user