ViewGroup and ViewFilters side effect in v2 (#15096)
# Introduction ### Summary Implements side effect handling for `ViewGroup` and `ViewFilters` when field metadata is updated in the v2 architecture. This ensures that view-related records are properly maintained when enum field options are modified, deleted, or created. ### Side effects - **Side Effect System**: Added side effect handling for field metadata updates that manages related view groups and view filters - **Enum Field Updates**: When enum field options are modified, the system now: - **View Groups**: Creates new groups for added options, updates existing groups for modified options, and deletes groups for removed options - **View Filters**: Updates filter values to reflect option changes and removes filters that reference deleted options ### Enum runner fix Update now works for both atomic enum and array enum ( multi select for instance ) ### Compute flat entity maps from to Standardized this method usage across v2 services Next step is to require dependencies dynamically ## Conclusion closes https://github.com/twentyhq/core-team-issues/issues/1649
This commit is contained in:
+89
-20
@@ -213,6 +213,8 @@ export class WorkspaceSchemaEnumManagerService {
|
||||
oldColumnName,
|
||||
newColumnName: columnName,
|
||||
oldToNewEnumOptionMap,
|
||||
columnDefinition,
|
||||
oldEnumTypeName: oldEnumName,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -315,49 +317,116 @@ export class WorkspaceSchemaEnumManagerService {
|
||||
oldColumnName,
|
||||
newColumnName,
|
||||
oldToNewEnumOptionMap,
|
||||
columnDefinition,
|
||||
oldEnumTypeName,
|
||||
}: {
|
||||
queryRunner: QueryRunner;
|
||||
schemaName: string;
|
||||
tableName: string;
|
||||
oldColumnName: string;
|
||||
newColumnName: string;
|
||||
oldEnumTypeName: string;
|
||||
oldToNewEnumOptionMap: Record<string, string>;
|
||||
columnDefinition: WorkspaceSchemaColumnDefinition;
|
||||
}): Promise<void> {
|
||||
const safeSchemaName = removeSqlDDLInjection(schemaName);
|
||||
const safeTableName = removeSqlDDLInjection(tableName);
|
||||
const safeOldColumnName = removeSqlDDLInjection(oldColumnName);
|
||||
const safeNewColumnName = removeSqlDDLInjection(newColumnName);
|
||||
|
||||
const newEnumTypeName = computePostgresEnumName({
|
||||
tableName,
|
||||
columnName: newColumnName,
|
||||
});
|
||||
|
||||
if (Object.keys(oldToNewEnumOptionMap).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const safeSchemaName = removeSqlDDLInjection(schemaName);
|
||||
const safeTableName = removeSqlDDLInjection(tableName);
|
||||
const safeOldColumnName = removeSqlDDLInjection(oldColumnName);
|
||||
const safeNewColumnName = removeSqlDDLInjection(newColumnName);
|
||||
const caseStatements = Object.entries(oldToNewEnumOptionMap)
|
||||
.map(
|
||||
([oldEnumOption, newEnumOption]) =>
|
||||
`WHEN '${removeSqlDDLInjection(oldEnumOption)}' THEN '${removeSqlDDLInjection(newEnumOption)}'::"${safeSchemaName}"."${newEnumTypeName}"`,
|
||||
)
|
||||
.join(' ');
|
||||
|
||||
const mappedValuesCondition = Object.keys(oldToNewEnumOptionMap)
|
||||
.map((oldValue) => `'${removeSqlDDLInjection(oldValue)}'`)
|
||||
.join(', ');
|
||||
|
||||
// Update rows with mapped enum values
|
||||
const updateMappedSql = `
|
||||
UPDATE "${safeSchemaName}"."${safeTableName}"
|
||||
SET "${safeNewColumnName}" =
|
||||
CASE "${safeOldColumnName}"::text
|
||||
${caseStatements}
|
||||
END
|
||||
WHERE "${safeOldColumnName}" IS NOT NULL
|
||||
AND "${safeOldColumnName}"::text IN (${mappedValuesCondition})`;
|
||||
const sqlQuery = columnDefinition.isArray
|
||||
? this.updateArrayEnum({
|
||||
safeSchemaName,
|
||||
safeTableName,
|
||||
safeOldColumnName,
|
||||
safeNewColumnName,
|
||||
newEnumTypeName,
|
||||
oldEnumTypeName,
|
||||
caseStatements,
|
||||
mappedValuesCondition,
|
||||
})
|
||||
: this.updateAtomicEnum({
|
||||
safeSchemaName,
|
||||
safeTableName,
|
||||
safeOldColumnName,
|
||||
safeNewColumnName,
|
||||
caseStatements,
|
||||
mappedValuesCondition,
|
||||
});
|
||||
|
||||
await queryRunner.query(updateMappedSql);
|
||||
await queryRunner.query(sqlQuery);
|
||||
}
|
||||
|
||||
private updateArrayEnum({
|
||||
safeNewColumnName,
|
||||
safeOldColumnName,
|
||||
safeSchemaName,
|
||||
safeTableName,
|
||||
newEnumTypeName,
|
||||
oldEnumTypeName,
|
||||
caseStatements,
|
||||
mappedValuesCondition,
|
||||
}: {
|
||||
safeSchemaName: string;
|
||||
safeTableName: string;
|
||||
safeOldColumnName: string;
|
||||
safeNewColumnName: string;
|
||||
newEnumTypeName: string;
|
||||
oldEnumTypeName: string;
|
||||
caseStatements: string;
|
||||
mappedValuesCondition: string;
|
||||
}) {
|
||||
return `
|
||||
UPDATE "${safeSchemaName}"."${safeTableName}"
|
||||
SET "${safeNewColumnName}" = (
|
||||
SELECT array_agg(
|
||||
CASE unnest_value::text
|
||||
${caseStatements}
|
||||
ELSE unnest_value::text::"${safeSchemaName}"."${newEnumTypeName}"
|
||||
END
|
||||
)
|
||||
FROM unnest("${safeOldColumnName}") AS unnest_value
|
||||
)
|
||||
WHERE "${safeOldColumnName}" IS NOT NULL
|
||||
AND "${safeOldColumnName}" && ARRAY[${mappedValuesCondition}]::"${safeSchemaName}"."${oldEnumTypeName}"[]`;
|
||||
}
|
||||
|
||||
private updateAtomicEnum({
|
||||
safeNewColumnName,
|
||||
safeOldColumnName,
|
||||
safeSchemaName,
|
||||
safeTableName,
|
||||
caseStatements,
|
||||
mappedValuesCondition,
|
||||
}: {
|
||||
caseStatements: string;
|
||||
mappedValuesCondition: string;
|
||||
safeSchemaName: string;
|
||||
safeTableName: string;
|
||||
safeOldColumnName: string;
|
||||
safeNewColumnName: string;
|
||||
}) {
|
||||
return `
|
||||
UPDATE "${safeSchemaName}"."${safeTableName}"
|
||||
SET "${safeNewColumnName}" =
|
||||
CASE "${safeOldColumnName}"::text
|
||||
${caseStatements}
|
||||
END
|
||||
WHERE "${safeOldColumnName}" IS NOT NULL
|
||||
AND "${safeOldColumnName}"::text IN (${mappedValuesCondition})`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user