shadowdb

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package shadowdb resolves WHICH postgres server hosts the generate-time schema-introspection shadow database, and — inside a generate run — makes every reader of the applied schema share ONE application of the migrations to it (applied.go).

Why this layer exists

forge derives ORM/CRUD code by applying a project's migrations to a throwaway "shadow" postgres and introspecting the live schema (pkg/schemadef). That needs a server. Historically the ONLY way to use a real running server instead of a fragile embedded one was the FORGE_TEST_POSTGRES_URL env var — a TEST-suite variable that leaked into being the production codegen config channel. Because it lived OUTSIDE forge's config system it silently diverged between steps, and because it was the only non-embedded path, embedded became the accidental default — which on a shared/resource-starved machine leaks SysV semaphores and fails initdb.

This package moves the "which server" DECISION into forge's own environment/config layer. schemadef and pkg/pgtest stay dumb mechanics: pgtest knows how to make an ephemeral database (embedded, or a scratch DB on a given server URL); schemadef applies migrations and introspects against whatever database it is handed. The POLICY of which server to use, and whether one is reachable at all, lives here — as does how often one run applies a migration set to it (once: see applied.go).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BeginRun added in v0.1.46

func BeginRun() (end func())

BeginRun opens a run scope: until the returned end is called, Tables and Open apply each distinct migration set once and share the result. Scopes nest; the templates are dropped when the outermost one ends. end is idempotent.

The server each project's shadow lives on is also resolved once per run, so every reader in one run sees the same postgres.

func Open added in v0.1.46

func Open(projectDir, migDir string) ([]schemadef.Table, *schemadef.Shadow, error)

Open is Tables plus a PRIVATE live database holding the applied schema, for a reader that must execute SQL against it (verify a fixture against a CHECK, insert a parent row in a rolled-back transaction). The caller owns the shadow and must Close it; writes to it reach nothing else.

A missing or empty directory returns (nil, nil, nil). On error nothing is left open.

func Resolve

func Resolve(projectDir string) string

Resolve returns the base DSN of a REACHABLE postgres SERVER to host the generate-time shadow database, or "" when none is available — in which case the caller falls back to embedded postgres (true zero-setup / CI).

projectDir is the directory containing forge.yaml.

Resolution order — first usable candidate wins:

  1. FORGE_TEST_POSTGRES_URL — the explicit override / escape hatch. It is honored as-is WITHOUT a reachability probe: an override that is set but wrong must fail loudly downstream (a hard CREATE DATABASE error), not silently fall back to embedded and hide the misconfiguration. forge's own e2e suite sets this to share one server across the parallel corpus, so this path must keep working unchanged.

  2. an exported DATABASE_URL — a dev shell that already points at the running stack.

  3. the project's per-env SECRET dotenv (`.env.<env>` DATABASE_URL) — the dev DB the app itself dials. A scaffolded project marks database_url `sensitive`, so its VALUE lives here (gitignored) and the git-tracked config.k carries only the Secret reference.

  4. the project's per-env config (deploy/kcl/<env>/config.k `database_url`) — the same DB, for a project that did NOT mark the field sensitive.

  5. the forge dev-stack convention — localhost:${POSTGRES_PORT:-5432} with ${POSTGRES_USER:-postgres}/${POSTGRES_PASSWORD:-postgres}, the SAME host coordinates the scaffold's docker-compose maps postgres to.

Candidates 2–5 are reduced to their SERVER coordinates against the maintenance database "postgres" and PROBED (pgtest.CanReach) before being returned, so the app's own database is never opened or mutated, and a candidate that is down or has wrong credentials is skipped rather than turned into a hard error. When none is reachable, "" is returned and the caller uses embedded postgres.

Note on the scaffold phase: at `forge new` / one-shot scaffold time the project's own dev DB is typically NOT up yet, so candidates 3–4 will not probe. Candidate 5 still lets a developer whose machine already runs a shared dev postgres at the conventional coordinates use it; otherwise the resolver returns "" and embedded is used — no configuration required.

func Tables added in v0.1.46

func Tables(projectDir, migDir string) ([]schemadef.Table, error)

Tables returns the applied schema of the migrations under migDir, on the shadow server Resolve(projectDir) picks: schemadef.ApplyAndIntrospectAt's answer. A missing or empty directory returns (nil, nil) without touching postgres. The caller owns the returned slice.

func Views added in v1.0.0

func Views(projectDir, migDir string) ([]schemadef.Table, error)

Views returns the applied schema's views (schemadef.IntrospectViews) on the same shadow Tables uses, from the same template within a run.

Types

type Stats added in v0.1.46

type Stats struct {
	Applies   int
	Reuses    int
	ApplyTime time.Duration
}

Stats counts what the applied-schema memo did in this process: how many migration sets it applied, how long that took, and how many readers it served from an existing template instead.

func CurrentStats added in v0.1.46

func CurrentStats() Stats

CurrentStats returns the process's running totals.

func StatsSince added in v0.1.46

func StatsSince(earlier Stats) Stats

StatsSince is what the memo did after the reading earlier: the process's running totals now, minus earlier.

Jump to

Keyboard shortcuts

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