Integration testing v2 enum field types fail and success path (#14010)
# Introduction Migrating and improving performances of field enum integrations tests success and failing tests cases to be using the new v2 api ## Discovered issue When deleting an object in v1 it will leave related enums until the object is re-created Something not done anymore within the create in v2 but in the delete operation We should implem an upgrade command to remove such relicas ## Bugs - Update/create default value multi select runner wrong sql query -> FIX - Update default value multi select regression, we should allow option without an id to be inserted -> FIX - default value compare dynamic json stringify convertion or not in compare tools for object and fields
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
import {
|
||||
BaseGraphQLError,
|
||||
ErrorCode,
|
||||
} from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { type WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
|
||||
import { fromWorkspaceMigrationBuilderExceptionToValidationResponseError } from 'src/engine/workspace-manager/workspace-migration-v2/interceptors/utils/from-workspace-migration-builder-exception-to-validation-response-error.util';
|
||||
|
||||
export const workspaceMigrationBuilderExceptionV2Formatter = (
|
||||
error: WorkspaceMigrationBuilderExceptionV2,
|
||||
) => {
|
||||
const { errors, summary } =
|
||||
fromWorkspaceMigrationBuilderExceptionToValidationResponseError(error);
|
||||
|
||||
throw new BaseGraphQLError(error.message, ErrorCode.BAD_USER_INPUT, {
|
||||
code: 'METADATA_VALIDATION_ERROR',
|
||||
errors,
|
||||
summary,
|
||||
message: `Validation failed for ${summary.invalidObjects} object(s) and ${summary.invalidFields} field(s)`,
|
||||
userFriendlyMessage: t`Validation failed for ${summary.invalidObjects} object(s) and ${summary.invalidFields} field(s)`,
|
||||
});
|
||||
};
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
import {
|
||||
type CallHandler,
|
||||
type ExecutionContext,
|
||||
type NestInterceptor,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { catchError, type Observable } from 'rxjs';
|
||||
|
||||
import {
|
||||
BaseGraphQLError,
|
||||
ErrorCode,
|
||||
} from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
|
||||
import { fromWorkspaceMigrationBuilderExceptionToValidationResponseError } from 'src/engine/workspace-manager/workspace-migration-v2/interceptors/utils/from-workspace-migration-builder-exception-to-validation-response-error.util';
|
||||
|
||||
export class WorkspaceMigrationBuilderExceptionV2Interceptor
|
||||
implements NestInterceptor
|
||||
{
|
||||
intercept(_: ExecutionContext, next: CallHandler): Observable<unknown> {
|
||||
return next.handle().pipe(
|
||||
catchError((error) => {
|
||||
if (!(error instanceof WorkspaceMigrationBuilderExceptionV2)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const { errors, summary } =
|
||||
fromWorkspaceMigrationBuilderExceptionToValidationResponseError(
|
||||
error,
|
||||
);
|
||||
|
||||
throw new BaseGraphQLError(error.message, ErrorCode.BAD_USER_INPUT, {
|
||||
code: 'METADATA_VALIDATION_ERROR',
|
||||
errors,
|
||||
summary,
|
||||
message: `Validation failed for ${summary.invalidObjects} object(s) and ${summary.invalidFields} field(s)`,
|
||||
userFriendlyMessage: t`Validation failed for ${summary.invalidObjects} object(s) and ${summary.invalidFields} field(s)`,
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -68,8 +68,8 @@ export class WorkspaceMigrationV2FieldActionsBuilderService {
|
||||
to: toFlatFieldMetadata,
|
||||
} of updatedFlatFieldMetadatas) {
|
||||
const updates = compareTwoFlatFieldMetadata({
|
||||
from: fromFlatFieldMetadata,
|
||||
to: toFlatFieldMetadata,
|
||||
fromFlatFieldMetadata,
|
||||
toFlatFieldMetadata,
|
||||
});
|
||||
|
||||
if (updates.length === 0) {
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ export type CreatedDeletedUpdatedObjectMetadataInputMatrix = FromTo<
|
||||
FlatObjectMetadata
|
||||
> & {
|
||||
buildOptions: WorkspaceMigrationV2BuilderOptions;
|
||||
fromFlatObjectMetadataMaps: FlatObjectMetadataMaps; // should be renamed to from
|
||||
fromFlatObjectMetadataMaps: FlatObjectMetadataMaps;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
|
||||
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { type FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-properties-to-compare.type';
|
||||
|
||||
export type FlatFieldMetadataPropertyUpdate<
|
||||
T extends FlatFieldMetadataPropertiesToCompare,
|
||||
> = {
|
||||
property: T;
|
||||
} & FromTo<FieldMetadataEntity[T]>;
|
||||
+2
-6
@@ -1,8 +1,6 @@
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
|
||||
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { type FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-properties-to-compare.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type FlatFieldMetadataPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/flat-field-metadata-property-update.type';
|
||||
|
||||
export type CreateFieldAction = {
|
||||
type: 'create_field';
|
||||
@@ -16,9 +14,7 @@ export type UpdateFieldAction = {
|
||||
objectMetadataId: string;
|
||||
updates: Array<
|
||||
{
|
||||
[P in FlatFieldMetadataPropertiesToCompare]: {
|
||||
property: P;
|
||||
} & FromTo<FieldMetadataEntity[P]>;
|
||||
[P in FlatFieldMetadataPropertiesToCompare]: FlatFieldMetadataPropertyUpdate<P>;
|
||||
}[FlatFieldMetadataPropertiesToCompare]
|
||||
>;
|
||||
};
|
||||
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
import { type ColumnType } from 'typeorm';
|
||||
|
||||
import { type FieldMetadataDefaultSerializableValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
|
||||
import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { isFunctionDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/is-function-default-value.util';
|
||||
import { serializeFunctionDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/serialize-function-default-value.util';
|
||||
import { removeSqlDDLInjection } from 'src/engine/workspace-manager/workspace-migration-runner/utils/remove-sql-injection.util';
|
||||
|
||||
type SerializeDefaultValueV2Args = {
|
||||
defaultValue?: FieldMetadataDefaultSerializableValue;
|
||||
columnType?: ColumnType;
|
||||
schemaName: string;
|
||||
tableName: string;
|
||||
columnName: string;
|
||||
};
|
||||
export const serializeDefaultValueV2 = ({
|
||||
columnType,
|
||||
defaultValue,
|
||||
schemaName,
|
||||
tableName,
|
||||
columnName,
|
||||
}: SerializeDefaultValueV2Args) => {
|
||||
const safeSchemaName = removeSqlDDLInjection(schemaName);
|
||||
const safeTableName = removeSqlDDLInjection(tableName);
|
||||
const safeColumnName = removeSqlDDLInjection(columnName);
|
||||
|
||||
if (defaultValue === undefined || defaultValue === null) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
// Function default values
|
||||
if (isFunctionDefaultValue(defaultValue)) {
|
||||
const serializedTypeDefaultValue =
|
||||
serializeFunctionDefaultValue(defaultValue);
|
||||
|
||||
if (!serializedTypeDefaultValue) {
|
||||
throw new FieldMetadataException(
|
||||
'Invalid default value',
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
return serializedTypeDefaultValue;
|
||||
}
|
||||
|
||||
const castSuffix =
|
||||
columnType === 'enum'
|
||||
? `::${safeSchemaName}."${safeTableName}_${safeColumnName}_enum"`
|
||||
: `::${columnType}`;
|
||||
|
||||
const sanitizeAndAddCastPrefix = (defaultValue: string) =>
|
||||
`'${removeSqlDDLInjection(defaultValue)}'` + castSuffix;
|
||||
|
||||
switch (typeof defaultValue) {
|
||||
case 'string': {
|
||||
if (!defaultValue.startsWith("'") || !defaultValue.endsWith("'")) {
|
||||
throw new FieldMetadataException(
|
||||
`Invalid string default value "${defaultValue}" should be single quoted`,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
return sanitizeAndAddCastPrefix(defaultValue);
|
||||
}
|
||||
case 'boolean':
|
||||
case 'number': {
|
||||
return sanitizeAndAddCastPrefix(`${defaultValue}`);
|
||||
}
|
||||
case 'object': {
|
||||
if (defaultValue instanceof Date) {
|
||||
return sanitizeAndAddCastPrefix(`'${defaultValue.toISOString()}'`);
|
||||
}
|
||||
|
||||
if (Array.isArray(defaultValue)) {
|
||||
const arrayValues = defaultValue
|
||||
.map((val) => `'${removeSqlDDLInjection(val)}'`)
|
||||
.join(',');
|
||||
|
||||
return `ARRAY[${arrayValues}]${castSuffix}[]`;
|
||||
}
|
||||
|
||||
return sanitizeAndAddCastPrefix(`'${JSON.stringify(defaultValue)}'`); // Won't work :thinking: at all will remove every brackets and so on
|
||||
}
|
||||
default: {
|
||||
throw new FieldMetadataException(
|
||||
`Invalid default value "${defaultValue}"`,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
+5
-5
@@ -63,6 +63,11 @@ export class CreateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
|
||||
operation: EnumOperation.CREATE,
|
||||
});
|
||||
|
||||
const columnDefinitions = generateColumnDefinitions({
|
||||
flatFieldMetadata: flatFieldMetadata,
|
||||
flatObjectMetadataWithoutFields: flatObjectMetadataWithFlatFieldMaps,
|
||||
});
|
||||
|
||||
await executeBatchEnumOperations({
|
||||
enumOperations,
|
||||
queryRunner,
|
||||
@@ -70,11 +75,6 @@ export class CreateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
|
||||
workspaceSchemaManagerService: this.workspaceSchemaManagerService,
|
||||
});
|
||||
|
||||
const columnDefinitions = generateColumnDefinitions({
|
||||
flatFieldMetadata: flatFieldMetadata,
|
||||
flatObjectMetadataWithoutFields: flatObjectMetadataWithFlatFieldMaps,
|
||||
});
|
||||
|
||||
await this.workspaceSchemaManagerService.columnManager.addColumns({
|
||||
queryRunner,
|
||||
schemaName,
|
||||
|
||||
+72
-59
@@ -1,21 +1,15 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { type EnumFieldMetadataType, type FromTo } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type QueryRunner } from 'typeorm';
|
||||
import { ColumnType, type QueryRunner } from 'typeorm';
|
||||
|
||||
import { type FieldMetadataDefaultValueForAnyType } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
|
||||
|
||||
import {
|
||||
type FieldMetadataComplexOption,
|
||||
type FieldMetadataDefaultOption,
|
||||
} from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
|
||||
import { getCompositeTypeOrThrow } from 'src/engine/metadata-modules/field-metadata/utils/get-composite-type-or-throw.util';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { unserializeDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/unserialize-default-value';
|
||||
import { FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-properties-to-compare.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isCompositeFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-composite-flat-field-metadata.util';
|
||||
import { isEnumFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-enum-flat-field-metadata.util';
|
||||
@@ -23,9 +17,13 @@ import { isRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-fi
|
||||
import { findFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util';
|
||||
import { findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-with-flat-field-maps-in-flat-object-metadata-maps-or-throw.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { fromFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-with-flat-field-maps-to-flat-object-metadatas.util';
|
||||
import { fieldMetadataTypeToColumnType } from 'src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util';
|
||||
import { WorkspaceSchemaManagerService } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.service';
|
||||
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
|
||||
import { FlatFieldMetadataPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/flat-field-metadata-property-update.type';
|
||||
import { type UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
|
||||
import { serializeDefaultValueV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/serialize-default-value-v2.util';
|
||||
import {
|
||||
WorkspaceMigrationRunnerException,
|
||||
WorkspaceMigrationRunnerExceptionCode,
|
||||
@@ -40,6 +38,16 @@ import {
|
||||
executeBatchEnumOperations,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/utils/workspace-schema-enum-operations.util';
|
||||
|
||||
type UpdateFieldPropertyUpdateHandlerArgs<
|
||||
T extends FlatFieldMetadataPropertiesToCompare,
|
||||
> = {
|
||||
queryRunner: QueryRunner;
|
||||
schemaName: string;
|
||||
tableName: string;
|
||||
flatFieldMetadata: FlatFieldMetadata;
|
||||
update: FlatFieldMetadataPropertyUpdate<T>;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
|
||||
'update_field',
|
||||
@@ -85,12 +93,6 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
|
||||
flatObjectMetadata: flatObjectMetadataWithFlatFieldMaps,
|
||||
});
|
||||
|
||||
const flatObjectMetadata =
|
||||
findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsOrThrow({
|
||||
flatObjectMetadataMaps,
|
||||
objectMetadataId,
|
||||
});
|
||||
|
||||
const currentFlatFieldMetadata =
|
||||
findFlatFieldMetadataInFlatObjectMetadataMapsOrThrow({
|
||||
flatObjectMetadataMaps,
|
||||
@@ -102,51 +104,52 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
|
||||
|
||||
for (const update of updates) {
|
||||
if (update.property === 'name') {
|
||||
await this.handleFieldNameUpdate(
|
||||
await this.handleFieldNameUpdate({
|
||||
queryRunner,
|
||||
schemaName,
|
||||
tableName,
|
||||
optimisticFlatFieldMetadata,
|
||||
flatFieldMetadata: optimisticFlatFieldMetadata,
|
||||
update,
|
||||
);
|
||||
});
|
||||
optimisticFlatFieldMetadata.name = update.to;
|
||||
}
|
||||
if (update.property === 'defaultValue') {
|
||||
await this.handleFieldDefaultValueUpdate(
|
||||
await this.handleFieldDefaultValueUpdate({
|
||||
queryRunner,
|
||||
schemaName,
|
||||
tableName,
|
||||
optimisticFlatFieldMetadata,
|
||||
flatFieldMetadata: optimisticFlatFieldMetadata,
|
||||
update,
|
||||
);
|
||||
});
|
||||
optimisticFlatFieldMetadata.defaultValue = update.to;
|
||||
}
|
||||
if (
|
||||
update.property === 'options' &&
|
||||
isEnumFlatFieldMetadata(optimisticFlatFieldMetadata)
|
||||
) {
|
||||
await this.handleFieldOptionsUpdate(
|
||||
await this.handleFieldOptionsUpdate({
|
||||
queryRunner,
|
||||
schemaName,
|
||||
tableName,
|
||||
flatObjectMetadata,
|
||||
optimisticFlatFieldMetadata,
|
||||
flatObjectMetadata:
|
||||
fromFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadata(
|
||||
flatObjectMetadataWithFlatFieldMaps,
|
||||
),
|
||||
flatFieldMetadata: optimisticFlatFieldMetadata,
|
||||
update,
|
||||
);
|
||||
});
|
||||
optimisticFlatFieldMetadata.options = update.to ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async handleFieldNameUpdate(
|
||||
queryRunner: QueryRunner,
|
||||
schemaName: string,
|
||||
tableName: string,
|
||||
flatFieldMetadata: FlatFieldMetadata,
|
||||
update: {
|
||||
property: 'name';
|
||||
} & FromTo<string>,
|
||||
) {
|
||||
private async handleFieldNameUpdate({
|
||||
flatFieldMetadata,
|
||||
queryRunner,
|
||||
schemaName,
|
||||
tableName,
|
||||
update,
|
||||
}: UpdateFieldPropertyUpdateHandlerArgs<'name'>) {
|
||||
if (isCompositeFlatFieldMetadata(flatFieldMetadata)) {
|
||||
const compositeType = getCompositeTypeOrThrow(flatFieldMetadata.type);
|
||||
|
||||
@@ -208,15 +211,17 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
|
||||
});
|
||||
}
|
||||
|
||||
private async handleFieldDefaultValueUpdate(
|
||||
queryRunner: QueryRunner,
|
||||
schemaName: string,
|
||||
tableName: string,
|
||||
flatFieldMetadata: FlatFieldMetadata,
|
||||
update: {
|
||||
property: 'defaultValue';
|
||||
} & FromTo<FieldMetadataDefaultValueForAnyType>,
|
||||
) {
|
||||
private async handleFieldDefaultValueUpdate({
|
||||
flatFieldMetadata,
|
||||
queryRunner,
|
||||
schemaName,
|
||||
tableName,
|
||||
update,
|
||||
}: UpdateFieldPropertyUpdateHandlerArgs<'defaultValue'>) {
|
||||
const columnType = fieldMetadataTypeToColumnType(
|
||||
flatFieldMetadata.type,
|
||||
) as ColumnType;
|
||||
|
||||
if (isCompositeFieldMetadataType(flatFieldMetadata.type)) {
|
||||
const compositeType = getCompositeTypeOrThrow(flatFieldMetadata.type);
|
||||
|
||||
@@ -233,11 +238,15 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
|
||||
property,
|
||||
);
|
||||
// @ts-expect-error - TODO: fix this
|
||||
let compositeDefaultValue = update.to?.[property.name];
|
||||
let compositeDefaultValue = update.to?.[property.name]; // not valid should be serialized
|
||||
|
||||
const serializedNewDefaultValue = unserializeDefaultValue(
|
||||
compositeDefaultValue,
|
||||
);
|
||||
const serializedNewDefaultValue = serializeDefaultValueV2({
|
||||
columnName: compositeColumnName,
|
||||
schemaName,
|
||||
tableName,
|
||||
columnType,
|
||||
defaultValue: compositeDefaultValue,
|
||||
});
|
||||
|
||||
await this.workspaceSchemaManagerService.columnManager.alterColumnDefault(
|
||||
{
|
||||
@@ -250,7 +259,13 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const serializedNewDefaultValue = unserializeDefaultValue(update.to);
|
||||
const serializedNewDefaultValue = serializeDefaultValueV2({
|
||||
columnName: flatFieldMetadata.name,
|
||||
schemaName,
|
||||
tableName,
|
||||
columnType,
|
||||
defaultValue: update.to,
|
||||
});
|
||||
|
||||
await this.workspaceSchemaManagerService.columnManager.alterColumnDefault(
|
||||
{
|
||||
@@ -264,18 +279,16 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
|
||||
}
|
||||
}
|
||||
|
||||
private async handleFieldOptionsUpdate(
|
||||
queryRunner: QueryRunner,
|
||||
schemaName: string,
|
||||
tableName: string,
|
||||
flatObjectMetadata: FlatObjectMetadata,
|
||||
flatFieldMetadata: FlatFieldMetadata<EnumFieldMetadataType>,
|
||||
update: {
|
||||
property: 'options';
|
||||
} & FromTo<
|
||||
FieldMetadataDefaultOption[] | FieldMetadataComplexOption[] | null
|
||||
>,
|
||||
) {
|
||||
private async handleFieldOptionsUpdate({
|
||||
flatFieldMetadata,
|
||||
queryRunner,
|
||||
schemaName,
|
||||
tableName,
|
||||
update,
|
||||
flatObjectMetadata,
|
||||
}: UpdateFieldPropertyUpdateHandlerArgs<'options'> & {
|
||||
flatObjectMetadata: FlatObjectMetadata;
|
||||
}) {
|
||||
const fromOptionsById = new Map(
|
||||
(update.from ?? [])
|
||||
.filter((opt) => isDefined(opt.id))
|
||||
|
||||
+10
-10
@@ -55,7 +55,7 @@ describe('Generate Column Definitions', () => {
|
||||
isArray: false,
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
default: null,
|
||||
default: 'NULL',
|
||||
});
|
||||
});
|
||||
|
||||
@@ -98,7 +98,7 @@ describe('Generate Column Definitions', () => {
|
||||
isArray: true,
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
default: null,
|
||||
default: 'NULL',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -188,7 +188,7 @@ describe('Generate Column Definitions', () => {
|
||||
columns.forEach((column) => {
|
||||
expect(column.isNullable).toBe(true);
|
||||
expect(column.isUnique).toBe(false);
|
||||
expect(column.default).toBe(null);
|
||||
expect(column.default).toBe('NULL');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -199,7 +199,7 @@ describe('Generate Column Definitions', () => {
|
||||
type: FieldMetadataType.CURRENCY,
|
||||
name: 'price',
|
||||
defaultValue: {
|
||||
amountMicros: '100000000',
|
||||
amountMicros: "'100000000'",
|
||||
currencyCode: "'USD'",
|
||||
},
|
||||
});
|
||||
@@ -220,7 +220,7 @@ describe('Generate Column Definitions', () => {
|
||||
type: 'numeric',
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
default: '100000000',
|
||||
default: "'100000000'::numeric",
|
||||
});
|
||||
|
||||
expect(columns[1]).toMatchObject({
|
||||
@@ -228,7 +228,7 @@ describe('Generate Column Definitions', () => {
|
||||
type: 'text',
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
default: 'USD',
|
||||
default: "'USD'::text",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -254,7 +254,7 @@ describe('Generate Column Definitions', () => {
|
||||
type: 'text',
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
default: null,
|
||||
default: 'NULL',
|
||||
isArray: false,
|
||||
},
|
||||
]);
|
||||
@@ -280,7 +280,7 @@ describe('Generate Column Definitions', () => {
|
||||
type: 'boolean',
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
default: true,
|
||||
default: "'true'::boolean",
|
||||
isArray: false,
|
||||
},
|
||||
]);
|
||||
@@ -307,7 +307,7 @@ describe('Generate Column Definitions', () => {
|
||||
type: 'text',
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
default: null,
|
||||
default: 'NULL',
|
||||
isArray: false,
|
||||
},
|
||||
]);
|
||||
@@ -332,7 +332,7 @@ describe('Generate Column Definitions', () => {
|
||||
type: 'uuid',
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
default: null,
|
||||
default: 'NULL',
|
||||
isArray: false,
|
||||
},
|
||||
]);
|
||||
|
||||
+23
-15
@@ -1,4 +1,5 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { type ColumnType } from 'typeorm';
|
||||
|
||||
import { type CompositeProperty } from 'src/engine/metadata-modules/field-metadata/interfaces/composite-type.interface';
|
||||
|
||||
@@ -8,8 +9,6 @@ import {
|
||||
computeCompositeColumnName,
|
||||
} from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
|
||||
import { getCompositeTypeOrThrow } from 'src/engine/metadata-modules/field-metadata/utils/get-composite-type-or-throw.util';
|
||||
import { serializeDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/serialize-default-value';
|
||||
import { unserializeDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/unserialize-default-value';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isCompositeFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-composite-flat-field-metadata.util';
|
||||
import { isFlatFieldMetadataEntityOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
|
||||
@@ -17,6 +16,7 @@ import { type FlatObjectMetadataWithoutFields } from 'src/engine/metadata-module
|
||||
import { fieldMetadataTypeToColumnType } from 'src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util';
|
||||
import { type WorkspaceSchemaColumnDefinition } from 'src/engine/twenty-orm/workspace-schema-manager/types/workspace-schema-column-definition.type';
|
||||
import { computePostgresEnumName } from 'src/engine/workspace-manager/workspace-migration-runner/utils/compute-postgres-enum-name.util';
|
||||
import { serializeDefaultValueV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/serialize-default-value-v2.util';
|
||||
import {
|
||||
WorkspaceMigrationRunnerException,
|
||||
WorkspaceMigrationRunnerExceptionCode,
|
||||
@@ -54,10 +54,14 @@ export const generateCompositeColumnDefinition = ({
|
||||
const defaultValue =
|
||||
// @ts-expect-error - TODO: fix this
|
||||
parentFieldMetadata.defaultValue?.[compositeProperty.name];
|
||||
|
||||
const unserializedDefaultValue = unserializeDefaultValue(defaultValue);
|
||||
|
||||
const columnType = fieldMetadataTypeToColumnType(compositeProperty.type);
|
||||
const serializedDefaultValue = serializeDefaultValueV2({
|
||||
columnName,
|
||||
schemaName,
|
||||
tableName,
|
||||
columnType: columnType as ColumnType,
|
||||
defaultValue,
|
||||
});
|
||||
|
||||
const isArrayFlag =
|
||||
compositeProperty.type === FieldMetadataType.ARRAY ||
|
||||
@@ -72,7 +76,7 @@ export const generateCompositeColumnDefinition = ({
|
||||
: columnType,
|
||||
isNullable: parentFieldMetadata.isNullable || !compositeProperty.isRequired,
|
||||
isUnique: parentFieldMetadata.isUnique ?? false,
|
||||
default: unserializedDefaultValue,
|
||||
default: serializedDefaultValue,
|
||||
isArray: isArrayFlag,
|
||||
};
|
||||
|
||||
@@ -120,23 +124,29 @@ const generateRelationColumnDefinition = (
|
||||
};
|
||||
};
|
||||
|
||||
const generateStandardColumnDefinition = (
|
||||
const generateColumnDefinition = (
|
||||
flatFieldMetadata: FlatFieldMetadata,
|
||||
tableName: string,
|
||||
schemaName: string,
|
||||
): WorkspaceSchemaColumnDefinition => {
|
||||
const columnName = computeColumnName(flatFieldMetadata.name);
|
||||
const serializedDefaultValue = serializeDefaultValue(
|
||||
flatFieldMetadata.defaultValue,
|
||||
);
|
||||
const columnType = fieldMetadataTypeToColumnType(flatFieldMetadata.type);
|
||||
const columnType = fieldMetadataTypeToColumnType(
|
||||
flatFieldMetadata.type,
|
||||
) as ColumnType;
|
||||
const serializedDefaultValue = serializeDefaultValueV2({
|
||||
columnName,
|
||||
schemaName,
|
||||
tableName,
|
||||
columnType,
|
||||
defaultValue: flatFieldMetadata.defaultValue,
|
||||
});
|
||||
|
||||
return {
|
||||
name: columnName,
|
||||
type:
|
||||
columnType === 'enum'
|
||||
? `"${schemaName}"."${computePostgresEnumName({ tableName, columnName })}"`
|
||||
: columnType,
|
||||
: (columnType as string),
|
||||
isNullable: flatFieldMetadata.isNullable ?? true,
|
||||
isArray:
|
||||
flatFieldMetadata.type === FieldMetadataType.ARRAY ||
|
||||
@@ -194,7 +204,5 @@ export const generateColumnDefinitions = ({
|
||||
return relationColumn ? [relationColumn] : [];
|
||||
}
|
||||
|
||||
return [
|
||||
generateStandardColumnDefinition(flatFieldMetadata, tableName, schemaName),
|
||||
];
|
||||
return [generateColumnDefinition(flatFieldMetadata, tableName, schemaName)];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user