-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Description
Hello,
sqlUnit is strongly connected with database/sql because of *sql.Tx.
However, sql.Tx could be placed in an interface with Begin, Commit and Rollback functions.
That gives the ability to change databases without changes the unit implementation.
What do you think about the idea?
interface{} version
package main
import (
"context"
"database/sql"
"github.com/DATA-DOG/go-sqlmock"
)
type TrM interface {
Do(ctx context.Context, fn func(ctx context.Context, tx interface{}) error) error
}
type Mapper interface {
Insert(ctx context.Context, tx interface{}, additions ...interface{}) error
}
type trm struct {
db *sql.DB
}
func (t trm) Do(ctx context.Context, fn func(ctx context.Context, tx interface{}) error) error {
tx, _ := t.db.BeginTx(ctx, nil)
defer tx.Commit()
return fn(ctx, tx)
}
type sqlMapper struct{}
func (s sqlMapper) Insert(_ context.Context, txAny interface{}, _ ...interface{}) error {
tx, _ := txAny.(*sql.Tx)
_ = tx
// tx.Exec(...)
return nil
}
type unit struct {
trm TrM
mapper Mapper
additions []interface{}
}
func (u *unit) Save(ctx context.Context) error {
return u.trm.Do(ctx, func(ctx context.Context, tx interface{}) error {
return u.mapper.Insert(ctx, tx, u.additions...)
})
}
func main() {
db, mock, _ := sqlmock.New()
mock.ExpectBegin()
mock.ExpectCommit()
u := &unit{
trm: trm{db: db},
mapper: sqlMapper{},
}
u.Save(context.Background())
if err := mock.ExpectationsWereMet(); err != nil {
panic(err)
}
}
generic version
//go:build go1.18
// +build go1.18
package main
import (
"context"
"database/sql"
"github.com/DATA-DOG/go-sqlmock"
)
type TrM[Tx any] interface {
Do(ctx context.Context, fn func(ctx context.Context, tx Tx) error) error
}
type Mapper[Tx any] interface {
Insert(ctx context.Context, tx Tx, additions ...interface{}) error
}
type trm struct {
db *sql.DB
}
func (t trm) Do(ctx context.Context, fn func(ctx context.Context, tx *sql.Tx) error) error {
tx, _ := t.db.BeginTx(ctx, nil)
defer tx.Commit()
return fn(ctx, tx)
}
type record struct {
ID int
}
type recordMapper struct{}
func (r recordMapper) Insert(_ context.Context, _ *sql.Tx, _ ...interface{}) error {
return nil
}
type unit[Tx any] struct {
trm TrM[Tx]
mapper Mapper[Tx] // replace on map
additions []interface{}
}
func (u *unit[Tx]) Save(ctx context.Context) error {
return u.trm.Do(ctx, func(ctx context.Context, tx Tx) error {
return u.mapper.Insert(ctx, tx, u.additions...)
})
}
func main() {
db, mock, _ := sqlmock.New()
mock.ExpectBegin()
mock.ExpectCommit()
u := &unit[*sql.Tx]{
trm: trm{db: db},
mapper: recordMapper{},
}
u.Save(context.Background())
if err := mock.ExpectationsWereMet(); err != nil {
panic(err)
}
}
Metadata
Metadata
Assignees
Labels
No labels