Idiomatic Go and the hardship of running two methods in the same DB transaction
Tags: help, go
Published: 2018-03-31 22:03:46

---
title: Idiomatic Go and the hardship of running two methods in the same DB transaction
published: true
tags: help, golang
---

In the effort of learning Go a bit better, I am trying to refactor a series of functions which accept a DB connection as the first argument into struct methods and something a bit more "idiomatically" Go.

Right now my "data store" methods are something like this:

```go
func CreateA(db orm.DB, a *A) error {
    db.Exec("INSERT...")
}

func CreateB(db orm.DB, b *B) error {
    db.Exec("INSERT...")
}
```

These the functions work perfectly fine. `orm.DB` is the [DB interface of go-pg](https://godoc.org/github.com/go-pg/pg/orm#DB).

Since the two functions accept a db connection I can either pass an actual connection or a [transaction](https://godoc.org/github.com/go-pg/pg#Tx) (which implements the same interface). I can be sure that both functions issuing SQL INSERTs run in the same transaction, avoiding having inconsistent state in the DB in case either one of them fails.

The trouble started when I decided to read more about how to structure the code a little better and to make it "mockable" in case I need to. 

So I googled a bit, read the article [Practical Persistence in Go: Organising Database Access](http://www.alexedwards.net/blog/organising-database-access) and tried to refactor the code to use proper interfaces.

The result is something like this:

```golang
type Store {
    CreateA(a *A) error
    CreateB(a *A) error
}

type DB struct {
    orm.DB
}

func NewDBConnection(p *ConnParams) (*DB, error) {
    .... create db connection ...
    return &DB{db}, nil
}

func (db *DB) CreateA(a *A) error {
...
}

func (db *DB) CreateB(b *B) error {
...
}
```

which allows me to write code like:

```go
db := NewDBConnection()
DB.CreateA(a)
DB.CreateB(b)
```

instead of:

```go
db := NewDBConnection()
CreateA(db, a)
CreateB(db, b)
```

The actual issue is that I lost the ability to run the two functions in the same transaction. Before I could do:

```go
pgDB := DB.DB.(*pg.DB) // convert the interface to an actual connection
pgDB.RunInTransaction(func(tx *pg.Tx) error {
    CreateA(tx, a)
    CreateB(tx, b)
})
```

or something like:

```go
tx := db.DB.Begin()

err = CreateA(tx, a)
err = CreateB(tx, b)

if err != nil {
  tx.Rollback()
} else {
  tx.Commit()
}
```

which is more or less the same thing.

Since the functions were accepting the common interface between a connection and a transaction I could abstract from my model layer the transaction logic sending down either a full connection or a transaction. This allowed me to decide in the "HTTP handler" when to create a trasaction and when I didn't need to.

Keep in mind that the connection is a global object representing a pool of connections handled automatically by go, so the hack I tried:


```go
pgDB := DB.DB.(*pg.DB) // convert the interface to an actual connection
err = pgDB.RunInTransaction(func(tx *pg.Tx) error {
    DB.DB = tx // replace the connection with a transaction
    DB.CreateA(a)
    DB.CreateB(a)
})
```

it's clearly a bad idea, because although it works, it works only once because we replace the global connection with a transaction. The following request breaks the server.

I broke my server trying to improve the code quality basically :-D

Any ideas? I can't find information about this around, probably because I don't know the right keywords :-D