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

Generic *sqlx.DB or *sqlx.Tx? #344

Closed
mewben opened this issue Jul 27, 2017 · 6 comments
Closed

Generic *sqlx.DB or *sqlx.Tx? #344

mewben opened this issue Jul 27, 2017 · 6 comments

Comments

@mewben
Copy link

mewben commented Jul 27, 2017

Hi, is there a way I could accept a parameter which is either sqlx.DB or sqlx.Tx?

I have this function wherein I have to pass *sqlx.DB:

func GetUser(db *sqlx.DB, username string) ...

There's no problem with this, until I create a new Transaction and inside that transaction, I need to call GetUser. So I ended up implementing 2 functions to provide the same result...

func GetUser2(tx *sqlx.Tx, username string) ...

Is there a way I can make this into 1 function? I tried this:

func GetUser(db *sqlx.DB, tx *sqlx.Tx, username string) (*User, error) {
  if tx != nil {
    // use tx
  } else {
    // use db
  }
  ...
}

but is this okay? I wish there is something like this:

func GetUser(db *sqlx.DBorTxSomething, ...

:)

@jhngrant
Copy link

@mewben This is consistent with *sql.Tx and *sql.DB in the standard library.

Over in golang-nuts, @davecheney suggests defining your own interface.

See: https://groups.google.com/forum/#!topic/golang-nuts/yLg6IWbwPPw

@alhails
Copy link

alhails commented Jul 27, 2017

@mewben I've achieved this by creating an interface that covers the sqlx methods I need and then creating two implementations that wrap sqlx.DB and sqlx.Tx respectively. Then your GetUser method can accept that interface instead of the concrete types.

@eexit
Copy link

eexit commented Jul 27, 2017

Hey, you need to create a common interface that is used by both *sqlx.DB and *sqlx.Tx.
Example:

type DB interface {
	Querier
	Begin() (Tx, error)
	Close() error
}

type Tx interface {
	Querier
	Commit() error
	Rollback() error
}

type Querier interface {
	QueryRow(query string, args ...interface{}) Row
	Select(dest interface{}, query string, args ...interface{}) error
	NamedQuery(query string, arg interface{}) (Rows, error)
	NamedExec(query string, arg interface{}) (sql.Result, error)
}


func GetUser(q *Querier, username string) {}

But of course, it requires you to wrap sqlx :)

@mewben
Copy link
Author

mewben commented Jul 27, 2017

Ahhh.. I get it now.. Thank you all...

@mewben mewben closed this as completed Jul 27, 2017
@tj
Copy link

tj commented May 9, 2019

I'd still love to see this, bit of a pain to need yet-another layer. It'd be easy to argue it's not sqlx's concern, but sqlx exists to provide convenience so it seems fine to me.

@wubin1989
Copy link

Hey, you need to create a common interface that is used by both *sqlx.DB and *sqlx.Tx.
Example:

type DB interface {
	Querier
	Begin() (Tx, error)
	Close() error
}

type Tx interface {
	Querier
	Commit() error
	Rollback() error
}

type Querier interface {
	QueryRow(query string, args ...interface{}) Row
	Select(dest interface{}, query string, args ...interface{}) error
	NamedQuery(query string, arg interface{}) (Rows, error)
	NamedExec(query string, arg interface{}) (sql.Result, error)
}


func GetUser(q *Querier, username string) {}

But of course, it requires you to wrap sqlx :)

Thank you for your advice. I written a wrapper of *sqlx.DB and *sqlx.Tx in my open source microservice framework go-doudou. Here is the link: https://github.com/unionj-cloud/go-doudou/blob/main/ddl/wrapper.go. Hope to help others.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants