Add field create and delete migration to metadata sync (#2942)

add field create and delete migration to metadata sync
This commit is contained in:
Weiko
2023-12-11 17:42:09 +01:00
committed by GitHub
parent b9de9f1a08
commit d2a42c14d2
4 changed files with 83 additions and 4 deletions

View File

@ -9,6 +9,7 @@ export enum WorkspaceMigrationColumnActionType {
CREATE = 'CREATE', CREATE = 'CREATE',
ALTER = 'ALTER', ALTER = 'ALTER',
RELATION = 'RELATION', RELATION = 'RELATION',
DROP = 'DROP',
} }
export type WorkspaceMigrationEnum = string | { from: string; to: string }; export type WorkspaceMigrationEnum = string | { from: string; to: string };
@ -41,12 +42,18 @@ export type WorkspaceMigrationColumnRelation = {
isUnique?: boolean; isUnique?: boolean;
}; };
export type WorkspaceMigrationColumnDrop = {
action: WorkspaceMigrationColumnActionType.DROP;
columnName: string;
};
export type WorkspaceMigrationColumnAction = { export type WorkspaceMigrationColumnAction = {
action: WorkspaceMigrationColumnActionType; action: WorkspaceMigrationColumnActionType;
} & ( } & (
| WorkspaceMigrationColumnCreate | WorkspaceMigrationColumnCreate
| WorkspaceMigrationColumnAlter | WorkspaceMigrationColumnAlter
| WorkspaceMigrationColumnRelation | WorkspaceMigrationColumnRelation
| WorkspaceMigrationColumnDrop
); );
export type WorkspaceMigrationTableAction = { export type WorkspaceMigrationTableAction = {

View File

@ -187,6 +187,12 @@ export class WorkspaceMigrationRunnerService {
columnMigration, columnMigration,
); );
break; break;
case WorkspaceMigrationColumnActionType.DROP:
await queryRunner.dropColumn(
`${schemaName}.${tableName}`,
columnMigration.columnName,
);
break;
default: default:
throw new Error(`Migration column action not supported`); throw new Error(`Migration column action not supported`);
} }

View File

@ -144,7 +144,8 @@ function generateFieldMetadata<T extends FieldMetadataType>(
name: fieldKey, name: fieldKey,
...metadata, ...metadata,
targetColumnMap: targetColumnMap, targetColumnMap: targetColumnMap,
isNullable: metadata.type === FieldMetadataType.RELATION ? true : isNullable, isNullable:
metadata.type === FieldMetadataType.RELATION ? true : isNullable,
isSystem, isSystem,
isCustom: false, isCustom: false,
options: null, // TODO: handle options + stringify for the diff. options: null, // TODO: handle options + stringify for the diff.

View File

@ -125,6 +125,7 @@ export class WorkspaceSyncMetadataService {
if (value === null || typeof value !== 'object') { if (value === null || typeof value !== 'object') {
return [key, value]; return [key, value];
} }
return [ return [
key, key,
filterIgnoredProperties( filterIgnoredProperties(
@ -134,6 +135,7 @@ export class WorkspaceSyncMetadataService {
if (property !== null && typeof property === 'object') { if (property !== null && typeof property === 'object') {
return JSON.stringify(property); return JSON.stringify(property);
} }
return property; return property;
}, },
), ),
@ -157,6 +159,7 @@ export class WorkspaceSyncMetadataService {
// We only handle CHANGE here as REMOVE and CREATE are handled earlier. // We only handle CHANGE here as REMOVE and CREATE are handled earlier.
if (diff.type === 'CHANGE') { if (diff.type === 'CHANGE') {
const property = diff.path[0]; const property = diff.path[0];
objectsToUpdate[objectInDB.id] = { objectsToUpdate[objectInDB.id] = {
...objectsToUpdate[objectInDB.id], ...objectsToUpdate[objectInDB.id],
[property]: diff.value, [property]: diff.value,
@ -166,6 +169,7 @@ export class WorkspaceSyncMetadataService {
for (const diff of fieldsDiff) { for (const diff of fieldsDiff) {
const fieldName = diff.path[0]; const fieldName = diff.path[0];
if (diff.type === 'CREATE') if (diff.type === 'CREATE')
fieldsToCreate.push({ fieldsToCreate.push({
...standardObjectFields[fieldName], ...standardObjectFields[fieldName],
@ -175,6 +179,7 @@ export class WorkspaceSyncMetadataService {
fieldsToDelete.push(objectInDBFields[fieldName]); fieldsToDelete.push(objectInDBFields[fieldName]);
if (diff.type === 'CHANGE') { if (diff.type === 'CHANGE') {
const property = diff.path[diff.path.length - 1]; const property = diff.path[diff.path.length - 1];
fieldsToUpdate[objectInDBFields[fieldName].id] = { fieldsToUpdate[objectInDBFields[fieldName].id] = {
...fieldsToUpdate[objectInDBFields[fieldName].id], ...fieldsToUpdate[objectInDBFields[fieldName].id],
[property]: diff.value, [property]: diff.value,
@ -221,6 +226,7 @@ export class WorkspaceSyncMetadataService {
const fieldsToDeleteWithoutRelationType = fieldsToDelete.filter( const fieldsToDeleteWithoutRelationType = fieldsToDelete.filter(
(field) => field.type !== FieldMetadataType.RELATION, (field) => field.type !== FieldMetadataType.RELATION,
); );
if (fieldsToDeleteWithoutRelationType.length > 0) { if (fieldsToDeleteWithoutRelationType.length > 0) {
await this.fieldMetadataRepository.delete( await this.fieldMetadataRepository.delete(
fieldsToDeleteWithoutRelationType.map((field) => field.id), fieldsToDeleteWithoutRelationType.map((field) => field.id),
@ -233,6 +239,7 @@ export class WorkspaceSyncMetadataService {
objectsToDelete, objectsToDelete,
fieldsToCreate, fieldsToCreate,
fieldsToDelete, fieldsToDelete,
objectsInDB,
); );
// We run syncRelationMetadata after everything to ensure that all objects and fields are // We run syncRelationMetadata after everything to ensure that all objects and fields are
@ -263,7 +270,9 @@ export class WorkspaceSyncMetadataService {
objectsInDBByName, objectsInDBByName,
).reduce((result, currentObject) => { ).reduce((result, currentObject) => {
const key = `${currentObject.fromObjectMetadataId}->${currentObject.fromFieldMetadataId}`; const key = `${currentObject.fromObjectMetadataId}->${currentObject.fromFieldMetadataId}`;
result[key] = currentObject; result[key] = currentObject;
return result; return result;
}, {}); }, {});
@ -279,7 +288,9 @@ export class WorkspaceSyncMetadataService {
) )
.reduce((result, currentObject) => { .reduce((result, currentObject) => {
const key = `${currentObject.fromObjectMetadataId}->${currentObject.fromFieldMetadataId}`; const key = `${currentObject.fromObjectMetadataId}->${currentObject.fromFieldMetadataId}`;
result[key] = currentObject; result[key] = currentObject;
return result; return result;
}, {}); }, {});
@ -324,8 +335,9 @@ export class WorkspaceSyncMetadataService {
private async generateMigrationsFromSync( private async generateMigrationsFromSync(
objectsToCreate: ObjectMetadataEntity[], objectsToCreate: ObjectMetadataEntity[],
_objectsToDelete: ObjectMetadataEntity[], _objectsToDelete: ObjectMetadataEntity[],
_fieldsToCreate: FieldMetadataEntity[], fieldsToCreate: FieldMetadataEntity[],
_fieldsToDelete: FieldMetadataEntity[], fieldsToDelete: FieldMetadataEntity[],
objectsInDB: ObjectMetadataEntity[],
) { ) {
const migrationsToSave: Partial<WorkspaceMigrationEntity>[] = []; const migrationsToSave: Partial<WorkspaceMigrationEntity>[] = [];
@ -359,6 +371,59 @@ export class WorkspaceSyncMetadataService {
}); });
} }
// TODO: handle object delete migrations.
// Note: we need to delete the relation first due to the DB constraint.
const objectsInDbById = objectsInDB.reduce((result, currentObject) => {
result[currentObject.id] = currentObject;
return result;
}, {});
if (fieldsToCreate.length > 0) {
fieldsToCreate.map((field) => {
const migrations = [
{
name: objectsInDbById[field.objectMetadataId].targetTableName,
action: 'alter',
columns: this.workspaceMigrationFactory.createColumnActions(
WorkspaceMigrationColumnActionType.CREATE,
field,
),
} satisfies WorkspaceMigrationTableAction,
];
migrationsToSave.push({
workspaceId: field.workspaceId,
isCustom: false,
migrations,
});
});
}
if (fieldsToDelete.length > 0) {
fieldsToDelete.map((field) => {
const migrations = [
{
name: objectsInDbById[field.objectMetadataId].targetTableName,
action: 'alter',
columns: [
{
action: WorkspaceMigrationColumnActionType.DROP,
columnName: field.name,
},
],
} satisfies WorkspaceMigrationTableAction,
];
migrationsToSave.push({
workspaceId: field.workspaceId,
isCustom: false,
migrations,
});
});
}
await this.workspaceMigrationRepository.save(migrationsToSave); await this.workspaceMigrationRepository.save(migrationsToSave);
// TODO: handle delete migrations // TODO: handle delete migrations