86 lines
2.0 KiB
Go
86 lines
2.0 KiB
Go
package pgsql
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"runtime/debug"
|
|
"strings"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
const (
|
|
defaultApplicationPrefix = "relspecgo"
|
|
postgresIdentifierMaxLen = 63
|
|
)
|
|
|
|
// BuildApplicationName returns a PostgreSQL application_name in the form:
|
|
// relspecgo/<version>[:<component>]
|
|
func BuildApplicationName(component string) string {
|
|
appName := fmt.Sprintf("%s/%s", defaultApplicationPrefix, relspecVersion())
|
|
component = strings.TrimSpace(component)
|
|
if component != "" {
|
|
appName = appName + ":" + component
|
|
}
|
|
if len(appName) > postgresIdentifierMaxLen {
|
|
appName = appName[:postgresIdentifierMaxLen]
|
|
}
|
|
return appName
|
|
}
|
|
|
|
// ParseConfigWithApplicationName parses a connection string and applies a default
|
|
// application_name when one is not explicitly provided by the caller.
|
|
func ParseConfigWithApplicationName(connString, component string) (*pgx.ConnConfig, error) {
|
|
cfg, err := pgx.ParseConfig(connString)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if cfg.RuntimeParams == nil {
|
|
cfg.RuntimeParams = map[string]string{}
|
|
}
|
|
|
|
if strings.TrimSpace(cfg.RuntimeParams["application_name"]) == "" {
|
|
cfg.RuntimeParams["application_name"] = BuildApplicationName(component)
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
// Connect establishes a PostgreSQL connection with a default relspec
|
|
// application_name when the caller does not provide one in the DSN.
|
|
func Connect(ctx context.Context, connString, component string) (*pgx.Conn, error) {
|
|
cfg, err := ParseConfigWithApplicationName(connString, component)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return pgx.ConnectConfig(ctx, cfg)
|
|
}
|
|
|
|
func relspecVersion() string {
|
|
info, ok := debug.ReadBuildInfo()
|
|
if !ok {
|
|
return "dev"
|
|
}
|
|
|
|
version := strings.TrimSpace(info.Main.Version)
|
|
if version != "" && version != "(devel)" {
|
|
return version
|
|
}
|
|
|
|
for _, setting := range info.Settings {
|
|
if setting.Key == "vcs.revision" {
|
|
revision := strings.TrimSpace(setting.Value)
|
|
if len(revision) >= 7 {
|
|
return revision[:7]
|
|
}
|
|
if revision != "" {
|
|
return revision
|
|
}
|
|
}
|
|
}
|
|
|
|
return "dev"
|
|
}
|