doug-martin / goqu

SQL builder and query library for golang
http://doug-martin.github.io/goqu/
MIT License
2.39k stars 206 forks source link

v7 api changed: how to new TxDatabase #95

Closed chen56 closed 5 years ago

chen56 commented 5 years ago

in goqu.v5, i can use goqu.TxDatabase{...} create a goqu tx, but v7 how to do this :

func inTx_goqu_v5(sqlxTx *sqlx.Tx, txFunc func(tx *Tx) error) (err error) {
    tx := &Tx{sqlxTx, &goqu.TxDatabase{Dialect: sqlxTx.DriverName(), Tx: sqlxTx.Tx}}
    defer func() {
        if r := recover(); r != nil {
            //已在一个panic中,不理会Rollback的err
            err := tx.Rollback()
            logrus.Error(err)
            // re-throw panic after Rollback
            panic(r)
        }
        if err != nil {
            //err已非空,不理会Rollback的err
            err := tx.Rollback()
            logrus.Error(err)
            return
        }
        // err==nil, commit; 如果commit失败,则返回err
        err = tx.Commit()
    }()

    err = txFunc(tx)

    return err
}
doug-martin commented 5 years ago

The standard way of using this library for that would be to use db.Begin() however it looks like you're using sqlx, which is probably why you can't.

If I changed goqu to accept a interface ( since sqlx.DB and Tx both keep the same contract as sql.DB) when creating a goqu.Database would that suit your needs?

doug-martin commented 5 years ago

I added the change I described in my previous comment. This should allow you to create a new goqu db instance with your sqlx instance. From there you can just do db.From to get a new transaction instance.

Let me know if this helps!

chen56 commented 5 years ago

thanks, You're so quick!

I have some Legacy Code (sqlx and goqu.v5) , mixture use sqlx and goqu.v5 in one tx

like this :


import (
    "context"
    "database/sql"
    "github.com/jmoiron/sqlx"
    "github.com/sirupsen/logrus"
    "gopkg.in/doug-martin/goqu.v5"
    _ "gopkg.in/doug-martin/goqu.v5/adapters/mysql"
)

func XXXXXXQuery(){
        mydatebase:=NewDb(sqlx.MustConnect("mysql", "localhost:3306................"))
    err = mydatebase.InTxContext(ctx, &sql.TxOptions{ReadOnly: true}, func(myTx *mysqlx.Tx) error {
               //use sqlx tx
               row := tx.Tx.QueryRowx("select * from abc")
               ...

               // use goqu Tx
            found, err := tx.Goqu.From(goqu.I("abc").As("c")).Select("c.xxx").ScanStruct(&res)
               ...
        return err
    })

}        

// DB ext
type DB struct {
    DB   *sqlx.DB
    Goqu *goqu.Database
}

// Tx ext
type Tx struct {
    Tx   *sqlx.Tx
    Goqu *goqu.TxDatabase
}

// NewDb  
func NewDb(db *sqlx.DB) *DB {
    return &DB{
        DB:   db,
        Goqu: goqu.New("mysql", db.DB),
    }
}

// InTxContext  
func (db *DB) InTxContext(ctx context.Context, opts *sql.TxOptions, txFunc func(tx *Tx) error) (err error) {
    tx, err := db.DB.BeginTxx(ctx, opts)
    if err != nil {
        return
    }
    return inTx(tx, txFunc)
}

//InTx ref: https://stackoverflow.com/questions/16184238/database-sql-tx-detecting-commit-or-rollback
func (db *DB) InTx(txFunc func(tx *Tx) error) (err error) {
    tx, err := db.DB.Beginx()
    if err != nil {
        return
    }
    return inTx(tx, txFunc)
}

func inTx(sqlxTx *sqlx.Tx, txFunc func(tx *Tx) error) (err error) {
    tx := &Tx{sqlxTx, &goqu.TxDatabase{Dialect: sqlxTx.DriverName(), Tx: sqlxTx.Tx}}
    defer func() {
        if r := recover(); r != nil {
            //已在一个panic中,不理会Rollback的err
            err := tx.Tx.Rollback()
            logrus.Error(err)
            // re-throw panic after Rollback
            panic(r)
        }
        if err != nil {
            //err已非空,不理会Rollback的err
            err := tx.Tx.Rollback()
            logrus.Error(err)
            return
        }
        // err==nil, commit; 如果commit失败,则返回err
        err = tx.Tx.Commit()
    }()

    err = txFunc(tx)

    return err
}

in goqu.v7 , I saw your new code,Still unable to do this:

    goquTx, err := db.Goqu.Begin()
    if err != nil {
        return
    }
        myTx:=Tx{
             Tx:   ?????,  //  sqlx.Tx:    sqlx  also does not support NewTx(otherTx)
             goqu: goquTx,
        }
doug-martin commented 5 years ago

Ok I added a goqu.NewTx function which you should be able to pass in the sqlx.Tx into to create a new goqu.TxDatabase