import { PermissionAction } from '@supabase/shared-types/out/constants'
import { Fragment, useState } from 'react'
import { Input } from 'ui'
import { AutoField } from 'uniforms-bootstrap4'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
import AlertError from 'components/ui/AlertError'
import Divider from 'components/ui/Divider'
import Panel from 'components/ui/Panel'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import { usePoolingConfigurationQuery } from 'data/database/pooling-configuration-query'
import { usePoolingConfigurationUpdateMutation } from 'data/database/pooling-configuration-update-mutation'
import { useCheckPermissions, useStore } from 'hooks'
import { pluckObjectFields } from 'lib/helpers'
const ConnectionPooling = () => {
const { project } = useProjectContext()
const projectRef = project?.ref ?? 'default'
const {
data: poolingConfiguration,
error,
isLoading,
isError,
isSuccess,
} = usePoolingConfigurationQuery({ projectRef })
const formModel = poolingConfiguration
const DB_FIELDS = ['db_host', 'db_name', 'db_port', 'db_user', 'inserted_at']
const connectionInfo = isSuccess ? pluckObjectFields(formModel, DB_FIELDS) : {}
const BOUNCER_FIELDS = [
'default_pool_size',
'ignore_startup_parameters',
'pool_mode',
'pgbouncer_enabled',
'supavisor_enabled',
'max_client_conn',
'connectionString',
]
const bouncerInfo = isSuccess ? pluckObjectFields(formModel, BOUNCER_FIELDS) : {}
return (
<>
{isLoading && (
Connection Pooling
}
>
{Array.from({ length: 5 }).map((_, i) => (
))}
)}
{isError && (
)}
{isSuccess && (
<>
{!poolingConfiguration?.pgbouncer_enabled && poolingConfiguration?.pool_mode === null ? (
Connection Pooling is not available for this project
}
>
Please start a new project to enable this feature.
) : (
)}
>
)}
>
)
}
export default ConnectionPooling
interface ConfigProps {
projectRef: string
bouncerInfo: {
default_pool_size: number
ignore_startup_parameters: 'string'
pool_mode: string
pgbouncer_enabled: boolean
max_client_conn: number
connectionString: string
supavisor_enabled: boolean
}
connectionInfo: {
db_host: string
db_name: string
db_port: number
db_user: string
inserted_at: string
}
}
export const PgbouncerConfig = ({ projectRef, bouncerInfo, connectionInfo }: ConfigProps) => {
const { ui } = useStore()
const { project } = useProjectContext()
const [updates, setUpdates] = useState({
pool_mode: bouncerInfo.pool_mode || 'transaction',
default_pool_size: bouncerInfo.default_pool_size || undefined,
ignore_startup_parameters: bouncerInfo.ignore_startup_parameters || '',
pgbouncer_enabled: bouncerInfo.pgbouncer_enabled,
max_client_conn: bouncerInfo.max_client_conn || undefined,
})
const { mutateAsync: updateConfiguration, isLoading: isUpdating } =
usePoolingConfigurationUpdateMutation({
onSuccess: (res) => {
setUpdates({ ...(res as any) })
ui.setNotification({ category: 'success', message: 'Successfully saved settings' })
},
})
const canUpdateConnectionPoolingConfiguration = useCheckPermissions(
PermissionAction.UPDATE,
'projects',
{
resource: {
project_id: project?.id,
},
}
)
const updateConfig = async (updatedConfig: any) => {
try {
await updateConfiguration({
ref: projectRef,
pgbouncer_enabled: updatedConfig.pgbouncer_enabled,
default_pool_size: updatedConfig.default_pool_size,
ignore_startup_parameters: updatedConfig.ignore_startup_parameters,
pool_mode: updatedConfig.pool_mode,
max_client_conn: updatedConfig.max_client_conn,
})
} finally {
}
}
const formSchema = {
properties: {
pool_mode: {
title: 'Pool Mode',
type: 'string',
options: [
{
label: 'Transaction',
value: 'transaction',
},
{
label: 'Session',
value: 'session',
},
],
},
ignore_startup_parameters: {
title: 'Ignore Startup Parameters',
type: 'string',
help: 'Defaults are either blank or "extra_float_digits"',
},
max_client_conn: {
title: 'Max Client Connections',
oneOf: [{ type: 'integer' }, { type: 'null' }],
help: 'The maximum number of concurrent client connections allowed. Overrides default optimizations; refer to https://supabase.com/docs/guides/platform/custom-postgres-config#pooler-config',
},
default_pool_size: {
title: 'Default Pool Size',
oneOf: [{ type: 'integer' }, { type: 'null' }],
help: 'The maximum number of connections made to the underlying Postgres cluster, per user+db combination. Overrides default optimizations; refer to https://supabase.com/docs/guides/platform/custom-postgres-config#pooler-config',
},
},
required: ['pool_mode'],
type: 'object',
}
return (
setUpdates(model)}
onSubmit={(model: any) => updateConfig(model)}
onReset={() => setUpdates(bouncerInfo)}
disabled={!canUpdateConnectionPoolingConfiguration}
disabledMessage="You need additional permissions to update connection pooling settings"
>
)
}