Generating Code¶
This guide explains how to run pGenie and what it produces.
Running the Generator¶
From the root of your project (the directory containing project1.pgn.yaml), run:
pGenie will:
- Start a temporary PostgreSQL Docker container.
- Apply all migrations in
migrations/in natural sort order by filename. - Analyze all queries in
queries/. - For each query: write a signature file (
*.sig1.pgn.yaml) if none exists, or compare the freshly-resolved signature against the existing one and fail if they differ. - Run each configured code generator.
- Write the generated artifacts to
artifacts/<generator-name>/. - Shut down the container.
Output Structure¶
After a successful run, your project directory will look like this:
my-project/
├── project1.pgn.yaml
├── freeze1.pgn.yaml ← created and updated on first use of a generator
├── migrations/
│ ├── 1.sql
│ └── 2.sql
├── queries/
│ ├── insert_album.sql
│ ├── insert_album.sig1.pgn.yaml ← created on first run (not overwritten)
│ ├── select_album_by_name.sql
│ └── select_album_by_name.sig1.pgn.yaml ← created on first run (not overwritten)
└── artifacts/
└── haskell/ ← generated Haskell library
└── ...
└── rust/ ← generated Rust library
└── ...
Committing Generated Artifacts¶
Whether to commit the artifacts/ directory to version control is a matter of preference:
- Commit artifacts if you want the generated library available without running pGenie (e.g. for consumers who don't have pGenie installed).
- Exclude artifacts (via
.gitignore) if you prefer to generate them in CI and distribute as uploaded packages (e.g., via a package registry or by attaching to a release via GitHub Actions).
Signature files (*.sig1.pgn.yaml) and the freeze file (freeze1.pgn.yaml) should always be committed - they record the type contracts of your queries and pin the generator versions for reproducible builds.
Working with Signature Files¶
Signature files (.sig1.pgn.yaml) record the resolved type contract for each query. Understanding how pGenie handles them is important for day-to-day use.
Lifecycle¶
| Event | What pGenie does |
|---|---|
| First run (no sig file) | Writes the sig file with the types resolved from the database |
| Subsequent run (sig file present) | Compares resolved types against the sig file; fails the build if they differ |
| Sig file deleted | Treated as "first run" — pGenie regenerates it |
pGenie never silently overwrites an existing signature file.
Editing a signature file¶
You can edit a signature file by hand to tighten constraints. The most common edit is marking a parameter as non-nullable when you know callers will always pass a concrete value:
After editing, commit the file. On the next run pGenie will use your edited version as the expected signature.
Regenerating a signature file¶
To regenerate a signature file from scratch (for example, after a schema change that you want pGenie to re-resolve):
- Delete the existing
.sig1.pgn.yamlfile. - Run
pgn generate(orpgn analyse). pGenie will write a fresh sig file with the types from the current schema.
Schema drift detection¶
If a migration changes a column type that a query references, the next pgn generate run will detect that the freshly-resolved signature no longer matches the committed sig file and will fail the build. To resolve the failure, either:
- Update the sig file to reflect the new reality (acknowledging the breaking change), or
- Revert the migration so it no longer affects the query's type signature.
This design ensures that every schema change that affects a query's API is an explicit, reviewable commit in version control.
Troubleshooting¶
Docker not found / not running
Ensure Docker is installed and the daemon is running:
First run hangs at "Loading"
The first run downloads the PostgreSQL Docker image and caches Dhall generators. This can take up to 3 minutes. Subsequent runs are fast.
Query analysis error
If a query references a column that does not exist in the current schema, pGenie will report an error. Check that:
- All referenced tables and columns exist after applying the migrations.
- Parameters and column names are spelled correctly.
- The parameter syntax uses
$snake_casenames.