Fix multi-select option removal crashing when records contain removed values (#18871)

## Summary

- Fixes a bug where removing an option from a MULTI_SELECT field fails
with `invalid input value for enum` when existing records contain the
removed value alongside surviving values.
- The root cause was the `ELSE` branch in `updateArrayEnum` which tried
to cast removed enum values (e.g. `DISTRIBUTOR`) to the new enum type
that no longer includes them.
- The fix replaces the `ELSE` cast with a NULL-producing implicit CASE
default and uses `array_agg(...) FILTER (WHERE mapped_value IS NOT
NULL)` to silently strip removed values from existing arrays.

### Before (bug)
```sql
-- ELSE branch tries to cast removed value to new enum → crash
CASE unnest_value::text
  WHEN 'IMPL' THEN 'IMPL'::new_enum
  WHEN 'APP' THEN 'APP'::new_enum
  ELSE unnest_value::text::new_enum  -- 'DISTRIBUTOR' fails here
END
```

### After (fix)
```sql
-- No ELSE: removed values produce NULL, filtered out by array_agg
SELECT array_agg(mapped_value) FILTER (WHERE mapped_value IS NOT NULL)
FROM (
  SELECT CASE unnest_value::text
    WHEN 'IMPL' THEN 'IMPL'::new_enum
    WHEN 'APP' THEN 'APP'::new_enum
  END AS mapped_value
  FROM unnest(old_column) AS unnest_value
) enum_mapping
```
This commit is contained in:
Charles Bochet
2026-03-23 21:06:34 +01:00
committed by GitHub
parent e2c85b5af0
commit 708e53d829
2 changed files with 222 additions and 10 deletions
@@ -327,7 +327,6 @@ export class WorkspaceSchemaEnumManagerService {
escapedTable,
escapedOldColumn,
escapedNewColumn,
escapedNewEnumType,
escapedOldEnumType: `${escapedSchema}.${escapeIdentifier(oldEnumTypeName)}`,
caseStatements,
mappedValuesCondition,
@@ -349,7 +348,6 @@ export class WorkspaceSchemaEnumManagerService {
escapedOldColumn,
escapedSchema,
escapedTable,
escapedNewEnumType,
escapedOldEnumType,
caseStatements,
mappedValuesCondition,
@@ -358,7 +356,6 @@ export class WorkspaceSchemaEnumManagerService {
escapedTable: string;
escapedOldColumn: string;
escapedNewColumn: string;
escapedNewEnumType: string;
escapedOldEnumType: string;
caseStatements: string;
mappedValuesCondition: string;
@@ -366,13 +363,14 @@ export class WorkspaceSchemaEnumManagerService {
return `
UPDATE ${escapedSchema}.${escapedTable}
SET ${escapedNewColumn} = (
SELECT array_agg(
CASE unnest_value::text
${caseStatements}
ELSE unnest_value::text::${escapedNewEnumType}
END
)
FROM unnest(${escapedOldColumn}) AS unnest_value
SELECT array_agg(mapped_value) FILTER (WHERE mapped_value IS NOT NULL)
FROM (
SELECT
CASE unnest_value::text
${caseStatements}
END AS mapped_value
FROM unnest(${escapedOldColumn}) AS unnest_value
) enum_mapping
)
WHERE ${escapedOldColumn} IS NOT NULL
AND ${escapedOldColumn} && ARRAY[${mappedValuesCondition}]::${escapedOldEnumType}[]`;