gin-gorm

command
v0.1.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 5, 2026 License: MIT Imports: 15 Imported by: 0

README

gin-gorm

The BENCH-1 primary framework-tax control (issue #141): the canonical /api/projects CRUD API (../../docs/schema.md) implemented with idiomatic Gin + GORM, deliberately without Huma or framework.App. This is the cleanest isolation of Gombit's incremental cost — same language, runtime, and ORM family as the gombit app being compared against it.

Run

docker compose -f benchmarks/compose.yml up -d postgres

# migrate + seed (1,000 users, 100,000 projects) — idempotent, truncates first
go run ./benchmarks/apps/gin-gorm -seed

# serve
go run ./benchmarks/apps/gin-gorm
Under compose (containerized, with the §7 resource budget)

The app is also containerized (Dockerfile, built from the repo root since it imports benchmarks/apps/shared) and wired into benchmarks/compose.yml with the issue #141 §7 app ceiling (2 vCPU / 1 GiB). Because a compose budget is only an intention — whether deploy.resources.limits is honored is engine/version-dependent — the running container is verified rather than trusted:

# build + start postgres and the app (Compose v2 enforces the limits on `up`)
docker compose --env-file benchmarks/config/versions.env \
  -f benchmarks/compose.yml up -d postgres gin-gorm

# seed once (truncate + insert), then the served container keeps running
docker compose --env-file benchmarks/config/versions.env \
  -f benchmarks/compose.yml run --rm gin-gorm seed

# confirm the ceiling actually landed on the live container
go run ./benchmarks/scripts/inspect-limits \
  -container "$(docker compose -f benchmarks/compose.yml ps -q gin-gorm)" \
  -cpus 2 -memory 1g

The entrypoint takes three verbs, migrate, seed, and serve (default), so the orchestrator drives every app the same way; here migrate is a no-op (GORM AutoMigrate runs on seed/serve, and the database is the postgres service's POSTGRES_DB). make benchmark-crud-all brings all six apps up and runs run-crud over each; this app is one leg of it.

Env vars (all optional, defaults match benchmarks/compose.yml):

Var Default
DATABASE_URL postgres://gombit:gombit@127.0.0.1:55432/gombit_bench?sslmode=disable
PORT 8081
POOL_MAX_OPEN 20 issue #141 "Connection pooling" pins this to 20 across every implementation
POOL_MAX_IDLE 20

Test

# needs a live PostgreSQL instance — this package has no non-integration
# test files of its own; the seed-content formulas it shares with gombit
# are tested once in benchmarks/apps/shared
docker compose -f benchmarks/compose.yml up -d postgres
go test -tags integration ./benchmarks/apps/gin-gorm/... \
  -database.dsn "postgres://gombit:gombit@127.0.0.1:55432/gombit_bench?sslmode=disable"

The DB-backed suite is gated behind the integration build tag (matching database/integration_test.go's convention) since it needs a live PostgreSQL instance. CI runs it in .github/workflows/ci.yml's database-postgres job, against a separate gombit_bench database on that job's Postgres service — not the gombit database the auth/database/ admin integration tests use, since gin-gorm's User model maps to a users table too (same name, different columns) and sharing a database would let one AutoMigrate alter the schema the other relies on.

Covers: full create/get/update/delete/404/validation-failure round trip, including that a foreign-key violation (owner_id referencing no existing user) is rejected as a 422 client error, not reported as a 500 (TestCreateRejectsInvalidOwnerID); list pagination meta (page/limit/total) and deterministic id DESC ordering across a page boundary; query-count regression guards for both a non-empty page (TestListDoesNotN1, exactly 3 SQL statements — count, page, one batched owner IN (...) preload, not one owner query per row) and an empty one (TestListDoesNotN1EmptyPage, exactly 2 — no rows means no owners to preload); and the seed contract's own DB-backed half — the real truncate-then-seed path run twice at reduced scale to confirm it's idempotent rather than accumulating duplicate data (TestSeedDatabaseNIsIdempotentAndCorrect). The seed content formulas themselves (UserEmail, ProjectOwnerID, ...) and their pure, no-database tests (TestSeedContentIsDeterministic, TestProjectOwnerIDRoundRobin) live in ../shared — shared with gombit so the two apps can't silently seed different content for the same row N.

Status

Schema, seed, this control app, the gombit app implementing the same API, and the cross-implementation fairness check comparing them are all done (tracked in docs/plans/BENCH-1-benchmark-suite.md Phase 3). See ../gombit/README.md for the Gombit-side details, including one discovered framework gap and two bugs the fairness comparison caught. All six apps are now containerized with benchmarks/compose.yml services carrying the §7 budget (see Run above), and make benchmark-crud-all brings each up, records the live inspect-limits verdict as metadata.resource_limits, and runs run-crud over each; make benchmark-footprint captures the container footprint (cold-start, memory, CPU). Still open: wiring the fairness check into automated CI (it needs both databases at the full canonical 1,000/100,000 scale, deferred to Phase 8's lighter-seed CI work) and the embedded-Gombit single-binary footprint variant.

Documentation

Overview

Command gin-gorm is the BENCH-1 primary framework-tax control (issue #141 "Gin + GORM ... This comparison is especially important because it isolates the incremental cost of adopting Gombit rather than changing programming languages"): the canonical /api/projects CRUD API (benchmarks/docs/schema.md) implemented with idiomatic Gin + GORM, deliberately without Huma or framework.App.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL