Skip to content

fix(pg-delta): handle leading enum additions#316

Open
xmh1011 wants to merge 7 commits into
supabase:mainfrom
xmh1011:fix/pg-delta-issue-304-leading-enum-values
Open

fix(pg-delta): handle leading enum additions#316
xmh1011 wants to merge 7 commits into
supabase:mainfrom
xmh1011:fix/pg-delta-issue-304-leading-enum-values

Conversation

@xmh1011

@xmh1011 xmh1011 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fix enum ADD VALUE planning so every BEFORE/AFTER anchor already exists when emitted.
  • Preserve empty enum extraction and empty-string enum labels.
  • Reject unsupported existing enum label reorders instead of silently producing no-op or incorrect append-only plans.
  • Restore enum security labels when removed-label replacement recreates the type.

Closes #304

Testing

  • bun test packages/pg-delta/src/core/objects/type/enum/enum.diff.test.ts packages/pg-delta/src/core/objects/type/enum/changes/enum.alter.test.ts packages/pg-delta/src/core/objects/type/enum/changes/enum.create.test.ts from /tmp using the worktree Bun binary: 24 pass, 0 fail.

Note: the normal cd packages/pg-delta && bun run test ... path hung after starting these unit files, consistent with the repo note that package-local pg-delta test execution can enter the Docker/global-setup path. I interrupted that run and used the documented unit-only workaround from outside the package directory.

@changeset-bot

changeset-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 52b2fb1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@supabase/pg-delta Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

xmh1011 added 7 commits July 1, 2026 20:45
Adds regression coverage for issue supabase#304 where multiple labels inserted before the first existing enum value must use anchors that already exist when each ALTER executes.

Also covers empty enums, pure append runs, and empty-string labels as values and anchors.

RED evidence before the fix:

- leading run failed with generated order: ALTER TYPE public.e1 ADD VALUE 'a' BEFORE 'b'; ALTER TYPE public.e1 ADD VALUE 'b' AFTER 'a' instead of anchoring 'b' BEFORE 'c' first.

- empty enum edge failed with: Could not find an existing enum label anchor for added values: a.

- empty-string edge generated [] for [] -> [''] and dropped AFTER '' during serialization.
Schedule enum ADD VALUE changes against labels that already exist in the simulated working enum. Leading inserted runs are emitted from the nearest existing successor back toward the start, so PostgreSQL never sees BEFORE/AFTER references to labels that have not been added yet.

When the source enum is empty, emit the first added value without a position and then anchor subsequent values from the working list.

Use explicit undefined checks so valid empty-string enum labels remain usable as new values and BEFORE/AFTER anchors.

Includes a patch changeset for @supabase/pg-delta.
Adds regression coverage for empty enum types and empty-string enum labels at both catalog extraction and enum ADD VALUE serialization/diff layers.

RED evidence before the extractor fix:

- add enum values to an empty enum expected ALTER TYPE public.empty_enum_status ADD VALUE ''; ALTER TYPE public.empty_enum_status ADD VALUE 'ready' AFTER '', but createPlan produced CREATE TYPE public.empty_enum_status AS ENUM ('', 'ready') because the existing empty enum was absent from the extracted main catalog.
Build enum catalog rows from pg_type typtype = 'e' and left join pg_enum so CREATE TYPE ... AS ENUM () is preserved as labels: [].

Only append label rows when pg_enum fields are non-null, which keeps empty-string labels valid while ignoring the null row produced for empty enums.

This prevents main empty enums from being missed and later misplanned as CREATE TYPE when the branch adds labels.
Covers CREATE TYPE ... AS ENUM () serialization and an explicit createPlan assertion for creating an empty enum type.

This avoids a roundtripFidelityTest false positive when createPlan returns null for an empty target enum.
Adds regressions for existing enum label reordering, reordering combined with additions, and enum replacement preserving security labels.

RED evidence before the fix:

- ['a','b'] -> ['b','a'] returned [] instead of surfacing unsupported reorder.

- ['a','b'] -> ['b','a','c'] emitted ADD VALUE 'c' AFTER 'a', leaving final order different from branch.

- removed-label replacement emitted DropEnum/CreateEnum but no CreateSecurityLabelOnEnum for branch security labels.
Detect existing enum label reordering before scheduling ADD VALUE statements so createPlan fails explicitly instead of producing no migration or an incorrect append-only plan.

When enum replacement is needed for removed labels, recreate branch security labels after the replacement type is created.
@xmh1011
xmh1011 force-pushed the fix/pg-delta-issue-304-leading-enum-values branch from e74f273 to 52b2fb1 Compare July 1, 2026 12: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.

pg-delta: multiple leading enum values generate ADD VALUE before a non-existent label

1 participant