txdb

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2024 License: BSD-3-Clause Imports: 7 Imported by: 60

README

Build Status GoDoc

Single transaction based sql.Driver for GO

Package txdb is a single transaction based database sql driver. When the connection is opened, it starts a transaction and all operations performed on this sql.DB will be within that transaction. If concurrent actions are performed, the lock is acquired and connection is always released the statements and rows are not holding the connection.

Why is it useful. A very basic use case would be if you want to make functional tests you can prepare a test database and within each test you do not have to reload a database. All tests are isolated within transaction and though, performs fast. And you do not have to interface your sql.DB reference in your code, txdb is like a standard sql.Driver.

This driver supports any sql.Driver connection to be opened. You can register txdb for different sql drivers and have it under different driver names. Under the hood whenever a txdb driver is opened, it attempts to open a real connection and starts transaction. When close is called, it rollbacks transaction leaving your prepared test database in the same state as before.

Given, you have a mysql database called txdb_test and a table users with a username column.

package main

import (
    "database/sql"
    "log"

    "github.com/DATA-DOG/go-txdb"
    _ "github.com/go-sql-driver/mysql"
)

func init() {
    // we register an sql driver named "txdb"
    txdb.Register("txdb", "mysql", "root@/txdb_test")
}

func main() {
    // dsn serves as an unique identifier for connection pool
    db, err := sql.Open("txdb", "identifier")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    if _, err := db.Exec(`INSERT INTO users(username) VALUES("gopher")`); err != nil {
        log.Fatal(err)
    }
}

You can also use sql.OpenDB (added in Go 1.10) rather than registering a txdb driver instance, if you prefer:

package main

import (
    "database/sql"
    "log"

    "github.com/DATA-DOG/go-txdb"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    db := sql.OpenDB(txdb.New("mysql", "root@/txdb_test"))
    defer db.Close()

    if _, err := db.Exec(`INSERT INTO users(username) VALUES("gopher")`); err != nil {
        log.Fatal(err)
    }
}

Every time you will run this application, it will remain in the same state as before.

Testing

Usage is mainly intended for testing purposes. Tests require database access, support using postgres and mysql databases. The easiest way to do this is by using testcontainers, which is enabled by setting the respective database DSN values to AUTO. Example:

MYSQL_DSN=AUTO PSQL_DSN=AUTO go test ./...

If you wish to use a running local database instance, you can also provide the DSN directly, and it will be used:

MYSQL_DSN=root:pass@/ PSQL_DSN=postgres://postgres:pass@localhost/ go test ./...

To run tests only against MySQL or PostgreSQL, you may provide only the respective DSN values; any unset DSN is skipped for tests.

Documentation

See godoc for general API details. See .travis.yml for supported go versions.

Contributions

Feel free to open a pull request. Note, if you wish to contribute an extension to public (exported methods or types) - please open an issue before to discuss whether these changes can be accepted. All backward incompatible changes are and will be treated cautiously.

The public API is locked since it is an sql.Driver and will not change.

License

txdb is licensed under the three clause BSD license

Documentation

Overview

Package txdb is a single transaction based database/sql/driver implementation. When the connection is opened, it starts a transaction and all operations performed on the returned database/sql.DB will be within that transaction. If concurrent actions are performed, the lock is acquired and connection is always released the statements and rows are not holding the connection.

Why is it useful? A very basic use case would be if you want to make functional tests, you can prepare a test database and within each test you do not have to reload a database. All tests are isolated within a transaction and execute fast. And you do not have to interface your database/sql.DB reference in your code, txdb is like a standard database/sql/driver.Driver.

This driver supports any database/sql/driver.Driver connection to be opened. You can register txdb for different drivers and have it under different driver names. Under the hood whenever a txdb driver is opened, it attempts to open a real connection and starts transaction. When close is called, it rollbacks transaction leaving your prepared test database in the same state as before.

Example, assuming you have a mysql database called txdb_test and a table users with a username:

package main

import (
	"database/sql"
	"log"

	"github.com/DATA-DOG/go-txdb"
	_ "github.com/go-sql-driver/mysql"
)

func init() {
	// we register an sql driver named "txdb"
	txdb.Register("txdb", "mysql", "root@/txdb_test")
}

func main() {
	// dsn serves as an unique identifier for connection pool
	db, err := sql.Open("txdb", "identifier")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec(`INSERT INTO users(username) VALUES("gopher")`); err != nil {
		log.Fatal(err)
	}
}

Every time you will run this application, it will remain in the same state as before.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New added in v0.1.8

func New(drv, dsn string, options ...func(*conn) error) driver.Connector

New returns a database/sql/driver.Connector, which can be passed to database/sql.OpenDB. This can be used in place of Register. It takes the same arguments as Register, with the omission of name.

func Register

func Register(name, drv, dsn string, options ...func(*conn) error)

Register registers a txdb sql driver under the given sql driver name which can be used to open a single transaction based database connection.

When Open is called any number of times it returns the same transaction connection.

Any Begin, Commit calls will not start or close the transaction. Instead the savepoint will be created, released, or rolled back. If your SQL driver does not support save points, use nil for the SavePointOption argument. If driver has non-default save point logic, you can override the default with SavePointOption.

When [Close] is called, the transaction is rolled back.

The drv dsn are passed to databse/sql.Open.

Note: if you open a secondary database, make sure to differentiate the dsn string when opening the driver/sql.DB. The transaction will be isolated within that dsn.

func SavePointOption added in v0.1.3

func SavePointOption(savePoint SavePoint) func(*conn) error

SavePointOption allows to modify the logic for transaction save points. In such cases if your driver does not support it, use nil. If not compatible with default use custom.

Types

type SavePoint added in v0.1.3

type SavePoint interface {
	Create(id string) string
	Release(id string) string
	Rollback(id string) string
}

SavePoint defines the syntax to create savepoints within transaction

type TxDriver added in v0.1.7

type TxDriver struct {
	sync.Mutex
	// contains filtered or unexported fields
}

TxDriver is a database/sql/driver.Driver implementation which runs on single transaction. When database/sql.DB.Close is called, transaction is rolled back.

func (*TxDriver) DB added in v0.1.7

func (d *TxDriver) DB() *sql.DB

func (*TxDriver) Open added in v0.1.7

func (d *TxDriver) Open(dsn string) (driver.Conn, error)

func (*TxDriver) OpenConnector added in v0.1.8

func (d *TxDriver) OpenConnector(name string) (driver.Connector, error)

OpenConnector satisfies the database/sql/driver.DriverContext interface.

Jump to

Keyboard shortcuts

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