Files
GL/infrastructure/postgres/database.go

101 lines
2.2 KiB
Go

// 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 Rows interface {
Next() bool
Scan(dest ...any) error
Err() error
Close()
}
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)
Exec(context.Context, string, ...any) (pgconn.CommandTag, error)
QueryRow(context.Context, string, ...any) Row
Query(context.Context, string, ...any) (Rows, error)
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) Query(ctx context.Context, sql string, args ...any) (Rows, error) {
return p.pool.Query(ctx, sql, args...)
}
func (p *Pool) Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error) {
return p.pool.Exec(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...)
}