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
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) ?? this.getDefaultValue(alteredFieldMetadata.defaultValue) ??
options?.defaultValue; options?.defaultValue;
const serializedDefaultValue = serializeDefaultValue(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 { return {
action: WorkspaceMigrationColumnActionType.ALTER, action: WorkspaceMigrationColumnActionType.ALTER,
currentColumnDefinition: { currentColumnDefinition: {
columnName: currentFieldMetadata.targetColumnMap.value, columnName: currentColumnName,
columnType: fieldMetadataTypeToColumnType(currentFieldMetadata.type), columnType: fieldMetadataTypeToColumnType(currentFieldMetadata.type),
isNullable: currentFieldMetadata.isNullable, isNullable: currentFieldMetadata.isNullable,
defaultValue: serializeDefaultValue( defaultValue: serializeDefaultValue(
@ -67,7 +78,7 @@ export class BasicColumnActionFactory extends ColumnActionAbstractFactory<BasicF
), ),
}, },
alteredColumnDefinition: { alteredColumnDefinition: {
columnName: alteredFieldMetadata.targetColumnMap.value, columnName: alteredColumnName,
columnType: fieldMetadataTypeToColumnType(alteredFieldMetadata.type), columnType: fieldMetadataTypeToColumnType(alteredFieldMetadata.type),
isNullable: alteredFieldMetadata.isNullable, isNullable: alteredFieldMetadata.isNullable,
defaultValue: serializedDefaultValue, defaultValue: serializedDefaultValue,

View File

@ -71,11 +71,22 @@ export class EnumColumnActionFactory extends ColumnActionAbstractFactory<EnumFie
}), }),
] ]
: undefined; : 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 { return {
action: WorkspaceMigrationColumnActionType.ALTER, action: WorkspaceMigrationColumnActionType.ALTER,
currentColumnDefinition: { currentColumnDefinition: {
columnName: currentFieldMetadata.targetColumnMap.value, columnName: currentColumnName,
columnType: fieldMetadataTypeToColumnType(currentFieldMetadata.type), columnType: fieldMetadataTypeToColumnType(currentFieldMetadata.type),
enum: currentFieldMetadata.options enum: currentFieldMetadata.options
? [...currentFieldMetadata.options.map((option) => option.value)] ? [...currentFieldMetadata.options.map((option) => option.value)]
@ -87,7 +98,7 @@ export class EnumColumnActionFactory extends ColumnActionAbstractFactory<EnumFie
), ),
}, },
alteredColumnDefinition: { alteredColumnDefinition: {
columnName: alteredFieldMetadata.targetColumnMap.value, columnName: alteredColumnName,
columnType: fieldMetadataTypeToColumnType(alteredFieldMetadata.type), columnType: fieldMetadataTypeToColumnType(alteredFieldMetadata.type),
enum: enumOptions, enum: enumOptions,
isArray: alteredFieldMetadata.type === FieldMetadataType.MULTI_SELECT, isArray: alteredFieldMetadata.type === FieldMetadataType.MULTI_SELECT,

View File

@ -127,13 +127,40 @@ export class WorkspaceMetadataUpdaterService {
/** /**
* Update field metadata * Update field metadata
*/ */
const oldFieldMetadataCollection = await fieldMetadataRepository.find({ const oldFieldMetadataCollection = await fieldMetadataRepository.findBy({
where: { id: In(storage.fieldMetadataUpdateCollection.map((field) => field.id)),
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( const updatedFieldMetadataCollection = await fieldMetadataRepository.save(
storage.fieldMetadataUpdateCollection as DeepPartial<FieldMetadataEntity>[], fieldMetadataUpdateCollection,
); );
/** /**
@ -156,26 +183,21 @@ export class WorkspaceMetadataUpdaterService {
return { return {
createdFieldMetadataCollection: createdFieldMetadataCollection:
createdFieldMetadataCollection as FieldMetadataEntity[], createdFieldMetadataCollection as FieldMetadataEntity[],
updatedFieldMetadataCollection: oldFieldMetadataCollection.map( updatedFieldMetadataCollection: updatedFieldMetadataCollection.map(
(oldFieldMetadata) => { (alteredFieldMetadata) => {
const alteredFieldMetadata = updatedFieldMetadataCollection.find( const oldFieldMetadata = oldFieldMetadataMap.get(
(field) => field.id === oldFieldMetadata.id, alteredFieldMetadata.id,
); );
if (!alteredFieldMetadata) { if (!oldFieldMetadata) {
throw new Error( throw new Error(`
`Field ${oldFieldMetadata.id} not found in updatedFieldMetadataCollection`, Field ${alteredFieldMetadata.id} not found in oldFieldMetadataCollection
); `);
} }
return { return {
current: oldFieldMetadata as FieldMetadataEntity, current: oldFieldMetadata as FieldMetadataEntity,
// TypeORM save method doesn't return the whole entity... altered: alteredFieldMetadata as FieldMetadataEntity,
// https://github.com/typeorm/typeorm/issues/3490
altered: {
...oldFieldMetadata,
...alteredFieldMetadata,
} as FieldMetadataEntity,
}; };
}, },
), ),

View File

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