Files
twenty/packages/twenty-server/src/workspace/workspace-sync-metadata/workspace-sync-metadata.service.ts
2024-02-08 18:22:29 +01:00

120 lines
4.2 KiB
TypeScript

import { Injectable, Logger } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { WorkspaceSyncContext } from 'src/workspace/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
import { WorkspaceMigrationRunnerService } from 'src/workspace/workspace-migration-runner/workspace-migration-runner.service';
import { FeatureFlagFactory } from 'src/workspace/workspace-sync-metadata/factories/feature-flags.factory';
import { WorkspaceSyncObjectMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-object-metadata.service';
import { WorkspaceSyncRelationMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-relation-metadata.service';
import { WorkspaceSyncStorage } from 'src/workspace/workspace-sync-metadata/storage/workspace-sync.storage';
import { WorkspaceMigrationEntity } from 'src/metadata/workspace-migration/workspace-migration.entity';
@Injectable()
export class WorkspaceSyncMetadataService {
private readonly logger = new Logger(WorkspaceSyncMetadataService.name);
constructor(
@InjectDataSource('metadata')
private readonly metadataDataSource: DataSource,
private readonly featureFlagFactory: FeatureFlagFactory,
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
private readonly workspaceSyncObjectMetadataService: WorkspaceSyncObjectMetadataService,
private readonly workspaceSyncRelationMetadataService: WorkspaceSyncRelationMetadataService,
) {}
/**
*
* Sync all standard objects and fields metadata for a given workspace and data source
* This will update the metadata if it has changed and generate migrations based on the diff.
*
* @param dataSourceId
* @param workspaceId
*/
public async syncStandardObjectsAndFieldsMetadata(
context: WorkspaceSyncContext,
options: { applyChanges?: boolean } = { applyChanges: true },
): Promise<{
workspaceMigrations: WorkspaceMigrationEntity[];
storage: WorkspaceSyncStorage;
}> {
let workspaceMigrations: WorkspaceMigrationEntity[] = [];
const storage = new WorkspaceSyncStorage();
const queryRunner = this.metadataDataSource.createQueryRunner();
this.logger.log('Syncing standard objects and fields metadata');
await queryRunner.connect();
await queryRunner.startTransaction();
const manager = queryRunner.manager;
try {
const workspaceMigrationRepository = manager.getRepository(
WorkspaceMigrationEntity,
);
// Retrieve feature flags
const workspaceFeatureFlagsMap =
await this.featureFlagFactory.create(context);
this.logger.log('Syncing standard objects and fields metadata');
const workspaceObjectMigrations =
await this.workspaceSyncObjectMetadataService.synchronize(
context,
manager,
storage,
workspaceFeatureFlagsMap,
);
const workspaceRelationMigrations =
await this.workspaceSyncRelationMetadataService.synchronize(
context,
manager,
storage,
workspaceFeatureFlagsMap,
);
// Save workspace migrations into the database
workspaceMigrations = await workspaceMigrationRepository.save([
...workspaceObjectMigrations,
...workspaceRelationMigrations,
]);
// If we're running a dry run, rollback the transaction and do not execute migrations
if (!options.applyChanges) {
this.logger.log('Running in dry run mode, rolling back transaction');
await queryRunner.rollbackTransaction();
await queryRunner.release();
return {
workspaceMigrations,
storage,
};
}
await queryRunner.commitTransaction();
// Execute migrations
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
context.workspaceId,
);
} catch (error) {
console.error('Sync of standard objects failed with:', error);
await queryRunner.rollbackTransaction();
} finally {
await queryRunner.release();
}
return {
workspaceMigrations,
storage,
};
}
}