diff --git a/README.md b/README.md index 208773b..0ea4f71 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,11 @@ relspec convert --from pgsql --from-conn "postgres://..." --to sqlite --to-path relspec convert --from json --from-list "a.json,b.json" --to yaml --to-path merged.yaml ``` +PostgreSQL connections opened by relspec set `application_name` by default to +`relspecgo/` (with component suffixes internally, e.g. readers/writers). +If you need a custom value, provide `application_name` explicitly in the connection +string query parameters. + ### `merge` — Additive schema merge (never modifies existing items) ```bash diff --git a/pkg/pgsql/connection_test.go b/pkg/pgsql/connection_test.go new file mode 100644 index 0000000..c517fc7 --- /dev/null +++ b/pkg/pgsql/connection_test.go @@ -0,0 +1,53 @@ +package pgsql + +import ( + "strings" + "testing" +) + +func TestBuildApplicationName_IncludesVersion(t *testing.T) { + got := BuildApplicationName("") + if !strings.HasPrefix(got, "relspecgo/") { + t.Fatalf("BuildApplicationName() = %q, expected prefix relspecgo/", got) + } +} + +func TestBuildApplicationName_IncludesComponent(t *testing.T) { + got := BuildApplicationName("reader-pgsql") + if !strings.Contains(got, ":reader-pgsql") { + t.Fatalf("BuildApplicationName(component) = %q, expected component suffix", got) + } +} + +func TestBuildApplicationName_RespectsPostgresLengthLimit(t *testing.T) { + got := BuildApplicationName(strings.Repeat("x", 200)) + if len(got) > 63 { + t.Fatalf("BuildApplicationName() length = %d, expected <= 63", len(got)) + } +} + +func TestParseConfigWithApplicationName_AddsWhenMissing(t *testing.T) { + cfg, err := ParseConfigWithApplicationName("postgres://user:pass@localhost:5432/db", "reader-pgsql") + if err != nil { + t.Fatalf("ParseConfigWithApplicationName() error = %v", err) + } + + appName := cfg.RuntimeParams["application_name"] + if appName == "" { + t.Fatal("expected application_name to be set") + } + if !strings.HasPrefix(appName, "relspecgo/") { + t.Fatalf("application_name = %q, expected relspecgo/ prefix", appName) + } +} + +func TestParseConfigWithApplicationName_PreservesExplicitValue(t *testing.T) { + cfg, err := ParseConfigWithApplicationName("postgres://user:pass@localhost:5432/db?application_name=custom-app", "reader-pgsql") + if err != nil { + t.Fatalf("ParseConfigWithApplicationName() error = %v", err) + } + + if got := cfg.RuntimeParams["application_name"]; got != "custom-app" { + t.Fatalf("application_name = %q, expected %q", got, "custom-app") + } +} diff --git a/pkg/readers/pgsql/README.md b/pkg/readers/pgsql/README.md index 258e284..78de0c4 100644 --- a/pkg/readers/pgsql/README.md +++ b/pkg/readers/pgsql/README.md @@ -89,6 +89,10 @@ postgres://user@localhost/mydb?sslmode=disable postgres://user:pass@db.example.com:5432/production?sslmode=require ``` +By default, relspec sets `application_name` to `relspecgo/` for PostgreSQL +sessions so they are identifiable in `pg_stat_activity`. If you provide +`application_name` in the connection string, your explicit value is preserved. + ## Extracted Information ### Tables diff --git a/pkg/readers/pgsql/reader.go b/pkg/readers/pgsql/reader.go index fba8061..04a00ca 100644 --- a/pkg/readers/pgsql/reader.go +++ b/pkg/readers/pgsql/reader.go @@ -5,10 +5,11 @@ import ( "fmt" "strings" + "github.com/jackc/pgx/v5" + "git.warky.dev/wdevs/relspecgo/pkg/models" "git.warky.dev/wdevs/relspecgo/pkg/pgsql" "git.warky.dev/wdevs/relspecgo/pkg/readers" - "github.com/jackc/pgx/v5" ) // Reader implements the readers.Reader interface for PostgreSQL databases diff --git a/pkg/writers/sqlexec/writer.go b/pkg/writers/sqlexec/writer.go index 35feb9a..267f340 100644 --- a/pkg/writers/sqlexec/writer.go +++ b/pkg/writers/sqlexec/writer.go @@ -8,6 +8,7 @@ import ( "github.com/jackc/pgx/v5" "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/pgsql" "git.warky.dev/wdevs/relspecgo/pkg/writers" ) @@ -42,7 +43,7 @@ func (w *Writer) WriteDatabase(db *models.Database) error { // Connect to database ctx := context.Background() - conn, err := pgx.Connect(ctx, connString) + conn, err := pgsql.Connect(ctx, connString, "writer-sqlexec") if err != nil { return fmt.Errorf("failed to connect to database: %w", err) } @@ -72,7 +73,7 @@ func (w *Writer) WriteSchema(schema *models.Schema) error { // Connect to database ctx := context.Background() - conn, err := pgx.Connect(ctx, connString) + conn, err := pgsql.Connect(ctx, connString, "writer-sqlexec") if err != nil { return fmt.Errorf("failed to connect to database: %w", err) }