cratefield-adapter-postgres
The [Database] port over sqlx Postgres 16 for the Cratefield
harness native runtime (ADR 0004,
issue #18). Native only — the crate fails compilation on any wasm
target with a clear message, and the sqlx dependency is target-gated to
non-wasm builds, so it can never slip into a Worker.
use Postgres;
let db = connect.await?;
db.apply_harness_migrations.await?; // see below
// … through Arc<dyn Database> as with any adapter
Postgres::connect(url)opens a pool (sqlx0.8,runtime-tokio,tls-rustls);batchruns all statements in one transaction (atomic).- Port statements arrive in the portable
?-placeholder form rendered by sea-query'sSqliteQueryBuilder; the adapter rewrites them to$n(skipping string literals, quoted identifiers and comments) and binds the values positionally. The migration runner's own bookkeeping is rendered by sea-query'sPostgresQueryBuilder. apply_harness_migrations(&Harness)applies every module's migrations in lock order (module config order, then zero-padded migration id — the orderfz migrations collectpins). Per module it applies thepostgresmigration set when the module ships one, else thesqliteset when it passes the portable-SQL lint (cratefield-core'slint_portable_sql, the same predicatefz doctorenforces).apply_migrations(module, &[SqlMigration])is the per-module entry point: idempotent, each migration applied in its own transaction and tracked under<module>/<id>inharness_migrations(id, applied_at).- CLI:
fz migrations apply --dialect postgres --url …(thefzbinary must be built with cratefield-cli'spostgresfeature).
The SQLite → Postgres mapping actually used
The portable subset is the intersection of both engines, so the same migration files run verbatim:
| Portable concept | SQLite | Postgres | Notes |
|---|---|---|---|
| ULID ids | TEXT PRIMARY KEY |
TEXT PRIMARY KEY |
no AUTOINCREMENT/SERIAL |
| timestamps | ISO-8601 TEXT |
ISO-8601 TEXT |
computed in Rust, never NOW()/datetime() |
| counters | INTEGER |
INTEGER (int4) |
|
| booleans | INTEGER 0/1 convention |
INTEGER 0/1 convention |
no SQL BOOLEAN columns; SeaValue::Bool binds as SMALLINT 0/1 |
| upserts | INSERT … ON CONFLICT … |
identical syntax | sea-query renders both |
| read-back writes | INSERT … RETURNING … |
identical syntax | sea-query renders both |
Tests
Tests that need a server are gated on FZ_TEST_POSTGRES_URL and skipped
with a printed reason when it is unset (CI provides a postgres:16
service container). Locally:
MIT. Built in the open for Cratefield, a Factory Zero venture.