Skip to content

Commit

Permalink
feat: wip sync standard id (#4373)
Browse files Browse the repository at this point in the history
* feat: wip sync standard id

feat: implement standardId for sync command

* fix: rebase

* fix: tests

* fix: deterministic uuid

* fix: sync custom not working

* fix: create custom not adding standardId

* fix: readability
  • Loading branch information
magrinj authored Mar 13, 2024
1 parent 7b63cf1 commit d8b3707
Show file tree
Hide file tree
Showing 52 changed files with 926 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddStandardId1709894431938 implements MigrationInterface {
name = 'AddStandardId1709894431938';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "metadata"."objectMetadata" ADD "standardId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "metadata"."fieldMetadata" ADD "standardId" uuid`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "metadata"."fieldMetadata" DROP COLUMN "standardId"`,
);
await queryRunner.query(
`ALTER TABLE "metadata"."objectMetadata" DROP COLUMN "standardId"`,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ export class FieldMetadataEntity<
@PrimaryGeneratedColumn('uuid')
id: string;

@Column({ nullable: true, type: 'uuid' })
standardId: string | null;

@Column({ nullable: false, type: 'uuid' })
objectMetadataId: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export class ObjectMetadataEntity implements ObjectMetadataInterface {
@PrimaryGeneratedColumn('uuid')
id: string;

@Column({ nullable: true, type: 'uuid' })
standardId: string | null;

@Column({ nullable: false, type: 'uuid' })
dataSourceId: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-tar
import { DeleteOneObjectInput } from 'src/metadata/object-metadata/dtos/delete-object.input';
import { RelationToDelete } from 'src/metadata/relation-metadata/types/relation-to-delete';
import { generateMigrationName } from 'src/metadata/workspace-migration/utils/generate-migration-name.util';
import {
activityTargetStandardFieldIds,
attachmentStandardFieldIds,
baseObjectStandardFieldIds,
customObjectStandardFieldIds,
favoriteStandardFieldIds,
} from 'src/workspace/workspace-sync-metadata/constants/standard-field-ids';
import { createDeterministicUuid } from 'src/workspace/workspace-sync-metadata/utils/create-deterministic-uuid.util';

import { ObjectMetadataEntity } from './object-metadata.entity';

Expand Down Expand Up @@ -229,6 +237,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
// created with default values which is not supported yet by workspace migrations.
[
{
standardId: baseObjectStandardFieldIds.id,
type: FieldMetadataType.UUID,
name: 'id',
label: 'Id',
Expand All @@ -245,6 +254,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
defaultValue: { type: 'uuid' },
},
{
standardId: customObjectStandardFieldIds.name,
type: FieldMetadataType.TEXT,
name: 'name',
label: 'Name',
Expand All @@ -260,6 +270,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
defaultValue: { value: 'Untitled' },
},
{
standardId: baseObjectStandardFieldIds.createdAt,
type: FieldMetadataType.DATE_TIME,
name: 'createdAt',
label: 'Creation date',
Expand All @@ -275,6 +286,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
defaultValue: { type: 'now' },
},
{
standardId: baseObjectStandardFieldIds.updatedAt,
type: FieldMetadataType.DATE_TIME,
name: 'updatedAt',
label: 'Update date',
Expand All @@ -291,6 +303,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
defaultValue: { type: 'now' },
},
{
standardId: customObjectStandardFieldIds.position,
type: FieldMetadataType.POSITION,
name: 'position',
label: 'Position',
Expand Down Expand Up @@ -587,6 +600,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
await this.fieldMetadataRepository.save([
// FROM
{
standardId: customObjectStandardFieldIds.activityTargets,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
Expand All @@ -601,6 +615,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
},
// TO
{
standardId: activityTargetStandardFieldIds.custom,
objectMetadataId: activityTargetObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
Expand All @@ -615,6 +630,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
},
// Foreign key
{
standardId: createDeterministicUuid(
activityTargetStandardFieldIds.custom,
),
objectMetadataId: activityTargetObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
Expand Down Expand Up @@ -681,6 +699,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
await this.fieldMetadataRepository.save([
// FROM
{
standardId: customObjectStandardFieldIds.attachments,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
Expand All @@ -695,6 +714,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
},
// TO
{
standardId: attachmentStandardFieldIds.custom,
objectMetadataId: attachmentObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
Expand All @@ -709,6 +729,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
},
// Foreign key
{
standardId: createDeterministicUuid(
attachmentStandardFieldIds.custom,
),
objectMetadataId: attachmentObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
Expand Down Expand Up @@ -773,6 +796,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
await this.fieldMetadataRepository.save([
// FROM
{
standardId: customObjectStandardFieldIds.favorites,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
Expand All @@ -788,6 +812,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
},
// TO
{
standardId: favoriteStandardFieldIds.custom,
objectMetadataId: favoriteObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
Expand All @@ -802,6 +827,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
},
// Foreign key
{
standardId: createDeterministicUuid(favoriteStandardFieldIds.custom),
objectMetadataId: favoriteObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { Logger } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';

import { Command, CommandRunner } from 'nest-commander';
import { DataSource } from 'typeorm';

import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
import { FieldMetadataEntity } from 'src/metadata/field-metadata/field-metadata.entity';
import { standardObjectMetadataDefinitions } from 'src/workspace/workspace-sync-metadata/standard-objects';
import { StandardObjectFactory } from 'src/workspace/workspace-sync-metadata/factories/standard-object.factory';
import { computeStandardObject } from 'src/workspace/workspace-sync-metadata/utils/compute-standard-object.util';
import { StandardFieldFactory } from 'src/workspace/workspace-sync-metadata/factories/standard-field.factory';
import { CustomObjectMetadata } from 'src/workspace/workspace-sync-metadata/custom-objects/custom.object-metadata';

@Command({
name: 'workspace:add-standard-id',
description: 'Add standard id to all metadata objects and fields',
})
export class AddStandardIdCommand extends CommandRunner {
private readonly logger = new Logger(AddStandardIdCommand.name);

constructor(
@InjectDataSource('metadata')
private readonly metadataDataSource: DataSource,
private readonly standardObjectFactory: StandardObjectFactory,
private readonly standardFieldFactory: StandardFieldFactory,
) {
super();
}

async run(): Promise<void> {
const queryRunner = this.metadataDataSource.createQueryRunner();

await queryRunner.connect();
await queryRunner.startTransaction();

const manager = queryRunner.manager;

this.logger.log('Adding standardId to metadata objects and fields');

try {
const standardObjectMetadataCollection =
this.standardObjectFactory.create(
standardObjectMetadataDefinitions,
{
// We don't need to provide the workspace id and data source id as we're only adding standardId
workspaceId: '',
dataSourceId: '',
},
{
IS_BLOCKLIST_ENABLED: true,
IS_CALENDAR_ENABLED: true,
IS_SELF_BILLING_ENABLED: true,
},
);
const standardFieldMetadataCollection = this.standardFieldFactory.create(
CustomObjectMetadata,
{
workspaceId: '',
dataSourceId: '',
},
{
IS_BLOCKLIST_ENABLED: true,
IS_CALENDAR_ENABLED: true,
IS_SELF_BILLING_ENABLED: true,
},
);

const objectMetadataRepository =
manager.getRepository(ObjectMetadataEntity);
const fieldMetadataRepository =
manager.getRepository(FieldMetadataEntity);

/**
* Update all object metadata with standard id
*/
const updateObjectMetadataCollection: Partial<ObjectMetadataEntity>[] =
[];
const updateFieldMetadataCollection: Partial<FieldMetadataEntity>[] = [];
const originalObjectMetadataCollection =
await objectMetadataRepository.find({
where: {
fields: { isCustom: false },
},
relations: ['fields'],
});
const customObjectMetadataCollection =
originalObjectMetadataCollection.filter(
(metadata) => metadata.isCustom,
);
const standardObjectMetadataMap = new Map(
standardObjectMetadataCollection.map((metadata) => [
metadata.nameSingular,
metadata,
]),
);

for (const originalObjectMetadata of originalObjectMetadataCollection) {
const standardObjectMetadata = standardObjectMetadataMap.get(
originalObjectMetadata.nameSingular,
);

if (!standardObjectMetadata && !originalObjectMetadata.isCustom) {
continue;
}

const computedStandardObjectMetadata = computeStandardObject(
standardObjectMetadata ?? {
...originalObjectMetadata,
fields: standardFieldMetadataCollection,
},
originalObjectMetadata,
customObjectMetadataCollection,
);

if (
!originalObjectMetadata.isCustom &&
!originalObjectMetadata.standardId
) {
updateObjectMetadataCollection.push({
id: originalObjectMetadata.id,
standardId: computedStandardObjectMetadata.standardId,
});
}

for (const fieldMetadata of originalObjectMetadata.fields) {
const standardFieldMetadata =
computedStandardObjectMetadata.fields.find(
(field) => field.name === fieldMetadata.name && !field.isCustom,
);

if (!standardFieldMetadata || fieldMetadata.standardId) {
continue;
}

updateFieldMetadataCollection.push({
id: fieldMetadata.id,
standardId: standardFieldMetadata.standardId,
});
}
}

await objectMetadataRepository.save(updateObjectMetadataCollection);

await fieldMetadataRepository.save(updateFieldMetadataCollection);

await queryRunner.commitTransaction();
} catch (error) {
await queryRunner.rollbackTransaction();
this.logger.error('Error adding standard id to metadata', error);
} finally {
await queryRunner.release();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DataSourceModule } from 'src/metadata/data-source/data-source.module';
import { WorkspaceSyncMetadataModule } from 'src/workspace/workspace-sync-metadata/workspace-sync-metadata.module';
import { WorkspaceHealthModule } from 'src/workspace/workspace-health/workspace-health.module';
import { WorkspaceModule } from 'src/core/workspace/workspace.module';
import { AddStandardIdCommand } from 'src/workspace/workspace-sync-metadata/commands/add-standard-id.command';

import { SyncWorkspaceMetadataCommand } from './sync-workspace-metadata.command';

Expand All @@ -16,6 +17,10 @@ import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.ser
WorkspaceModule,
DataSourceModule,
],
providers: [SyncWorkspaceMetadataCommand, SyncWorkspaceLoggerService],
providers: [
SyncWorkspaceMetadataCommand,
AddStandardIdCommand,
SyncWorkspaceLoggerService,
],
})
export class WorkspaceSyncMetadataCommandsModule {}
Loading

0 comments on commit d8b3707

Please sign in to comment.