Packages
adapters
Concrete implementations of the contract interfaces. Each adapter satisfies a port — business logic never imports these directly.
adapter/gorm
defaultGORM v2 · satisfies contract.ORM
The default database adapter. All CLI-generated modules use contract.ORM and GORM queries out of the box.
import gormadapter "github.com/BounkhongDev/bkgo/adapter/gorm"
db, err := gormadapter.New(cfg.Postgres)
if err != nil {
log.Fatal(err)
}
defer db.Close()
// db satisfies contract.ORM
// db.Raw() returns *gorm.DB for AutoMigrate, etc.Using in a repository:
type userRepo struct{ db contract.ORM }
func (r *userRepo) FindByID(ctx context.Context, id string) (*User, error) {
var u User
err := r.db.Session(ctx).First(&u, "id = ?", id).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errs.NotFound("user not found")
}
return &u, err
}
func (r *userRepo) Create(ctx context.Context, u *User) error {
return r.db.Session(ctx).Create(u).Error
}
func (r *userRepo) FindAll(ctx context.Context) ([]*User, error) {
var list []*User
return list, r.db.Session(ctx).Order("created_at desc").Find(&list).Error
}Transaction:
err := db.Transaction(ctx, func(tx *gorm.DB) error {
if err := tx.Create(&order).Error; err != nil {
return err
}
return tx.Model(&inventory).
Update("stock", gorm.Expr("stock - ?", qty)).Error
})
// rolls back automatically on errorGORM model tags (generated by CLI):
type User struct {
ID string `json:"id" gorm:"primaryKey;type:uuid;default:gen_random_uuid()"`
Name string `json:"name"`
Email string `json:"email" gorm:"uniqueIndex"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
}
func (User) TableName() string { return "users" }adapter/postgres
pgx v5 · satisfies contract.Database + contract.Transactional
Raw SQL alternative. Use when you want full control over queries or need pgx-specific features like COPY.
import "github.com/BounkhongDev/bkgo/adapter/postgres"
db, err := postgres.New(ctx, cfg.Postgres)
defer db.Close()
// Satisfies contract.Database and contract.Transactional
pool := db.Pool() // *pgxpool.Pool — for bulk COPY etc.Raw SQL query:
row := db.QueryRow(ctx, `SELECT id, name FROM users WHERE id = $1`, id)
var u User
row.Scan(&u.ID, &u.Name)Transaction:
tx, err := db.BeginTx(ctx)
if err != nil { return err }
defer tx.Rollback(ctx)
tx.Exec(ctx, "INSERT INTO orders ...", ...)
tx.Exec(ctx, "UPDATE inventories SET stock = stock - $1 ...", qty)
return tx.Commit(ctx)adapter/redis
go-redis v9 · satisfies contract.Cache
import "github.com/BounkhongDev/bkgo/adapter/redis"
cache, err := redis.New(cfg.Redis)
defer cache.Close()
// Values are json.Marshaled — consistent with mock.Cache
cache.Set(ctx, "user:123", user, 10*time.Minute)
cache.Get(ctx, "user:123", &dest)
cache.Delete(ctx, "user:123")
exists, _ := cache.Exists(ctx, "user:123")adapter/minio
minio-go v7 · satisfies contract.Storage
import "github.com/BounkhongDev/bkgo/adapter/minio"
store, err := minio.New(ctx, cfg.MinIO)
// Auto-creates cfg.MinIO.Bucket if it doesn't exist
store.Upload(ctx, "uploads", "avatar.jpg", reader, size, "image/jpeg")
url, err := store.URL(ctx, "uploads", "avatar.jpg", 24*time.Hour)
store.Delete(ctx, "uploads", "avatar.jpg")adapter/jwt
golang-jwt v5 · satisfies contract.Token
import "github.com/BounkhongDev/bkgo/adapter/jwt"
token := jwt.New(cfg.JWT) // secret from JWT_SECRET env
tokenStr, err := token.Sign(contract.Claims{
"user_id": "abc-123",
"role": "admin",
}, 24*time.Hour)
claims, err := token.Verify(tokenStr)
userID := claims["user_id"].(string)