sqalx

package module
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 7, 2024 License: MIT Imports: 6 Imported by: 2

README

⚠ Warning: This repository is considered inactive and no change will be made to it except for security updates.

sqalx

GoDoc Go Report Card

sqalx (pronounced 'scale-x') is a library built on top of sqlx that allows to seamlessly create nested transactions and to avoid thinking about whether or not a function is called within a transaction. With sqalx you can easily create reusable and composable functions that can be called within or out of transactions and that can create transactions themselves.

Getting started

$ go get github.com/heetch/sqalx
Import sqalx
import "github.com/heetch/sqalx"
Usage
package main

import (
	"log"

	"github.com/heetch/sqalx"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
)

func main() {
	// Connect to PostgreSQL with sqlx.
	db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}

	defer db.Close()

	// Pass the db to sqalx.
	// It returns a sqalx.Node. A Node is a wrapper around sqlx.DB or sqlx.Tx.
	node, err := sqalx.New(db)
	if err != nil {
		log.Fatal(err)
	}

	err = createUser(node)
	if err != nil {
		log.Fatal(err)
	}
}

func createUser(node sqalx.Node) error {
	// Exec a query
	_, _ = node.Exec("INSERT INTO ....") // you can use a node as if it were a *sqlx.DB or a *sqlx.Tx

	// Let's create a transaction.
	// A transaction is also a sqalx.Node.
	tx, err := node.Beginx()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	_, _ = tx.Exec("UPDATE ...")

	// Now we call another function and pass it the transaction.
	err = updateGroups(tx)
	if err != nil {
		return nil
	}

	return tx.Commit()
}

func updateGroups(node sqalx.Node) error {
	// Notice we are creating a new transaction.
	// This would normally cause a dead lock without sqalx.
	tx, err := node.Beginx()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	_, _ = tx.Exec("INSERT ...")
	_, _ = tx.Exec("UPDATE ...")
	_, _ = tx.Exec("DELETE ...")

	return tx.Commit()
}
PostgreSQL Savepoints

When using the PostgreSQL driver, an option can be passed to New to enable the use of PostgreSQL Savepoints for nested transactions.

node, err := sqalx.New(db, sqalx.SavePoint(true))

Issue

Please open an issue if you encounter any problem.

Development

sqalx is covered by a go test suite. In order to test against specific databases we include a docker-compose file that runs Postgres and MySQL.

Running all tests

To run the tests, first run docker-compose up to run both Postgres and MySQL in locally-exposed docker images. Then run your tests via make test which sets up the above described data sources and runs all tests.

Running specific tests

To test against the Postgres instance be sure to export the following DSN:

export POSTGRESQL_DATASOURCE="postgresql://sqalx:sqalx@localhost:5432/sqalx?sslmode=disable"

To test against the MySQL instance be sure to export the following DSN:

export MYSQL_DATASOURCE="sqalx:sqalx@tcp(localhost:3306)/sqalx"

To test against SQlite export the following DSN:

export SQLITE_DATASOURCE=":memory:"

Note: If you are developing on an M1 Mac you will need to use the officially supported by Oracle image rather than the default mysql:tag image. It is commented out in docker-compose.yml.

License

The library is released under the MIT license. See LICENSE file.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotInTransaction is returned when using Commit
	// outside of a transaction.
	ErrNotInTransaction = errors.New("not in transaction")

	// ErrIncompatibleOption is returned when using an option incompatible
	// with the selected driver.
	ErrIncompatibleOption = errors.New("incompatible option")
)

Functions

This section is empty.

Types

type Driver

type Driver interface {
	sqlx.Execer
	sqlx.ExecerContext
	sqlx.Queryer
	sqlx.QueryerContext
	sqlx.Preparer
	sqlx.PreparerContext
	BindNamed(query string, arg interface{}) (string, []interface{}, error)
	DriverName() string
	Get(dest interface{}, query string, args ...interface{}) error
	GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error
	MustExec(query string, args ...interface{}) sql.Result
	MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result
	NamedExec(query string, arg interface{}) (sql.Result, error)
	NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error)
	NamedQuery(query string, arg interface{}) (*sqlx.Rows, error)
	PrepareNamed(query string) (*sqlx.NamedStmt, error)
	PrepareNamedContext(ctx context.Context, query string) (*sqlx.NamedStmt, error)
	Preparex(query string) (*sqlx.Stmt, error)
	PreparexContext(ctx context.Context, query string) (*sqlx.Stmt, error)
	QueryRow(string, ...interface{}) *sql.Row
	QueryRowContext(context.Context, string, ...interface{}) *sql.Row
	Rebind(query string) string
	Select(dest interface{}, query string, args ...interface{}) error
	SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error
}

A Driver can query the database. It can either be a *sqlx.DB or a *sqlx.Tx and therefore is limited to the methods they have in common.

type Node

type Node interface {
	Driver

	// Close the underlying sqlx connection.
	Close() error
	// Begin a new transaction.
	Beginx() (Node, error)
	// Begin a new transaction using the provided context and options.
	// Note that the provided parameters are only used when opening a new transaction,
	// not on nested ones.
	BeginTxx(ctx context.Context, opts *sql.TxOptions) (Node, error)
	// Rollback the associated transaction.
	Rollback() error
	// Commit the assiociated transaction.
	Commit() error
	// Tx returns the underlying transaction.
	Tx() *sqlx.Tx
}

A Node is a database driver that can manage nested transactions.

func Connect

func Connect(driverName, dataSourceName string, options ...Option) (Node, error)

Connect to a database.

func New

func New(db *sqlx.DB, options ...Option) (Node, error)

New creates a new Node with the given DB.

func NewFromTransaction

func NewFromTransaction(tx *sqlx.Tx, options ...Option) (Node, error)

NewFromTransaction creates a new Node from the given transaction.

type Option

type Option func(*node) error

Option to configure sqalx

func SavePoint

func SavePoint(enabled bool) Option

SavePoint option enables PostgreSQL and SQLite Savepoints for nested transactions.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL