Add featureFlag gateDecorator for sync-metadata (#2956)
* Add featureFlag gateDecorator for sync-metadata * remove gate exampels * gate messaging objects * gate messaging recipient object * add missing gate
This commit is contained in:
@ -10,7 +10,7 @@ import { WorkspaceModule } from 'src/core/workspace/workspace.module';
|
|||||||
import { DataSeedWorkspaceCommand } from 'src/database/commands/data-seed-dev-workspace.command';
|
import { DataSeedWorkspaceCommand } from 'src/database/commands/data-seed-dev-workspace.command';
|
||||||
import { DataSeedDemoWorkspaceCommand } from 'src/database/commands/data-seed-demo-workspace.command';
|
import { DataSeedDemoWorkspaceCommand } from 'src/database/commands/data-seed-demo-workspace.command';
|
||||||
import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/workspace-datasource.module';
|
import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/workspace-datasource.module';
|
||||||
import { WorkspaceSyncMetadataModule } from 'src/workspace/workspace-sync-metadata/worksapce-sync-metadata.module';
|
import { WorkspaceSyncMetadataModule } from 'src/workspace/workspace-sync-metadata/workspace-sync-metadata.module';
|
||||||
import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metadata.module';
|
import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metadata.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { DataSourceModule } from 'src/metadata/data-source/data-source.module';
|
|||||||
import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metadata.module';
|
import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metadata.module';
|
||||||
import { WorkspaceMigrationModule } from 'src/metadata/workspace-migration/workspace-migration.module';
|
import { WorkspaceMigrationModule } from 'src/metadata/workspace-migration/workspace-migration.module';
|
||||||
import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/workspace-datasource.module';
|
import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/workspace-datasource.module';
|
||||||
import { WorkspaceSyncMetadataModule } from 'src/workspace/workspace-sync-metadata/worksapce-sync-metadata.module';
|
import { WorkspaceSyncMetadataModule } from 'src/workspace/workspace-sync-metadata/workspace-sync-metadata.module';
|
||||||
|
|
||||||
import { WorkspaceManagerService } from './workspace-manager.service';
|
import { WorkspaceManagerService } from './workspace-manager.service';
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,7 @@ export class SyncWorkspaceMetadataCommand extends CommandRunner {
|
|||||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||||
options.workspaceId,
|
options.workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.workspaceSyncMetadataService.syncStandardObjectsAndFieldsMetadata(
|
await this.workspaceSyncMetadataService.syncStandardObjectsAndFieldsMetadata(
|
||||||
dataSourceMetadata.id,
|
dataSourceMetadata.id,
|
||||||
options.workspaceId,
|
options.workspaceId,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
import { DataSourceModule } from 'src/metadata/data-source/data-source.module';
|
import { DataSourceModule } from 'src/metadata/data-source/data-source.module';
|
||||||
import { WorkspaceSyncMetadataModule } from 'src/workspace/workspace-sync-metadata/worksapce-sync-metadata.module';
|
import { WorkspaceSyncMetadataModule } from 'src/workspace/workspace-sync-metadata/workspace-sync-metadata.module';
|
||||||
|
|
||||||
import { SyncWorkspaceMetadataCommand } from './sync-workspace-metadata.command';
|
import { SyncWorkspaceMetadataCommand } from './sync-workspace-metadata.command';
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,10 @@ export type RelationMetadataDecorator = {
|
|||||||
inverseSideFieldName?: string;
|
inverseSideFieldName?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type GateDecorator = {
|
||||||
|
featureFlag: string;
|
||||||
|
};
|
||||||
|
|
||||||
function convertClassNameToObjectMetadataName(name: string): string {
|
function convertClassNameToObjectMetadataName(name: string): string {
|
||||||
const classSuffix = 'ObjectMetadata';
|
const classSuffix = 'ObjectMetadata';
|
||||||
let objectName = camelCase(name);
|
let objectName = camelCase(name);
|
||||||
@ -48,6 +52,8 @@ export function ObjectMetadata(
|
|||||||
return (target) => {
|
return (target) => {
|
||||||
const isSystem = Reflect.getMetadata('isSystem', target) || false;
|
const isSystem = Reflect.getMetadata('isSystem', target) || false;
|
||||||
|
|
||||||
|
const gate = Reflect.getMetadata('gate', target) || undefined;
|
||||||
|
|
||||||
const objectName = convertClassNameToObjectMetadataName(target.name);
|
const objectName = convertClassNameToObjectMetadataName(target.name);
|
||||||
|
|
||||||
Reflect.defineMetadata(
|
Reflect.defineMetadata(
|
||||||
@ -55,6 +61,7 @@ export function ObjectMetadata(
|
|||||||
{
|
{
|
||||||
nameSingular: objectName,
|
nameSingular: objectName,
|
||||||
...metadata,
|
...metadata,
|
||||||
|
gate,
|
||||||
targetTableName: objectName,
|
targetTableName: objectName,
|
||||||
isSystem,
|
isSystem,
|
||||||
isCustom: false,
|
isCustom: false,
|
||||||
@ -82,6 +89,16 @@ export function IsSystem() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function Gate(metadata: GateDecorator) {
|
||||||
|
return function (target: object, fieldKey?: string) {
|
||||||
|
if (fieldKey) {
|
||||||
|
Reflect.defineMetadata('gate', metadata, target, fieldKey);
|
||||||
|
} else {
|
||||||
|
Reflect.defineMetadata('gate', metadata, target);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function FieldMetadata<T extends FieldMetadataType>(
|
export function FieldMetadata<T extends FieldMetadataType>(
|
||||||
metadata: FieldMetadataDecorator<T>,
|
metadata: FieldMetadataDecorator<T>,
|
||||||
): PropertyDecorator {
|
): PropertyDecorator {
|
||||||
@ -94,6 +111,8 @@ export function FieldMetadata<T extends FieldMetadataType>(
|
|||||||
|
|
||||||
const isSystem = Reflect.getMetadata('isSystem', target, fieldKey) || false;
|
const isSystem = Reflect.getMetadata('isSystem', target, fieldKey) || false;
|
||||||
|
|
||||||
|
const gate = Reflect.getMetadata('gate', target, fieldKey) || undefined;
|
||||||
|
|
||||||
const { joinColumn, ...fieldMetadata } = metadata;
|
const { joinColumn, ...fieldMetadata } = metadata;
|
||||||
|
|
||||||
Reflect.defineMetadata(
|
Reflect.defineMetadata(
|
||||||
@ -105,6 +124,7 @@ export function FieldMetadata<T extends FieldMetadataType>(
|
|||||||
fieldKey,
|
fieldKey,
|
||||||
isNullable,
|
isNullable,
|
||||||
isSystem,
|
isSystem,
|
||||||
|
gate,
|
||||||
),
|
),
|
||||||
...(joinColumn && fieldMetadata.type === FieldMetadataType.RELATION
|
...(joinColumn && fieldMetadata.type === FieldMetadataType.RELATION
|
||||||
? {
|
? {
|
||||||
@ -119,6 +139,7 @@ export function FieldMetadata<T extends FieldMetadataType>(
|
|||||||
joinColumn,
|
joinColumn,
|
||||||
isNullable,
|
isNullable,
|
||||||
true,
|
true,
|
||||||
|
gate,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
@ -133,6 +154,7 @@ function generateFieldMetadata<T extends FieldMetadataType>(
|
|||||||
fieldKey: string,
|
fieldKey: string,
|
||||||
isNullable: boolean,
|
isNullable: boolean,
|
||||||
isSystem: boolean,
|
isSystem: boolean,
|
||||||
|
gate: GateDecorator | undefined = undefined,
|
||||||
) {
|
) {
|
||||||
const targetColumnMap = JSON.stringify(
|
const targetColumnMap = JSON.stringify(
|
||||||
generateTargetColumnMap(metadata.type, false, fieldKey),
|
generateTargetColumnMap(metadata.type, false, fieldKey),
|
||||||
@ -152,6 +174,7 @@ function generateFieldMetadata<T extends FieldMetadataType>(
|
|||||||
description: metadata.description ?? null,
|
description: metadata.description ?? null,
|
||||||
icon: metadata.icon ?? null,
|
icon: metadata.icon ?? null,
|
||||||
defaultValue: defaultValue ? JSON.stringify(defaultValue) : null,
|
defaultValue: defaultValue ? JSON.stringify(defaultValue) : null,
|
||||||
|
gate,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +185,8 @@ export function RelationMetadata(
|
|||||||
const existingRelationMetadata =
|
const existingRelationMetadata =
|
||||||
Reflect.getMetadata('relationMetadata', target.constructor) || [];
|
Reflect.getMetadata('relationMetadata', target.constructor) || [];
|
||||||
|
|
||||||
|
const gate = Reflect.getMetadata('gate', target, fieldKey) || undefined;
|
||||||
|
|
||||||
const objectName = convertClassNameToObjectMetadataName(
|
const objectName = convertClassNameToObjectMetadataName(
|
||||||
target.constructor.name,
|
target.constructor.name,
|
||||||
);
|
);
|
||||||
@ -176,6 +201,7 @@ export function RelationMetadata(
|
|||||||
toObjectNameSingular: metadata.objectName,
|
toObjectNameSingular: metadata.objectName,
|
||||||
fromFieldMetadataName: fieldKey,
|
fromFieldMetadataName: fieldKey,
|
||||||
toFieldMetadataName: metadata.inverseSideFieldName ?? objectName,
|
toFieldMetadataName: metadata.inverseSideFieldName ?? objectName,
|
||||||
|
gate,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
target.constructor,
|
target.constructor,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
FieldMetadata,
|
FieldMetadata,
|
||||||
IsNullable,
|
IsNullable,
|
||||||
RelationMetadata,
|
RelationMetadata,
|
||||||
|
Gate,
|
||||||
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
||||||
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
||||||
import { MessageChannelObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/message-channel.object-metadata';
|
import { MessageChannelObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/message-channel.object-metadata';
|
||||||
@ -18,6 +19,9 @@ import { WorkspaceMemberObjectMetadata } from 'src/workspace/workspace-sync-meta
|
|||||||
description: 'A connected account',
|
description: 'A connected account',
|
||||||
icon: 'IconAt',
|
icon: 'IconAt',
|
||||||
})
|
})
|
||||||
|
@Gate({
|
||||||
|
featureFlag: 'IS_MESSAGING_ENABLED',
|
||||||
|
})
|
||||||
@IsSystem()
|
@IsSystem()
|
||||||
export class ConnectedAccountObjectMetadata extends BaseObjectMetadata {
|
export class ConnectedAccountObjectMetadata extends BaseObjectMetadata {
|
||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
FieldMetadata,
|
FieldMetadata,
|
||||||
IsNullable,
|
IsNullable,
|
||||||
RelationMetadata,
|
RelationMetadata,
|
||||||
|
Gate,
|
||||||
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
||||||
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
||||||
import { ConnectedAccountObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/connected-account.object-metadata';
|
import { ConnectedAccountObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/connected-account.object-metadata';
|
||||||
@ -18,6 +19,9 @@ import { MessageThreadObjectMetadata } from 'src/workspace/workspace-sync-metada
|
|||||||
description: 'Message Channels',
|
description: 'Message Channels',
|
||||||
icon: 'IconMessage',
|
icon: 'IconMessage',
|
||||||
})
|
})
|
||||||
|
@Gate({
|
||||||
|
featureFlag: 'IS_MESSAGING_ENABLED',
|
||||||
|
})
|
||||||
@IsSystem()
|
@IsSystem()
|
||||||
export class MessageChannelObjectMetadata extends BaseObjectMetadata {
|
export class MessageChannelObjectMetadata extends BaseObjectMetadata {
|
||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
IsSystem,
|
IsSystem,
|
||||||
FieldMetadata,
|
FieldMetadata,
|
||||||
IsNullable,
|
IsNullable,
|
||||||
|
Gate,
|
||||||
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
||||||
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
||||||
import { MessageObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/message.object-metadata';
|
import { MessageObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/message.object-metadata';
|
||||||
@ -17,6 +18,9 @@ import { WorkspaceMemberObjectMetadata } from 'src/workspace/workspace-sync-meta
|
|||||||
description: 'Message Recipients',
|
description: 'Message Recipients',
|
||||||
icon: 'IconUserCircle',
|
icon: 'IconUserCircle',
|
||||||
})
|
})
|
||||||
|
@Gate({
|
||||||
|
featureFlag: 'IS_MESSAGING_ENABLED',
|
||||||
|
})
|
||||||
@IsSystem()
|
@IsSystem()
|
||||||
export class MessageRecipientObjectMetadata extends BaseObjectMetadata {
|
export class MessageRecipientObjectMetadata extends BaseObjectMetadata {
|
||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
FieldMetadata,
|
FieldMetadata,
|
||||||
IsNullable,
|
IsNullable,
|
||||||
RelationMetadata,
|
RelationMetadata,
|
||||||
|
Gate,
|
||||||
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
||||||
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
||||||
import { MessageChannelObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/message-channel.object-metadata';
|
import { MessageChannelObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/message-channel.object-metadata';
|
||||||
@ -18,6 +19,9 @@ import { MessageObjectMetadata } from 'src/workspace/workspace-sync-metadata/sta
|
|||||||
description: 'Message Thread',
|
description: 'Message Thread',
|
||||||
icon: 'IconMessage',
|
icon: 'IconMessage',
|
||||||
})
|
})
|
||||||
|
@Gate({
|
||||||
|
featureFlag: 'IS_MESSAGING_ENABLED',
|
||||||
|
})
|
||||||
@IsSystem()
|
@IsSystem()
|
||||||
export class MessageThreadObjectMetadata extends BaseObjectMetadata {
|
export class MessageThreadObjectMetadata extends BaseObjectMetadata {
|
||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
FieldMetadata,
|
FieldMetadata,
|
||||||
IsNullable,
|
IsNullable,
|
||||||
RelationMetadata,
|
RelationMetadata,
|
||||||
|
Gate,
|
||||||
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
||||||
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
||||||
import { MessageRecipientObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/message-recipient.object-metadata';
|
import { MessageRecipientObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/message-recipient.object-metadata';
|
||||||
@ -18,6 +19,9 @@ import { MessageThreadObjectMetadata } from 'src/workspace/workspace-sync-metada
|
|||||||
description: 'Message',
|
description: 'Message',
|
||||||
icon: 'IconMessage',
|
icon: 'IconMessage',
|
||||||
})
|
})
|
||||||
|
@Gate({
|
||||||
|
featureFlag: 'IS_MESSAGING_ENABLED',
|
||||||
|
})
|
||||||
@IsSystem()
|
@IsSystem()
|
||||||
export class MessageObjectMetadata extends BaseObjectMetadata {
|
export class MessageObjectMetadata extends BaseObjectMetadata {
|
||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
IsNullable,
|
IsNullable,
|
||||||
RelationMetadata,
|
RelationMetadata,
|
||||||
IsSystem,
|
IsSystem,
|
||||||
|
Gate,
|
||||||
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
||||||
import { ActivityTargetObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/activity-target.object-metadata';
|
import { ActivityTargetObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/activity-target.object-metadata';
|
||||||
import { AttachmentObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/attachment.object-metadata';
|
import { AttachmentObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/attachment.object-metadata';
|
||||||
@ -186,6 +187,9 @@ export class PersonObjectMetadata extends BaseObjectMetadata {
|
|||||||
objectName: 'messageRecipient',
|
objectName: 'messageRecipient',
|
||||||
inverseSideFieldName: 'person',
|
inverseSideFieldName: 'person',
|
||||||
})
|
})
|
||||||
|
@Gate({
|
||||||
|
featureFlag: 'IS_MESSAGING_ENABLED',
|
||||||
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
messageRecipients: MessageRecipientObjectMetadata[];
|
messageRecipients: MessageRecipientObjectMetadata[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
FieldMetadata,
|
FieldMetadata,
|
||||||
IsNullable,
|
IsNullable,
|
||||||
RelationMetadata,
|
RelationMetadata,
|
||||||
|
Gate,
|
||||||
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
} from 'src/workspace/workspace-sync-metadata/decorators/metadata.decorator';
|
||||||
import { ActivityObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/activity.object-metadata';
|
import { ActivityObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/activity.object-metadata';
|
||||||
import { AttachmentObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/attachment.object-metadata';
|
import { AttachmentObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/attachment.object-metadata';
|
||||||
@ -163,6 +164,9 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
objectName: 'connectedAccount',
|
objectName: 'connectedAccount',
|
||||||
inverseSideFieldName: 'accountOwner',
|
inverseSideFieldName: 'accountOwner',
|
||||||
})
|
})
|
||||||
|
@Gate({
|
||||||
|
featureFlag: 'IS_MESSAGING_ENABLED',
|
||||||
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
connectedAccounts: ConnectedAccountObjectMetadata[];
|
connectedAccounts: ConnectedAccountObjectMetadata[];
|
||||||
|
|
||||||
@ -177,6 +181,9 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
objectName: 'messageRecipient',
|
objectName: 'messageRecipient',
|
||||||
inverseSideFieldName: 'workspaceMember',
|
inverseSideFieldName: 'workspaceMember',
|
||||||
})
|
})
|
||||||
|
@Gate({
|
||||||
|
featureFlag: 'IS_MESSAGING_ENABLED',
|
||||||
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
messageRecipients: MessageRecipientObjectMetadata[];
|
messageRecipients: MessageRecipientObjectMetadata[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,109 +9,156 @@ export class MetadataParser {
|
|||||||
metadata: typeof BaseObjectMetadata,
|
metadata: typeof BaseObjectMetadata,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
dataSourceId: string,
|
dataSourceId: string,
|
||||||
) {
|
workspaceFeatureFlagsMap: Record<string, boolean>,
|
||||||
|
): ObjectMetadataEntity | undefined {
|
||||||
const objectMetadata = Reflect.getMetadata('objectMetadata', metadata);
|
const objectMetadata = Reflect.getMetadata('objectMetadata', metadata);
|
||||||
const fieldMetadata = Reflect.getMetadata('fieldMetadata', metadata);
|
const fieldMetadata = Reflect.getMetadata('fieldMetadata', metadata);
|
||||||
|
|
||||||
if (objectMetadata) {
|
if (!objectMetadata) {
|
||||||
const fields = Object.values(fieldMetadata);
|
throw new Error(
|
||||||
|
`Object metadata decorator not found, can\'t parse ${metadata.name}`,
|
||||||
return {
|
);
|
||||||
...objectMetadata,
|
|
||||||
workspaceId,
|
|
||||||
dataSourceId,
|
|
||||||
fields: fields.map((field: FieldMetadataEntity) => ({
|
|
||||||
...field,
|
|
||||||
workspaceId,
|
|
||||||
isSystem: objectMetadata.isSystem || field.isSystem,
|
|
||||||
defaultValue: field.defaultValue || null,
|
|
||||||
options: field.options || null,
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
if (isGatedAndNotEnabled(objectMetadata, workspaceFeatureFlagsMap)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = Object.values(fieldMetadata).filter(
|
||||||
|
(field) => !isGatedAndNotEnabled(field, workspaceFeatureFlagsMap),
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...objectMetadata,
|
||||||
|
workspaceId,
|
||||||
|
dataSourceId,
|
||||||
|
fields: fields.map((field: FieldMetadataEntity) => ({
|
||||||
|
...field,
|
||||||
|
workspaceId,
|
||||||
|
isSystem: objectMetadata.isSystem || field.isSystem,
|
||||||
|
defaultValue: field.defaultValue || null,
|
||||||
|
options: field.options || null,
|
||||||
|
})),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static parseAllMetadata(
|
static parseAllMetadata(
|
||||||
metadataCollection: (typeof BaseObjectMetadata)[],
|
metadataCollection: (typeof BaseObjectMetadata)[],
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
dataSourceId: string,
|
dataSourceId: string,
|
||||||
) {
|
workspaceFeatureFlagsMap: Record<string, boolean>,
|
||||||
return metadataCollection.map((metadata) =>
|
): ObjectMetadataEntity[] {
|
||||||
MetadataParser.parseMetadata(metadata, workspaceId, dataSourceId),
|
return metadataCollection
|
||||||
);
|
.map((metadata) =>
|
||||||
|
MetadataParser.parseMetadata(
|
||||||
|
metadata,
|
||||||
|
workspaceId,
|
||||||
|
dataSourceId,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
(metadata): metadata is ObjectMetadataEntity => metadata !== undefined,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static parseRelationMetadata(
|
static parseRelationMetadata(
|
||||||
metadata: typeof BaseObjectMetadata,
|
metadata: typeof BaseObjectMetadata,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
objectMetadataFromDB: Record<string, ObjectMetadataEntity>,
|
objectMetadataFromDB: Record<string, ObjectMetadataEntity>,
|
||||||
|
workspaceFeatureFlagsMap: Record<string, boolean>,
|
||||||
) {
|
) {
|
||||||
const objectMetadata = Reflect.getMetadata('objectMetadata', metadata);
|
const objectMetadata = Reflect.getMetadata('objectMetadata', metadata);
|
||||||
const relationMetadata = Reflect.getMetadata('relationMetadata', metadata);
|
const relationMetadata = Reflect.getMetadata('relationMetadata', metadata);
|
||||||
|
|
||||||
if (!relationMetadata) return [];
|
if (!relationMetadata) return [];
|
||||||
|
|
||||||
return relationMetadata.map((relation) => {
|
if (!objectMetadata) {
|
||||||
const fromObjectMetadata =
|
throw new Error(
|
||||||
objectMetadataFromDB[relation.fromObjectNameSingular];
|
`Object metadata decorator not found, can\'t parse ${metadata.name}`,
|
||||||
|
|
||||||
assert(
|
|
||||||
fromObjectMetadata,
|
|
||||||
`Object ${relation.fromObjectNameSingular} not found in DB
|
|
||||||
for relation defined in class ${objectMetadata.nameSingular}`,
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const toObjectMetadata =
|
if (isGatedAndNotEnabled(objectMetadata, workspaceFeatureFlagsMap)) {
|
||||||
objectMetadataFromDB[relation.toObjectNameSingular];
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
assert(
|
return relationMetadata
|
||||||
toObjectMetadata,
|
.filter(
|
||||||
`Object ${relation.toObjectNameSingular} not found in DB
|
(relation) => !isGatedAndNotEnabled(relation, workspaceFeatureFlagsMap),
|
||||||
for relation defined in class ${objectMetadata.nameSingular}`,
|
)
|
||||||
);
|
.map((relation) => {
|
||||||
|
const fromObjectMetadata =
|
||||||
|
objectMetadataFromDB[relation.fromObjectNameSingular];
|
||||||
|
|
||||||
const fromFieldMetadata =
|
assert(
|
||||||
fromObjectMetadata?.fields[relation.fromFieldMetadataName];
|
fromObjectMetadata,
|
||||||
|
`Object ${relation.fromObjectNameSingular} not found in DB
|
||||||
|
for fromRelation defined in class ${objectMetadata.nameSingular}`,
|
||||||
|
);
|
||||||
|
|
||||||
assert(
|
const toObjectMetadata =
|
||||||
fromFieldMetadata,
|
objectMetadataFromDB[relation.toObjectNameSingular];
|
||||||
`Field ${relation.fromFieldMetadataName} not found in object ${relation.fromObjectNameSingular}
|
|
||||||
for relation defined in class ${objectMetadata.nameSingular}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const toFieldMetadata =
|
assert(
|
||||||
toObjectMetadata?.fields[relation.toFieldMetadataName];
|
toObjectMetadata,
|
||||||
|
`Object ${relation.toObjectNameSingular} not found in DB
|
||||||
|
for toRelation defined in class ${objectMetadata.nameSingular}`,
|
||||||
|
);
|
||||||
|
|
||||||
assert(
|
const fromFieldMetadata =
|
||||||
toFieldMetadata,
|
fromObjectMetadata?.fields[relation.fromFieldMetadataName];
|
||||||
`Field ${relation.toFieldMetadataName} not found in object ${relation.toObjectNameSingular}
|
|
||||||
for relation defined in class ${objectMetadata.nameSingular}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
assert(
|
||||||
relationType: relation.type,
|
fromFieldMetadata,
|
||||||
fromObjectMetadataId: fromObjectMetadata?.id,
|
`Field ${relation.fromFieldMetadataName} not found in object ${relation.fromObjectNameSingular}
|
||||||
toObjectMetadataId: toObjectMetadata?.id,
|
for fromRelation defined in class ${objectMetadata.nameSingular}`,
|
||||||
fromFieldMetadataId: fromFieldMetadata?.id,
|
);
|
||||||
toFieldMetadataId: toFieldMetadata?.id,
|
|
||||||
workspaceId,
|
const toFieldMetadata =
|
||||||
};
|
toObjectMetadata?.fields[relation.toFieldMetadataName];
|
||||||
});
|
|
||||||
|
assert(
|
||||||
|
toFieldMetadata,
|
||||||
|
`Field ${relation.toFieldMetadataName} not found in object ${relation.toObjectNameSingular}
|
||||||
|
for toRelation defined in class ${objectMetadata.nameSingular}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
relationType: relation.type,
|
||||||
|
fromObjectMetadataId: fromObjectMetadata?.id,
|
||||||
|
toObjectMetadataId: toObjectMetadata?.id,
|
||||||
|
fromFieldMetadataId: fromFieldMetadata?.id,
|
||||||
|
toFieldMetadataId: toFieldMetadata?.id,
|
||||||
|
workspaceId,
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static parseAllRelations(
|
static parseAllRelations(
|
||||||
metadataCollection: (typeof BaseObjectMetadata)[],
|
metadataCollection: (typeof BaseObjectMetadata)[],
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
objectMetadataFromDB: Record<string, ObjectMetadataEntity>,
|
objectMetadataFromDB: Record<string, ObjectMetadataEntity>,
|
||||||
|
workspaceFeatureFlagsMap: Record<string, boolean>,
|
||||||
) {
|
) {
|
||||||
return metadataCollection.flatMap((metadata) =>
|
return metadataCollection.flatMap((metadata) =>
|
||||||
MetadataParser.parseRelationMetadata(
|
MetadataParser.parseRelationMetadata(
|
||||||
metadata,
|
metadata,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataFromDB,
|
objectMetadataFromDB,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isGatedAndNotEnabled(
|
||||||
|
metadata,
|
||||||
|
workspaceFeatureFlagsMap: Record<string, boolean>,
|
||||||
|
): boolean {
|
||||||
|
const featureFlagValue =
|
||||||
|
metadata.gate?.featureFlag &&
|
||||||
|
workspaceFeatureFlagsMap[metadata.gate.featureFlag];
|
||||||
|
|
||||||
|
return metadata.gate?.featureFlag !== undefined && !featureFlagValue;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
|
||||||
|
import { FeatureFlagEntity } from 'src/core/feature-flag/feature-flag.entity';
|
||||||
import { FieldMetadataEntity } from 'src/metadata/field-metadata/field-metadata.entity';
|
import { FieldMetadataEntity } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
||||||
import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-metadata.entity';
|
import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-metadata.entity';
|
||||||
@ -22,6 +23,7 @@ import { WorkspaceSyncMetadataService } from 'src/workspace/workspace-sync-metad
|
|||||||
],
|
],
|
||||||
'metadata',
|
'metadata',
|
||||||
),
|
),
|
||||||
|
TypeOrmModule.forFeature([FeatureFlagEntity], 'core'),
|
||||||
],
|
],
|
||||||
exports: [WorkspaceSyncMetadataService],
|
exports: [WorkspaceSyncMetadataService],
|
||||||
providers: [WorkspaceSyncMetadataService],
|
providers: [WorkspaceSyncMetadataService],
|
||||||
@ -16,9 +16,9 @@ import {
|
|||||||
} from 'src/metadata/relation-metadata/relation-metadata.entity';
|
} from 'src/metadata/relation-metadata/relation-metadata.entity';
|
||||||
import { MetadataParser } from 'src/workspace/workspace-sync-metadata/utils/metadata.parser';
|
import { MetadataParser } from 'src/workspace/workspace-sync-metadata/utils/metadata.parser';
|
||||||
import {
|
import {
|
||||||
mapObjectMetadataByUniqueIdentifier,
|
|
||||||
filterIgnoredProperties,
|
filterIgnoredProperties,
|
||||||
convertStringifiedFieldsToJSON,
|
convertStringifiedFieldsToJSON,
|
||||||
|
mapObjectMetadataByUniqueIdentifier,
|
||||||
} from 'src/workspace/workspace-sync-metadata/utils/sync-metadata.util';
|
} from 'src/workspace/workspace-sync-metadata/utils/sync-metadata.util';
|
||||||
import { standardObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects';
|
import { standardObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects';
|
||||||
import {
|
import {
|
||||||
@ -29,6 +29,7 @@ import {
|
|||||||
} from 'src/metadata/workspace-migration/workspace-migration.entity';
|
} from 'src/metadata/workspace-migration/workspace-migration.entity';
|
||||||
import { WorkspaceMigrationFactory } from 'src/metadata/workspace-migration/workspace-migration.factory';
|
import { WorkspaceMigrationFactory } from 'src/metadata/workspace-migration/workspace-migration.factory';
|
||||||
import { WorkspaceMigrationRunnerService } from 'src/workspace/workspace-migration-runner/workspace-migration-runner.service';
|
import { WorkspaceMigrationRunnerService } from 'src/workspace/workspace-migration-runner/workspace-migration-runner.service';
|
||||||
|
import { FeatureFlagEntity } from 'src/core/feature-flag/feature-flag.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkspaceSyncMetadataService {
|
export class WorkspaceSyncMetadataService {
|
||||||
@ -44,6 +45,8 @@ export class WorkspaceSyncMetadataService {
|
|||||||
private readonly relationMetadataRepository: Repository<RelationMetadataEntity>,
|
private readonly relationMetadataRepository: Repository<RelationMetadataEntity>,
|
||||||
@InjectRepository(WorkspaceMigrationEntity, 'metadata')
|
@InjectRepository(WorkspaceMigrationEntity, 'metadata')
|
||||||
private readonly workspaceMigrationRepository: Repository<WorkspaceMigrationEntity>,
|
private readonly workspaceMigrationRepository: Repository<WorkspaceMigrationEntity>,
|
||||||
|
@InjectRepository(FeatureFlagEntity, 'core')
|
||||||
|
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,13 +61,27 @@ export class WorkspaceSyncMetadataService {
|
|||||||
dataSourceId: string,
|
dataSourceId: string,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
) {
|
) {
|
||||||
const standardObjects = MetadataParser.parseAllMetadata(
|
|
||||||
standardObjectMetadata,
|
|
||||||
workspaceId,
|
|
||||||
dataSourceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const workspaceFeatureFlags = await this.featureFlagRepository.find({
|
||||||
|
where: { workspaceId },
|
||||||
|
});
|
||||||
|
|
||||||
|
const workspaceFeatureFlagsMap = workspaceFeatureFlags.reduce(
|
||||||
|
(result, currentFeatureFlag) => {
|
||||||
|
result[currentFeatureFlag.key] = currentFeatureFlag.value;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
const standardObjects = MetadataParser.parseAllMetadata(
|
||||||
|
standardObjectMetadata,
|
||||||
|
workspaceId,
|
||||||
|
dataSourceId,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
const objectsInDB = await this.objectMetadataRepository.find({
|
const objectsInDB = await this.objectMetadataRepository.find({
|
||||||
where: { workspaceId, dataSourceId, isCustom: false },
|
where: { workspaceId, dataSourceId, isCustom: false },
|
||||||
relations: ['fields'],
|
relations: ['fields'],
|
||||||
@ -244,7 +261,11 @@ export class WorkspaceSyncMetadataService {
|
|||||||
|
|
||||||
// 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
|
||||||
// in the DB before creating relations.
|
// in the DB before creating relations.
|
||||||
await this.syncRelationMetadata(workspaceId, dataSourceId);
|
await this.syncRelationMetadata(
|
||||||
|
workspaceId,
|
||||||
|
dataSourceId,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
// Execute migrations
|
// Execute migrations
|
||||||
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
|
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
|
||||||
@ -258,6 +279,7 @@ export class WorkspaceSyncMetadataService {
|
|||||||
private async syncRelationMetadata(
|
private async syncRelationMetadata(
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
dataSourceId: string,
|
dataSourceId: string,
|
||||||
|
workspaceFeatureFlagsMap: Record<string, boolean>,
|
||||||
) {
|
) {
|
||||||
const objectsInDB = await this.objectMetadataRepository.find({
|
const objectsInDB = await this.objectMetadataRepository.find({
|
||||||
where: { workspaceId, dataSourceId, isCustom: false },
|
where: { workspaceId, dataSourceId, isCustom: false },
|
||||||
@ -268,13 +290,8 @@ export class WorkspaceSyncMetadataService {
|
|||||||
standardObjectMetadata,
|
standardObjectMetadata,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectsInDBByName,
|
objectsInDBByName,
|
||||||
).reduce((result, currentObject) => {
|
workspaceFeatureFlagsMap,
|
||||||
const key = `${currentObject.fromObjectMetadataId}->${currentObject.fromFieldMetadataId}`;
|
);
|
||||||
|
|
||||||
result[key] = currentObject;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
// TODO: filter out custom relations once isCustom has been added to relationMetadata table
|
// TODO: filter out custom relations once isCustom has been added to relationMetadata table
|
||||||
const relationsInDB = await this.relationMetadataRepository.find({
|
const relationsInDB = await this.relationMetadataRepository.find({
|
||||||
|
|||||||
Reference in New Issue
Block a user