Files
relspecgo/pkg/ui/connstring_check.go
T
SG CommandandClaude Sonnet 5.5 0235a28add feat(ui): file browser and connection string builder dialogs (#44)
Enter on File Path inputs opens a file browser (load/save, extension
filter, hidden toggle, overwrite confirm). Enter on Connection String
inputs opens a builder for PostgreSQL, MSSQL and SQLite with masked
password/preview, parsing and optional connection test.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 11:35:12 +02:00

63 lines
1.5 KiB
Go

package ui
import (
"context"
"database/sql"
"fmt"
"os"
"strings"
"time"
"github.com/jackc/pgx/v5"
_ "github.com/microsoft/go-mssqldb"
_ "modernc.org/sqlite"
)
// connTestTimeout bounds how long "Test connection" may block.
const connTestTimeout = 5 * time.Second
// TestConnection opens and pings the database described by f. Any occurrence
// of the password in the returned error is masked.
func TestConnection(f ConnFields) error {
ctx, cancel := context.WithTimeout(context.Background(), connTestTimeout)
defer cancel()
err := testConnection(ctx, f)
if err != nil && f.Password != "" {
err = fmt.Errorf("%s", strings.ReplaceAll(err.Error(), f.Password, maskedPassword))
}
return err
}
func testConnection(ctx context.Context, f ConnFields) error {
switch f.Kind {
case ConnPostgres:
conn, err := pgx.Connect(ctx, BuildConnString(f, false))
if err != nil {
return err
}
return conn.Close(ctx)
case ConnMSSQL:
return pingSQL(ctx, "sqlserver", BuildConnString(f, false))
case ConnSQLite:
if f.FilePath == "" {
return fmt.Errorf("file path is required")
}
// Opening a missing SQLite file would silently create it.
if _, err := os.Stat(f.FilePath); err != nil {
return err
}
return pingSQL(ctx, "sqlite", f.FilePath)
}
return fmt.Errorf("unsupported connection type %q", f.Kind)
}
func pingSQL(ctx context.Context, driver, dsn string) error {
db, err := sql.Open(driver, dsn)
if err != nil {
return err
}
defer db.Close()
return db.PingContext(ctx)
}