Skip to content

feat(export): classify metadata-described columns for volatile defaults#1461

Merged
pyramation merged 3 commits into
mainfrom
feat/export-metadata-table-volatility
Jul 26, 2026
Merged

feat(export): classify metadata-described columns for volatile defaults#1461
pyramation merged 3 commits into
mainfrom
feat/export-metadata-table-volatility

Conversation

@pyramation

@pyramation pyramation commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

@pgpmjs/export could only detect volatile-default columns for physically deployed tables: getDataExportColumns reads pg_attrdef + pg_proc.provolatile off a live relation. Callers with metadata-only planes (tables that exist as schema metadata but aren't physically deployed at export time) had no shared way to run the same classification, so they hand-rolled regexes over default-expression text.

This adds a first-class metadata-table entry point that runs the exact same provolatile-based classification:

interface MetadataExportColumn { name: string; type: string; columnDefault: string | null }

getMetadataExportColumns(db, columns): Promise<DataExportColumn[]>

Implementation builds an ephemeral CREATE TEMP TABLE pgpm_metadata_export_columns (c0 <type> [DEFAULT <expr>], ...) from the supplied descriptions, then calls getDataExportColumns on it — one shared code path. Results preserve input order/names, so callers reuse isVolatileTimestampColumn unchanged:

const volatile = (await getMetadataExportColumns(db, fields))
  .filter(isVolatileTimestampColumn);

Transactional & deterministic — zero residue. The whole classification runs inside a transaction that is always rolled back (BEGIN … ROLLBACK, or SAVEPOINT … ROLLBACK TO when the caller is already inside a transaction, e.g. pgsql-test). DDL is transactional in Postgres, so even a mid-flight failure erases the temp table — nothing is ever committed, the table name is a fixed deterministic identifier (no random suffix), and a failure cannot abort the caller's transaction. db must be a single session (client, not pool), as with any temp-table work.

Synthetic c0..cN column identifiers keep the DDL immune to reserved words / duplicate names. Each column's type must resolve in the connected DB and each non-null default must be a valid default expression for that type.

Notes

  • Consumed by constructive-db's generate_constructive.ts (scoped-plane meta-export), which is replacing its regex fallback with this API — see constructive-io/constructive-db#2490. That consumer needs this published (@pgpmjs/export next minor, ^1.4.0) before it can adopt it.
  • Tests: getMetadataExportColumns coverage in pgpm/export/__tests__/export-data.test.ts asserting parity with getDataExportColumns over an equivalent physical table, isVolatileTimestampColumn selection, input-order preservation, rollback cleanup, and the failure path (no leftover temp table, session still usable). Full package suite green.

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

Add getMetadataExportColumns to @pgpmjs/export: classify columns supplied
as metadata (name/type/default expression) rather than a live physical
table, running the exact same provolatile-based volatility classification
as getDataExportColumns via an ephemeral temp table. Lets metadata-only
planes reuse isVolatileTimestampColumn instead of pattern-matching default
expression text.
@pyramation pyramation self-assigned this Jul 26, 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

…eterministic

Run getMetadataExportColumns inside a rolled-back transaction (or a
savepoint when the caller is already in one): the temp table has a fixed
name, is never committed, and cannot survive a failure. Add a failure-path
test asserting no residue and a still-usable session.
@pyramation
pyramation merged commit dfeeda5 into main Jul 26, 2026
15 checks passed
@pyramation
pyramation deleted the feat/export-metadata-table-volatility branch July 26, 2026 07:45
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