Packages

adapters

Concrete implementations of the contract interfaces. Each adapter satisfies a port — business logic never imports these directly.


adapter/gorm

default

GORM 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 error

GORM 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)