feat: refactor workspace sync fields (#6069)

This PR was first here to fix the issue related to ticket #5004, after
some testing it seems that changing the name of a relation is actually
properly working, if we rename `ONE-TO-MANY` side, the only things that
is going to be updated is the FieldMetadata as the `joinColumn` is
stored on the opposite object.
For `MANY-TO-ONE` relations, the `joinColumn` migration is properly
generated. We need to take care that if we rename a side of a relation,
sometimes the opposite side doesn't have `inverseSideFieldKey`
implemented and used by default the name of the opposite object, so this
is going to throw an error as the field can't be found in the object.

---------

Co-authored-by: Marie <51697796+ijreilly@users.noreply.github.com>
This commit is contained in:
Jérémy M 2024-07-02 17:21:13 +02:00 committed by GitHub
parent a163ccced6
commit 5b26452649
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 229 additions and 149 deletions

View File

@ -43,21 +43,21 @@
"[typescript]": { "[typescript]": {
"editor.formatOnSave": false, "editor.formatOnSave": false,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": true, "source.fixAll.eslint": "explicit",
"source.addMissingImports": "always" "source.addMissingImports": "always"
} }
}, },
"[javascript]": { "[javascript]": {
"editor.formatOnSave": false, "editor.formatOnSave": false,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": true, "source.fixAll.eslint": "explicit",
"source.addMissingImports": "always" "source.addMissingImports": "always"
} }
}, },
"[typescriptreact]": { "[typescriptreact]": {
"editor.formatOnSave": false, "editor.formatOnSave": false,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": true, "source.fixAll.eslint": "explicit",
"source.addMissingImports": "always" "source.addMissingImports": "always"
} }
}, },

View File

@ -122,7 +122,7 @@ export class TimelineCalendarEventService {
return { return {
totalNumberOfCalendarEvents: total, totalNumberOfCalendarEvents: total,
timelineCalendarEvents, timelineCalendarEvents: timelineCalendarEvents,
}; };
} }

View File

@ -8,9 +8,9 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects'; import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects';
import { StandardObjectFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory'; import { StandardObjectFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory';
import { computeStandardObject } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-object.util';
import { StandardFieldFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory'; import { StandardFieldFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory';
import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity'; import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity';
import { computeStandardFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-fields.util';
interface RunCommandOptions { interface RunCommandOptions {
workspaceId?: string; workspaceId?: string;
@ -123,11 +123,8 @@ export class AddStandardIdCommand extends CommandRunner {
continue; continue;
} }
const computedStandardObjectMetadata = computeStandardObject( const computedStandardFieldMetadataCollection = computeStandardFields(
standardObjectMetadata ?? { standardFieldMetadataCollection,
...originalObjectMetadata,
fields: standardFieldMetadataCollection,
},
originalObjectMetadata, originalObjectMetadata,
customObjectMetadataCollection, customObjectMetadataCollection,
); );
@ -135,13 +132,13 @@ export class AddStandardIdCommand extends CommandRunner {
if (!originalObjectMetadata.isCustom) { if (!originalObjectMetadata.isCustom) {
updateObjectMetadataCollection.push({ updateObjectMetadataCollection.push({
id: originalObjectMetadata.id, id: originalObjectMetadata.id,
standardId: computedStandardObjectMetadata.standardId, standardId: originalObjectMetadata.standardId,
}); });
} }
for (const fieldMetadata of originalObjectMetadata.fields) { for (const fieldMetadata of originalObjectMetadata.fields) {
const standardFieldMetadata = const standardFieldMetadata =
computedStandardObjectMetadata.fields.find( computedStandardFieldMetadataCollection.find(
(field) => field.name === fieldMetadata.name && !field.isCustom, (field) => field.name === fieldMetadata.name && !field.isCustom,
); );

View File

@ -36,7 +36,7 @@ describe('WorkspaceFieldComparator', () => {
], ],
} as any; } as any;
const result = comparator.compare(original, standard); const result = comparator.compare('', original.fields, standard.fields);
expect(result).toEqual([ expect(result).toEqual([
{ {
@ -65,7 +65,7 @@ describe('WorkspaceFieldComparator', () => {
], ],
} as any; } as any;
const result = comparator.compare(original, standard); const result = comparator.compare('', original.fields, standard.fields);
expect(result).toEqual([ expect(result).toEqual([
{ {
@ -88,7 +88,7 @@ describe('WorkspaceFieldComparator', () => {
} as any; } as any;
const standard = { fields: [] } as any; const standard = { fields: [] } as any;
const result = comparator.compare(original, standard); const result = comparator.compare('', original.fields, standard.fields);
expect(result).toEqual([ expect(result).toEqual([
{ {
@ -108,7 +108,7 @@ describe('WorkspaceFieldComparator', () => {
fields: [createMockFieldMetadata({ standardId: '1' })], fields: [createMockFieldMetadata({ standardId: '1' })],
} as any; } as any;
const result = comparator.compare(original, standard); const result = comparator.compare('', original.fields, standard.fields);
expect(result).toHaveLength(0); expect(result).toHaveLength(0);
}); });

View File

@ -7,9 +7,7 @@ import {
FieldComparatorResult, FieldComparatorResult,
} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface'; } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface';
import { ComputedPartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface'; import { ComputedPartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
import { ComputedPartialWorkspaceEntity } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util'; import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
import { import {
FieldMetadataEntity, FieldMetadataEntity,
@ -35,8 +33,9 @@ export class WorkspaceFieldComparator {
constructor() {} constructor() {}
public compare( public compare(
originalObjectMetadata: ObjectMetadataEntity, originalObjectMetadataId: string,
standardObjectMetadata: ComputedPartialWorkspaceEntity, originalFieldMetadataCollection: FieldMetadataEntity[],
standardFieldMetadataCollection: ComputedPartialFieldMetadata[],
): FieldComparatorResult[] { ): FieldComparatorResult[] {
const result: FieldComparatorResult[] = []; const result: FieldComparatorResult[] = [];
const fieldPropertiesToUpdateMap: Record< const fieldPropertiesToUpdateMap: Record<
@ -46,7 +45,7 @@ export class WorkspaceFieldComparator {
// Double security to only compare non-custom fields // Double security to only compare non-custom fields
const filteredOriginalFieldCollection = const filteredOriginalFieldCollection =
originalObjectMetadata.fields.filter((field) => !field.isCustom); originalFieldMetadataCollection.filter((field) => !field.isCustom);
const originalFieldMetadataMap = transformMetadataForComparison( const originalFieldMetadataMap = transformMetadataForComparison(
filteredOriginalFieldCollection, filteredOriginalFieldCollection,
{ {
@ -73,7 +72,7 @@ export class WorkspaceFieldComparator {
}, },
); );
const standardFieldMetadataMap = transformMetadataForComparison( const standardFieldMetadataMap = transformMetadataForComparison(
standardObjectMetadata.fields, standardFieldMetadataCollection,
{ {
shouldIgnoreProperty: (property, originalMetadata) => { shouldIgnoreProperty: (property, originalMetadata) => {
if (commonFieldPropertiesToIgnore.includes(property)) { if (commonFieldPropertiesToIgnore.includes(property)) {
@ -117,9 +116,9 @@ export class WorkspaceFieldComparator {
}; };
// Object shouldn't have thousands of fields, so we can use find here // Object shouldn't have thousands of fields, so we can use find here
const standardFieldMetadata = const standardFieldMetadata =
standardObjectMetadata.fields.find(findField); standardFieldMetadataCollection.find(findField);
const originalFieldMetadata = const originalFieldMetadata =
originalObjectMetadata.fields.find(findField); originalFieldMetadataCollection.find(findField);
switch (difference.type) { switch (difference.type) {
case 'CREATE': { case 'CREATE': {
@ -133,7 +132,7 @@ export class WorkspaceFieldComparator {
action: ComparatorAction.CREATE, action: ComparatorAction.CREATE,
object: { object: {
...standardFieldMetadata, ...standardFieldMetadata,
objectMetadataId: originalObjectMetadata.id, objectMetadataId: originalObjectMetadataId,
}, },
}); });
break; break;

View File

@ -27,8 +27,8 @@ export class WorkspaceObjectComparator {
constructor() {} constructor() {}
public compare( public compare(
originalObjectMetadata: ObjectMetadataEntity | undefined, originalObjectMetadata: Omit<ObjectMetadataEntity, 'fields'> | undefined,
standardObjectMetadata: ComputedPartialWorkspaceEntity, standardObjectMetadata: Omit<ComputedPartialWorkspaceEntity, 'fields'>,
): ObjectComparatorResult { ): ObjectComparatorResult {
// If the object doesn't exist in the original metadata, we need to create it // If the object doesn't exist in the original metadata, we need to create it
if (!originalObjectMetadata) { if (!originalObjectMetadata) {

View File

@ -24,10 +24,53 @@ export class StandardFieldFactory {
target: typeof BaseWorkspaceEntity, target: typeof BaseWorkspaceEntity,
context: WorkspaceSyncContext, context: WorkspaceSyncContext,
workspaceFeatureFlagsMap: FeatureFlagMap, workspaceFeatureFlagsMap: FeatureFlagMap,
): Array<PartialFieldMetadata | PartialComputedFieldMetadata> { ): (PartialFieldMetadata | PartialComputedFieldMetadata)[];
create(
targets: (typeof BaseWorkspaceEntity)[],
context: WorkspaceSyncContext,
workspaceFeatureFlagsMap: FeatureFlagMap, // Map of standardId to field metadata
): Map<string, (PartialFieldMetadata | PartialComputedFieldMetadata)[]>;
create(
targetOrTargets:
| typeof BaseWorkspaceEntity
| (typeof BaseWorkspaceEntity)[],
context: WorkspaceSyncContext,
workspaceFeatureFlagsMap: FeatureFlagMap,
):
| (PartialFieldMetadata | PartialComputedFieldMetadata)[]
| Map<string, (PartialFieldMetadata | PartialComputedFieldMetadata)[]> {
if (Array.isArray(targetOrTargets)) {
return targetOrTargets.reduce((acc, target) => {
const workspaceEntityMetadataArgs =
metadataArgsStorage.filterEntities(target);
if (!workspaceEntityMetadataArgs) {
return acc;
}
if (
isGatedAndNotEnabled(
workspaceEntityMetadataArgs.gate,
workspaceFeatureFlagsMap,
)
) {
return acc;
}
acc.set(
workspaceEntityMetadataArgs.standardId,
this.create(target, context, workspaceFeatureFlagsMap),
);
return acc;
}, new Map<string, (PartialFieldMetadata | PartialComputedFieldMetadata)[]>());
}
const workspaceEntityMetadataArgs = const workspaceEntityMetadataArgs =
metadataArgsStorage.filterEntities(target); metadataArgsStorage.filterEntities(targetOrTargets);
const metadataCollections = this.collectMetadata(target); const metadataCollections = this.collectMetadata(targetOrTargets);
return [ return [
...this.processMetadata( ...this.processMetadata(

View File

@ -8,17 +8,13 @@ import { isGatedAndNotEnabled } from 'src/engine/workspace-manager/workspace-syn
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage'; import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
import { StandardFieldFactory } from './standard-field.factory';
@Injectable() @Injectable()
export class StandardObjectFactory { export class StandardObjectFactory {
constructor(private readonly standardFieldFactory: StandardFieldFactory) {}
create( create(
standardObjectMetadataDefinitions: (typeof BaseWorkspaceEntity)[], standardObjectMetadataDefinitions: (typeof BaseWorkspaceEntity)[],
context: WorkspaceSyncContext, context: WorkspaceSyncContext,
workspaceFeatureFlagsMap: FeatureFlagMap, workspaceFeatureFlagsMap: FeatureFlagMap,
): PartialWorkspaceEntity[] { ): Omit<PartialWorkspaceEntity, 'fields'>[] {
return standardObjectMetadataDefinitions return standardObjectMetadataDefinitions
.map((metadata) => .map((metadata) =>
this.createObjectMetadata(metadata, context, workspaceFeatureFlagsMap), this.createObjectMetadata(metadata, context, workspaceFeatureFlagsMap),
@ -30,7 +26,7 @@ export class StandardObjectFactory {
target: typeof BaseWorkspaceEntity, target: typeof BaseWorkspaceEntity,
context: WorkspaceSyncContext, context: WorkspaceSyncContext,
workspaceFeatureFlagsMap: FeatureFlagMap, workspaceFeatureFlagsMap: FeatureFlagMap,
): PartialWorkspaceEntity | undefined { ): Omit<PartialWorkspaceEntity, 'fields'> | undefined {
const workspaceEntityMetadataArgs = const workspaceEntityMetadataArgs =
metadataArgsStorage.filterEntities(target); metadataArgsStorage.filterEntities(target);
@ -49,12 +45,6 @@ export class StandardObjectFactory {
return undefined; return undefined;
} }
const fields = this.standardFieldFactory.create(
target,
context,
workspaceFeatureFlagsMap,
);
return { return {
...workspaceEntityMetadataArgs, ...workspaceEntityMetadataArgs,
// TODO: Remove targetTableName when we remove the old metadata // TODO: Remove targetTableName when we remove the old metadata
@ -64,7 +54,6 @@ export class StandardObjectFactory {
isCustom: false, isCustom: false,
isRemote: false, isRemote: false,
isSystem: workspaceEntityMetadataArgs.isSystem ?? false, isSystem: workspaceEntityMetadataArgs.isSystem ?? false,
fields,
}; };
} }
} }

View File

@ -33,9 +33,9 @@ export interface ComparatorDeleteResult<T> {
export type ObjectComparatorResult = export type ObjectComparatorResult =
| ComparatorSkipResult | ComparatorSkipResult
| ComparatorCreateResult<ComputedPartialWorkspaceEntity> | ComparatorCreateResult<Omit<ComputedPartialWorkspaceEntity, 'fields'>>
| ComparatorUpdateResult< | ComparatorUpdateResult<
Partial<ComputedPartialWorkspaceEntity> & { id: string } Partial<Omit<ComputedPartialWorkspaceEntity, 'fields'>> & { id: string }
>; >;
export type FieldComparatorResult = export type FieldComparatorResult =

View File

@ -47,9 +47,6 @@ export class WorkspaceMetadataUpdaterService {
storage.objectMetadataCreateCollection.map((objectMetadata) => ({ storage.objectMetadataCreateCollection.map((objectMetadata) => ({
...objectMetadata, ...objectMetadata,
isActive: true, isActive: true,
fields: objectMetadata.fields.map((field) =>
this.prepareFieldMetadataForCreation(field),
),
})) as DeepPartial<ObjectMetadataEntity>[], })) as DeepPartial<ObjectMetadataEntity>[],
); );
const identifiers = createdPartialObjectMetadataCollection.map( const identifiers = createdPartialObjectMetadataCollection.map(

View File

@ -15,7 +15,9 @@ import { WorkspaceSyncStorage } from 'src/engine/workspace-manager/workspace-syn
import { WorkspaceMigrationFieldFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field.factory'; import { WorkspaceMigrationFieldFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field.factory';
import { StandardFieldFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory'; import { StandardFieldFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory';
import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity'; import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity';
import { computeStandardObject } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-object.util'; import { computeStandardFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-fields.util';
import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects';
import { mapObjectMetadataByUniqueIdentifier } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/sync-metadata.util';
@Injectable() @Injectable()
export class WorkspaceSyncFieldMetadataService { export class WorkspaceSyncFieldMetadataService {
@ -47,56 +49,25 @@ export class WorkspaceSyncFieldMetadataService {
}, },
relations: ['dataSource', 'fields'], relations: ['dataSource', 'fields'],
}); });
// Filter out non-custom objects
const customObjectMetadataCollection = const customObjectMetadataCollection =
originalObjectMetadataCollection.filter( originalObjectMetadataCollection.filter(
(objectMetadata) => objectMetadata.isCustom, (objectMetadata) => objectMetadata.isCustom,
); );
// Create standard field metadata collection await this.synchronizeStandardObjectFields(
const standardFieldMetadataCollection = this.standardFieldFactory.create(
CustomWorkspaceEntity,
context, context,
originalObjectMetadataCollection,
customObjectMetadataCollection,
storage,
workspaceFeatureFlagsMap, workspaceFeatureFlagsMap,
); );
// Loop over all custom objects from the DB and compare their fields with standard fields await this.synchronizeCustomObjectFields(
for (const customObjectMetadata of customObjectMetadataCollection) { context,
// Also, maybe it's better to refactor a bit and move generation part into a separate module ? customObjectMetadataCollection,
const standardObjectMetadata = computeStandardObject( storage,
{ workspaceFeatureFlagsMap,
...customObjectMetadata, );
fields: standardFieldMetadataCollection,
},
customObjectMetadata,
);
/**
* COMPARE FIELD METADATA
*/
const fieldComparatorResults = this.workspaceFieldComparator.compare(
customObjectMetadata,
standardObjectMetadata,
);
for (const fieldComparatorResult of fieldComparatorResults) {
switch (fieldComparatorResult.action) {
case ComparatorAction.CREATE: {
storage.addCreateFieldMetadata(fieldComparatorResult.object);
break;
}
case ComparatorAction.UPDATE: {
storage.addUpdateFieldMetadata(fieldComparatorResult.object);
break;
}
case ComparatorAction.DELETE: {
storage.addDeleteFieldMetadata(fieldComparatorResult.object);
break;
}
}
}
}
this.logger.log('Updating workspace metadata'); this.logger.log('Updating workspace metadata');
@ -137,4 +108,120 @@ export class WorkspaceSyncFieldMetadataService {
...deleteFieldWorkspaceMigrations, ...deleteFieldWorkspaceMigrations,
]; ];
} }
/**
* This can be optimized to avoid import of standardObjectFactory here.
* We should refactor the logic of the factory, so this one only create the objects and not the fields.
* Then standardFieldFactory should be used to create the fields of standard objects.
*/
private async synchronizeStandardObjectFields(
context: WorkspaceSyncContext,
originalObjectMetadataCollection: ObjectMetadataEntity[],
customObjectMetadataCollection: ObjectMetadataEntity[],
storage: WorkspaceSyncStorage,
workspaceFeatureFlagsMap: FeatureFlagMap,
): Promise<void> {
// Create standard field metadata map
const standardObjectStandardFieldMetadataMap =
this.standardFieldFactory.create(
standardObjectMetadataDefinitions,
context,
workspaceFeatureFlagsMap,
);
// Create map of original and standard object metadata by standard ids
const originalObjectMetadataMap = mapObjectMetadataByUniqueIdentifier(
originalObjectMetadataCollection,
);
this.logger.log('Comparing standard objects and fields metadata');
// Loop over all standard objects and compare them with the objects in DB
for (const [
standardObjectId,
standardFieldMetadataCollection,
] of standardObjectStandardFieldMetadataMap) {
const originalObjectMetadata =
originalObjectMetadataMap[standardObjectId];
const computedStandardFieldMetadataCollection = computeStandardFields(
standardFieldMetadataCollection,
originalObjectMetadata,
// We need to provide this for generated relations with custom objects
customObjectMetadataCollection,
);
const fieldComparatorResults = this.workspaceFieldComparator.compare(
originalObjectMetadata.id,
originalObjectMetadata.fields,
computedStandardFieldMetadataCollection,
);
for (const fieldComparatorResult of fieldComparatorResults) {
switch (fieldComparatorResult.action) {
case ComparatorAction.CREATE: {
storage.addCreateFieldMetadata(fieldComparatorResult.object);
break;
}
case ComparatorAction.UPDATE: {
storage.addUpdateFieldMetadata(fieldComparatorResult.object);
break;
}
case ComparatorAction.DELETE: {
storage.addDeleteFieldMetadata(fieldComparatorResult.object);
break;
}
}
}
}
}
private async synchronizeCustomObjectFields(
context: WorkspaceSyncContext,
customObjectMetadataCollection: ObjectMetadataEntity[],
storage: WorkspaceSyncStorage,
workspaceFeatureFlagsMap: FeatureFlagMap,
): Promise<void> {
// Create standard field metadata collection
const customObjectStandardFieldMetadataCollection =
this.standardFieldFactory.create(
CustomWorkspaceEntity,
context,
workspaceFeatureFlagsMap,
);
// Loop over all custom objects from the DB and compare their fields with standard fields
for (const customObjectMetadata of customObjectMetadataCollection) {
// Also, maybe it's better to refactor a bit and move generation part into a separate module ?
const standardFieldMetadataCollection = computeStandardFields(
customObjectStandardFieldMetadataCollection,
customObjectMetadata,
);
/**
* COMPARE FIELD METADATA
*/
const fieldComparatorResults = this.workspaceFieldComparator.compare(
customObjectMetadata.id,
customObjectMetadata.fields,
standardFieldMetadataCollection,
);
for (const fieldComparatorResult of fieldComparatorResults) {
switch (fieldComparatorResult.action) {
case ComparatorAction.CREATE: {
storage.addCreateFieldMetadata(fieldComparatorResult.object);
break;
}
case ComparatorAction.UPDATE: {
storage.addUpdateFieldMetadata(fieldComparatorResult.object);
break;
}
case ComparatorAction.DELETE: {
storage.addDeleteFieldMetadata(fieldComparatorResult.object);
break;
}
}
}
}
}
} }

View File

@ -12,11 +12,9 @@ import { mapObjectMetadataByUniqueIdentifier } from 'src/engine/workspace-manage
import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { StandardObjectFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory'; import { StandardObjectFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory';
import { WorkspaceObjectComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator'; import { WorkspaceObjectComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator';
import { WorkspaceFieldComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator';
import { WorkspaceMetadataUpdaterService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service'; import { WorkspaceMetadataUpdaterService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service';
import { WorkspaceSyncStorage } from 'src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage'; import { WorkspaceSyncStorage } from 'src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage';
import { WorkspaceMigrationObjectFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-object.factory'; import { WorkspaceMigrationObjectFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-object.factory';
import { computeStandardObject } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-object.util';
import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects'; import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects';
@Injectable() @Injectable()
@ -26,7 +24,6 @@ export class WorkspaceSyncObjectMetadataService {
constructor( constructor(
private readonly standardObjectFactory: StandardObjectFactory, private readonly standardObjectFactory: StandardObjectFactory,
private readonly workspaceObjectComparator: WorkspaceObjectComparator, private readonly workspaceObjectComparator: WorkspaceObjectComparator,
private readonly workspaceFieldComparator: WorkspaceFieldComparator,
private readonly workspaceMetadataUpdaterService: WorkspaceMetadataUpdaterService, private readonly workspaceMetadataUpdaterService: WorkspaceMetadataUpdaterService,
private readonly workspaceMigrationObjectFactory: WorkspaceMigrationObjectFactory, private readonly workspaceMigrationObjectFactory: WorkspaceMigrationObjectFactory,
) {} ) {}
@ -49,10 +46,6 @@ export class WorkspaceSyncObjectMetadataService {
}, },
relations: ['dataSource', 'fields'], relations: ['dataSource', 'fields'],
}); });
const customObjectMetadataCollection =
originalObjectMetadataCollection.filter(
(objectMetadata) => objectMetadata.isCustom,
);
// Create standard object metadata collection // Create standard object metadata collection
const standardObjectMetadataCollection = this.standardObjectFactory.create( const standardObjectMetadataCollection = this.standardObjectFactory.create(
@ -87,11 +80,8 @@ export class WorkspaceSyncObjectMetadataService {
for (const standardObjectId in standardObjectMetadataMap) { for (const standardObjectId in standardObjectMetadataMap) {
const originalObjectMetadata = const originalObjectMetadata =
originalObjectMetadataMap[standardObjectId]; originalObjectMetadataMap[standardObjectId];
const standardObjectMetadata = computeStandardObject( const standardObjectMetadata =
standardObjectMetadataMap[standardObjectId], standardObjectMetadataMap[standardObjectId];
originalObjectMetadata,
customObjectMetadataCollection,
);
/** /**
* COMPARE OBJECT METADATA * COMPARE OBJECT METADATA
@ -109,35 +99,6 @@ export class WorkspaceSyncObjectMetadataService {
if (objectComparatorResult.action === ComparatorAction.UPDATE) { if (objectComparatorResult.action === ComparatorAction.UPDATE) {
storage.addUpdateObjectMetadata(objectComparatorResult.object); storage.addUpdateObjectMetadata(objectComparatorResult.object);
} }
/**
* COMPARE FIELD METADATA
* NOTE: This should be moved to WorkspaceSyncFieldMetadataService for more clarity since
* this code only adds field metadata to the storage but it's actually used in the other service.
* NOTE2: WorkspaceSyncFieldMetadataService has been added for custom fields sync, it should be refactored to handle
* both custom and non-custom fields.
*/
const fieldComparatorResults = this.workspaceFieldComparator.compare(
originalObjectMetadata,
standardObjectMetadata,
);
for (const fieldComparatorResult of fieldComparatorResults) {
switch (fieldComparatorResult.action) {
case ComparatorAction.CREATE: {
storage.addCreateFieldMetadata(fieldComparatorResult.object);
break;
}
case ComparatorAction.UPDATE: {
storage.addUpdateFieldMetadata(fieldComparatorResult.object);
break;
}
case ComparatorAction.DELETE: {
storage.addDeleteFieldMetadata(fieldComparatorResult.object);
break;
}
}
}
} }
this.logger.log('Updating workspace metadata'); this.logger.log('Updating workspace metadata');

View File

@ -28,6 +28,7 @@ import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/stan
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity';
// TODO: Maybe we should automate this with the DiscoverService of Nest.JS
export const standardObjectMetadataDefinitions = [ export const standardObjectMetadataDefinitions = [
ActivityTargetWorkspaceEntity, ActivityTargetWorkspaceEntity,
ActivityWorkspaceEntity, ActivityWorkspaceEntity,

View File

@ -8,9 +8,13 @@ import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/
export class WorkspaceSyncStorage { export class WorkspaceSyncStorage {
// Object metadata // Object metadata
private readonly _objectMetadataCreateCollection: ComputedPartialWorkspaceEntity[] = private readonly _objectMetadataCreateCollection: Omit<
[]; ComputedPartialWorkspaceEntity,
private readonly _objectMetadataUpdateCollection: (Partial<ComputedPartialWorkspaceEntity> & { 'fields'
>[] = [];
private readonly _objectMetadataUpdateCollection: (Partial<
Omit<ComputedPartialWorkspaceEntity, 'fields'>
> & {
id: string; id: string;
})[] = []; })[] = [];
private readonly _objectMetadataDeleteCollection: ObjectMetadataEntity[] = []; private readonly _objectMetadataDeleteCollection: ObjectMetadataEntity[] = [];
@ -88,7 +92,9 @@ export class WorkspaceSyncStorage {
return this._indexMetadataDeleteCollection; return this._indexMetadataDeleteCollection;
} }
addCreateObjectMetadata(object: ComputedPartialWorkspaceEntity) { addCreateObjectMetadata(
object: Omit<ComputedPartialWorkspaceEntity, 'fields'>,
) {
this._objectMetadataCreateCollection.push(object); this._objectMetadataCreateCollection.push(object);
} }

View File

@ -1,8 +1,8 @@
import { import {
ComputedPartialWorkspaceEntity, ComputedPartialFieldMetadata,
PartialWorkspaceEntity, PartialComputedFieldMetadata,
} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-object-metadata.interface'; PartialFieldMetadata,
import { ComputedPartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface'; } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
@ -11,16 +11,18 @@ import {
createRelationDeterministicUuid, createRelationDeterministicUuid,
} from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util'; } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util';
export const computeStandardObject = ( export const computeStandardFields = (
standardObjectMetadata: Omit<PartialWorkspaceEntity, 'standardId'> & { standardFieldMetadataCollection: (
standardId: string | null; | PartialFieldMetadata
}, | PartialComputedFieldMetadata
)[],
originalObjectMetadata: ObjectMetadataEntity, originalObjectMetadata: ObjectMetadataEntity,
customObjectMetadataCollection: ObjectMetadataEntity[] = [], customObjectMetadataCollection: ObjectMetadataEntity[] = [],
): ComputedPartialWorkspaceEntity => { ): ComputedPartialFieldMetadata[] => {
const fields: ComputedPartialFieldMetadata[] = []; const fields: ComputedPartialFieldMetadata[] = [];
for (const partialFieldMetadata of standardObjectMetadata.fields) { for (const partialFieldMetadata of standardFieldMetadataCollection) {
// Relation from standard object to custom object
if ('argsFactory' in partialFieldMetadata) { if ('argsFactory' in partialFieldMetadata) {
// Compute standard fields of custom object // Compute standard fields of custom object
for (const customObjectMetadata of customObjectMetadataCollection) { for (const customObjectMetadata of customObjectMetadataCollection) {
@ -63,6 +65,7 @@ export const computeStandardObject = (
}); });
} }
} else { } else {
// Relation from standard object to standard object
const labelText = const labelText =
typeof partialFieldMetadata.label === 'function' typeof partialFieldMetadata.label === 'function'
? partialFieldMetadata.label(originalObjectMetadata) ? partialFieldMetadata.label(originalObjectMetadata)
@ -80,8 +83,5 @@ export const computeStandardObject = (
} }
} }
return { return fields;
...standardObjectMetadata,
fields,
};
}; };