nettools/pg/pg.go

51 lines
1.2 KiB
Go

package pgUtils
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/matchsystems/werr"
)
type PgxQuerier interface {
Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
}
// Query executes query on a provided querier and tries to parse db response
// Works only with structs
//
// Usage:
//
// type User struct {
// Id int `db:"id"`
// Name string `db:"name"`
// }
//
// db := pgx.Connect(context.Background(), "<url>")
// users, err := pgUtils.Query[User](context.Background(), db, "SELECT id, name FROM users")
func Query[T any](ctx context.Context, db PgxQuerier, query string, args ...any) (out []T, err error) {
rows, err := db.Query(ctx, query, args)
if err != nil {
return nil, err
}
entities, err := pgx.CollectRows(rows, pgx.RowToStructByNameLax[T])
if err != nil {
return nil, werr.Wrapf(err, "failed to parse query results")
}
return entities, nil
}
// Tx creates new transaction. Cancels it if returned not nil err
func Tx(ctx context.Context, db *pgxpool.Pool, exec func(ctx context.Context, tx pgx.Tx) error) error {
tx, err := db.Begin(ctx)
if err != nil {
return err
}
err = exec(ctx, tx)
if err != nil {
_ = tx.Rollback(ctx)
return err
}
return tx.Commit(ctx)
}