fix: sync and health (#4095)

* fix: throw error if we try to create a migration without columnName

* fix: typeorm save for update breaking everything
This commit is contained in:
Jérémy M 2024-02-20 17:55:23 +01:00 committed by GitHub
parent 8c46e66cf5
commit 3914e8d77c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 73 additions and 27 deletions

View File

@ -55,11 +55,22 @@ export class BasicColumnActionFactory extends ColumnActionAbstractFactory<BasicF
this.getDefaultValue(alteredFieldMetadata.defaultValue) ??
options?.defaultValue;
const serializedDefaultValue = serializeDefaultValue(defaultValue);
const currentColumnName = currentFieldMetadata.targetColumnMap.value;
const alteredColumnName = alteredFieldMetadata.targetColumnMap.value;
if (!currentColumnName || !alteredColumnName) {
this.logger.error(
`Column name not found for current or altered field metadata, can be due to a missing or an invalid target column map. Current column name: ${currentColumnName}, Altered column name: ${alteredColumnName}.`,
);
throw new Error(
`Column name not found for current or altered field metadata`,
);
}
return {
action: WorkspaceMigrationColumnActionType.ALTER,
currentColumnDefinition: {
columnName: currentFieldMetadata.targetColumnMap.value,
columnName: currentColumnName,
columnType: fieldMetadataTypeToColumnType(currentFieldMetadata.type),
isNullable: currentFieldMetadata.isNullable,
defaultValue: serializeDefaultValue(
@ -67,7 +78,7 @@ export class BasicColumnActionFactory extends ColumnActionAbstractFactory<BasicF
),
},
alteredColumnDefinition: {
columnName: alteredFieldMetadata.targetColumnMap.value,
columnName: alteredColumnName,
columnType: fieldMetadataTypeToColumnType(alteredFieldMetadata.type),
isNullable: alteredFieldMetadata.isNullable,
defaultValue: serializedDefaultValue,

View File

@ -71,11 +71,22 @@ export class EnumColumnActionFactory extends ColumnActionAbstractFactory<EnumFie
}),
]
: undefined;
const currentColumnName = currentFieldMetadata.targetColumnMap.value;
const alteredColumnName = alteredFieldMetadata.targetColumnMap.value;
if (!currentColumnName || !alteredColumnName) {
this.logger.error(
`Column name not found for current or altered field metadata, can be due to a missing or an invalid target column map. Current column name: ${currentColumnName}, Altered column name: ${alteredColumnName}.`,
);
throw new Error(
`Column name not found for current or altered field metadata`,
);
}
return {
action: WorkspaceMigrationColumnActionType.ALTER,
currentColumnDefinition: {
columnName: currentFieldMetadata.targetColumnMap.value,
columnName: currentColumnName,
columnType: fieldMetadataTypeToColumnType(currentFieldMetadata.type),
enum: currentFieldMetadata.options
? [...currentFieldMetadata.options.map((option) => option.value)]
@ -87,7 +98,7 @@ export class EnumColumnActionFactory extends ColumnActionAbstractFactory<EnumFie
),
},
alteredColumnDefinition: {
columnName: alteredFieldMetadata.targetColumnMap.value,
columnName: alteredColumnName,
columnType: fieldMetadataTypeToColumnType(alteredFieldMetadata.type),
enum: enumOptions,
isArray: alteredFieldMetadata.type === FieldMetadataType.MULTI_SELECT,

View File

@ -127,13 +127,40 @@ export class WorkspaceMetadataUpdaterService {
/**
* Update field metadata
*/
const oldFieldMetadataCollection = await fieldMetadataRepository.find({
where: {
id: In(storage.fieldMetadataUpdateCollection.map((field) => field.id)),
},
const oldFieldMetadataCollection = await fieldMetadataRepository.findBy({
id: In(storage.fieldMetadataUpdateCollection.map((field) => field.id)),
});
// Pre-process old collection into a mapping for quick access
const oldFieldMetadataMap = new Map(
oldFieldMetadataCollection.map((field) => [field.id, field]),
);
// Combine old and new field metadata to get whole updated entities
const fieldMetadataUpdateCollection =
storage.fieldMetadataUpdateCollection.map((updateFieldMetadata) => {
const oldFieldMetadata = oldFieldMetadataMap.get(
updateFieldMetadata.id,
);
if (!oldFieldMetadata) {
throw new Error(`
Field ${updateFieldMetadata.id} not found in oldFieldMetadataCollection`);
}
// TypeORM 😢
// If we didn't provide the old value, it will be set to null fields that are not in the updateFieldMetadata
// and override the old value with null in the DB.
// Also save method doesn't return the whole entity if you give a partial one.
// https://github.com/typeorm/typeorm/issues/3490
// To avoid calling update in a for loop, we did this hack.
return {
...oldFieldMetadata,
...updateFieldMetadata,
options: updateFieldMetadata.options ?? oldFieldMetadata.options,
};
});
const updatedFieldMetadataCollection = await fieldMetadataRepository.save(
storage.fieldMetadataUpdateCollection as DeepPartial<FieldMetadataEntity>[],
fieldMetadataUpdateCollection,
);
/**
@ -156,26 +183,21 @@ export class WorkspaceMetadataUpdaterService {
return {
createdFieldMetadataCollection:
createdFieldMetadataCollection as FieldMetadataEntity[],
updatedFieldMetadataCollection: oldFieldMetadataCollection.map(
(oldFieldMetadata) => {
const alteredFieldMetadata = updatedFieldMetadataCollection.find(
(field) => field.id === oldFieldMetadata.id,
updatedFieldMetadataCollection: updatedFieldMetadataCollection.map(
(alteredFieldMetadata) => {
const oldFieldMetadata = oldFieldMetadataMap.get(
alteredFieldMetadata.id,
);
if (!alteredFieldMetadata) {
throw new Error(
`Field ${oldFieldMetadata.id} not found in updatedFieldMetadataCollection`,
);
if (!oldFieldMetadata) {
throw new Error(`
Field ${alteredFieldMetadata.id} not found in oldFieldMetadataCollection
`);
}
return {
current: oldFieldMetadata as FieldMetadataEntity,
// TypeORM save method doesn't return the whole entity...
// https://github.com/typeorm/typeorm/issues/3490
altered: {
...oldFieldMetadata,
...alteredFieldMetadata,
} as FieldMetadataEntity,
altered: alteredFieldMetadata as FieldMetadataEntity,
};
},
),

View File

@ -15,9 +15,9 @@ export class WorkspaceSyncStorage {
// Field metadata
private readonly _fieldMetadataCreateCollection: PartialFieldMetadata[] = [];
private readonly _fieldMetadataUpdateCollection: Partial<
PartialFieldMetadata & { id: string }
>[] = [];
private readonly _fieldMetadataUpdateCollection: (Partial<PartialFieldMetadata> & {
id: string;
})[] = [];
private readonly _fieldMetadataDeleteCollection: FieldMetadataEntity[] = [];
// Relation metadata
@ -76,7 +76,9 @@ export class WorkspaceSyncStorage {
this._fieldMetadataCreateCollection.push(field);
}
addUpdateFieldMetadata(field: Partial<PartialFieldMetadata>) {
addUpdateFieldMetadata(
field: Partial<PartialFieldMetadata> & { id: string },
) {
this._fieldMetadataUpdateCollection.push(field);
}