This library provides a convenient wrapper around the pgx library developed by Jack Christensen. It simplifies database interactions with PostgreSQL by allowing easy scanning of query results into nested Go structures and slices.
If you've ever encountered the inconvenience of scanning and retrieving lists with pgx
, this tool allows you to fully enjoy the pgx
library by simplifying these operations.
- Easy Scanning into Nested Structures: Automatically maps SQL query results to Go structs, including nested structs.
- Convenient Handling of Slices: Supports scanning multiple rows into slices of structs or pointers to structs.
- Transaction Support: Provides wrappers for transactional operations with methods for beginning, committing, and rolling back transactions.
- Integration with pgx: Built on top of the high-performance pgx PostgreSQL driver, leveraging its robust features and reliability.
And even Jacks has mentioned this lib here.
- PgxWrappy
Documentation can be found here.
To use this library, you need to have Go installed and set up. Import the package into your project:
go get -u github.com/Arlandaren/pgxWrappy
import "github.com/Arlandaren/pgxWrappy/pkg/postgres"
First, you need to initialize a connection pool using pgxpool
and then create a new wrapper instance.
import (
"context"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/Arlandaren/pgxWrappy/pkg/postgres"
)
func main() {
ctx := context.Background()
pool, err := pgxpool.New(ctx, "postgres://username:password@localhost:5432/database")
if err != nil {
// Handle error
}
dbWrapper := pgxwrappy.NewWrapper(pool)
// Use dbWrapper for database operations
}
You can execute queries using the QueryRow
, Query
, and Exec
methods, which are wrappers around the corresponding pgx
methods.
// Executing a query that returns a single row
row := dbWrapper.QueryRow(ctx, "SELECT id, name FROM users WHERE id=$1", userID)
// Executing a query that returns multiple rows
rows, err := dbWrapper.Query(ctx, "SELECT id, name FROM users")
// Executing a command that doesn't return rows
_, err := dbWrapper.Exec(ctx, "UPDATE users SET name=$1 WHERE id=$2", newName, userID)
The Get
method executes a query that is expected to return a single row and scans the result into a struct.
type User struct {
ID int `db:"id"`
Name string `db:"name"`
}
var user User
err := dbWrapper.Get(ctx, &user, "SELECT id, name FROM users WHERE id=$1", userID)
if err != nil {
// Handle error
}
// Use the 'user' struct
The Select
method executes a query that returns multiple rows and scans the results into a slice of structs.
var users []User
err := dbWrapper.Select(ctx, &users, "SELECT id, name FROM users")
if err != nil {
// Handle error
}
// Use the 'users' slice
You can perform transactional operations using the Begin
, BeginTx
, Commit
, and Rollback
methods.
txWrapper, err := dbWrapper.Begin(ctx)
if err != nil {
// Handle error
}
defer func() {
if err != nil {
txWrapper.Rollback(ctx)
} else {
txWrapper.Commit(ctx)
}
}()
// Perform transactional operations using txWrapper
err = txWrapper.Exec(ctx, "UPDATE accounts SET balance=balance-$1 WHERE id=$2", amount, fromAccountID)
if err != nil {
return err
}
err = txWrapper.Exec(ctx, "UPDATE accounts SET balance=balance+$1 WHERE id=$2", amount, toAccountID)
if err != nil {
return err
}
Note: To ensure correct scanning of query results into your structs, it's important to use the db
struct tags to match the column names in your database. The tags should correspond exactly to the column names or use appropriate mapping if the names differ.
type User struct {
ID int `db:"id"`
FirstName string `db:"first_name"`
LastName string `db:"last_name"`
Email string `db:"email"`
}
For nested structs, the field tags are used to flatten the structure during scanning.
type Address struct {
Street string `db:"street"`
City string `db:"city"`
ZipCode string `db:"zip_code"`
}
type User struct {
ID int `db:"id"`
Name string `db:"name"`
Address Address `db:"-"`
}
In your SQL query, you should alias the columns appropriately:
SELECT
id,
name,
street,
city,
zip_code
FROM users
This ensures that the scanning process correctly maps the SQL result columns to the fields in your nested structs.
- It is also possible to give a tag
db:"address"
, then the expected columns in the query would be:address_street
,address_city
,address_zip_code
When working with PostgreSQL in Go, developers have several driver options to choose from. pgx
stands out among other drivers for several reasons, and pgxWrappy
addresses some of the common inconveniences developers face.
- Description: Go's standard library interface for SQL databases.
- Pros:
- Familiar interface for Go developers.
- Supports multiple database backends.
- Cons:
- Requires driver-specific implementations for full PostgreSQL features.
- Less performant due to generalized abstractions.
- Limited support for PostgreSQL-specific data types and features.
- Inconvenient Scanning: Requires manual scanning of rows into variables, leading to verbose and repetitive code.
- Description: Pure Go driver for PostgreSQL, compatible with
database/sql
. - Pros:
- Simple and reliable for basic operations.
- Widely used and tested.
- Cons:
- No longer actively developed with new features.
- Limited performance optimizations.
- Doesn't support advanced PostgreSQL features out of the box.
- Inefficient Scanning: Similar to
database/sql
, scanning rows can be cumbersome and boilerplate-heavy.
- Description: High-performance PostgreSQL driver and toolkit for Go, developed by Jack Christensen.
- Pros:
- Best-in-Class Performance: Optimized for speed and efficiency.
- Full PostgreSQL Feature Support: Access to advanced data types and protocols.
- Active Development: Regular updates and community support.
- Flexibility: Can be used with or without
database/sql
.
- Cons:
- Slightly steeper learning curve due to extensive features.
- Inconvenient Scanning of Nested Structures: While
pgx
is powerful, scanning query results into complex nested structs or slices requires manual code and can be cumbersome.
pgx
is the best option for Go developers working with PostgreSQL, offering superior performance, comprehensive feature support, and active maintenance.
By using pgx
in conjunction with pgxWrappy
, you further enhance your development experience:
- Ease of Development: Simplified scanning of query results into nested structures without boilerplate code.
- Enhanced Productivity: Focus on application logic rather than handling complex data mappings.
- High Performance: Leverage
pgx
's speed while enjoying a more convenient API. - Seamless Transactions: Intuitive methods for managing database transactions.
Example Usage with pgxWrappy
:
import (
"context"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/Arlandaren/pgxWrappy/pkg/postgres"
)
func main() {
ctx := context.Background()
pool, err := pgxpool.New(ctx, "postgres://username:password@localhost:5432/database")
if err != nil {
// Handle error
}
dbWrapper := pgxwrappy.NewWrapper(pool)
// Use dbWrapper for database operations
// And other methods see above.
}
By choosing pgx
paired with pgxWrappy
, you embrace the most efficient and developer-friendly tools for PostgreSQL in Go. This combination allows you to fully enjoy the capabilities of pgx
, making your database interactions smoother and more effective.
If you've ever encountered the inconvenience of scanning and retrieving lists with pgx
, this tool allows you to fully enjoy the pgx
library by simplifying these operations. By focusing on convenient scanning of nested structures and slices, this library aims to make database operations in Go more straightforward and efficient. It addresses common pain points that developers face when dealing with database interactions, especially the boilerplate code required for scanning query results into complex data structures.
Using this library, you can reduce code redundancy, improve readability, and maintain high performance in your applications. It's an excellent choice for developers who need more than what the standard library offers but prefer to avoid the overhead of a full ORM.
Note: This library builds upon the pgx PostgreSQL driver for Go, developed by Jack Christensen. Special thanks to him for creating and maintaining such a high-performance and feature-rich driver.
Contributions are welcome! If you find a bug or want to add a feature, please open an issue or submit a pull request on GitHub.
This project is licensed under the MIT License. See the LICENSE file for details.
By integrating pgxWrappy
into your projects, you streamline your database interactions and harness the full power of pgx
with added convenience. Give it a try and experience more efficient and enjoyable database programming in Go, just take a first step