Skip to content

gerpo

gerpo (Golang + Repository) is a generic repository pattern for Go with pluggable adapters and minimal reflection. It is not an ORM: no migrations, no relations between entities, no struct tags. The entire SQL behavior is described declaratively in the repository configuration.

One-line ideology

Schema and SQL live inside the repository configuration; columns are bound to struct fields via pointers — not strings, not tags.

Database support

gerpo currently targets PostgreSQL (and PG-compatible databases such as CockroachDB). The SQL fragments gerpo emits — placeholder format, LIKE type-casts, INSERT … RETURNING, window functions — assume PostgreSQL. MySQL, MS SQL Server, and older SQLite are not supported today. See TODO for the multi-dialect backlog.

Install

go get github.com/insei/gerpo@latest

Minimum Go version is 1.24.

Quick start

package main

import (
    "context"
    "time"

    "github.com/google/uuid"
    "github.com/insei/gerpo"
    "github.com/insei/gerpo/executor/adapters/pgx5"
    "github.com/insei/gerpo/query"
    "github.com/jackc/pgx/v5/pgxpool"
)

type User struct {
    ID        uuid.UUID
    Name      string
    Email     *string // nullable
    Age       int
    CreatedAt time.Time
}

func main() {
    pool, _ := pgxpool.New(context.Background(), "postgres://...")

    repo, err := gerpo.New[User]().
        Adapter(pgx5.NewPoolAdapter(pool)).
        Table("users").
        Columns(func(m *User, c *gerpo.ColumnBuilder[User]) {
            c.Field(&m.ID).OmitOnUpdate()
            c.Field(&m.Name)
            c.Field(&m.Email)
            c.Field(&m.Age)
            c.Field(&m.CreatedAt).OmitOnUpdate()
        }).
        Build()
    if err != nil {
        panic(err)
    }

    ctx := context.Background()

    // Insert
    u := &User{ID: uuid.New(), Name: "Alice", Age: 30, CreatedAt: time.Now()}
    _ = repo.Insert(ctx, u)

    // Query
    list, _ := repo.GetList(ctx, func(m *User, h query.GetListHelper[User]) {
        h.Where().Field(&m.Age).GTE(18)
        h.OrderBy().Field(&m.CreatedAt).DESC()
        h.Page(1).Size(20)
    })
    _ = list
}

Full runnable sample lives in examples/todo-api/ — a CRUD REST service with PostgreSQL, goose migrations and docker-compose wiring. Additional end-to-end scenarios are in the integration tests.

  • Why gerpo? →

    How gerpo compares to GORM, ent, bun, sqlc and sqlx — feature matrix, strengths, weaknesses, and when each tool is the better pick.

  • Production-ready setup →

    Copy-paste starting point: pgx v5 + goose migrations + OpenTelemetry tracer + request-scope cache + domain error mapping + transactions — all in one place.

  • Runnable example →

    examples/todo-api/ — a CRUD REST service with PostgreSQL, goose migrations and docker-compose wiring. docker compose up --build and you have a working tasks API. ~350 lines of Go in one place.

  • Features →

    A walkthrough of every repository capability: CRUD, filters, ordering, hooks, soft delete, virtual columns, cache, transactions, adapters.

  • Static analysis (gerpolint) →

    Catch EQ("18") on an int field at go vet time. Ships as a standalone binary and as a golangci-lint v2 plugin.

  • Architecture →

    How gerpo is built internally: layers, SQL generation, pointer-based field mapping via fmap, adapter implementations, Cache. For contributors.

  • API reference →

    Autogenerated on pkg.go.dev — including runnable examples next to every method.

  • Repository →

    Source, issue tracker, pull requests.

Supported adapters

gerpo talks to a database through an executor.Adapter — a thin wrapper around an underlying SQL driver. gerpo targets PostgreSQL today; all three bundled adapters wrap PostgreSQL drivers:

Adapter Package Wraps driver Placeholder format
pgx v5 executor/adapters/pgx5 github.com/jackc/pgx/v5 $1, $2, …
pgx v4 executor/adapters/pgx4 github.com/jackc/pgx/v4 $1, $2, …
database/sql executor/adapters/databasesql any database/sql driver — pair with a PG driver (pq, pgx/stdlib) ? or $1 (configurable)

PG-compatible databases (CockroachDB, MariaDB ≥10.5, SQLite ≥3.35) are likely to work drop-in but are not formally tested. MySQL, MS SQL Server, and older SQLite are not supported — the SQL gerpo emits (LIKE CAST(? AS text), INSERT … RETURNING, COUNT(*) OVER ()) assumes PostgreSQL. See the TODO file for the multi-dialect backlog.

You can wrap a custom adapter — implement executor.Adapter (ExecContext, QueryContext, BeginTx). See Adapters.