Skip to content

i4erkasov/go-pgsql

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-pgsql

build workflow PkgGoDev GitHub go.mod Go version Go Report Card GitHub release (latest SemVer)

go-pgsql is a comprehensive Go package that facilitates managing PostgreSQL connection pools, database migrations, and transaction management. It leverages the robust pgx library for pool management and golang-migrate for database migrations, providing a full suite of tools for working with PostgreSQL in Go applications.

Features

External Packages

This package uses the following external libraries:

Installation

go get -u github.com/i4erkasov/go-pgsql

Connection Pool Management

Using Viper for Configuration

pgsql:
  pgpool:
    default:
      nodes: [
        "postgres://user:password@127.0.0.1:5432/db?sslmode=disable&client_encoding=UTF8"
        "postgres://user:password@127.0.1.2:5432/db?sslmode=disable&client_encoding=UTF8"
        "postgres://user:password@127.1.1.3:5432/db?sslmode=disable&client_encoding=UTF8"
      ]
      max_conns: 5 # Default 4
      min_conns: 1 # Default 0
      max_conn_lifetime: "90m" # Default: 1 hour
      max_conn_idle_time: "31m" # Default: 30 minutes
      health_check_period: "1m" # Default: 1 minute
      lazy_conn: false # Optional
      prefer_simple_protocol: true # Optional
import (
    "github.com/spf13/viper"
    "github.com/i4erkasov/go-pgsql/pgxpool"
)

func main() {
    viper.SetConfigName("config")
    viper.AddConfigPath(".")
    viper.AutomaticEnv()

    err := viper.ReadInConfig()
    if err != nil {
        // Handle configuration read error
    }

    registry, err := pgxpool.NewWithViper(viper.GetViper())
    if err != nil {
        // Handle registry creation error
    }

    // Use the registry
}

Using Direct Configurations

import "github.com/i4erkasov/go-pgsql/pgxpool"

func main() {
    registry, err := pgxpool.NewWithConfigOptions(
        WithConfig(pgxpool.DEFAULT, Config{/* ... configuration params ... */}),
        WithConfig("pool1", Config{/* ... configuration params ... */}),
        WithConfig("pool2", Config{/* ... configuration params ... */}),
        // Other configuration...
    )

    if err != nil {
        // Handle registry creation error
    }
	
    //Use the registry
}

or

import "github.com/i4erkasov/go-pgsql/pgxpool"

func main() {
    config := pgxpool.Config{
    // Set your configuration here
    }

    registry, err := pgxpool.NewWithConfigs(map[string]pgxpool.Config{
        "default": config,
    })
    if err != nil {
        // Handle registry creation error
    }

    // Use the registry
}

Configuration Parameters

  • nodes: (Required): Array of database connection strings.
  • max_conns: Maximum number of connections in the pool (default: 4).
  • min_conns: Minimum number of connections in the pool (default: 0).
  • max_conn_lifetime: Maximum lifetime of a connection (default: 1 hour).
  • max_conn_idle_time: Maximum idle time of a connection (default: 30 minutes).
  • health_check_period: Frequency of health checks for idle connections (default: 1 minute).
  • lazy_conn: Whether to establish a new connection lazily (default: false).
  • prefer_simple_protocol: Whether to use simple protocol for new connections (default: false).
func main() {
    // ...
	
    // Use the registry
	
    pool, err := registry.Pools() // is DEFAULT pool getter
    // or
    pool1, err := registry.GetPoolName("pool1") // is pool getter by name.
    
    master := pool.Maser() // returns master connections pool
    slave := pool.Slave() // returns slave connections pool
}

Transaction Management

The package includes a sophisticated transaction manager that allows for simple and complex transactional operations, including support for nested transactions.

Using

Initializing TxManager

To manage transactions, you need to create an instance of TxManager by passing it a registry from the package "github.com/i4erkasov/go-pgsql/pgxpool". TxManager uses the connection pool provided through registry to manage transactions in your application.

import (
    "github.com/i4erkasov/go-pgsql/tx"
)

func main() {
    txManager, err := tx.NewTxManager(registry)
    if err != nil {
    // Handle error
    }

    // Use the txManager
}

TxManager offers WithTx and WithNestedTx methods to perform operations within the context of transactions. These methods simplify transaction management by automatically handling the start, completion, and rollback of transactions as necessary.

Executing Functions Within a Transaction

The WithTx method allows you to execute a function within the context of a transaction. It manages the lifecycle of the transaction automatically:

For detailed usage examples and more information, see the Transaction Management section in our README.

err := txManager.WithTx(ctx, func(ctx context.Context, tx pgx.Tx) error {
    // Perform your transactional operations here
	
    _, err = tx.Query(ctx, 'query', 'params ...')
    if err != nil {
        return err
    }
	
    // ...
	
    return nil
})

if err != nil {
    // Handle error
}

Executing Functions WithNestedTx a Transaction

For more complex scenarios involving nested transactions, use the WithNestedTx method:

err := txManager.WithNestedTx(ctx, func(ctx context.Context, tx pgx.Tx) error {
    // Perform operations within a nested transaction here

    _, err = tx.Query(ctx, 'query', 'params ...')
    if err != nil {
        return err 
    }

    txManager.WithNestedTx(ctx, func(ctx context.Context, tx pgx.Tx) error {
        _, err = tx.Query(ctx, 'query2', 'params ...')
        if err != nil {
            return err
        }

        return nil
    })

    // ...
	
    return nil
})
if err != nil {
    // Handle error
}

Migrate

Migrate is a Go package for managing database migrations, specifically designed for PostgreSQL using the pgx library.

Features

  • Easy setup and management of database migrations.
  • Support for PostgreSQL databases using golang-migrate.
  • Flexible configuration options through Viper or direct configuration.

Using

Creating a New Migrator

Using Direct Configuration

import (
    "github.com/i4erkasov/go-pgsql/migrate"
)

func main() {
    config := migrate.Config{
        Driver:          "postgres",
        DataSourceName:  "postgres://user:password@localhost:5432/dbname",
        PathMigration:   "migrations",
        Scheme:          "public",
        Table:           "migration",
        ConnMaxLifetime: 10 * time.Minute,
    }

    migrator, err := migrate.NewWithConfig(config)
    if err != nil {
        // Handle error
    }
}

Using Viper for Configuration

pgsql:
  migrations:
      driver: "postgres" # Default: "postgres"
      table: "migrations" # Default: "migrations"
      path: "migrations" # Default: "migrations"
      scheme: "public" # Default: "public"
      host: "127.0.0.1" # Required if not `dsn`
      port: "5432" # Required if not `dsn`
      user: "user" # Required if not `dsn`
      password: "password" # Required if not `dsn` 
      dbname: "db" # Required if not `dsn`
      conn_max_lifetime: '10m' # Default: 10 minutes
      options: # Optional
        sslmode: "disable" # Optional
        encoding: "UTF8" # Optional

or

pgsql:
  migrations:
      driver: "postgres" # Default: "postgres"
      table: "migrations" # Default: "migrations"
      path: "migrations" # Default: "migrations"
      scheme: "public" # Default: "public"
      dsn: "postgres://user:password@127.0.0.1:5432/db?sslmode=disable&client_encoding=UTF8"
      conn_max_lifetime: '10m' # Default: 10 minutes
import (
    "github.com/spf13/viper"
    "github.com/i4erkasov/go-pgsql/migrate"
)

func main() {
    viper.SetConfigName("config") // Name of config file (without extension)
    viper.AddConfigPath(".")      // Path to look for the config file in
    viper.AutomaticEnv()          // Automatically override values from environment variables

    migrator, err := migrate.NewWithViper(viper.GetViper())
    if err != nil {
        // Handle error
    }
}

Configuration Parameters

  • Driver: Database driver (default: "postgres").
  • DataSourceName: Data source name or DSN (required).
  • PathMigration: Path to migration files (default: "migrations").
  • Scheme: Database schema (default: "public").
  • Table: Migration table name (default: "migration").
  • ConnMaxLifetime: Maximum lifetime of database connections (default: 10 * time.Minute).

Applying and Reverting Migrations

err := migrator.Up(context.Background())
if err != nil {
    // Handle error
}
    
// To revert migrations
err = migrator.Down(context.Background(), 1) // Revert 1 step
if err != nil {
    // Handle error
}

An example of using migration with the cobra package

import (
    "errors"
    "github.com/i4erkasov/go-pgsql/migrate"
    "github.com/spf13/cobra"
    "golang.org/x/exp/slices"
)

const (
    MigrationCommand      = "sql-migrate"
    VersionMigrateService = "0.0.1"
    MigrationUpArg        = "up"
    MigrationDownArg      = "down"
)

var steps int // variable to store the number of steps

var sqlMigrate = &cobra.Command{
    Use:        MigrationCommand,
    Short:      "Run database migration",
    Version:    VersionMigrateService,
    Args:       cobra.MaximumNArgs(1),
    ArgAliases: []string{MigrationUpArg, MigrationDownArg},
    RunE: func(cmd *cobra.Command, args []string) (err error) {
        var migration migrate.SQLMigrator
        if migration, err = migrate.NewWithViper(cfg.Sub("app")); err != nil {
            return err
        }

        switch true {
        case slices.Contains(args, MigrationUpArg):
            return migration.Up(cmd.Context())
        case slices.Contains(args, MigrationDownArg):
            return migration.Down(cmd.Context(), steps)
        default:
            return errors.New("invalid argument. please specify 'up' or 'down' for migration")
        }
    },
}

func init() {
    sqlMigrate.Flags().IntVarP(&steps, "steps", "s", 1, "Number of steps to migrate down")

    cmd.AddCommand(sqlMigrate)
}

Contributing

Contributions to the go-pgsql package are welcome. Please submit pull requests to GitHub repository.

Licensed under the MIT License.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages