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)
}
}
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
generic version