SQLC e Transação
O que é uma transação? – Uma transação é um conjunto de operações SQL que são tratadas como uma única unidade de trabalho. Ou todas as operações são aplicadas com sucesso, ou nenhuma delas é aplicada. O objetivo é garantir a consistência dos dados.
No nosso post anterior vimos sobre SQLC e Migração, agora falamos ver como fazer uma transação em SQLC.
Crie na pasta cmd a pasta execSQLCTX e adicone um arquivo main.go, feito isso só analisarmos o código do main.go:
package main
import (
"context"
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/google/uuid"
"github.com/rafaelsouzaribeiro/sqlc/internal/db"
)
type Library struct {
dbConn *sql.DB
*db.Queries
}
func NewLibrary(dbConn *sql.DB) *Library {
return &Library{
dbConn: dbConn,
Queries: db.New(dbConn),
}
}
type Author struct {
ID string
Name string
Bio sql.NullString
}
type Books struct {
ID string
Name string
Description sql.NullString
AuthorsID string
Price float64
}
func (c *Library) callTx(ctx context.Context, fn func(*db.Queries) error) error {
tx, err := c.dbConn.BeginTx(ctx, nil)
if err != nil {
return err
}
qtx := c.WithTx(tx)
err = fn(qtx)
if err != nil {
if errRb := tx.Rollback(); errRb != nil {
return fmt.Errorf("error on rollback: %v, original error: %w", errRb, err)
}
return err
}
return tx.Commit()
}
func (c *Library) CreateAuthorAndBook(ctx context.Context, argsAuthor Author, argsBook Books) error {
if argsAuthor.ID == "" || argsAuthor.Name == "" {
return fmt.Errorf("author ID and Name are required")
}
if argsBook.Name == "" || argsBook.AuthorsID == "" || argsBook.Price == 0 {
return fmt.Errorf("book ID, Name, AuthorsID and Price are required")
}
err := c.callTx(ctx, func(q *db.Queries) error {
var err error
err = q.CreateAuthor(ctx, db.CreateAuthorParams{
ID: argsAuthor.ID,
Name: argsAuthor.Name,
Bio: argsAuthor.Bio,
})
if err != nil {
return err
}
err = q.CreateBook(ctx, db.CreateBookParams{
ID: argsBook.ID,
Name: argsBook.Name,
Description: argsBook.Description,
AuthorsID: argsBook.AuthorsID,
Price: argsBook.Price,
})
if err != nil {
return err
}
return nil
})
if err != nil {
return err
}
return nil
}
func main() {
ctx := context.Background()
dbConn, err := sql.Open("mysql", "root:root@tcp(localhost:3306)/library")
if err != nil {
panic(err)
}
defer dbConn.Close()
queries := db.New(dbConn)
authorArgs := Author{
ID: uuid.New().String(),
Name: "John Doe",
Bio: sql.NullString{String: "Author Bio", Valid: true},
}
bookArgs := Books{
ID: uuid.New().String(),
Name: "Go",
Description: sql.NullString{String: "Go Course", Valid: true},
AuthorsID: authorArgs.ID,
Price: 24.99,
}
library := NewLibrary(dbConn)
err = library.CreateAuthorAndBook(ctx, authorArgs, bookArgs)
if err != nil {
panic(err)
}
books, err := queries.ListBooks(ctx)
if err != nil {
panic(err)
}
for _, book := range books {
println("Book:", book.Name, "Author:", book.AuthorName, "Price:", book.Price)
}
}Veja que nossa função callTx fica com a obrigação de verificar se os nossos comandos estão todos corretos antes de inserir qualquer comando SQL. Agora é só executar o arquivo main.go e está feito nossa transação.

0 comentários