Skip to content

feat: pgpm-based ORM generation for constructive_infra_public (sdk/)#62

Open
pyramation wants to merge 2 commits into
feat/compute-workerfrom
feat/sdk-orm-codegen
Open

feat: pgpm-based ORM generation for constructive_infra_public (sdk/)#62
pyramation wants to merge 2 commits into
feat/compute-workerfrom
feat/sdk-orm-codegen

Conversation

@pyramation
Copy link
Copy Markdown
Contributor

@pyramation pyramation commented Jun 8, 2026

Summary

Adds a typed ORM for the constructive_infra_public schema, generated from the pgpm module — not hand-written — mirroring constructive-db's Pattern A (deploy pgpm → ephemeral DB → introspect SDL → codegen ORM), plus the GitHub Actions to automate that generation. Today www/server/index.ts reads functions/secrets/invocations with raw pg SQL; this gives those callers a typed client they can migrate to later (migration is out of scope here).

Pipeline (two new workspace packages under sdk/):

pgpm/constructive-infra ──▶ sdk/functions-schema ──▶ sdk/functions-sdk
  (source of truth)         deploy to ephemeral DB    @constructive-io/graphql-codegen
                            + PostGraphile introspect → typed ORM at src/<target>/
                            → schemas/infra.graphql      + orm-infra skill

Root scripts:

pnpm run generate:schema   # pgpm module -> ephemeral DB -> schemas/*.graphql
pnpm run generate:sdk      # schemas/*.graphql -> sdk/functions-sdk/src/*
pnpm run generate:orm      # both, in order

Generated client surface (6 tables):

import { infra } from '@constructive-io/functions-sdk';
const db = infra.createClient({ endpoint: process.env.GRAPHQL_URL!, headers: { 'X-Database-Id': id } });
await db.platformFunctionDefinition.findMany({ select: { id: true, name: true } }).execute();

CI automation (workflows)

Three workflows under .github/workflows/ mirror constructive-db's generate-all / schema-sdk-update / validate-introspection split, so the ORM stays in sync with the pgpm module without manual local regen:

  • generate-orm.yml — reusable (workflow_call + dispatch), the single source of truth. Spins up constructiveio/postgres-plus:18, bootstraps roles, runs pnpm run generate:orm (ephemeral deploy → SDL → ORM), detects drift, uploads the generated tree as an artifact, and exposes has_changes / ref_sha outputs. It only generates/reports — callers decide what to do.
  • validate-orm.yml — PR check on pgpm/** / sdk/**. Regenerates via generate-orm.yml and fails the PR if the committed output is stale (forces contributors to commit fresh codegen). pull_requestmain.
  • sdk-update.yml — manual workflow_dispatch. Regenerates, downloads the artifact, and opens a chore/regenerate-orm-* PR with the fresh output when anything changed.

Notes for reviewers

Two non-obvious bits live in sdk/functions-sdk/scripts/generate-sdk.ts (the hand-written generator), both working around current @constructive-io/graphql-codegen behavior so a single-target package builds cleanly:

  • Root barrel for single target. generateMulti only writes the top-level src/index.ts when there are 2+ targets. With one target (infra) it writes nothing, so the script emits the barrel itself (export * as infra from './infra'). Works unchanged when more targets are added.
  • Composite input-type stub. PostGraphile exposes the function_requirement composite as both FunctionRequirement (object) and FunctionRequirementInput (input). Codegen stubs the object form as export type FunctionRequirement = unknown; but omits the *Input counterpart, leaving dangling references that break tsc. The script appends export type FunctionRequirementInput = unknown; for any input X { from the SDL that is referenced but undeclared — derived from the SDL so it stays in sync.

eslint.config.mjs ignores the generated SDK output (sdk/functions-sdk/src/**, sdk/functions-schema/src/**) — these are codegen artifacts (a newer no-empty-object-type rule flags them) and must not be hand-edited. Hand-written scripts/ are still linted.

Generated — do not edit (regenerate via pnpm run generate:orm)

  • sdk/functions-schema/schemas/*.graphql, sdk/functions-schema/src/index.ts
  • sdk/functions-sdk/src/**
  • .agents/skills/orm-infra/

Requires constructiveio/postgres-plus:18 for the ephemeral DB (Postgres 18 uuidv7()).

Verification

  • pnpm run generate:orm reproducible end-to-end (ephemeral deploy → SDL → ORM)
  • pnpm --filter @constructive-io/functions-schema --filter @constructive-io/functions-sdk run build — clean tsc
  • pnpm run lint (full repo) — passes
  • All three workflow YAMLs validated (parse clean)

Link to Devin session: https://app.devin.ai/sessions/633efc205f0c445dbbb61c40679c2f78
Requested by: @pyramation

@devin-ai-integration
Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant