Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some GoDoc updates and fixes #62

Merged
merged 1 commit into from
Mar 13, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 59 additions & 63 deletions db.go
Original file line number Diff line number Diff line change
@@ -1,53 +1,52 @@
/*
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.

Example:

package main

import (
"database/sql"
"log"

"github.com/DATA-DOG/go-txdb"
_ "github.com/go-sql-driver/mysql"
)
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 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()

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)
}
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.
*/
Expand Down Expand Up @@ -78,29 +77,25 @@ func New(drv, dsn string, options ...func(*conn) error) driver.Connector {
}
}

// Register a txdb sql driver under the given sql driver name
// which can be used to open a single transaction based database
// connection.
// 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.
// 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.
// In case if your SQL driver does not support save points - use nil
// for the SavePointOption argument. If driver has non default
// 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.
//
// Use drv (Driver) and dsn (DataSourceName) as the standard sql properties for
// your test database connection to be isolated within transaction.
// When [Close] is called, the transaction is rolled back.
//
// The drv and dsn are the same items passed into `sql.Open(drv, dsn)`.
// The drv dsn are passed to [databse/sql.Open].
//
// Note: if you open a secondary database, make sure to differianciate
// the dsn string when opening the sql.DB. The transaction will be
// isolated within that dsn
// 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 Register(name, drv, dsn string, options ...func(*conn) error) {
sql.Register(name, &TxDriver{
dsn: dsn,
Expand All @@ -123,8 +118,9 @@ type conn struct {
ctx interface{ Done() <-chan struct{} }
}

// TxDriver is an sql driver which runs on single transaction
// when the Close is called, transaction is rolled back
// TxDriver is a [database/sql/driver.Driver] implementation which runs on
// single transaction. When [database/sql.DB.Close] is called, transaction is
// rolled back.
type TxDriver struct {
sync.Mutex
db *sql.DB
Expand Down
Loading