PostgreSQL
Edit on GitHubReference for the go-chi-postgres deployment target
Last updated:
This page documents what the compiler emits when a spec is compiled against the go-chi-postgres
target. It is the concrete companion to the target-agnostic
Code Generation Pipeline research doc.
The canonical source of truth is the emitter at
codegen/go/EmitGo.scala, which renders the Handlebars
templates under codegen/resources/templates/go/chi/. Running
sbt "cli/run compile --framework chi --db postgres --ignore-verify --out /tmp/out fixtures/spec/url_shortener.spec"produces the tree this page describes. If this page and the emitter disagree, the emitter wins; file
an issue or PR to correct the doc. The full byte-level shape of the output for url_shortener.spec
is checked in under fixtures/golden/codegen/go/chi/postgres/url_shortener/ and asserted by
EmitGoTest.
At a glance
| Aspect | Value |
|---|---|
| Language | Go 1.22 |
| Framework | chi v5 (net/http) |
| ORM / driver | Bun (uptrace/bun) + bun/driver/pgdriver |
| Migration tool | golang-migrate (raw SQL under migrations/) |
| Database | PostgreSQL 16+ |
| Validation | go-playground/validator/v10 struct tags |
| Config | caarlos0/env/v11 (env vars) |
| HTTP server | net/http w/ chi middleware (RequestID, Logger, Recoverer, …) |
| Logging | log/slog (JSON handler) |
Project layout
.
├── go.mod
├── cmd/server/main.go # entrypoint, chi router wiring
├── internal/
│ ├── config/config.go # env-driven Config struct
│ ├── database/database.go # bun.NewDB connect + ping
│ ├── models/{entity}.go # struct + create/read DTOs + ErrorResponse
│ ├── handlers/
│ │ ├── common.go # writeJSON / writeError helpers
│ │ └── {entity_plural}.go # chi handler funcs (1 per operation)
│ └── services/
│ ├── common.go # ErrNotFound sentinel
│ └── {entity}.go # Bun query-builder business logic
├── migrations/
│ ├── 001_initial_schema.up.sql
│ └── 001_initial_schema.down.sql
├── Dockerfile # multi-stage build → distroless
├── docker-compose.yml # app + db services
├── Makefile # build / run / test / migrate-up
├── .env.example
├── .gitignore
├── .dockerignore
├── README.md
├── .github/workflows/ci.yml
├── tests/health_test.go
└── openapi.yaml # target-agnostic OpenAPI 3.1Type mapping
| Spec type | Go type | PostgreSQL column |
|---|---|---|
String | string | TEXT |
Int | int64 | BIGINT |
Float | float64 | DOUBLE PRECISION |
Bool | bool | BOOLEAN |
DateTime | time.Time | TIMESTAMPTZ |
Date | time.Time | DATE |
UUID | uuid.UUID | UUID |
Decimal | decimal.Decimal | NUMERIC |
Bytes | []byte | BYTEA |
Money | int64 | BIGINT |
Option[T] | *T | nullable column |
Set[T] | []T | JSONB |
Seq[T] | []T | JSONB |
The mapping is in profile/TypeMap.scala.
Operation routing
RouteKind.classify (target-agnostic) maps each operation to one of create, read, list,
delete, redirect, other. The Go emitter renders the matching handler/service template.
Operations whose body shape does not match the entity's field set route to other and emit a stub
the user fills in (the spec contract is preserved by the verify gate, so the stub still has a known
interface).
Dafny → Go integration
When compile --framework chi --db postgres --with-synthesis is invoked and the verified-body cache
is populated, the compiler:
- Routes through
dafny translate -go(viaTargetLanguage.Go). - Lays the produced Go files under
internal/dafnykernel/. - Emits operation bindings of the form
dafnykernel.{OperationName}.
The kernel is only emitted when at least one operation is classified as LLM_SYNTHESIS; otherwise
the Go project is purely CRUD/Bun.
CI gate
.github/workflows/go-build.yml is a {postgres, sqlite, mysql} matrix. On every PR that touches
the Go templates, profile, emitter, or the shared migration renderer it re-runs
compile --framework chi --db <dialect>, then go mod tidy && go vet && go build against the
emitted project and a golang-migrate round-trip (up → down -all → up) against a real
postgres:17 / mysql:8.4 service (SQLite uses a file) — so the emitted migrations/*.sql is
proven to apply and reverse on every supported dialect, not just that the Go code compiles.
Test generation
Conformance / property / stateful test generation (--with-tests) is available for
go-chi-* on every dialect (postgres, sqlite, mysql), emitted in the target's own
language: go test + rapid property tests, not
Python. testgen plugs the Go renderers into the shared Backend.scala seam
(ExprBackend / StrategyBackend / HarnessTemplates); the same spec-derived
derivation engine feeds the Python (fastapi) path, which stays the byte-identical
differential oracle (#278,
#279,
#280; closes
#265).
--with-tests emits under tests/ (Go package tests, build-tagged conformance):
behavioral (<svc>_behavioral_test.go, positive-ensures under rapid.Check), stateful
(<svc>_stateful_test.go, random operation sequences asserting invariants per step),
and structural-lite (<svc>_structural_test.go, fuzzes every non-stub operation with
type-valid input and asserts no 5xx — schemathesis's core check minus full schema
validation; fail-loud stubs are honest-skipped exactly as the Python schemathesis
renderer excludes them, recorded in tests/_testgen_skips.json). The
/__test_admin__/* reset/state/seed router is a spec-derived
internal/testadmin/admin_conformance.go (build tag conformance); the normal build
links an always-present !conformance no-op stub, so the plain go build matrix is
unaffected and the test-admin code never ships in production binaries.
Run it against a server built with the conformance tag:
go build -tags conformance -o server ./cmd/server
ENABLE_TEST_ADMIN=1 ./server &
bash tests/run_conformance.sh smoke # or: go test -tags conformance ./tests/...go-chi -> conformance suite runs this in CI (go-build.yml) across all four
fixtures × postgres/sqlite, mirroring the python-build.yml pattern. (The
spec-to-rest test CLI wrapper still drives only the Python runner; see
CLI Reference.)