Skip to content

docs(examples): pgpm projections — one schema, every shape, one meaning - #1582

Merged
pyramation merged 1 commit into
mainfrom
feat/pgpm-projections-example
Aug 1, 2026
Merged

docs(examples): pgpm projections — one schema, every shape, one meaning#1582
pyramation merged 1 commit into
mainfrom
feat/pgpm-projections-example

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

The capstone example for the pgpm import / transform / diff dials work (planning #1340 Part C, #1329). It demonstrates the whole story on one small, realistic schema: normalize a schema to an identity-keyed object set, then everything downstream is a projection of that one model — a projection changes the representation, never the meaning.

examples/pgpm-projections/ — a two-schema blog platform (blog_app + blog_sec) authored as plain SQL, projected along every axis:

schema.sql ──pgpm import──▶ blog (object module)
                            │
              pgpm transform├─ blog-atomic
                            └─ blog-consolidated
schema.sql ──pgpm import --partition──▶ blog-core + blog-security
schema.sql → schema-v2.sql ──pgpm diff──▶ blog-migration  (+ --emit-sql migration.sql)

A database-free jest suite runs the real CLI (node pgpm/cli/dist/index.js) and compares the emitted artifacts semantically at the identity-keyed model:

  • granularity-invariantobjectconsolidated (empty diff)
  • partition-invariantblog-core + blog-security recombine ≡ single module (empty diff)
  • diff is exactv1 → v2 yields precisely: added {tags, post_tags tables; audit_log_insert policy}, modified {posts table, published_post_count function}, removed {} — nothing guessed
  • composable output — one diff run emits a module and a linear .sql, dependency-ordered, not.toMatch(/CREATE OR REPLACE/)

Deploy-level catalog equivalence for every granularity — including atomic — is already proven against live Postgres by pgpm/cli transform-e2e (dial parity) and diff-e2e, so this example stays DB-free and runs in the no-services unit-tests (pglite …) batch.

Notes for the reviewer

  • Lockfile: only the new package's importer entry was added by hand (three workspace:^ links). A clean pnpm install on main rewrites ~7k lines of pnpm-lock.yaml for unrelated reasons (stale committed lockfile); I deliberately avoided that churn. pnpm install --frozen-lockfile passes and leaves the lockfile unchanged.
  • Honest atomic caveat (README + commit): atomic authorship emits standalone ALTER TABLE … ADD CONSTRAINT statements whose names Postgres assigns at deploy time. The semantic normalizer folds standalone columns back into their table (covered by semantic-diff-driver unit test) but not yet standalone constraints, so atomic is guaranteed catalog-equivalent rather than AST-identical to object/consolidated. That's why the DB-free suite asserts AST-identity only for object/consolidated/partition. Tightening the normalizer to fold standalone constraints (making atomic AST-invariant too) is filed as a follow-up in constructive-planning.

Open decision

Built inside constructive/examples/ (reversible). If you'd prefer a standalone constructive-io/pgpm-projections-example repo, I can lift it out — say the word and pick public/private.

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

The capstone example for the import/transform/diff dials work (planning
#1340 Part C / #1329). A single blog schema (blog_app + blog_sec) is imported
into a pgpm module and then projected along every axis:

- granularity: object / consolidated (and atomic) via pgpm transform
- partition: split into app + security modules via pgpm import --partition
- diff: schema.sql -> schema-v2.sql as a generated migration via pgpm diff
- output: one diff run emits a pgpm module AND a linear .sql at once

A database-free jest suite runs the real CLI and proves the invariants at the
identity-keyed model: object == consolidated (granularity-invariant), core +
security == single module (partition-invariant), the v1->v2 diff is exactly the
real changes (2 new tables, 1 new policy, changed posts table, changed function
body) with nothing guessed, and the linear SQL projection is dependency-ordered
with no CREATE OR REPLACE. Deploy-level catalog equivalence for every
granularity (incl. atomic) is already covered against live Postgres by
pgpm/cli transform-e2e (dial parity) and diff-e2e.

Runs in the no-services 'unit-tests (pglite ...)' CI batch. The lockfile gets
only the new package's importer entry (surgical, all workspace:^ links) to
avoid the unrelated full-lockfile rewrite a clean install produces on main.

Note: atomic authorship emits standalone ADD CONSTRAINT statements whose names
Postgres assigns at deploy time; the semantic normalizer does not yet fold
those back into the owning table, so atomic is catalog-equivalent rather than
AST-identical to object/consolidated. Tracked in constructive-planning.
@pyramation pyramation self-assigned this Aug 1, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 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

@pyramation
pyramation merged commit 5c6fdbe into main Aug 1, 2026
17 checks passed
@pyramation
pyramation deleted the feat/pgpm-projections-example branch August 1, 2026 04:14
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