Go repository implementation with SQLC integration following hexagonal architecture. Use when implementing data persistence layer, creating repository interfaces, or working with SQLC-generated queries. Focuses on domain model conversion, transaction handling, and error patterns.
This skill provides guidance on implementing repository pattern in Go using SQLC with hexagonal architecture principles.
internal/port/db.DBTXwithTx) only for repository methods that execute multiple SQLC queries; single-query methods can execute directly without transaction wrappingmap[SQLCType]ToDomain[DomainType](row db.Row) (domain.Type, error)mapDomain[Type]To[SQLCParams](model domain.Type) db.Paramsrow for single records, rows for slicesfunc New(dbtx db.DBTX) (port.Repository, error) {
if dbtx == nil {
return nil, fmt.Errorf("dbtx is nil")
}
return &repo{q: db.New(dbtx), dbtx: dbtx}, nil
}
func (r *repo) Method(ctx context.Context, id uuid.UUID) (domain.Model, error) {
if id == uuid.Nil {
return domain.Model{}, fmt.Errorf("id is empty")
}
result, err := r.q.SQLCMethod(ctx, id)
if err != nil {
return domain.Model{}, fmt.Errorf("q.SQLCMethod: %w", err)
}
return mapSQLCToDomain(result)
}
result, err := withTx(ctx, r.dbtx, func(q *db.Queries) (Type, error) {
if err := q.First(ctx, params); err != nil {
return zero, fmt.Errorf("q.First: %w", err)
}
second, err := q.Second(ctx, params)
if err != nil {
return zero, fmt.Errorf("q.Second: %w", err)
}
return second, nil
})
// Not found handling
if errors.Is(err, pgx.ErrNoRows) {
return Model{}, fmt.Errorf("q.Method: %w", ErrNotFound)
}
// Affected rows check
if cmdTag.RowsAffected() == 0 {
return fmt.Errorf("q.Method: %w", ErrNotFound)
}
// SQLC to Domain - always with error return
func mapGetOrderRowToDomainOrder(row db.GetOrderRow) (domain.Order, error) {
currency, err := currency.ParseISO(row.Currency)
if err != nil {
return domain.Order{}, fmt.Errorf("currency[%s]: %w", row.Currency, err)
}
return domain.Order{Currency: currency}, nil
}
// Domain to SQLC - typically no error
func mapDomainFilterToParams(filter domain.Filter) db.Params {
return db.Params{IDs: nilSliceIfEmpty(filter.IDs)}
}
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer