supabase-cli/pkg/config/db.go

190 lines
8.2 KiB
Go

package config
import (
"bytes"
"github.com/go-errors/errors"
v1API "github.com/supabase/cli/pkg/api"
"github.com/supabase/cli/pkg/cast"
"github.com/supabase/cli/pkg/diff"
)
type PoolMode string
const (
TransactionMode PoolMode = "transaction"
SessionMode PoolMode = "session"
)
func (m *PoolMode) UnmarshalText(text []byte) error {
allowed := []PoolMode{TransactionMode, SessionMode}
if *m = PoolMode(text); !sliceContains(allowed, *m) {
return errors.Errorf("must be one of %v", allowed)
}
return nil
}
type SessionReplicationRole string
const (
SessionReplicationRoleOrigin SessionReplicationRole = "origin"
SessionReplicationRoleReplica SessionReplicationRole = "replica"
SessionReplicationRoleLocal SessionReplicationRole = "local"
)
func (r *SessionReplicationRole) UnmarshalText(text []byte) error {
allowed := []SessionReplicationRole{SessionReplicationRoleOrigin, SessionReplicationRoleReplica, SessionReplicationRoleLocal}
if *r = SessionReplicationRole(text); !sliceContains(allowed, *r) {
return errors.Errorf("must be one of %v", allowed)
}
return nil
}
type (
settings struct {
EffectiveCacheSize *string `toml:"effective_cache_size"`
LogicalDecodingWorkMem *string `toml:"logical_decoding_work_mem"`
MaintenanceWorkMem *string `toml:"maintenance_work_mem"`
MaxConnections *uint `toml:"max_connections"`
MaxLocksPerTransaction *uint `toml:"max_locks_per_transaction"`
MaxParallelMaintenanceWorkers *uint `toml:"max_parallel_maintenance_workers"`
MaxParallelWorkers *uint `toml:"max_parallel_workers"`
MaxParallelWorkersPerGather *uint `toml:"max_parallel_workers_per_gather"`
MaxReplicationSlots *uint `toml:"max_replication_slots"`
MaxSlotWalKeepSize *string `toml:"max_slot_wal_keep_size"`
MaxStandbyArchiveDelay *string `toml:"max_standby_archive_delay"`
MaxStandbyStreamingDelay *string `toml:"max_standby_streaming_delay"`
MaxWalSize *string `toml:"max_wal_size"`
MaxWalSenders *uint `toml:"max_wal_senders"`
MaxWorkerProcesses *uint `toml:"max_worker_processes"`
SessionReplicationRole *SessionReplicationRole `toml:"session_replication_role"`
SharedBuffers *string `toml:"shared_buffers"`
StatementTimeout *string `toml:"statement_timeout"`
TrackActivityQuerySize *string `toml:"track_activity_query_size"`
TrackCommitTimestamp *bool `toml:"track_commit_timestamp"`
WalKeepSize *string `toml:"wal_keep_size"`
WalSenderTimeout *string `toml:"wal_sender_timeout"`
WorkMem *string `toml:"work_mem"`
}
db struct {
Image string `toml:"-"`
Port uint16 `toml:"port"`
ShadowPort uint16 `toml:"shadow_port"`
MajorVersion uint `toml:"major_version"`
Password string `toml:"-"`
RootKey string `toml:"-" mapstructure:"root_key"`
Pooler pooler `toml:"pooler"`
Migrations migrations `toml:"migrations"`
Seed seed `toml:"seed"`
Settings settings `toml:"settings"`
Vault map[string]Secret `toml:"vault"`
}
migrations struct {
SchemaPaths Glob `toml:"schema_paths"`
}
seed struct {
Enabled bool `toml:"enabled"`
SqlPaths Glob `toml:"sql_paths"`
}
pooler struct {
Enabled bool `toml:"enabled"`
Image string `toml:"-"`
Port uint16 `toml:"port"`
PoolMode PoolMode `toml:"pool_mode"`
DefaultPoolSize uint `toml:"default_pool_size"`
MaxClientConn uint `toml:"max_client_conn"`
ConnectionString string `toml:"-"`
TenantId string `toml:"-"`
EncryptionKey string `toml:"-"`
SecretKeyBase string `toml:"-"`
}
)
func (a *settings) ToUpdatePostgresConfigBody() v1API.UpdatePostgresConfigBody {
body := v1API.UpdatePostgresConfigBody{}
// Parameters that require restart
body.MaxConnections = cast.UintToIntPtr(a.MaxConnections)
body.MaxWorkerProcesses = cast.UintToIntPtr(a.MaxWorkerProcesses)
body.MaxParallelWorkers = cast.UintToIntPtr(a.MaxParallelWorkers)
body.MaxWalSenders = cast.UintToIntPtr(a.MaxWalSenders)
body.MaxReplicationSlots = cast.UintToIntPtr(a.MaxReplicationSlots)
body.SharedBuffers = a.SharedBuffers
// Parameters that can be changed without restart
body.EffectiveCacheSize = a.EffectiveCacheSize
body.LogicalDecodingWorkMem = a.LogicalDecodingWorkMem
body.MaintenanceWorkMem = a.MaintenanceWorkMem
body.MaxLocksPerTransaction = cast.UintToIntPtr(a.MaxLocksPerTransaction)
body.MaxParallelMaintenanceWorkers = cast.UintToIntPtr(a.MaxParallelMaintenanceWorkers)
body.MaxParallelWorkersPerGather = cast.UintToIntPtr(a.MaxParallelWorkersPerGather)
body.MaxSlotWalKeepSize = a.MaxSlotWalKeepSize
body.MaxStandbyArchiveDelay = a.MaxStandbyArchiveDelay
body.MaxStandbyStreamingDelay = a.MaxStandbyStreamingDelay
body.MaxWalSize = a.MaxWalSize
body.SessionReplicationRole = (*v1API.UpdatePostgresConfigBodySessionReplicationRole)(a.SessionReplicationRole)
body.StatementTimeout = a.StatementTimeout
body.TrackActivityQuerySize = a.TrackActivityQuerySize
body.TrackCommitTimestamp = a.TrackCommitTimestamp
body.WalKeepSize = a.WalKeepSize
body.WalSenderTimeout = a.WalSenderTimeout
body.WorkMem = a.WorkMem
return body
}
func (a *settings) FromRemotePostgresConfig(remoteConfig v1API.PostgresConfigResponse) {
a.EffectiveCacheSize = remoteConfig.EffectiveCacheSize
a.LogicalDecodingWorkMem = remoteConfig.LogicalDecodingWorkMem
a.MaintenanceWorkMem = remoteConfig.MaintenanceWorkMem
a.MaxConnections = cast.IntToUintPtr(remoteConfig.MaxConnections)
a.MaxLocksPerTransaction = cast.IntToUintPtr(remoteConfig.MaxLocksPerTransaction)
a.MaxParallelMaintenanceWorkers = cast.IntToUintPtr(remoteConfig.MaxParallelMaintenanceWorkers)
a.MaxParallelWorkers = cast.IntToUintPtr(remoteConfig.MaxParallelWorkers)
a.MaxParallelWorkersPerGather = cast.IntToUintPtr(remoteConfig.MaxParallelWorkersPerGather)
a.MaxReplicationSlots = cast.IntToUintPtr(remoteConfig.MaxReplicationSlots)
a.MaxSlotWalKeepSize = remoteConfig.MaxSlotWalKeepSize
a.MaxStandbyArchiveDelay = remoteConfig.MaxStandbyArchiveDelay
a.MaxStandbyStreamingDelay = remoteConfig.MaxStandbyStreamingDelay
a.MaxWalSenders = cast.IntToUintPtr(remoteConfig.MaxWalSenders)
a.MaxWalSize = remoteConfig.MaxWalSize
a.MaxWorkerProcesses = cast.IntToUintPtr(remoteConfig.MaxWorkerProcesses)
a.SessionReplicationRole = (*SessionReplicationRole)(remoteConfig.SessionReplicationRole)
a.SharedBuffers = remoteConfig.SharedBuffers
a.StatementTimeout = remoteConfig.StatementTimeout
a.TrackActivityQuerySize = remoteConfig.TrackActivityQuerySize
a.TrackCommitTimestamp = remoteConfig.TrackCommitTimestamp
a.WalKeepSize = remoteConfig.WalKeepSize
a.WalSenderTimeout = remoteConfig.WalSenderTimeout
a.WorkMem = remoteConfig.WorkMem
}
const pgConfHeader = "\n# supabase [db.settings] configuration\n"
// create a valid string to append to /etc/postgresql/postgresql.conf
func (a *settings) ToPostgresConfig() string {
// Assuming postgres settings is always a flat struct, we can serialise
// using toml, then replace double quotes with single.
data, _ := ToTomlBytes(*a)
body := bytes.ReplaceAll(data, []byte{'"'}, []byte{'\''})
return pgConfHeader + string(body)
}
func (a *settings) DiffWithRemote(remoteConfig v1API.PostgresConfigResponse) ([]byte, error) {
copy := *a
// Convert the config values into easily comparable remoteConfig values
currentValue, err := ToTomlBytes(copy)
if err != nil {
return nil, err
}
copy.FromRemotePostgresConfig(remoteConfig)
remoteCompare, err := ToTomlBytes(copy)
if err != nil {
return nil, err
}
return diff.Diff("remote[db.settings]", remoteCompare, "local[db.settings]", currentValue), nil
}