feat: ✨ PostgreSQL connections opened by relspec set application_name by default to relspecgo/<version>
This commit is contained in:
@@ -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
|
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/<version>` (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)
|
### `merge` — Additive schema merge (never modifies existing items)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
53
pkg/pgsql/connection_test.go
Normal file
53
pkg/pgsql/connection_test.go
Normal file
@@ -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/<version> 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,6 +89,10 @@ postgres://user@localhost/mydb?sslmode=disable
|
|||||||
postgres://user:pass@db.example.com:5432/production?sslmode=require
|
postgres://user:pass@db.example.com:5432/production?sslmode=require
|
||||||
```
|
```
|
||||||
|
|
||||||
|
By default, relspec sets `application_name` to `relspecgo/<version>` 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
|
## Extracted Information
|
||||||
|
|
||||||
### Tables
|
### Tables
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
|
||||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||||
"git.warky.dev/wdevs/relspecgo/pkg/pgsql"
|
"git.warky.dev/wdevs/relspecgo/pkg/pgsql"
|
||||||
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||||
"github.com/jackc/pgx/v5"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reader implements the readers.Reader interface for PostgreSQL databases
|
// Reader implements the readers.Reader interface for PostgreSQL databases
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
|
|
||||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||||
|
"git.warky.dev/wdevs/relspecgo/pkg/pgsql"
|
||||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ func (w *Writer) WriteDatabase(db *models.Database) error {
|
|||||||
|
|
||||||
// Connect to database
|
// Connect to database
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
conn, err := pgx.Connect(ctx, connString)
|
conn, err := pgsql.Connect(ctx, connString, "writer-sqlexec")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to connect to database: %w", err)
|
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
|
// Connect to database
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
conn, err := pgx.Connect(ctx, connString)
|
conn, err := pgsql.Connect(ctx, connString, "writer-sqlexec")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to connect to database: %w", err)
|
return fmt.Errorf("failed to connect to database: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user