diff options
| author | Stefan Majewsky <majewsky@gmx.net> | 2026-07-30 23:48:18 +0200 |
|---|---|---|
| committer | Stefan Majewsky <majewsky@gmx.net> | 2026-07-30 23:48:18 +0200 |
| commit | 2bf760b9b4d71d3b67c5489d2c46bfa04d4629f9 (patch) | |
| tree | 969fd9eb4d6cb1b83372159fc6c37cf32cc57c17 /interface.go | |
| parent | 584bdd9d0c0a0e066df69cc5f11de352166d7271 (diff) | |
| download | go-gg-pgx-2bf760b9b4d71d3b67c5489d2c46bfa04d4629f9.tar.gz | |
add full implementation
Diffstat (limited to 'interface.go')
| -rw-r--r-- | interface.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/interface.go b/interface.go new file mode 100644 index 0000000..d4a5b56 --- /dev/null +++ b/interface.go @@ -0,0 +1,168 @@ +// SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net> +// SPDX-License-Identifier: Apache-2.0 + +// Package gg_pgx contains integration for using [gg/gsql] (and libraries based on it, such as [Oblast]) with the PostgreSQL driver library [pgx]. +// +// [gg/gsql]: https://pkg.go.dev/go.xyrillian.de/gg/gsql +// [Oblast]: https://pkg.go.dev/go.xyrillian.de/oblast +// [pgx]: https://github.com/jackc/pgx +package gg_pgx + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" + "go.xyrillian.de/gg/gsql" +) + +// TODO: test coverage (via gg/pgruntime) + +// NOTE: The internal structure of these types follows the pattern established +// by (and explained in) `std.go` of `go.xyrillian.de/gg/gsql`. + +// Conn wraps [*pgx.Conn] into a [gsql.Handle]. +// +// Because this type has [*pgx.Conn] as an embedded field, +// all methods from that type work on this type as well. +type Conn struct { + *pgx.Conn + gsql.ConnectionHandle +} + +// NewConn wraps an instance of [*pgx.Conn] into the [Conn] type that implements [gsql.Handle]. +func NewConn(conn *pgx.Conn) *Conn { + return &Conn{conn, connHandle{conn}} +} + +// Begin is like [pgx.Conn.Begin], but wraps the resulting transaction into a [Handle]. +func (conn *Conn) Begin(ctx context.Context) (*Tx, error) { + tx, err := conn.Conn.Begin(ctx) + return maybeNewTx(tx), err +} + +// BeginTx is like [pgx.Conn.BeginTx], but wraps the resulting transaction into a [Handle]. +func (conn *Conn) BeginTx(ctx context.Context, opts pgx.TxOptions) (*Tx, error) { + tx, err := conn.Conn.BeginTx(ctx, opts) + return maybeNewTx(tx), err +} + +// Pool wraps [*pgxpool.Pool] into a [gsql.Handle]. +// +// Because this type has [*pgxpool.Pool] as an embedded field, +// all methods from that type work on this type as well. +type Pool struct { + *pgxpool.Pool + gsql.ConnectionHandle +} + +// NewPool wraps an instance of [*pgxpool.Pool] into the [Pool] type that implements [gsql.Handle]. +func NewPool(pool *pgxpool.Pool) *Pool { + return &Pool{pool, poolHandle{pool}} +} + +// Acquire is like [pgxpool.Pool.Acquire], but wraps the resulting connection into a [Handle]. +func (pool *Pool) Acquire(ctx context.Context) (*PoolConn, error) { + conn, err := pool.Pool.Acquire(ctx) + return maybe(NewPoolConn, conn), err +} + +// AcquireAllIdle is like [pgxpool.Pool.AcquireAllIdle], but wraps the resulting connections into [Handle] instances. +func (pool *Pool) AcquireAllIdle(ctx context.Context) []*PoolConn { + conns := pool.Pool.AcquireAllIdle(ctx) + result := make([]*PoolConn, len(conns)) + for idx, conn := range conns { + result[idx] = maybe(NewPoolConn, conn) + } + return result +} + +// AcquireFunc is like [pgxpool.Pool.AcquireFunc], but wraps the resulting connection into a [Handle]. +func (pool *Pool) AcquireFunc(ctx context.Context, f func(*PoolConn) error) error { + return pool.Pool.AcquireFunc(ctx, func(conn *pgxpool.Conn) error { + return f(maybe(NewPoolConn, conn)) + }) +} + +// Begin is like [pgxpool.Pool.Begin], but wraps the resulting transaction into a [Handle]. +func (pool *Pool) Begin(ctx context.Context) (*Tx, error) { + tx, err := pool.Pool.Begin(ctx) + return maybeNewTx(tx), err +} + +// BeginTx is like [pgxpool.Pool.BeginTx], but wraps the resulting transaction into a [Handle]. +func (pool *Pool) BeginTx(ctx context.Context, opts pgx.TxOptions) (*Tx, error) { + tx, err := pool.Pool.BeginTx(ctx, opts) + return maybeNewTx(tx), err +} + +// PoolConn wraps [*pgxpool.Conn] into a [gsql.Handle]. +// +// Because this type has [*pgxpool.Conn] as an embedded field, +// all methods from that type work on this type as well. +type PoolConn struct { + *pgxpool.Conn + gsql.ConnectionHandle +} + +// NewPoolConn wraps an instance of [*pgxpool.Conn] into the [PoolConn] type that implements [gsql.Handle]. +func NewPoolConn(pool *pgxpool.Conn) *PoolConn { + return &PoolConn{pool, poolConnHandle{pool}} +} + +// Begin is like [pgxpool.Conn.Begin], but wraps the resulting transaction into a [Handle]. +func (conn *PoolConn) Begin(ctx context.Context) (*Tx, error) { + tx, err := conn.Conn.Begin(ctx) + return maybeNewTx(tx), err +} + +// BeginTx is like [pgxpool.Conn.BeginTx], but wraps the resulting transaction into a [Handle]. +func (conn *PoolConn) BeginTx(ctx context.Context, opts pgx.TxOptions) (*Tx, error) { + tx, err := conn.Conn.BeginTx(ctx, opts) + return maybeNewTx(tx), err +} + +// GetConn is like [pgxpool.Conn.Conn], but wraps the resulting connection into a [Handle]. +// +// This method should be called "Conn", but one of the embedded fields of this type blocks that name. +func (conn *PoolConn) GetConn() *Conn { + return maybe(NewConn, conn.Conn.Conn()) +} + +// Hijack is like [pgxpool.Conn.Conn], but wraps the resulting connection into a [Handle]. +func (conn *PoolConn) Hijack() *Conn { + return maybe(NewConn, conn.Conn.Hijack()) +} + +// Tx wraps [pgx.Tx] into a [gsql.Handle]. +// +// Because this type has [pgx.Tx] as an embedded field, +// all methods from that type work on this type as well. +type Tx struct { + pgx.Tx + gsql.Handle +} + +// NewTx wraps an instance of [pgx.Tx] into the [Tx] type that implements [Handle]. +func NewTx(tx pgx.Tx) *Tx { + return &Tx{tx, txHandle{tx}} +} + +// Conn is like the Conn() method of [pgx.Tx], but wraps the resulting connection into a [Handle]. +func (t *Tx) Conn() *Conn { + return maybe(NewConn, t.Tx.Conn()) +} + +func maybeNewTx(tx pgx.Tx) *Tx { + if tx == nil { + return nil + } + return NewTx(tx) +} + +func maybe[T, U any](wrap func(*T) *U, value *T) *U { + if value == nil { + return nil + } + return wrap(value) +} |
