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:
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user