Fred Hors
Fred Hors

Reputation: 4156

A way to not write long defer using the latest err value?

I have this code that works.

func (r *repoPG) WithTransaction(txFunc func() error) (err error) {
    tx := db.NewTx()

    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("panic: %v", r)
            tx.Rollback()
        } else if err != nil {
            tx.Rollback()
        } else {
            tx.Commit()
        }
    }()

    err = txFunc()
    return
}

I want to avod every time to write that long defer, so I'm trying to write a func like this:

func TxDefer(tx, err) {
  if r := recover(); r != nil {
    err = fmt.Errorf("panic: %v", r)
    tx.Rollback()
  } else if err != nil {
    tx.Rollback()
  } else {
    tx.Commit()
  }
}

using it like:

func (r *repoPG) WithTransaction(txFunc func() error) (err error) {
    tx := db.NewTx()

    defer TxDefer(tx, err)

    err = txFunc()
    return
}

But this is miserably incorrect because the err it's always the original one, not the result of txFunc(), right?

How can I fix this?

Upvotes: 1

Views: 350

Answers (1)

user13631587
user13631587

Reputation:

Pass the address of the error to the function. This allows the function to access the current value of the caller's variable. It also allows function to set the variable.

Rollback and Commit return errors. These errors should be returned to the caller.

func TxDefer(tx Transaction, perr *error) {
  if r := recover(); r != nil {
    *perr = fmt.Errorf("panic: %v", r)
    tx.Rollback()
  } else if *perr != nil {
    err = tx.Rollback()
    if err != nil {
       // replace original error with rollback error
       *perr = err
    }
  } else {
    *perr = tx.Commit()
  }
}

Use it like this:

func (r *repoPG) WithTransaction(txFunc func() error) (err error) {
    tx := db.NewTx()
    defer TxDefer(tx, &err)
    err = txFunc()
    return
}

In the code above, the expression *perr evaluates to the current value of err in WithTransaction. The value of err in the question is the value of err at the time of the defer.

Upvotes: 3

Related Questions