// Package postgres provides GL's PostgreSQL adapters. package postgres import ( "context" "fmt" "net/url" "strconv" "gl/infrastructure/config" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "github.com/jackc/pgx/v5/pgxpool" ) type Row interface { Scan(dest ...any) error } type Tx interface { Exec(context.Context, string, ...any) (pgconn.CommandTag, error) QueryRow(context.Context, string, ...any) Row Commit(context.Context) error Rollback(context.Context) error } type Database interface { Begin(context.Context) (Tx, error) QueryRow(context.Context, string, ...any) Row Ping(context.Context) error Close() } type Pool struct { pool *pgxpool.Pool } func Open(ctx context.Context, cfg config.DatabaseConfig) (*Pool, error) { connectionURL := &url.URL{ Scheme: "postgres", User: url.UserPassword(cfg.User, cfg.Password), Host: cfg.Host + ":" + strconv.Itoa(cfg.Port), Path: cfg.Name, } query := connectionURL.Query() query.Set("sslmode", cfg.SSLMode) connectionURL.RawQuery = query.Encode() pool, err := pgxpool.New(ctx, connectionURL.String()) if err != nil { return nil, fmt.Errorf("create postgres pool: %w", err) } return &Pool{pool: pool}, nil } func (p *Pool) Begin(ctx context.Context) (Tx, error) { tx, err := p.pool.BeginTx(ctx, pgx.TxOptions{}) if err != nil { return nil, err } return txAdapter{Tx: tx}, nil } func (p *Pool) Ping(ctx context.Context) error { return p.pool.Ping(ctx) } func (p *Pool) QueryRow(ctx context.Context, sql string, args ...any) Row { return p.pool.QueryRow(ctx, sql, args...) } func (p *Pool) Close() { p.pool.Close() } type txAdapter struct { pgx.Tx } func (t txAdapter) QueryRow(ctx context.Context, sql string, args ...any) Row { return t.Tx.QueryRow(ctx, sql, args...) }