Skip to content

Commit

Permalink
feat: wip sync standard id
Browse files Browse the repository at this point in the history
feat: implement standardId for sync command
  • Loading branch information
magrinj committed Mar 12, 2024
1 parent 0d8e700 commit 9619dae
Show file tree
Hide file tree
Showing 48 changed files with 866 additions and 22 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
@@ -0,0 +1,157 @@
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,
}
: standardObjectMetadata,
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,
);

if (!standardFieldMetadata || standardFieldMetadata.isCustom) {
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 {}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import { ComputedPartialObjectMetadata } from 'src/workspace/workspace-sync-meta

import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
import { transformMetadataForComparison } from 'src/workspace/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
import {
FieldMetadataEntity,
FieldMetadataType,
} from 'src/metadata/field-metadata/field-metadata.entity';

const commonFieldPropertiesToIgnore = [
'id',
Expand Down Expand Up @@ -61,7 +64,8 @@ export class WorkspaceFieldComparator {
},
propertiesToStringify: fieldPropertiesToStringify,
keyFactory(datum) {
return datum.name;
// Happen when the field is custom
return datum.standardId || datum.name;
},
},
);
Expand All @@ -85,7 +89,8 @@ export class WorkspaceFieldComparator {
},
propertiesToStringify: fieldPropertiesToStringify,
keyFactory(datum) {
return datum.name;
// Happen when the field is custom
return datum.standardId || datum.name;
},
},
);
Expand All @@ -98,13 +103,20 @@ export class WorkspaceFieldComparator {

for (const difference of fieldMetadataDifference) {
const fieldName = difference.path[0];
const findField = (
field: ComputedPartialFieldMetadata | FieldMetadataEntity,
) => {
if (field.isCustom) {
return field.name === fieldName;
}

return field.standardId === fieldName;
};
// Object shouldn't have thousands of fields, so we can use find here
const standardFieldMetadata = standardObjectMetadata.fields.find(
(field) => field.name === fieldName,
);
const originalFieldMetadata = originalObjectMetadata.fields.find(
(field) => field.name === fieldName,
);
const standardFieldMetadata =
standardObjectMetadata.fields.find(findField);
const originalFieldMetadata =
originalObjectMetadata.fields.find(findField);

switch (difference.type) {
case 'CREATE': {
Expand Down
Loading

0 comments on commit 9619dae

Please sign in to comment.