Skip to content

Instantly share code, notes, and snippets.

@hielfx
Last active March 2, 2023 15:24
Show Gist options
  • Save hielfx/4469d35127d085fc3501d483e34d4bad to your computer and use it in GitHub Desktop.
Save hielfx/4469d35127d085fc3501d483e34d4bad to your computer and use it in GitHub Desktop.
Generic interface for using both sqlx.DB and sqlx.Tx independently. E.g. if you want to use a transaction or not but want the possibility to use both any time
package domain
import (
"context"
"database/sql"
"github.com/jmoiron/sqlx"
)
//SQLDB An interface to use for both sqlx.DB and sqlx.Tx (to use a transaction or not)
type SQLDB interface {
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)
QueryRowx(query string, args ...interface{}) *sqlx.Row
QueryRowxContext(ctx context.Context, query string, args ...interface{}) *sqlx.Row
Queryx(query string, args ...interface{}) (*sqlx.Rows, error)
QueryxContext(ctx context.Context, query string, args ...interface{}) (*sqlx.Rows, error)
Rebind(query string) string
Select(dest interface{}, query string, args ...interface{}) error
SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error
}
@hielfx
Copy link
Author

hielfx commented Mar 26, 2020

Usage example:

Imagine the following function:

func CreateUser(db SQLDB, user User) (*uint64, error){
    query := `INSERT INTO user VALUES (...)`
	stmt, err := db.PrepareNamed(query)
	if err != nil {
		return nil, err
	}

	res, err := stmt.Exec(&user)
	if err != nil {
		return nil, err
	}

	id, err := res.LastInsertId()
	if err != nil {
		return nil, err
	}

	result := uint64(id)
	return &result, nil
}

You can use it without transaction:

    // Open the connection
    db := sqlx.MustConnect("mysql", databaseURL)

    user := User {
        //...
    }
    if _, err := CreateUser(db, user); err != nil{
        panic(err)
    }

Or with a previously created transaction:

    var err error

    // Open the connection
    db := sqlx.MustConnect("mysql", databaseURL)

    // Create the transaction
    tx := db.MustBegin()

     user := User {
        //...
    }
    if _, err = CreateUser(tx, user); err != nil{
        tx.Rollback()
        panic(err)
    }

    // More database operations with the transaction...

    // Commit the transaction
    if err = tx.Commit(); err != nil{
        panic(err)
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment