STX is a lightweight Go package that provides context-based transaction management for GORM. It allows you to seamlessly integrate database transactions with Go's context package, making it easy to pass database connections and transactions through your application layers.
state (ctx) + transaction = stx
- Context-based transaction management: Embed GORM database instances in Go contexts
- Thread-safe operations: Concurrent access to database connections is handled safely
- Flexible transaction control: Support for both automatic and manual transaction management
- Graceful error handling: Commit/Rollback operations return nil when no transaction is active
- GORM integration: Works seamlessly with existing GORM code
- Zero dependencies: Only depends on GORM and standard Go libraries
- 100% test coverage: Comprehensive test suite with full coverage
go get github.com/restayway/stxpackage main
import (
"context"
"log"
"github.com/restayway/stx"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"not null"`
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
// Create context with database
ctx := stx.New(context.Background(), db)
// Use the context to get database connection
db = stx.Current(ctx)
// Auto-migrate
db.AutoMigrate(&User{})
// Create user
user := User{Name: "John Doe"}
db.Create(&user)
}// Automatic transaction management
err := stx.WithTransaction(ctx, func(txCtx context.Context) error {
txDB := stx.Current(txCtx)
// All operations within this function are in a transaction
user := User{Name: "Jane Doe"}
if err := txDB.Create(&user).Error; err != nil {
return err // Transaction will be rolled back
}
// Transaction will be committed if no error is returned
return nil
})// Begin transaction
txCtx := stx.Begin(ctx)
txDB := stx.Current(txCtx)
// Perform operations
user := User{Name: "Bob Smith"}
if err := txDB.Create(&user).Error; err != nil {
stx.Rollback(txCtx)
return err
}
// Commit transaction
if err := stx.Commit(txCtx); err != nil {
return err
}// Elegant defer pattern with automatic panic recovery and transaction handling
func demo(ctx context.Context) (err error) {
txCtx, cleanup := stx.WithDefer(ctx)
defer cleanup(&err)
db := stx.Current(txCtx)
// Create user
user := User{Name: "Alice"}
if err := db.Create(&user).Error; err != nil {
return err // Transaction will be rolled back
}
// Transaction will be committed automatically if no error
return nil
}if stx.IsTx(ctx) {
log.Println("Currently in a transaction")
} else {
log.Println("Not in a transaction")
}Creates a new context with the given GORM database instance.
Retrieves the current GORM database instance from the context. Returns nil if no database is found.
Executes the given function within a database transaction. The transaction is automatically committed if the function returns nil, or rolled back if it returns an error.
Begins a new database transaction and returns a new context with the transaction.
Commits the current transaction. Returns nil if no transaction is active (operations were performed directly without transactions).
Rolls back the current transaction. Returns nil if no transaction is active (operations were performed directly without transactions).
Begins a transaction and returns a context and cleanup function. The cleanup function should be called with defer and handles panic recovery and automatic commit/rollback based on the error state.
Returns true if the current context contains an active transaction.
STX provides graceful error handling for transaction operations:
- Commit/Rollback without transaction: When
Commit()orRollback()is called on a context without an active transaction, they returnnilinstead of an error. This design acknowledges that operations were performed directly without transactions. - Safe operation: This behavior allows for more flexible code patterns where you can safely call commit/rollback operations without checking if a transaction is active.
// Safe to call even if no transaction is active
ctx := stx.New(context.Background(), db)
err := stx.Commit(ctx) // Returns nil, no errorRun the test suite:
# Run tests
make test
# Run tests with coverage
make cover
# Run all checks (format, lint, test)
make checkWe welcome contributions! Please see our Contributing Guidelines for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- GORM for the excellent ORM library
- The Go community for inspiration and best practices