mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-26 13:42:44 +03:00
feat: standard fields on custom (#4332)
* feat: add ability to sync standard fields on custom object * fix: clean * fix: wrong compute during object creation * fix: missing cascade delete * fix: remove unused injected class * fix: naming * fix: rename factory to paramsFactory and clean * fix: rename ExtendCustomObjectMetadata to BaseCustomObjectMetadata * fix: partial fix inconsistent label and description * Fixes * Fix --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
parent
c3a024b047
commit
af6ffbcc68
51
.vscode/twenty.code-workspace
vendored
51
.vscode/twenty.code-workspace
vendored
@ -42,10 +42,59 @@
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"editor.formatOnSave": false,
|
||||||
|
"files.eol": "auto",
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.formatOnSave": false,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": true,
|
||||||
|
"source.addMissingImports": "always"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.formatOnSave": false,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": true,
|
||||||
|
"source.addMissingImports": "always"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"[typescriptreact]": {
|
||||||
|
"editor.formatOnSave": false,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": true,
|
||||||
|
"source.addMissingImports": "always"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"javascript.format.enable": false,
|
||||||
|
"typescript.format.enable": false,
|
||||||
|
"cSpell.enableFiletypes": [
|
||||||
|
"!javascript",
|
||||||
|
"!json",
|
||||||
|
"!typescript",
|
||||||
|
"!typescriptreact",
|
||||||
|
"md",
|
||||||
|
"mdx"
|
||||||
|
],
|
||||||
|
"cSpell.words": [
|
||||||
|
"twentyhq"
|
||||||
|
],
|
||||||
|
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||||
|
"[javascript][typescript][typescriptreact]": {
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": "explicit",
|
||||||
|
"source.addMissingImports": "always"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"search.exclude": {
|
||||||
|
"**/.yarn": true,
|
||||||
|
},
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"packages/": true
|
"packages/": true
|
||||||
},
|
},
|
||||||
"jest.autoEnable": false,
|
"jest.runMode": "on-demand",
|
||||||
"jest.disabledWorkspaceFolders": [
|
"jest.disabledWorkspaceFolders": [
|
||||||
"ROOT",
|
"ROOT",
|
||||||
"packages/twenty-zapier",
|
"packages/twenty-zapier",
|
||||||
|
@ -72,6 +72,7 @@ export const useInjectIntoActivityTargetsQueries = () => {
|
|||||||
overwriteFindManyActivityTargetsQueryInCache({
|
overwriteFindManyActivityTargetsQueryInCache({
|
||||||
objectRecordsToOverwrite: newActivityTargets,
|
objectRecordsToOverwrite: newActivityTargets,
|
||||||
queryVariables: findManyActivitiyTargetsQueryVariables,
|
queryVariables: findManyActivitiyTargetsQueryVariables,
|
||||||
|
depth: 2,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ export const useRemoveFromActivityTargetsQueries = () => {
|
|||||||
overwriteFindManyActivityTargetsQueryInCache({
|
overwriteFindManyActivityTargetsQueryInCache({
|
||||||
objectRecordsToOverwrite: newActivityTargetsForTargetableObject,
|
objectRecordsToOverwrite: newActivityTargetsForTargetableObject,
|
||||||
queryVariables: findManyActivityTargetsQueryVariables,
|
queryVariables: findManyActivityTargetsQueryVariables,
|
||||||
|
depth: 2,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ export const useInjectIntoActivityTargetInlineCellCache = () => {
|
|||||||
overwriteFindManyActivityTargetsQueryInCache({
|
overwriteFindManyActivityTargetsQueryInCache({
|
||||||
queryVariables: activityTargetInlineCellQueryVariables,
|
queryVariables: activityTargetInlineCellQueryVariables,
|
||||||
objectRecordsToOverwrite: activityTargetsToInject,
|
objectRecordsToOverwrite: activityTargetsToInject,
|
||||||
|
depth: 2,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,14 +20,16 @@ export const useUpsertFindManyRecordsQueryInCache = ({
|
|||||||
T extends ObjectRecord = ObjectRecord,
|
T extends ObjectRecord = ObjectRecord,
|
||||||
>({
|
>({
|
||||||
queryVariables,
|
queryVariables,
|
||||||
|
depth = MAX_QUERY_DEPTH_FOR_CACHE_INJECTION,
|
||||||
objectRecordsToOverwrite,
|
objectRecordsToOverwrite,
|
||||||
}: {
|
}: {
|
||||||
queryVariables: ObjectRecordQueryVariables;
|
queryVariables: ObjectRecordQueryVariables;
|
||||||
|
depth?: number;
|
||||||
objectRecordsToOverwrite: T[];
|
objectRecordsToOverwrite: T[];
|
||||||
}) => {
|
}) => {
|
||||||
const findManyRecordsQueryForCacheOverwrite = generateFindManyRecordsQuery({
|
const findManyRecordsQueryForCacheOverwrite = generateFindManyRecordsQuery({
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
depth: MAX_QUERY_DEPTH_FOR_CACHE_INJECTION, // TODO: fix this
|
depth, // TODO: fix this
|
||||||
});
|
});
|
||||||
|
|
||||||
const newObjectRecordConnection = getRecordConnectionFromRecords({
|
const newObjectRecordConnection = getRecordConnectionFromRecords({
|
||||||
|
3
packages/twenty-server/@types/common.d.ts
vendored
3
packages/twenty-server/@types/common.d.ts
vendored
@ -3,3 +3,6 @@ type DeepPartial<T> = {
|
|||||||
? Array<DeepPartial<R>>
|
? Array<DeepPartial<R>>
|
||||||
: DeepPartial<T[K]>;
|
: DeepPartial<T[K]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
type ExcludeFunctions<T> = T extends Function ? never : T;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"database:seed:dev": "npx nx command -- workspace:seed:dev",
|
"database:seed:dev": "npx nx command -- workspace:seed:dev",
|
||||||
"database:seed:demo": "npx nx command -- workspace:seed:demo",
|
"database:seed:demo": "npx nx command -- workspace:seed:demo",
|
||||||
"database:reset": "npx nx database:truncate && npx nx database:init",
|
"database:reset": "npx nx database:truncate && npx nx database:init",
|
||||||
|
"command": "node dist/src/command",
|
||||||
"queue:work": "node dist/src/queue-worker"
|
"queue:work": "node dist/src/queue-worker"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -61,12 +61,10 @@ export class DataSeedWorkspaceCommand extends CommandRunner {
|
|||||||
schemaName,
|
schemaName,
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.workspaceSyncMetadataService.syncStandardObjectsAndFieldsMetadata(
|
await this.workspaceSyncMetadataService.synchronize({
|
||||||
{
|
workspaceId: this.workspaceId,
|
||||||
workspaceId: this.workspaceId,
|
dataSourceId: dataSourceMetadata.id,
|
||||||
dataSourceId: dataSourceMetadata.id,
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|
||||||
|
@ -340,8 +340,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
action: WorkspaceMigrationColumnActionType.CREATE,
|
action: WorkspaceMigrationColumnActionType.CREATE,
|
||||||
columnName: `${computeObjectTargetTable(
|
columnName: `${computeCustomName(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata.nameSingular,
|
||||||
|
false,
|
||||||
)}Id`,
|
)}Id`,
|
||||||
columnType: 'uuid',
|
columnType: 'uuid',
|
||||||
isNullable: true,
|
isNullable: true,
|
||||||
@ -354,8 +355,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
|
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
|
||||||
columnName: `${computeObjectTargetTable(
|
columnName: `${computeCustomName(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata.nameSingular,
|
||||||
|
false,
|
||||||
)}Id`,
|
)}Id`,
|
||||||
referencedTableName: computeObjectTargetTable(
|
referencedTableName: computeObjectTargetTable(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata,
|
||||||
@ -372,8 +374,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
action: WorkspaceMigrationColumnActionType.CREATE,
|
action: WorkspaceMigrationColumnActionType.CREATE,
|
||||||
columnName: `${computeObjectTargetTable(
|
columnName: `${computeCustomName(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata.nameSingular,
|
||||||
|
false,
|
||||||
)}Id`,
|
)}Id`,
|
||||||
columnType: 'uuid',
|
columnType: 'uuid',
|
||||||
isNullable: true,
|
isNullable: true,
|
||||||
@ -386,8 +389,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
|
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
|
||||||
columnName: `${computeObjectTargetTable(
|
columnName: `${computeCustomName(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata.nameSingular,
|
||||||
|
false,
|
||||||
)}Id`,
|
)}Id`,
|
||||||
referencedTableName: computeObjectTargetTable(
|
referencedTableName: computeObjectTargetTable(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata,
|
||||||
@ -403,8 +407,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
action: WorkspaceMigrationColumnActionType.CREATE,
|
action: WorkspaceMigrationColumnActionType.CREATE,
|
||||||
columnName: `${computeObjectTargetTable(
|
columnName: `${computeCustomName(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata.nameSingular,
|
||||||
|
false,
|
||||||
)}Id`,
|
)}Id`,
|
||||||
columnType: 'uuid',
|
columnType: 'uuid',
|
||||||
isNullable: true,
|
isNullable: true,
|
||||||
@ -417,8 +422,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
|
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
|
||||||
columnName: `${computeObjectTargetTable(
|
columnName: `${computeCustomName(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata.nameSingular,
|
||||||
|
false,
|
||||||
)}Id`,
|
)}Id`,
|
||||||
referencedTableName: computeObjectTargetTable(
|
referencedTableName: computeObjectTargetTable(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata,
|
||||||
@ -582,7 +588,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
{
|
{
|
||||||
objectMetadataId: createdObjectMetadata.id,
|
objectMetadataId: createdObjectMetadata.id,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
isCustom: true,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
name: 'activityTargets',
|
name: 'activityTargets',
|
||||||
@ -596,7 +602,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
{
|
{
|
||||||
objectMetadataId: activityTargetObjectMetadata.id,
|
objectMetadataId: activityTargetObjectMetadata.id,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
isCustom: true,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
name: createdObjectMetadata.nameSingular,
|
name: createdObjectMetadata.nameSingular,
|
||||||
@ -610,13 +616,16 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
{
|
{
|
||||||
objectMetadataId: activityTargetObjectMetadata.id,
|
objectMetadataId: activityTargetObjectMetadata.id,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
isCustom: true,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.UUID,
|
type: FieldMetadataType.UUID,
|
||||||
name: `${createdObjectMetadata.nameSingular}Id`,
|
name: `${createdObjectMetadata.nameSingular}Id`,
|
||||||
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
|
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
|
||||||
targetColumnMap: {
|
targetColumnMap: {
|
||||||
value: `${computeObjectTargetTable(createdObjectMetadata)}Id`,
|
value: `${computeCustomName(
|
||||||
|
createdObjectMetadata.nameSingular,
|
||||||
|
false,
|
||||||
|
)}Id`,
|
||||||
},
|
},
|
||||||
description: `ActivityTarget ${createdObjectMetadata.labelSingular} id foreign key`,
|
description: `ActivityTarget ${createdObjectMetadata.labelSingular} id foreign key`,
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
@ -673,7 +682,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
{
|
{
|
||||||
objectMetadataId: createdObjectMetadata.id,
|
objectMetadataId: createdObjectMetadata.id,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
isCustom: true,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
name: 'attachments',
|
name: 'attachments',
|
||||||
@ -687,7 +696,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
{
|
{
|
||||||
objectMetadataId: attachmentObjectMetadata.id,
|
objectMetadataId: attachmentObjectMetadata.id,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
isCustom: true,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
name: createdObjectMetadata.nameSingular,
|
name: createdObjectMetadata.nameSingular,
|
||||||
@ -701,13 +710,16 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
{
|
{
|
||||||
objectMetadataId: attachmentObjectMetadata.id,
|
objectMetadataId: attachmentObjectMetadata.id,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
isCustom: true,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.UUID,
|
type: FieldMetadataType.UUID,
|
||||||
name: `${createdObjectMetadata.nameSingular}Id`,
|
name: `${createdObjectMetadata.nameSingular}Id`,
|
||||||
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
|
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
|
||||||
targetColumnMap: {
|
targetColumnMap: {
|
||||||
value: `${computeObjectTargetTable(createdObjectMetadata)}Id`,
|
value: `${computeCustomName(
|
||||||
|
createdObjectMetadata.nameSingular,
|
||||||
|
false,
|
||||||
|
)}Id`,
|
||||||
},
|
},
|
||||||
description: `Attachment ${createdObjectMetadata.labelSingular} id foreign key`,
|
description: `Attachment ${createdObjectMetadata.labelSingular} id foreign key`,
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
@ -739,6 +751,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
attachmentRelationFieldMetadataMap[createdObjectMetadata.id].id,
|
attachmentRelationFieldMetadataMap[createdObjectMetadata.id].id,
|
||||||
toFieldMetadataId:
|
toFieldMetadataId:
|
||||||
attachmentRelationFieldMetadataMap[attachmentObjectMetadata.id].id,
|
attachmentRelationFieldMetadataMap[attachmentObjectMetadata.id].id,
|
||||||
|
onDeleteAction: RelationOnDeleteAction.CASCADE,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -761,7 +774,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
{
|
{
|
||||||
objectMetadataId: createdObjectMetadata.id,
|
objectMetadataId: createdObjectMetadata.id,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
isCustom: true,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
name: 'favorites',
|
name: 'favorites',
|
||||||
@ -775,7 +788,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
{
|
{
|
||||||
objectMetadataId: favoriteObjectMetadata.id,
|
objectMetadataId: favoriteObjectMetadata.id,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
isCustom: true,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
name: createdObjectMetadata.nameSingular,
|
name: createdObjectMetadata.nameSingular,
|
||||||
@ -789,13 +802,16 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
{
|
{
|
||||||
objectMetadataId: favoriteObjectMetadata.id,
|
objectMetadataId: favoriteObjectMetadata.id,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
isCustom: true,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.UUID,
|
type: FieldMetadataType.UUID,
|
||||||
name: `${createdObjectMetadata.nameSingular}Id`,
|
name: `${createdObjectMetadata.nameSingular}Id`,
|
||||||
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
|
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
|
||||||
targetColumnMap: {
|
targetColumnMap: {
|
||||||
value: `${computeObjectTargetTable(createdObjectMetadata)}Id`,
|
value: `${computeCustomName(
|
||||||
|
createdObjectMetadata.nameSingular,
|
||||||
|
false,
|
||||||
|
)}Id`,
|
||||||
},
|
},
|
||||||
description: `Favorite ${createdObjectMetadata.labelSingular} id foreign key`,
|
description: `Favorite ${createdObjectMetadata.labelSingular} id foreign key`,
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
|
|
||||||
import { GateDecoratorParams } from 'src/workspace/workspace-sync-metadata/interfaces/gate-decorator.interface';
|
import { GateDecoratorParams } from 'src/workspace/workspace-sync-metadata/interfaces/gate-decorator.interface';
|
||||||
|
import { ReflectBaseCustomObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-custom-object-metadata.interface';
|
||||||
|
import { ReflectDynamicRelationFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-computed-relation-field-metadata.interface';
|
||||||
import { ReflectFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-field-metadata.interface';
|
import { ReflectFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-field-metadata.interface';
|
||||||
import { ReflectObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-object-metadata.interface';
|
import { ReflectObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-object-metadata.interface';
|
||||||
import { ReflectRelationMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-relation-metadata.interface';
|
import { ReflectRelationMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-relation-metadata.interface';
|
||||||
|
|
||||||
export interface ReflectMetadataTypeMap {
|
export interface ReflectMetadataTypeMap {
|
||||||
objectMetadata: ReflectObjectMetadata;
|
objectMetadata: ReflectObjectMetadata;
|
||||||
|
extendObjectMetadata: ReflectBaseCustomObjectMetadata;
|
||||||
fieldMetadataMap: ReflectFieldMetadata;
|
fieldMetadataMap: ReflectFieldMetadata;
|
||||||
relationMetadataCollection: ReflectRelationMetadata[];
|
dynamicRelationFieldMetadataMap: ReflectDynamicRelationFieldMetadata;
|
||||||
|
reflectRelationMetadataCollection: ReflectRelationMetadata[];
|
||||||
gate: GateDecoratorParams;
|
gate: GateDecoratorParams;
|
||||||
isNullable: true;
|
isNullable: true;
|
||||||
isSystem: true;
|
isSystem: true;
|
||||||
|
@ -38,12 +38,10 @@ export class WorkspaceManagerService {
|
|||||||
|
|
||||||
await this.setWorkspaceMaxRow(workspaceId, schemaName);
|
await this.setWorkspaceMaxRow(workspaceId, schemaName);
|
||||||
|
|
||||||
await this.workspaceSyncMetadataService.syncStandardObjectsAndFieldsMetadata(
|
await this.workspaceSyncMetadataService.synchronize({
|
||||||
{
|
workspaceId,
|
||||||
workspaceId,
|
dataSourceId: dataSourceMetadata.id,
|
||||||
dataSourceId: dataSourceMetadata.id,
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.prefillWorkspaceWithStandardObjects(
|
await this.prefillWorkspaceWithStandardObjects(
|
||||||
dataSourceMetadata,
|
dataSourceMetadata,
|
||||||
@ -70,12 +68,10 @@ export class WorkspaceManagerService {
|
|||||||
|
|
||||||
await this.setWorkspaceMaxRow(workspaceId, schemaName);
|
await this.setWorkspaceMaxRow(workspaceId, schemaName);
|
||||||
|
|
||||||
await this.workspaceSyncMetadataService.syncStandardObjectsAndFieldsMetadata(
|
await this.workspaceSyncMetadataService.synchronize({
|
||||||
{
|
workspaceId,
|
||||||
workspaceId,
|
dataSourceId: dataSourceMetadata.id,
|
||||||
dataSourceId: dataSourceMetadata.id,
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.prefillWorkspaceWithDemoObjects(dataSourceMetadata, workspaceId);
|
await this.prefillWorkspaceWithDemoObjects(dataSourceMetadata, workspaceId);
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ export class SyncWorkspaceMetadataCommand extends CommandRunner {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { storage, workspaceMigrations } =
|
const { storage, workspaceMigrations } =
|
||||||
await this.workspaceSyncMetadataService.syncStandardObjectsAndFieldsMetadata(
|
await this.workspaceSyncMetadataService.synchronize(
|
||||||
{
|
{
|
||||||
workspaceId,
|
workspaceId,
|
||||||
dataSourceId: dataSourceMetadata.id,
|
dataSourceId: dataSourceMetadata.id,
|
||||||
|
@ -6,8 +6,8 @@ import {
|
|||||||
ComparatorAction,
|
ComparatorAction,
|
||||||
FieldComparatorResult,
|
FieldComparatorResult,
|
||||||
} from 'src/workspace/workspace-sync-metadata/interfaces/comparator.interface';
|
} from 'src/workspace/workspace-sync-metadata/interfaces/comparator.interface';
|
||||||
import { PartialFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
import { ComputedPartialFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||||
import { PartialObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
import { ComputedPartialObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
||||||
|
|
||||||
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
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 { transformMetadataForComparison } from 'src/workspace/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
||||||
@ -30,12 +30,12 @@ export class WorkspaceFieldComparator {
|
|||||||
|
|
||||||
public compare(
|
public compare(
|
||||||
originalObjectMetadata: ObjectMetadataEntity,
|
originalObjectMetadata: ObjectMetadataEntity,
|
||||||
standardObjectMetadata: PartialObjectMetadata,
|
standardObjectMetadata: ComputedPartialObjectMetadata,
|
||||||
): FieldComparatorResult[] {
|
): FieldComparatorResult[] {
|
||||||
const result: FieldComparatorResult[] = [];
|
const result: FieldComparatorResult[] = [];
|
||||||
const fieldPropertiesToUpdateMap: Record<
|
const fieldPropertiesToUpdateMap: Record<
|
||||||
string,
|
string,
|
||||||
Partial<PartialFieldMetadata>
|
Partial<ComputedPartialFieldMetadata>
|
||||||
> = {};
|
> = {};
|
||||||
|
|
||||||
// Double security to only compare non-custom fields
|
// Double security to only compare non-custom fields
|
||||||
@ -69,7 +69,7 @@ export class WorkspaceFieldComparator {
|
|||||||
standardObjectMetadata.fields,
|
standardObjectMetadata.fields,
|
||||||
{
|
{
|
||||||
shouldIgnoreProperty: (property, originalMetadata) => {
|
shouldIgnoreProperty: (property, originalMetadata) => {
|
||||||
if (['options'].includes(property)) {
|
if (['options', 'gate'].includes(property)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
ComparatorAction,
|
ComparatorAction,
|
||||||
ObjectComparatorResult,
|
ObjectComparatorResult,
|
||||||
} from 'src/workspace/workspace-sync-metadata/interfaces/comparator.interface';
|
} from 'src/workspace/workspace-sync-metadata/interfaces/comparator.interface';
|
||||||
import { PartialObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
import { ComputedPartialObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
||||||
|
|
||||||
import { transformMetadataForComparison } from 'src/workspace/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
import { transformMetadataForComparison } from 'src/workspace/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
||||||
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
||||||
@ -28,7 +28,7 @@ export class WorkspaceObjectComparator {
|
|||||||
|
|
||||||
public compare(
|
public compare(
|
||||||
originalObjectMetadata: ObjectMetadataEntity | undefined,
|
originalObjectMetadata: ObjectMetadataEntity | undefined,
|
||||||
standardObjectMetadata: PartialObjectMetadata,
|
standardObjectMetadata: ComputedPartialObjectMetadata,
|
||||||
): 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) {
|
||||||
@ -38,7 +38,7 @@ export class WorkspaceObjectComparator {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const objectPropertiesToUpdate: Partial<PartialObjectMetadata> = {};
|
const objectPropertiesToUpdate: Partial<ComputedPartialObjectMetadata> = {};
|
||||||
|
|
||||||
// Only compare properties that are not ignored
|
// Only compare properties that are not ignored
|
||||||
const partialOriginalObjectMetadata = transformMetadataForComparison(
|
const partialOriginalObjectMetadata = transformMetadataForComparison(
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
import { BaseCustomObjectMetadata } from 'src/workspace/workspace-sync-metadata/decorators/base-custom-object-metadata.decorator';
|
||||||
|
import { FieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/field-metadata.decorator';
|
||||||
|
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
|
import { IsNullable } from 'src/workspace/workspace-sync-metadata/decorators/is-nullable.decorator';
|
||||||
|
import { IsSystem } from 'src/workspace/workspace-sync-metadata/decorators/is-system.decorator';
|
||||||
|
import { BaseObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/base.object-metadata';
|
||||||
|
import {
|
||||||
|
RelationMetadataType,
|
||||||
|
RelationOnDeleteAction,
|
||||||
|
} from 'src/metadata/relation-metadata/relation-metadata.entity';
|
||||||
|
import { ActivityTargetObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/activity-target.object-metadata';
|
||||||
|
import { RelationMetadata } from 'src/workspace/workspace-sync-metadata/decorators/relation-metadata.decorator';
|
||||||
|
import { FavoriteObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/favorite.object-metadata';
|
||||||
|
import { AttachmentObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/attachment.object-metadata';
|
||||||
|
|
||||||
|
@BaseCustomObjectMetadata()
|
||||||
|
export class CustomObjectMetadata extends BaseObjectMetadata {
|
||||||
|
@FieldMetadata({
|
||||||
|
label: 'Name',
|
||||||
|
description: 'Name',
|
||||||
|
type: FieldMetadataType.TEXT,
|
||||||
|
icon: 'IconAbc',
|
||||||
|
defaultValue: { value: 'Untitled' },
|
||||||
|
})
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@FieldMetadata({
|
||||||
|
label: 'Position',
|
||||||
|
description: 'Position',
|
||||||
|
type: FieldMetadataType.POSITION,
|
||||||
|
icon: 'IconHierarchy2',
|
||||||
|
})
|
||||||
|
@IsNullable()
|
||||||
|
@IsSystem()
|
||||||
|
position: number;
|
||||||
|
|
||||||
|
@FieldMetadata({
|
||||||
|
type: FieldMetadataType.RELATION,
|
||||||
|
label: 'Activities',
|
||||||
|
description: (objectMetadata) =>
|
||||||
|
`Activities tied to the ${objectMetadata.labelSingular}`,
|
||||||
|
icon: 'IconCheckbox',
|
||||||
|
})
|
||||||
|
@RelationMetadata({
|
||||||
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
|
inverseSideTarget: () => ActivityTargetObjectMetadata,
|
||||||
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
|
})
|
||||||
|
@IsNullable()
|
||||||
|
activityTargets: ActivityTargetObjectMetadata[];
|
||||||
|
|
||||||
|
@FieldMetadata({
|
||||||
|
type: FieldMetadataType.RELATION,
|
||||||
|
label: 'Favorites',
|
||||||
|
description: (objectMetadata) =>
|
||||||
|
`Favorites tied to the ${objectMetadata.labelSingular}`,
|
||||||
|
icon: 'IconHeart',
|
||||||
|
})
|
||||||
|
@RelationMetadata({
|
||||||
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
|
inverseSideTarget: () => FavoriteObjectMetadata,
|
||||||
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
|
})
|
||||||
|
@IsNullable()
|
||||||
|
favorites: FavoriteObjectMetadata[];
|
||||||
|
|
||||||
|
@FieldMetadata({
|
||||||
|
type: FieldMetadataType.RELATION,
|
||||||
|
label: 'Attachments',
|
||||||
|
description: (objectMetadata) =>
|
||||||
|
`Attachments tied to the ${objectMetadata.labelSingular}`,
|
||||||
|
icon: 'IconFileImport',
|
||||||
|
})
|
||||||
|
@RelationMetadata({
|
||||||
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
|
inverseSideTarget: () => AttachmentObjectMetadata,
|
||||||
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
|
})
|
||||||
|
@IsNullable()
|
||||||
|
attachments: AttachmentObjectMetadata[];
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import { BaseCustomObjectMetadataDecoratorParams } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-custom-object-metadata.interface';
|
||||||
|
|
||||||
|
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||||
|
|
||||||
|
export function BaseCustomObjectMetadata(
|
||||||
|
params?: BaseCustomObjectMetadataDecoratorParams,
|
||||||
|
): ClassDecorator {
|
||||||
|
return (target) => {
|
||||||
|
const gate = TypedReflect.getMetadata('gate', target);
|
||||||
|
|
||||||
|
TypedReflect.defineMetadata(
|
||||||
|
'extendObjectMetadata',
|
||||||
|
{
|
||||||
|
...params,
|
||||||
|
gate,
|
||||||
|
},
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
import { DynamicRelationFieldMetadataDecoratorParams } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-computed-relation-field-metadata.interface';
|
||||||
|
|
||||||
|
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||||
|
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
|
|
||||||
|
export function DynamicRelationFieldMetadata(
|
||||||
|
params: DynamicRelationFieldMetadataDecoratorParams,
|
||||||
|
): PropertyDecorator {
|
||||||
|
return (target: object, fieldKey: string) => {
|
||||||
|
const isSystem =
|
||||||
|
TypedReflect.getMetadata('isSystem', target, fieldKey) ?? false;
|
||||||
|
const gate = TypedReflect.getMetadata('gate', target, fieldKey);
|
||||||
|
|
||||||
|
TypedReflect.defineMetadata(
|
||||||
|
'dynamicRelationFieldMetadataMap',
|
||||||
|
{
|
||||||
|
type: FieldMetadataType.RELATION,
|
||||||
|
paramsFactory: params,
|
||||||
|
isCustom: false,
|
||||||
|
isNullable: true,
|
||||||
|
isSystem,
|
||||||
|
gate,
|
||||||
|
},
|
||||||
|
target.constructor,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
@ -6,33 +6,27 @@ import {
|
|||||||
} from 'src/workspace/workspace-sync-metadata/interfaces/reflect-relation-metadata.interface';
|
} from 'src/workspace/workspace-sync-metadata/interfaces/reflect-relation-metadata.interface';
|
||||||
|
|
||||||
import { TypedReflect } from 'src/utils/typed-reflect';
|
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||||
import { convertClassNameToObjectMetadataName } from 'src/workspace/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util';
|
|
||||||
import { RelationOnDeleteAction } from 'src/metadata/relation-metadata/relation-metadata.entity';
|
import { RelationOnDeleteAction } from 'src/metadata/relation-metadata/relation-metadata.entity';
|
||||||
|
|
||||||
export function RelationMetadata(
|
export function RelationMetadata<TClass extends object>(
|
||||||
params: RelationMetadataDecoratorParams,
|
params: RelationMetadataDecoratorParams<TClass>,
|
||||||
): PropertyDecorator {
|
): PropertyDecorator {
|
||||||
return (target: object, fieldKey: string) => {
|
return (target: object, fieldKey: string) => {
|
||||||
const relationMetadataCollection =
|
const relationMetadataCollection =
|
||||||
TypedReflect.getMetadata(
|
TypedReflect.getMetadata(
|
||||||
'relationMetadataCollection',
|
'reflectRelationMetadataCollection',
|
||||||
target.constructor,
|
target.constructor,
|
||||||
) ?? [];
|
) ?? [];
|
||||||
const gate = TypedReflect.getMetadata('gate', target, fieldKey);
|
const gate = TypedReflect.getMetadata('gate', target, fieldKey);
|
||||||
const objectName = convertClassNameToObjectMetadataName(
|
|
||||||
target.constructor.name,
|
|
||||||
);
|
|
||||||
|
|
||||||
Reflect.defineMetadata(
|
TypedReflect.defineMetadata(
|
||||||
'relationMetadataCollection',
|
'reflectRelationMetadataCollection',
|
||||||
[
|
[
|
||||||
...relationMetadataCollection,
|
...relationMetadataCollection,
|
||||||
{
|
{
|
||||||
type: params.type,
|
target,
|
||||||
fromObjectNameSingular: objectName,
|
fieldKey,
|
||||||
toObjectNameSingular: params.objectName,
|
...params,
|
||||||
fromFieldMetadataName: fieldKey,
|
|
||||||
toFieldMetadataName: params.inverseSideFieldName ?? objectName,
|
|
||||||
onDelete: params.onDelete ?? RelationOnDeleteAction.SET_NULL,
|
onDelete: params.onDelete ?? RelationOnDeleteAction.SET_NULL,
|
||||||
gate,
|
gate,
|
||||||
} satisfies ReflectRelationMetadata,
|
} satisfies ReflectRelationMetadata,
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { FeatureFlagFactory } from './feature-flags.factory';
|
import { FeatureFlagFactory } from './feature-flags.factory';
|
||||||
|
import { StandardFieldFactory } from './standard-field.factory';
|
||||||
import { StandardObjectFactory } from './standard-object.factory';
|
import { StandardObjectFactory } from './standard-object.factory';
|
||||||
import { StandardRelationFactory } from './standard-relation.factory';
|
import { StandardRelationFactory } from './standard-relation.factory';
|
||||||
|
|
||||||
export const workspaceSyncMetadataFactories = [
|
export const workspaceSyncMetadataFactories = [
|
||||||
FeatureFlagFactory,
|
FeatureFlagFactory,
|
||||||
|
StandardFieldFactory,
|
||||||
StandardObjectFactory,
|
StandardObjectFactory,
|
||||||
StandardRelationFactory,
|
StandardRelationFactory,
|
||||||
];
|
];
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { WorkspaceSyncContext } from 'src/workspace/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||||
|
import { FeatureFlagMap } from 'src/core/feature-flag/interfaces/feature-flag-map.interface';
|
||||||
|
import {
|
||||||
|
PartialComputedFieldMetadata,
|
||||||
|
PartialFieldMetadata,
|
||||||
|
} from 'src/workspace/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||||
|
import { ReflectFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-field-metadata.interface';
|
||||||
|
import { ReflectObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-object-metadata.interface';
|
||||||
|
import { ReflectDynamicRelationFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-computed-relation-field-metadata.interface';
|
||||||
|
|
||||||
|
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||||
|
import { isGatedAndNotEnabled } from 'src/workspace/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class StandardFieldFactory {
|
||||||
|
create(
|
||||||
|
target: object,
|
||||||
|
context: WorkspaceSyncContext,
|
||||||
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
|
): (PartialFieldMetadata | PartialComputedFieldMetadata)[] {
|
||||||
|
const reflectObjectMetadata = TypedReflect.getMetadata(
|
||||||
|
'objectMetadata',
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
const reflectFieldMetadataMap =
|
||||||
|
TypedReflect.getMetadata('fieldMetadataMap', target) ?? [];
|
||||||
|
const reflectDynamicRelationFieldMetadataMap = TypedReflect.getMetadata(
|
||||||
|
'dynamicRelationFieldMetadataMap',
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
const partialFieldMetadataCollection: (
|
||||||
|
| PartialFieldMetadata
|
||||||
|
| PartialComputedFieldMetadata
|
||||||
|
)[] = Object.values(reflectFieldMetadataMap)
|
||||||
|
.map((reflectFieldMetadata) =>
|
||||||
|
this.createFieldMetadata(
|
||||||
|
reflectObjectMetadata,
|
||||||
|
reflectFieldMetadata,
|
||||||
|
context,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.filter((metadata): metadata is PartialFieldMetadata => !!metadata);
|
||||||
|
const partialComputedFieldMetadata = this.createComputedFieldMetadata(
|
||||||
|
reflectDynamicRelationFieldMetadataMap,
|
||||||
|
context,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (partialComputedFieldMetadata) {
|
||||||
|
partialFieldMetadataCollection.push(partialComputedFieldMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return partialFieldMetadataCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createFieldMetadata(
|
||||||
|
reflectObjectMetadata: ReflectObjectMetadata | undefined,
|
||||||
|
reflectFieldMetadata: ReflectFieldMetadata[string],
|
||||||
|
context: WorkspaceSyncContext,
|
||||||
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
|
): PartialFieldMetadata | undefined {
|
||||||
|
if (
|
||||||
|
isGatedAndNotEnabled(reflectFieldMetadata.gate, workspaceFeatureFlagsMap)
|
||||||
|
) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...reflectFieldMetadata,
|
||||||
|
workspaceId: context.workspaceId,
|
||||||
|
isSystem:
|
||||||
|
reflectObjectMetadata?.isSystem || reflectFieldMetadata.isSystem,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private createComputedFieldMetadata(
|
||||||
|
reflectDynamicRelationFieldMetadata:
|
||||||
|
| ReflectDynamicRelationFieldMetadata
|
||||||
|
| undefined,
|
||||||
|
context: WorkspaceSyncContext,
|
||||||
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
|
): PartialComputedFieldMetadata | undefined {
|
||||||
|
if (
|
||||||
|
!reflectDynamicRelationFieldMetadata ||
|
||||||
|
isGatedAndNotEnabled(
|
||||||
|
reflectDynamicRelationFieldMetadata.gate,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...reflectDynamicRelationFieldMetadata,
|
||||||
|
workspaceId: context.workspaceId,
|
||||||
|
isSystem: reflectDynamicRelationFieldMetadata.isSystem,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -3,20 +3,23 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { WorkspaceSyncContext } from 'src/workspace/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
import { WorkspaceSyncContext } from 'src/workspace/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||||
import { PartialObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
import { PartialObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
||||||
import { FeatureFlagMap } from 'src/core/feature-flag/interfaces/feature-flag-map.interface';
|
import { FeatureFlagMap } from 'src/core/feature-flag/interfaces/feature-flag-map.interface';
|
||||||
import { PartialFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
|
||||||
|
|
||||||
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 { standardObjectMetadataCollection } from 'src/workspace/workspace-sync-metadata/standard-objects';
|
|
||||||
import { TypedReflect } from 'src/utils/typed-reflect';
|
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||||
import { isGatedAndNotEnabled } from 'src/workspace/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
|
import { isGatedAndNotEnabled } from 'src/workspace/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
|
||||||
|
|
||||||
|
import { StandardFieldFactory } from './standard-field.factory';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class StandardObjectFactory {
|
export class StandardObjectFactory {
|
||||||
|
constructor(private readonly standardFieldFactory: StandardFieldFactory) {}
|
||||||
|
|
||||||
create(
|
create(
|
||||||
|
standardObjectMetadataDefinitions: (typeof BaseObjectMetadata)[],
|
||||||
context: WorkspaceSyncContext,
|
context: WorkspaceSyncContext,
|
||||||
workspaceFeatureFlagsMap: FeatureFlagMap,
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
): PartialObjectMetadata[] {
|
): PartialObjectMetadata[] {
|
||||||
return standardObjectMetadataCollection
|
return standardObjectMetadataDefinitions
|
||||||
.map((metadata) =>
|
.map((metadata) =>
|
||||||
this.createObjectMetadata(metadata, context, workspaceFeatureFlagsMap),
|
this.createObjectMetadata(metadata, context, workspaceFeatureFlagsMap),
|
||||||
)
|
)
|
||||||
@ -29,8 +32,6 @@ export class StandardObjectFactory {
|
|||||||
workspaceFeatureFlagsMap: FeatureFlagMap,
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
): PartialObjectMetadata | undefined {
|
): PartialObjectMetadata | undefined {
|
||||||
const objectMetadata = TypedReflect.getMetadata('objectMetadata', metadata);
|
const objectMetadata = TypedReflect.getMetadata('objectMetadata', metadata);
|
||||||
const fieldMetadataMap =
|
|
||||||
TypedReflect.getMetadata('fieldMetadataMap', metadata) ?? [];
|
|
||||||
|
|
||||||
if (!objectMetadata) {
|
if (!objectMetadata) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -42,22 +43,10 @@ export class StandardObjectFactory {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields = Object.values(fieldMetadataMap).reduce(
|
const fields = this.standardFieldFactory.create(
|
||||||
// Omit gate as we don't want to store it in the DB
|
metadata,
|
||||||
(acc, { gate, ...fieldMetadata }) => {
|
context,
|
||||||
if (isGatedAndNotEnabled(gate, workspaceFeatureFlagsMap)) {
|
workspaceFeatureFlagsMap,
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
acc.push({
|
|
||||||
...fieldMetadata,
|
|
||||||
workspaceId: context.workspaceId,
|
|
||||||
isSystem: objectMetadata.isSystem || fieldMetadata.isSystem,
|
|
||||||
});
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
[] as PartialFieldMetadata[],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -4,42 +4,80 @@ import { WorkspaceSyncContext } from 'src/workspace/workspace-sync-metadata/inte
|
|||||||
import { FeatureFlagMap } from 'src/core/feature-flag/interfaces/feature-flag-map.interface';
|
import { FeatureFlagMap } from 'src/core/feature-flag/interfaces/feature-flag-map.interface';
|
||||||
|
|
||||||
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 { standardObjectMetadataCollection } from 'src/workspace/workspace-sync-metadata/standard-objects';
|
|
||||||
import { TypedReflect } from 'src/utils/typed-reflect';
|
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||||
import { isGatedAndNotEnabled } from 'src/workspace/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
|
import { isGatedAndNotEnabled } from 'src/workspace/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-metadata.entity';
|
import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-metadata.entity';
|
||||||
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
||||||
|
import { convertClassNameToObjectMetadataName } from 'src/workspace/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util';
|
||||||
|
|
||||||
|
interface CustomRelationFactory {
|
||||||
|
object: ObjectMetadataEntity;
|
||||||
|
metadata: typeof BaseObjectMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class StandardRelationFactory {
|
export class StandardRelationFactory {
|
||||||
create(
|
create(
|
||||||
|
customObjectFactories: CustomRelationFactory[],
|
||||||
|
context: WorkspaceSyncContext,
|
||||||
|
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
|
||||||
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
|
): Partial<RelationMetadataEntity>[];
|
||||||
|
|
||||||
|
create(
|
||||||
|
standardObjectMetadataDefinitions: (typeof BaseObjectMetadata)[],
|
||||||
|
context: WorkspaceSyncContext,
|
||||||
|
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
|
||||||
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
|
): Partial<RelationMetadataEntity>[];
|
||||||
|
|
||||||
|
create(
|
||||||
|
standardObjectMetadataDefinitionsOrCustomObjectFactories:
|
||||||
|
| (typeof BaseObjectMetadata)[]
|
||||||
|
| {
|
||||||
|
object: ObjectMetadataEntity;
|
||||||
|
metadata: typeof BaseObjectMetadata;
|
||||||
|
}[],
|
||||||
context: WorkspaceSyncContext,
|
context: WorkspaceSyncContext,
|
||||||
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
|
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
|
||||||
workspaceFeatureFlagsMap: FeatureFlagMap,
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
): Partial<RelationMetadataEntity>[] {
|
): Partial<RelationMetadataEntity>[] {
|
||||||
return standardObjectMetadataCollection.flatMap((standardObjectMetadata) =>
|
return standardObjectMetadataDefinitionsOrCustomObjectFactories.flatMap(
|
||||||
this.createRelationMetadata(
|
(
|
||||||
standardObjectMetadata,
|
standardObjectMetadata:
|
||||||
context,
|
| typeof BaseObjectMetadata
|
||||||
originalObjectMetadataMap,
|
| CustomRelationFactory,
|
||||||
workspaceFeatureFlagsMap,
|
) =>
|
||||||
),
|
this.createRelationMetadata(
|
||||||
|
standardObjectMetadata,
|
||||||
|
context,
|
||||||
|
originalObjectMetadataMap,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createRelationMetadata(
|
private createRelationMetadata(
|
||||||
standardObjectMetadata: typeof BaseObjectMetadata,
|
standardObjectMetadataOrCustomRelationFactory:
|
||||||
|
| typeof BaseObjectMetadata
|
||||||
|
| CustomRelationFactory,
|
||||||
context: WorkspaceSyncContext,
|
context: WorkspaceSyncContext,
|
||||||
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
|
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
|
||||||
workspaceFeatureFlagsMap: FeatureFlagMap,
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
): Partial<RelationMetadataEntity>[] {
|
): Partial<RelationMetadataEntity>[] {
|
||||||
|
const standardObjectMetadata =
|
||||||
|
'metadata' in standardObjectMetadataOrCustomRelationFactory
|
||||||
|
? standardObjectMetadataOrCustomRelationFactory.metadata
|
||||||
|
: standardObjectMetadataOrCustomRelationFactory;
|
||||||
const objectMetadata = TypedReflect.getMetadata(
|
const objectMetadata = TypedReflect.getMetadata(
|
||||||
'objectMetadata',
|
'metadata' in standardObjectMetadataOrCustomRelationFactory
|
||||||
|
? 'extendObjectMetadata'
|
||||||
|
: 'objectMetadata',
|
||||||
standardObjectMetadata,
|
standardObjectMetadata,
|
||||||
);
|
);
|
||||||
const relationMetadataCollection = TypedReflect.getMetadata(
|
const reflectRelationMetadataCollection = TypedReflect.getMetadata(
|
||||||
'relationMetadataCollection',
|
'reflectRelationMetadataCollection',
|
||||||
standardObjectMetadata,
|
standardObjectMetadata,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -50,67 +88,81 @@ export class StandardRelationFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!relationMetadataCollection ||
|
!reflectRelationMetadataCollection ||
|
||||||
isGatedAndNotEnabled(objectMetadata.gate, workspaceFeatureFlagsMap)
|
isGatedAndNotEnabled(objectMetadata?.gate, workspaceFeatureFlagsMap)
|
||||||
) {
|
) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return relationMetadataCollection
|
return reflectRelationMetadataCollection
|
||||||
.filter(
|
.filter(
|
||||||
(relationMetadata) =>
|
(reflectRelationMetadata) =>
|
||||||
!isGatedAndNotEnabled(
|
!isGatedAndNotEnabled(
|
||||||
relationMetadata.gate,
|
reflectRelationMetadata.gate,
|
||||||
workspaceFeatureFlagsMap,
|
workspaceFeatureFlagsMap,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.map((relationMetadata) => {
|
.map((reflectRelationMetadata) => {
|
||||||
|
// Compute reflect relation metadata
|
||||||
|
const fromObjectNameSingular =
|
||||||
|
'object' in standardObjectMetadataOrCustomRelationFactory
|
||||||
|
? standardObjectMetadataOrCustomRelationFactory.object.nameSingular
|
||||||
|
: convertClassNameToObjectMetadataName(
|
||||||
|
reflectRelationMetadata.target.constructor.name,
|
||||||
|
);
|
||||||
|
const toObjectNameSingular = convertClassNameToObjectMetadataName(
|
||||||
|
reflectRelationMetadata.inverseSideTarget().name,
|
||||||
|
);
|
||||||
|
const fromFieldMetadataName = reflectRelationMetadata.fieldKey;
|
||||||
|
const toFieldMetadataName =
|
||||||
|
(reflectRelationMetadata.inverseSideFieldKey as string | undefined) ??
|
||||||
|
fromObjectNameSingular;
|
||||||
const fromObjectMetadata =
|
const fromObjectMetadata =
|
||||||
originalObjectMetadataMap[relationMetadata.fromObjectNameSingular];
|
originalObjectMetadataMap[fromObjectNameSingular];
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
fromObjectMetadata,
|
fromObjectMetadata,
|
||||||
`Object ${relationMetadata.fromObjectNameSingular} not found in DB
|
`Object ${fromObjectNameSingular} not found in DB
|
||||||
for relation FROM defined in class ${objectMetadata.nameSingular}`,
|
for relation FROM defined in class ${fromObjectNameSingular}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const toObjectMetadata =
|
const toObjectMetadata =
|
||||||
originalObjectMetadataMap[relationMetadata.toObjectNameSingular];
|
originalObjectMetadataMap[toObjectNameSingular];
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
toObjectMetadata,
|
toObjectMetadata,
|
||||||
`Object ${relationMetadata.toObjectNameSingular} not found in DB
|
`Object ${toObjectNameSingular} not found in DB
|
||||||
for relation TO defined in class ${objectMetadata.nameSingular}`,
|
for relation TO defined in class ${fromObjectNameSingular}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const fromFieldMetadata = fromObjectMetadata?.fields.find(
|
const fromFieldMetadata = fromObjectMetadata?.fields.find(
|
||||||
(field) => field.name === relationMetadata.fromFieldMetadataName,
|
(field) => field.name === fromFieldMetadataName,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
fromFieldMetadata,
|
fromFieldMetadata,
|
||||||
`Field ${relationMetadata.fromFieldMetadataName} not found in object ${relationMetadata.fromObjectNameSingular}
|
`Field ${fromFieldMetadataName} not found in object ${fromObjectNameSingular}
|
||||||
for relation FROM defined in class ${objectMetadata.nameSingular}`,
|
for relation FROM defined in class ${fromObjectNameSingular}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const toFieldMetadata = toObjectMetadata?.fields.find(
|
const toFieldMetadata = toObjectMetadata?.fields.find(
|
||||||
(field) => field.name === relationMetadata.toFieldMetadataName,
|
(field) => field.name === toFieldMetadataName,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
toFieldMetadata,
|
toFieldMetadata,
|
||||||
`Field ${relationMetadata.toFieldMetadataName} not found in object ${relationMetadata.toObjectNameSingular}
|
`Field ${toFieldMetadataName} not found in object ${toObjectNameSingular}
|
||||||
for relation TO defined in class ${objectMetadata.nameSingular}`,
|
for relation TO defined in class ${fromObjectNameSingular}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
relationType: relationMetadata.type,
|
relationType: reflectRelationMetadata.type,
|
||||||
fromObjectMetadataId: fromObjectMetadata?.id,
|
fromObjectMetadataId: fromObjectMetadata?.id,
|
||||||
toObjectMetadataId: toObjectMetadata?.id,
|
toObjectMetadataId: toObjectMetadata?.id,
|
||||||
fromFieldMetadataId: fromFieldMetadata?.id,
|
fromFieldMetadataId: fromFieldMetadata?.id,
|
||||||
toFieldMetadataId: toFieldMetadata?.id,
|
toFieldMetadataId: toFieldMetadata?.id,
|
||||||
workspaceId: context.workspaceId,
|
workspaceId: context.workspaceId,
|
||||||
onDeleteAction: relationMetadata.onDelete,
|
onDeleteAction: reflectRelationMetadata.onDelete,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { FieldMetadataEntity } from 'src/metadata/field-metadata/field-metadata.entity';
|
import { FieldMetadataEntity } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-metadata.entity';
|
import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-metadata.entity';
|
||||||
|
|
||||||
import { PartialFieldMetadata } from './partial-field-metadata.interface';
|
import { ComputedPartialFieldMetadata } from './partial-field-metadata.interface';
|
||||||
import { PartialObjectMetadata } from './partial-object-metadata.interface';
|
import { ComputedPartialObjectMetadata } from './partial-object-metadata.interface';
|
||||||
|
|
||||||
export const enum ComparatorAction {
|
export const enum ComparatorAction {
|
||||||
SKIP = 'SKIP',
|
SKIP = 'SKIP',
|
||||||
@ -32,13 +32,15 @@ export interface ComparatorDeleteResult<T> {
|
|||||||
|
|
||||||
export type ObjectComparatorResult =
|
export type ObjectComparatorResult =
|
||||||
| ComparatorSkipResult
|
| ComparatorSkipResult
|
||||||
| ComparatorCreateResult<PartialObjectMetadata>
|
| ComparatorCreateResult<ComputedPartialObjectMetadata>
|
||||||
| ComparatorUpdateResult<Partial<PartialObjectMetadata>>;
|
| ComparatorUpdateResult<Partial<ComputedPartialObjectMetadata>>;
|
||||||
|
|
||||||
export type FieldComparatorResult =
|
export type FieldComparatorResult =
|
||||||
| ComparatorSkipResult
|
| ComparatorSkipResult
|
||||||
| ComparatorCreateResult<PartialFieldMetadata>
|
| ComparatorCreateResult<ComputedPartialFieldMetadata>
|
||||||
| ComparatorUpdateResult<Partial<PartialFieldMetadata> & { id: string }>
|
| ComparatorUpdateResult<
|
||||||
|
Partial<ComputedPartialFieldMetadata> & { id: string }
|
||||||
|
>
|
||||||
| ComparatorDeleteResult<FieldMetadataEntity>;
|
| ComparatorDeleteResult<FieldMetadataEntity>;
|
||||||
|
|
||||||
export type RelationComparatorResult =
|
export type RelationComparatorResult =
|
||||||
|
@ -1,6 +1,20 @@
|
|||||||
|
import { ReflectDynamicRelationFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-computed-relation-field-metadata.interface';
|
||||||
import { ReflectFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-field-metadata.interface';
|
import { ReflectFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-field-metadata.interface';
|
||||||
|
|
||||||
export type PartialFieldMetadata = ReflectFieldMetadata[string] & {
|
export type PartialFieldMetadata = Omit<
|
||||||
|
ReflectFieldMetadata[string],
|
||||||
|
'joinColumn'
|
||||||
|
> & {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
objectMetadataId?: string;
|
objectMetadataId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PartialComputedFieldMetadata =
|
||||||
|
ReflectDynamicRelationFieldMetadata & {
|
||||||
|
workspaceId: string;
|
||||||
|
objectMetadataId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ComputedPartialFieldMetadata = {
|
||||||
|
[K in keyof PartialFieldMetadata]: ExcludeFunctions<PartialFieldMetadata[K]>;
|
||||||
|
};
|
||||||
|
@ -1,9 +1,20 @@
|
|||||||
import { PartialFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
import {
|
||||||
|
ComputedPartialFieldMetadata,
|
||||||
|
PartialComputedFieldMetadata,
|
||||||
|
PartialFieldMetadata,
|
||||||
|
} from 'src/workspace/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||||
import { ReflectObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-object-metadata.interface';
|
import { ReflectObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/reflect-object-metadata.interface';
|
||||||
|
|
||||||
export type PartialObjectMetadata = ReflectObjectMetadata & {
|
export type PartialObjectMetadata = ReflectObjectMetadata & {
|
||||||
id?: string;
|
id?: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
dataSourceId: string;
|
dataSourceId: string;
|
||||||
fields: PartialFieldMetadata[];
|
fields: (PartialFieldMetadata | PartialComputedFieldMetadata)[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ComputedPartialObjectMetadata = Omit<
|
||||||
|
PartialObjectMetadata,
|
||||||
|
'fields'
|
||||||
|
> & {
|
||||||
|
fields: ComputedPartialFieldMetadata[];
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
import { GateDecoratorParams } from 'src/workspace/workspace-sync-metadata/interfaces/gate-decorator.interface';
|
||||||
|
|
||||||
|
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
|
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
||||||
|
|
||||||
|
export type DynamicRelationFieldMetadataDecoratorParams = (
|
||||||
|
oppositeObjectMetadata: ObjectMetadataEntity,
|
||||||
|
) => {
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
joinColumn: string;
|
||||||
|
description?: string;
|
||||||
|
icon?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ReflectDynamicRelationFieldMetadata {
|
||||||
|
type: FieldMetadataType.RELATION;
|
||||||
|
paramsFactory: DynamicRelationFieldMetadataDecoratorParams;
|
||||||
|
isNullable: boolean;
|
||||||
|
isSystem: boolean;
|
||||||
|
isCustom: boolean;
|
||||||
|
gate?: GateDecoratorParams;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import { GateDecoratorParams } from 'src/workspace/workspace-sync-metadata/interfaces/gate-decorator.interface';
|
||||||
|
|
||||||
|
export type BaseCustomObjectMetadataDecoratorParams =
|
||||||
|
| { allowObjectNameList?: string[] }
|
||||||
|
| { denyObjectNameList?: string[] };
|
||||||
|
|
||||||
|
export type ReflectBaseCustomObjectMetadata =
|
||||||
|
BaseCustomObjectMetadataDecoratorParams & {
|
||||||
|
gate?: GateDecoratorParams;
|
||||||
|
};
|
@ -4,13 +4,14 @@ import { FieldMetadataOptions } from 'src/metadata/field-metadata/interfaces/fie
|
|||||||
import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface';
|
import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface';
|
||||||
|
|
||||||
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
|
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
||||||
|
|
||||||
export interface FieldMetadataDecoratorParams<
|
export interface FieldMetadataDecoratorParams<
|
||||||
T extends FieldMetadataType | 'default',
|
T extends FieldMetadataType | 'default',
|
||||||
> {
|
> {
|
||||||
type: T;
|
type: T;
|
||||||
label: string;
|
label: string | ((objectMetadata: ObjectMetadataEntity) => string);
|
||||||
description?: string;
|
description?: string | ((objectMetadata: ObjectMetadataEntity) => string);
|
||||||
icon?: string;
|
icon?: string;
|
||||||
defaultValue?: FieldMetadataDefaultValue<T>;
|
defaultValue?: FieldMetadataDefaultValue<T>;
|
||||||
joinColumn?: string;
|
joinColumn?: string;
|
||||||
@ -28,7 +29,6 @@ export interface ReflectFieldMetadata {
|
|||||||
isNullable: boolean;
|
isNullable: boolean;
|
||||||
isSystem: boolean;
|
isSystem: boolean;
|
||||||
isCustom: boolean;
|
isCustom: boolean;
|
||||||
description?: string;
|
|
||||||
defaultValue: FieldMetadataDefaultValue<'default'> | null;
|
defaultValue: FieldMetadataDefaultValue<'default'> | null;
|
||||||
gate?: GateDecoratorParams;
|
gate?: GateDecoratorParams;
|
||||||
options?: FieldMetadataOptions<'default'> | null;
|
options?: FieldMetadataOptions<'default'> | null;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { ObjectType } from 'typeorm';
|
||||||
|
|
||||||
import { GateDecoratorParams } from 'src/workspace/workspace-sync-metadata/interfaces/gate-decorator.interface';
|
import { GateDecoratorParams } from 'src/workspace/workspace-sync-metadata/interfaces/gate-decorator.interface';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -5,19 +7,17 @@ import {
|
|||||||
RelationMetadataType,
|
RelationMetadataType,
|
||||||
} from 'src/metadata/relation-metadata/relation-metadata.entity';
|
} from 'src/metadata/relation-metadata/relation-metadata.entity';
|
||||||
|
|
||||||
export interface RelationMetadataDecoratorParams {
|
export interface RelationMetadataDecoratorParams<T> {
|
||||||
type: RelationMetadataType;
|
type: RelationMetadataType;
|
||||||
objectName: string;
|
inverseSideTarget: () => ObjectType<T>;
|
||||||
inverseSideFieldName?: string;
|
inverseSideFieldKey?: keyof T;
|
||||||
onDelete?: RelationOnDeleteAction;
|
onDelete?: RelationOnDeleteAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReflectRelationMetadata {
|
export interface ReflectRelationMetadata
|
||||||
type: RelationMetadataType;
|
extends RelationMetadataDecoratorParams<any> {
|
||||||
fromObjectNameSingular: string;
|
target: object;
|
||||||
toObjectNameSingular: string;
|
fieldKey: string;
|
||||||
fromFieldMetadataName: string;
|
|
||||||
toFieldMetadataName: string;
|
|
||||||
gate?: GateDecoratorParams;
|
gate?: GateDecoratorParams;
|
||||||
onDelete: RelationOnDeleteAction;
|
onDelete: RelationOnDeleteAction;
|
||||||
}
|
}
|
||||||
|
@ -153,8 +153,8 @@ export class WorkspaceMetadataUpdaterService {
|
|||||||
// https://github.com/typeorm/typeorm/issues/3490
|
// https://github.com/typeorm/typeorm/issues/3490
|
||||||
// To avoid calling update in a for loop, we did this hack.
|
// To avoid calling update in a for loop, we did this hack.
|
||||||
return {
|
return {
|
||||||
...oldFieldMetadata,
|
...omit(oldFieldMetadata, ['objectMetadataId', 'workspaceId']),
|
||||||
...updateFieldMetadata,
|
...omit(updateFieldMetadata, ['objectMetadataId', 'workspaceId']),
|
||||||
options: updateFieldMetadata.options ?? oldFieldMetadata.options,
|
options: updateFieldMetadata.options ?? oldFieldMetadata.options,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -197,7 +197,11 @@ export class WorkspaceMetadataUpdaterService {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
current: oldFieldMetadata as FieldMetadataEntity,
|
current: oldFieldMetadata as FieldMetadataEntity,
|
||||||
altered: alteredFieldMetadata as FieldMetadataEntity,
|
altered: {
|
||||||
|
...alteredFieldMetadata,
|
||||||
|
objectMetadataId: oldFieldMetadata.objectMetadataId,
|
||||||
|
workspaceId: oldFieldMetadata.workspaceId,
|
||||||
|
} as FieldMetadataEntity,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -0,0 +1,140 @@
|
|||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { EntityManager } from 'typeorm';
|
||||||
|
|
||||||
|
import { WorkspaceSyncContext } from 'src/workspace/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||||
|
import { ComparatorAction } from 'src/workspace/workspace-sync-metadata/interfaces/comparator.interface';
|
||||||
|
import { FeatureFlagMap } from 'src/core/feature-flag/interfaces/feature-flag-map.interface';
|
||||||
|
import { WorkspaceMigrationBuilderAction } from 'src/workspace/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface';
|
||||||
|
|
||||||
|
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
||||||
|
import { WorkspaceMigrationEntity } from 'src/metadata/workspace-migration/workspace-migration.entity';
|
||||||
|
import { WorkspaceFieldComparator } from 'src/workspace/workspace-sync-metadata/comparators/workspace-field.comparator';
|
||||||
|
import { WorkspaceMetadataUpdaterService } from 'src/workspace/workspace-sync-metadata/services/workspace-metadata-updater.service';
|
||||||
|
import { WorkspaceSyncStorage } from 'src/workspace/workspace-sync-metadata/storage/workspace-sync.storage';
|
||||||
|
import { WorkspaceMigrationFieldFactory } from 'src/workspace/workspace-migration-builder/factories/workspace-migration-field.factory';
|
||||||
|
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';
|
||||||
|
import { computeStandardObject } from 'src/workspace/workspace-sync-metadata/utils/compute-standard-object.util';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WorkspaceSyncFieldMetadataService {
|
||||||
|
private readonly logger = new Logger(WorkspaceSyncFieldMetadataService.name);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly standardFieldFactory: StandardFieldFactory,
|
||||||
|
private readonly workspaceFieldComparator: WorkspaceFieldComparator,
|
||||||
|
private readonly workspaceMetadataUpdaterService: WorkspaceMetadataUpdaterService,
|
||||||
|
private readonly workspaceMigrationFieldFactory: WorkspaceMigrationFieldFactory,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async synchronize(
|
||||||
|
context: WorkspaceSyncContext,
|
||||||
|
manager: EntityManager,
|
||||||
|
storage: WorkspaceSyncStorage,
|
||||||
|
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||||
|
): Promise<Partial<WorkspaceMigrationEntity>[]> {
|
||||||
|
const objectMetadataRepository =
|
||||||
|
manager.getRepository(ObjectMetadataEntity);
|
||||||
|
|
||||||
|
// Retrieve object metadata collection from DB
|
||||||
|
const originalObjectMetadataCollection =
|
||||||
|
await objectMetadataRepository.find({
|
||||||
|
where: {
|
||||||
|
workspaceId: context.workspaceId,
|
||||||
|
// We're only interested in standard fields
|
||||||
|
fields: { isCustom: false },
|
||||||
|
},
|
||||||
|
relations: ['dataSource', 'fields'],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter out custom objects
|
||||||
|
const customObjectMetadataCollection =
|
||||||
|
originalObjectMetadataCollection.filter(
|
||||||
|
(objectMetadata) => objectMetadata.isCustom,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create standard field metadata collection
|
||||||
|
const standardFieldMetadataCollection = this.standardFieldFactory.create(
|
||||||
|
CustomObjectMetadata,
|
||||||
|
context,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Loop over all standard objects and compare them with the objects in DB
|
||||||
|
for (const customObjectMetadata of customObjectMetadataCollection) {
|
||||||
|
// Also, maybe it's better to refactor a bit and move generation part into a separate module ?
|
||||||
|
const standardObjectMetadata = computeStandardObject(
|
||||||
|
{
|
||||||
|
...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');
|
||||||
|
|
||||||
|
const metadataFieldUpdaterResult =
|
||||||
|
await this.workspaceMetadataUpdaterService.updateFieldMetadata(
|
||||||
|
manager,
|
||||||
|
storage,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logger.log('Generating migrations');
|
||||||
|
|
||||||
|
const createFieldWorkspaceMigrations =
|
||||||
|
await this.workspaceMigrationFieldFactory.create(
|
||||||
|
originalObjectMetadataCollection,
|
||||||
|
metadataFieldUpdaterResult.createdFieldMetadataCollection,
|
||||||
|
WorkspaceMigrationBuilderAction.CREATE,
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateFieldWorkspaceMigrations =
|
||||||
|
await this.workspaceMigrationFieldFactory.create(
|
||||||
|
originalObjectMetadataCollection,
|
||||||
|
metadataFieldUpdaterResult.updatedFieldMetadataCollection,
|
||||||
|
WorkspaceMigrationBuilderAction.UPDATE,
|
||||||
|
);
|
||||||
|
|
||||||
|
const deleteFieldWorkspaceMigrations =
|
||||||
|
await this.workspaceMigrationFieldFactory.create(
|
||||||
|
originalObjectMetadataCollection,
|
||||||
|
storage.fieldMetadataDeleteCollection,
|
||||||
|
WorkspaceMigrationBuilderAction.DELETE,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logger.log('Saving migrations');
|
||||||
|
|
||||||
|
return [
|
||||||
|
...createFieldWorkspaceMigrations,
|
||||||
|
...updateFieldWorkspaceMigrations,
|
||||||
|
...deleteFieldWorkspaceMigrations,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,8 @@ import { WorkspaceFieldComparator } from 'src/workspace/workspace-sync-metadata/
|
|||||||
import { WorkspaceMetadataUpdaterService } from 'src/workspace/workspace-sync-metadata/services/workspace-metadata-updater.service';
|
import { WorkspaceMetadataUpdaterService } from 'src/workspace/workspace-sync-metadata/services/workspace-metadata-updater.service';
|
||||||
import { WorkspaceSyncStorage } from 'src/workspace/workspace-sync-metadata/storage/workspace-sync.storage';
|
import { WorkspaceSyncStorage } from 'src/workspace/workspace-sync-metadata/storage/workspace-sync.storage';
|
||||||
import { WorkspaceMigrationObjectFactory } from 'src/workspace/workspace-migration-builder/factories/workspace-migration-object.factory';
|
import { WorkspaceMigrationObjectFactory } from 'src/workspace/workspace-migration-builder/factories/workspace-migration-object.factory';
|
||||||
import { WorkspaceMigrationFieldFactory } from 'src/workspace/workspace-migration-builder/factories/workspace-migration-field.factory';
|
import { computeStandardObject } from 'src/workspace/workspace-sync-metadata/utils/compute-standard-object.util';
|
||||||
|
import { standardObjectMetadataDefinitions } from 'src/workspace/workspace-sync-metadata/standard-objects';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkspaceSyncObjectMetadataService {
|
export class WorkspaceSyncObjectMetadataService {
|
||||||
@ -28,7 +29,6 @@ export class WorkspaceSyncObjectMetadataService {
|
|||||||
private readonly workspaceFieldComparator: WorkspaceFieldComparator,
|
private readonly workspaceFieldComparator: WorkspaceFieldComparator,
|
||||||
private readonly workspaceMetadataUpdaterService: WorkspaceMetadataUpdaterService,
|
private readonly workspaceMetadataUpdaterService: WorkspaceMetadataUpdaterService,
|
||||||
private readonly workspaceMigrationObjectFactory: WorkspaceMigrationObjectFactory,
|
private readonly workspaceMigrationObjectFactory: WorkspaceMigrationObjectFactory,
|
||||||
private readonly workspaceMigrationFieldFactory: WorkspaceMigrationFieldFactory,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async synchronize(
|
async synchronize(
|
||||||
@ -45,14 +45,18 @@ export class WorkspaceSyncObjectMetadataService {
|
|||||||
await objectMetadataRepository.find({
|
await objectMetadataRepository.find({
|
||||||
where: {
|
where: {
|
||||||
workspaceId: context.workspaceId,
|
workspaceId: context.workspaceId,
|
||||||
isCustom: false,
|
|
||||||
fields: { isCustom: false },
|
fields: { isCustom: false },
|
||||||
},
|
},
|
||||||
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(
|
||||||
|
standardObjectMetadataDefinitions,
|
||||||
context,
|
context,
|
||||||
workspaceFeatureFlagsMap,
|
workspaceFeatureFlagsMap,
|
||||||
);
|
);
|
||||||
@ -68,7 +72,9 @@ export class WorkspaceSyncObjectMetadataService {
|
|||||||
this.logger.log('Comparing standard objects and fields metadata');
|
this.logger.log('Comparing standard objects and fields metadata');
|
||||||
|
|
||||||
// Store object that need to be deleted
|
// Store object that need to be deleted
|
||||||
for (const originalObjectMetadata of originalObjectMetadataCollection) {
|
for (const originalObjectMetadata of originalObjectMetadataCollection.filter(
|
||||||
|
(object) => !object.isCustom,
|
||||||
|
)) {
|
||||||
if (!standardObjectMetadataMap[originalObjectMetadata.nameSingular]) {
|
if (!standardObjectMetadataMap[originalObjectMetadata.nameSingular]) {
|
||||||
storage.addDeleteObjectMetadata(originalObjectMetadata);
|
storage.addDeleteObjectMetadata(originalObjectMetadata);
|
||||||
}
|
}
|
||||||
@ -78,8 +84,11 @@ export class WorkspaceSyncObjectMetadataService {
|
|||||||
for (const standardObjectName in standardObjectMetadataMap) {
|
for (const standardObjectName in standardObjectMetadataMap) {
|
||||||
const originalObjectMetadata =
|
const originalObjectMetadata =
|
||||||
originalObjectMetadataMap[standardObjectName];
|
originalObjectMetadataMap[standardObjectName];
|
||||||
const standardObjectMetadata =
|
const standardObjectMetadata = computeStandardObject(
|
||||||
standardObjectMetadataMap[standardObjectName];
|
standardObjectMetadataMap[standardObjectName],
|
||||||
|
originalObjectMetadata,
|
||||||
|
customObjectMetadataCollection,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* COMPARE OBJECT METADATA
|
* COMPARE OBJECT METADATA
|
||||||
@ -132,11 +141,6 @@ export class WorkspaceSyncObjectMetadataService {
|
|||||||
manager,
|
manager,
|
||||||
storage,
|
storage,
|
||||||
);
|
);
|
||||||
const metadataFieldUpdaterResult =
|
|
||||||
await this.workspaceMetadataUpdaterService.updateFieldMetadata(
|
|
||||||
manager,
|
|
||||||
storage,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.log('Generating migrations');
|
this.logger.log('Generating migrations');
|
||||||
|
|
||||||
@ -153,35 +157,11 @@ export class WorkspaceSyncObjectMetadataService {
|
|||||||
WorkspaceMigrationBuilderAction.DELETE,
|
WorkspaceMigrationBuilderAction.DELETE,
|
||||||
);
|
);
|
||||||
|
|
||||||
const createFieldWorkspaceMigrations =
|
|
||||||
await this.workspaceMigrationFieldFactory.create(
|
|
||||||
originalObjectMetadataCollection,
|
|
||||||
metadataFieldUpdaterResult.createdFieldMetadataCollection,
|
|
||||||
WorkspaceMigrationBuilderAction.CREATE,
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateFieldWorkspaceMigrations =
|
|
||||||
await this.workspaceMigrationFieldFactory.create(
|
|
||||||
originalObjectMetadataCollection,
|
|
||||||
metadataFieldUpdaterResult.updatedFieldMetadataCollection,
|
|
||||||
WorkspaceMigrationBuilderAction.UPDATE,
|
|
||||||
);
|
|
||||||
|
|
||||||
const deleteFieldWorkspaceMigrations =
|
|
||||||
await this.workspaceMigrationFieldFactory.create(
|
|
||||||
originalObjectMetadataCollection,
|
|
||||||
storage.fieldMetadataDeleteCollection,
|
|
||||||
WorkspaceMigrationBuilderAction.DELETE,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.log('Saving migrations');
|
this.logger.log('Saving migrations');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
...createObjectWorkspaceMigrations,
|
...createObjectWorkspaceMigrations,
|
||||||
...deleteObjectWorkspaceMigrations,
|
...deleteObjectWorkspaceMigrations,
|
||||||
...createFieldWorkspaceMigrations,
|
|
||||||
...updateFieldWorkspaceMigrations,
|
|
||||||
...deleteFieldWorkspaceMigrations,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ import { WorkspaceMetadataUpdaterService } from 'src/workspace/workspace-sync-me
|
|||||||
import { WorkspaceMigrationEntity } from 'src/metadata/workspace-migration/workspace-migration.entity';
|
import { WorkspaceMigrationEntity } from 'src/metadata/workspace-migration/workspace-migration.entity';
|
||||||
import { WorkspaceSyncStorage } from 'src/workspace/workspace-sync-metadata/storage/workspace-sync.storage';
|
import { WorkspaceSyncStorage } from 'src/workspace/workspace-sync-metadata/storage/workspace-sync.storage';
|
||||||
import { WorkspaceMigrationRelationFactory } from 'src/workspace/workspace-migration-builder/factories/workspace-migration-relation.factory';
|
import { WorkspaceMigrationRelationFactory } from 'src/workspace/workspace-migration-builder/factories/workspace-migration-relation.factory';
|
||||||
|
import { standardObjectMetadataDefinitions } from 'src/workspace/workspace-sync-metadata/standard-objects';
|
||||||
|
import { CustomObjectMetadata } from 'src/workspace/workspace-sync-metadata/custom-objects/custom.object-metadata';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkspaceSyncRelationMetadataService {
|
export class WorkspaceSyncRelationMetadataService {
|
||||||
@ -44,11 +46,14 @@ export class WorkspaceSyncRelationMetadataService {
|
|||||||
await objectMetadataRepository.find({
|
await objectMetadataRepository.find({
|
||||||
where: {
|
where: {
|
||||||
workspaceId: context.workspaceId,
|
workspaceId: context.workspaceId,
|
||||||
isCustom: false,
|
|
||||||
fields: { isCustom: false },
|
fields: { isCustom: false },
|
||||||
},
|
},
|
||||||
relations: ['dataSource', 'fields'],
|
relations: ['dataSource', 'fields'],
|
||||||
});
|
});
|
||||||
|
const customObjectMetadataCollection =
|
||||||
|
originalObjectMetadataCollection.filter(
|
||||||
|
(objectMetadata) => objectMetadata.isCustom,
|
||||||
|
);
|
||||||
|
|
||||||
// Create map of object metadata & field metadata by unique identifier
|
// Create map of object metadata & field metadata by unique identifier
|
||||||
const originalObjectMetadataMap = mapObjectMetadataByUniqueIdentifier(
|
const originalObjectMetadataMap = mapObjectMetadataByUniqueIdentifier(
|
||||||
@ -71,6 +76,18 @@ export class WorkspaceSyncRelationMetadataService {
|
|||||||
// Create standard relation metadata collection
|
// Create standard relation metadata collection
|
||||||
const standardRelationMetadataCollection =
|
const standardRelationMetadataCollection =
|
||||||
this.standardRelationFactory.create(
|
this.standardRelationFactory.create(
|
||||||
|
standardObjectMetadataDefinitions,
|
||||||
|
context,
|
||||||
|
originalObjectMetadataMap,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
const customRelationMetadataCollection =
|
||||||
|
this.standardRelationFactory.create(
|
||||||
|
customObjectMetadataCollection.map((objectMetadata) => ({
|
||||||
|
object: objectMetadata,
|
||||||
|
metadata: CustomObjectMetadata,
|
||||||
|
})),
|
||||||
context,
|
context,
|
||||||
originalObjectMetadataMap,
|
originalObjectMetadataMap,
|
||||||
workspaceFeatureFlagsMap,
|
workspaceFeatureFlagsMap,
|
||||||
@ -78,7 +95,10 @@ export class WorkspaceSyncRelationMetadataService {
|
|||||||
|
|
||||||
const relationComparatorResults = this.workspaceRelationComparator.compare(
|
const relationComparatorResults = this.workspaceRelationComparator.compare(
|
||||||
originalRelationMetadataCollection,
|
originalRelationMetadataCollection,
|
||||||
standardRelationMetadataCollection,
|
[
|
||||||
|
...standardRelationMetadataCollection,
|
||||||
|
...customRelationMetadataCollection,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const relationComparatorResult of relationComparatorResults) {
|
for (const relationComparatorResult of relationComparatorResults) {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
|
import { CustomObjectMetadata } from 'src/workspace/workspace-sync-metadata/custom-objects/custom.object-metadata';
|
||||||
|
import { DynamicRelationFieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/dynamic-field-metadata.interface';
|
||||||
import { FieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/field-metadata.decorator';
|
import { FieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/field-metadata.decorator';
|
||||||
import { IsNullable } from 'src/workspace/workspace-sync-metadata/decorators/is-nullable.decorator';
|
import { IsNullable } from 'src/workspace/workspace-sync-metadata/decorators/is-nullable.decorator';
|
||||||
import { IsSystem } from 'src/workspace/workspace-sync-metadata/decorators/is-system.decorator';
|
import { IsSystem } from 'src/workspace/workspace-sync-metadata/decorators/is-system.decorator';
|
||||||
@ -57,4 +59,13 @@ export class ActivityTargetObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
opportunity: OpportunityObjectMetadata;
|
opportunity: OpportunityObjectMetadata;
|
||||||
|
|
||||||
|
@DynamicRelationFieldMetadata((oppositeObjectMetadata) => ({
|
||||||
|
name: oppositeObjectMetadata.nameSingular,
|
||||||
|
label: oppositeObjectMetadata.labelSingular,
|
||||||
|
description: `ActivityTarget ${oppositeObjectMetadata.labelSingular}`,
|
||||||
|
joinColumn: `${oppositeObjectMetadata.nameSingular}Id`,
|
||||||
|
icon: 'IconBuildingSkyscraper',
|
||||||
|
}))
|
||||||
|
custom: CustomObjectMetadata;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ export class ActivityObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'activityTarget',
|
inverseSideTarget: () => ActivityTargetObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
activityTargets: ActivityTargetObjectMetadata[];
|
activityTargets: ActivityTargetObjectMetadata[];
|
||||||
@ -93,7 +93,7 @@ export class ActivityObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'attachment',
|
inverseSideTarget: () => AttachmentObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
attachments: AttachmentObjectMetadata[];
|
attachments: AttachmentObjectMetadata[];
|
||||||
@ -106,7 +106,7 @@ export class ActivityObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'comment',
|
inverseSideTarget: () => CommentObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
comments: CommentObjectMetadata[];
|
comments: CommentObjectMetadata[];
|
||||||
@ -123,7 +123,7 @@ export class ActivityObjectMetadata extends BaseObjectMetadata {
|
|||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
label: 'Assignee',
|
label: 'Assignee',
|
||||||
description: 'Acitivity assignee',
|
description: 'Activity assignee',
|
||||||
icon: 'IconUserCircle',
|
icon: 'IconUserCircle',
|
||||||
joinColumn: 'assigneeId',
|
joinColumn: 'assigneeId',
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
|
import { CustomObjectMetadata } from 'src/workspace/workspace-sync-metadata/custom-objects/custom.object-metadata';
|
||||||
|
import { DynamicRelationFieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/dynamic-field-metadata.interface';
|
||||||
import { FieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/field-metadata.decorator';
|
import { FieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/field-metadata.decorator';
|
||||||
import { IsNullable } from 'src/workspace/workspace-sync-metadata/decorators/is-nullable.decorator';
|
import { IsNullable } from 'src/workspace/workspace-sync-metadata/decorators/is-nullable.decorator';
|
||||||
import { IsSystem } from 'src/workspace/workspace-sync-metadata/decorators/is-system.decorator';
|
import { IsSystem } from 'src/workspace/workspace-sync-metadata/decorators/is-system.decorator';
|
||||||
@ -91,4 +93,13 @@ export class AttachmentObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
opportunity: OpportunityObjectMetadata;
|
opportunity: OpportunityObjectMetadata;
|
||||||
|
|
||||||
|
@DynamicRelationFieldMetadata((oppositeObjectMetadata) => ({
|
||||||
|
name: oppositeObjectMetadata.nameSingular,
|
||||||
|
label: oppositeObjectMetadata.labelSingular,
|
||||||
|
description: `Attachment ${oppositeObjectMetadata.labelSingular}`,
|
||||||
|
joinColumn: `${oppositeObjectMetadata.nameSingular}Id`,
|
||||||
|
icon: 'IconBuildingSkyscraper',
|
||||||
|
}))
|
||||||
|
custom: CustomObjectMetadata;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,9 @@ export abstract class BaseObjectMetadata {
|
|||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
type: FieldMetadataType.UUID,
|
type: FieldMetadataType.UUID,
|
||||||
label: 'Id',
|
label: 'Id',
|
||||||
|
description: 'Id',
|
||||||
defaultValue: { type: 'uuid' },
|
defaultValue: { type: 'uuid' },
|
||||||
|
icon: 'Icon123',
|
||||||
})
|
})
|
||||||
@IsSystem()
|
@IsSystem()
|
||||||
id: string;
|
id: string;
|
||||||
@ -14,6 +16,7 @@ export abstract class BaseObjectMetadata {
|
|||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
type: FieldMetadataType.DATE_TIME,
|
type: FieldMetadataType.DATE_TIME,
|
||||||
label: 'Creation date',
|
label: 'Creation date',
|
||||||
|
description: 'Creation date',
|
||||||
icon: 'IconCalendar',
|
icon: 'IconCalendar',
|
||||||
defaultValue: { type: 'now' },
|
defaultValue: { type: 'now' },
|
||||||
})
|
})
|
||||||
@ -22,6 +25,7 @@ export abstract class BaseObjectMetadata {
|
|||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
type: FieldMetadataType.DATE_TIME,
|
type: FieldMetadataType.DATE_TIME,
|
||||||
label: 'Update date',
|
label: 'Update date',
|
||||||
|
description: 'Update date',
|
||||||
icon: 'IconCalendar',
|
icon: 'IconCalendar',
|
||||||
defaultValue: { type: 'now' },
|
defaultValue: { type: 'now' },
|
||||||
})
|
})
|
||||||
|
@ -136,7 +136,7 @@ export class CalendarEventObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'calendarEventAttendee',
|
inverseSideTarget: () => CalendarEventAttendeeObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
eventAttendees: CalendarEventAttendeeObjectMetadata[];
|
eventAttendees: CalendarEventAttendeeObjectMetadata[];
|
||||||
|
@ -117,7 +117,7 @@ export class CompanyObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'person',
|
inverseSideTarget: () => PersonObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
people: PersonObjectMetadata[];
|
people: PersonObjectMetadata[];
|
||||||
@ -141,7 +141,7 @@ export class CompanyObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'activityTarget',
|
inverseSideTarget: () => ActivityTargetObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
@ -155,7 +155,7 @@ export class CompanyObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'opportunity',
|
inverseSideTarget: () => OpportunityObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
opportunities: OpportunityObjectMetadata[];
|
opportunities: OpportunityObjectMetadata[];
|
||||||
@ -168,7 +168,7 @@ export class CompanyObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'favorite',
|
inverseSideTarget: () => FavoriteObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
@ -182,7 +182,7 @@ export class CompanyObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'attachment',
|
inverseSideTarget: () => AttachmentObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
|
@ -80,7 +80,7 @@ export class ConnectedAccountObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'messageChannel',
|
inverseSideTarget: () => MessageChannelObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
messageChannels: MessageChannelObjectMetadata[];
|
messageChannels: MessageChannelObjectMetadata[];
|
||||||
@ -93,7 +93,7 @@ export class ConnectedAccountObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'calendarChannel',
|
inverseSideTarget: () => CalendarChannelObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@Gate({
|
@Gate({
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
|
import { CustomObjectMetadata } from 'src/workspace/workspace-sync-metadata/custom-objects/custom.object-metadata';
|
||||||
|
import { DynamicRelationFieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/dynamic-field-metadata.interface';
|
||||||
import { FieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/field-metadata.decorator';
|
import { FieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/field-metadata.decorator';
|
||||||
import { IsNullable } from 'src/workspace/workspace-sync-metadata/decorators/is-nullable.decorator';
|
import { IsNullable } from 'src/workspace/workspace-sync-metadata/decorators/is-nullable.decorator';
|
||||||
import { IsSystem } from 'src/workspace/workspace-sync-metadata/decorators/is-system.decorator';
|
import { IsSystem } from 'src/workspace/workspace-sync-metadata/decorators/is-system.decorator';
|
||||||
@ -66,4 +68,13 @@ export class FavoriteObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
opportunity: OpportunityObjectMetadata;
|
opportunity: OpportunityObjectMetadata;
|
||||||
|
|
||||||
|
@DynamicRelationFieldMetadata((oppositeObjectMetadata) => ({
|
||||||
|
name: oppositeObjectMetadata.nameSingular,
|
||||||
|
label: oppositeObjectMetadata.labelSingular,
|
||||||
|
description: `Favorite ${oppositeObjectMetadata.labelSingular}`,
|
||||||
|
joinColumn: `${oppositeObjectMetadata.nameSingular}Id`,
|
||||||
|
icon: 'IconBuildingSkyscraper',
|
||||||
|
}))
|
||||||
|
custom: CustomObjectMetadata;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import { ViewObjectMetadata } from 'src/workspace/workspace-sync-metadata/standa
|
|||||||
import { WebhookObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/webhook.object-metadata';
|
import { WebhookObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/webhook.object-metadata';
|
||||||
import { WorkspaceMemberObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/workspace-member.object-metadata';
|
import { WorkspaceMemberObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/workspace-member.object-metadata';
|
||||||
|
|
||||||
export const standardObjectMetadataCollection = [
|
export const standardObjectMetadataDefinitions = [
|
||||||
ActivityTargetObjectMetadata,
|
ActivityTargetObjectMetadata,
|
||||||
ActivityObjectMetadata,
|
ActivityObjectMetadata,
|
||||||
ApiKeyObjectMetadata,
|
ApiKeyObjectMetadata,
|
||||||
|
@ -87,7 +87,7 @@ export class MessageChannelObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'messageChannelMessageAssociation',
|
inverseSideTarget: () => MessageChannelMessageAssociationObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
|
@ -29,7 +29,7 @@ export class MessageThreadObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'message',
|
inverseSideTarget: () => MessageObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
@ -43,7 +43,7 @@ export class MessageThreadObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'messageChannelMessageAssociation',
|
inverseSideTarget: () => MessageChannelMessageAssociationObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.RESTRICT,
|
onDelete: RelationOnDeleteAction.RESTRICT,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
|
@ -86,8 +86,8 @@ export class MessageObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'messageParticipant',
|
inverseSideTarget: () => MessageParticipantObjectMetadata,
|
||||||
inverseSideFieldName: 'message',
|
inverseSideFieldKey: 'message',
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
@ -101,7 +101,7 @@ export class MessageObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'messageChannelMessageAssociation',
|
inverseSideTarget: () => MessageChannelMessageAssociationObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
|
@ -130,7 +130,7 @@ export class OpportunityObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'favorite',
|
inverseSideTarget: () => FavoriteObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
@ -144,7 +144,7 @@ export class OpportunityObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'activityTarget',
|
inverseSideTarget: () => ActivityTargetObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
@ -158,7 +158,7 @@ export class OpportunityObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'attachment',
|
inverseSideTarget: () => AttachmentObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
attachments: AttachmentObjectMetadata[];
|
attachments: AttachmentObjectMetadata[];
|
||||||
|
@ -124,8 +124,8 @@ export class PersonObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'opportunity',
|
inverseSideTarget: () => OpportunityObjectMetadata,
|
||||||
inverseSideFieldName: 'pointOfContact',
|
inverseSideFieldKey: 'pointOfContact',
|
||||||
})
|
})
|
||||||
pointOfContactForOpportunities: OpportunityObjectMetadata[];
|
pointOfContactForOpportunities: OpportunityObjectMetadata[];
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ export class PersonObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'activityTarget',
|
inverseSideTarget: () => ActivityTargetObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
activityTargets: ActivityTargetObjectMetadata[];
|
activityTargets: ActivityTargetObjectMetadata[];
|
||||||
@ -150,7 +150,7 @@ export class PersonObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'favorite',
|
inverseSideTarget: () => FavoriteObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
favorites: FavoriteObjectMetadata[];
|
favorites: FavoriteObjectMetadata[];
|
||||||
@ -163,7 +163,7 @@ export class PersonObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'attachment',
|
inverseSideTarget: () => AttachmentObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
attachments: AttachmentObjectMetadata[];
|
attachments: AttachmentObjectMetadata[];
|
||||||
@ -176,8 +176,8 @@ export class PersonObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'messageParticipant',
|
inverseSideTarget: () => MessageParticipantObjectMetadata,
|
||||||
inverseSideFieldName: 'person',
|
inverseSideFieldKey: 'person',
|
||||||
})
|
})
|
||||||
messageParticipants: MessageParticipantObjectMetadata[];
|
messageParticipants: MessageParticipantObjectMetadata[];
|
||||||
|
|
||||||
@ -189,8 +189,8 @@ export class PersonObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'calendarEventAttendee',
|
inverseSideTarget: () => CalendarEventAttendeeObjectMetadata,
|
||||||
inverseSideFieldName: 'person',
|
inverseSideFieldKey: 'person',
|
||||||
})
|
})
|
||||||
@Gate({
|
@Gate({
|
||||||
featureFlag: 'IS_CALENDAR_ENABLED',
|
featureFlag: 'IS_CALENDAR_ENABLED',
|
||||||
|
@ -52,7 +52,7 @@ export class PipelineStepObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'opportunity',
|
inverseSideTarget: () => OpportunityObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
opportunities: OpportunityObjectMetadata[];
|
opportunities: OpportunityObjectMetadata[];
|
||||||
|
@ -57,7 +57,7 @@ export class ViewObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'viewField',
|
inverseSideTarget: () => ViewFieldObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
viewFields: ViewFieldObjectMetadata[];
|
viewFields: ViewFieldObjectMetadata[];
|
||||||
@ -70,7 +70,7 @@ export class ViewObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'viewFilter',
|
inverseSideTarget: () => ViewFilterObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
viewFilters: ViewFilterObjectMetadata[];
|
viewFilters: ViewFilterObjectMetadata[];
|
||||||
@ -83,7 +83,7 @@ export class ViewObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'viewSort',
|
inverseSideTarget: () => ViewSortObjectMetadata,
|
||||||
})
|
})
|
||||||
@IsNullable()
|
@IsNullable()
|
||||||
viewSorts: ViewSortObjectMetadata[];
|
viewSorts: ViewSortObjectMetadata[];
|
||||||
|
@ -6,7 +6,6 @@ import {
|
|||||||
} from 'src/metadata/relation-metadata/relation-metadata.entity';
|
} from 'src/metadata/relation-metadata/relation-metadata.entity';
|
||||||
import { FieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/field-metadata.decorator';
|
import { FieldMetadata } from 'src/workspace/workspace-sync-metadata/decorators/field-metadata.decorator';
|
||||||
import { Gate } from 'src/workspace/workspace-sync-metadata/decorators/gate.decorator';
|
import { Gate } from 'src/workspace/workspace-sync-metadata/decorators/gate.decorator';
|
||||||
import { IsNullable } from 'src/workspace/workspace-sync-metadata/decorators/is-nullable.decorator';
|
|
||||||
import { IsSystem } from 'src/workspace/workspace-sync-metadata/decorators/is-system.decorator';
|
import { IsSystem } from 'src/workspace/workspace-sync-metadata/decorators/is-system.decorator';
|
||||||
import { ObjectMetadata } from 'src/workspace/workspace-sync-metadata/decorators/object-metadata.decorator';
|
import { ObjectMetadata } from 'src/workspace/workspace-sync-metadata/decorators/object-metadata.decorator';
|
||||||
import { RelationMetadata } from 'src/workspace/workspace-sync-metadata/decorators/relation-metadata.decorator';
|
import { RelationMetadata } from 'src/workspace/workspace-sync-metadata/decorators/relation-metadata.decorator';
|
||||||
@ -89,8 +88,8 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'activity',
|
inverseSideTarget: () => ActivityObjectMetadata,
|
||||||
inverseSideFieldName: 'author',
|
inverseSideFieldKey: 'author',
|
||||||
})
|
})
|
||||||
authoredActivities: ActivityObjectMetadata[];
|
authoredActivities: ActivityObjectMetadata[];
|
||||||
|
|
||||||
@ -102,10 +101,11 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'activity',
|
inverseSideTarget: () => ActivityObjectMetadata,
|
||||||
inverseSideFieldName: 'assignee',
|
inverseSideFieldKey: 'assignee',
|
||||||
})
|
})
|
||||||
@IsNullable()
|
assignedActivities: ActivityObjectMetadata[];
|
||||||
|
|
||||||
@FieldMetadata({
|
@FieldMetadata({
|
||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
label: 'Favorites',
|
label: 'Favorites',
|
||||||
@ -114,7 +114,7 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'favorite',
|
inverseSideTarget: () => FavoriteObjectMetadata,
|
||||||
onDelete: RelationOnDeleteAction.CASCADE,
|
onDelete: RelationOnDeleteAction.CASCADE,
|
||||||
})
|
})
|
||||||
favorites: FavoriteObjectMetadata[];
|
favorites: FavoriteObjectMetadata[];
|
||||||
@ -127,8 +127,8 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'company',
|
inverseSideTarget: () => CompanyObjectMetadata,
|
||||||
inverseSideFieldName: 'accountOwner',
|
inverseSideFieldKey: 'accountOwner',
|
||||||
})
|
})
|
||||||
accountOwnerForCompanies: CompanyObjectMetadata[];
|
accountOwnerForCompanies: CompanyObjectMetadata[];
|
||||||
|
|
||||||
@ -140,8 +140,8 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'attachment',
|
inverseSideTarget: () => AttachmentObjectMetadata,
|
||||||
inverseSideFieldName: 'author',
|
inverseSideFieldKey: 'author',
|
||||||
})
|
})
|
||||||
authoredAttachments: AttachmentObjectMetadata[];
|
authoredAttachments: AttachmentObjectMetadata[];
|
||||||
|
|
||||||
@ -153,8 +153,8 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'comment',
|
inverseSideTarget: () => CommentObjectMetadata,
|
||||||
inverseSideFieldName: 'author',
|
inverseSideFieldKey: 'author',
|
||||||
})
|
})
|
||||||
authoredComments: CommentObjectMetadata[];
|
authoredComments: CommentObjectMetadata[];
|
||||||
|
|
||||||
@ -166,8 +166,8 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'connectedAccount',
|
inverseSideTarget: () => ConnectedAccountObjectMetadata,
|
||||||
inverseSideFieldName: 'accountOwner',
|
inverseSideFieldKey: 'accountOwner',
|
||||||
})
|
})
|
||||||
connectedAccounts: ConnectedAccountObjectMetadata[];
|
connectedAccounts: ConnectedAccountObjectMetadata[];
|
||||||
|
|
||||||
@ -179,8 +179,8 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'messageParticipant',
|
inverseSideTarget: () => MessageParticipantObjectMetadata,
|
||||||
inverseSideFieldName: 'workspaceMember',
|
inverseSideFieldKey: 'workspaceMember',
|
||||||
})
|
})
|
||||||
messageParticipants: MessageParticipantObjectMetadata[];
|
messageParticipants: MessageParticipantObjectMetadata[];
|
||||||
|
|
||||||
@ -192,8 +192,8 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'blocklist',
|
inverseSideTarget: () => BlocklistObjectMetadata,
|
||||||
inverseSideFieldName: 'workspaceMember',
|
inverseSideFieldKey: 'workspaceMember',
|
||||||
})
|
})
|
||||||
blocklist: BlocklistObjectMetadata[];
|
blocklist: BlocklistObjectMetadata[];
|
||||||
|
|
||||||
@ -205,8 +205,8 @@ export class WorkspaceMemberObjectMetadata extends BaseObjectMetadata {
|
|||||||
})
|
})
|
||||||
@RelationMetadata({
|
@RelationMetadata({
|
||||||
type: RelationMetadataType.ONE_TO_MANY,
|
type: RelationMetadataType.ONE_TO_MANY,
|
||||||
objectName: 'calendarEventAttendee',
|
inverseSideTarget: () => CalendarEventAttendeeObjectMetadata,
|
||||||
inverseSideFieldName: 'workspaceMember',
|
inverseSideFieldKey: 'workspaceMember',
|
||||||
})
|
})
|
||||||
@Gate({
|
@Gate({
|
||||||
featureFlag: 'IS_CALENDAR_ENABLED',
|
featureFlag: 'IS_CALENDAR_ENABLED',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { PartialObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
import { ComputedPartialObjectMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
||||||
import { PartialFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
import { ComputedPartialFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||||
import { PartialRelationMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-relation-metadata.interface';
|
import { PartialRelationMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-relation-metadata.interface';
|
||||||
|
|
||||||
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
||||||
@ -8,15 +8,16 @@ import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-
|
|||||||
|
|
||||||
export class WorkspaceSyncStorage {
|
export class WorkspaceSyncStorage {
|
||||||
// Object metadata
|
// Object metadata
|
||||||
private readonly _objectMetadataCreateCollection: PartialObjectMetadata[] =
|
private readonly _objectMetadataCreateCollection: ComputedPartialObjectMetadata[] =
|
||||||
[];
|
[];
|
||||||
private readonly _objectMetadataUpdateCollection: Partial<PartialObjectMetadata>[] =
|
private readonly _objectMetadataUpdateCollection: Partial<ComputedPartialObjectMetadata>[] =
|
||||||
[];
|
[];
|
||||||
private readonly _objectMetadataDeleteCollection: ObjectMetadataEntity[] = [];
|
private readonly _objectMetadataDeleteCollection: ObjectMetadataEntity[] = [];
|
||||||
|
|
||||||
// Field metadata
|
// Field metadata
|
||||||
private readonly _fieldMetadataCreateCollection: PartialFieldMetadata[] = [];
|
private readonly _fieldMetadataCreateCollection: ComputedPartialFieldMetadata[] =
|
||||||
private readonly _fieldMetadataUpdateCollection: (Partial<PartialFieldMetadata> & {
|
[];
|
||||||
|
private readonly _fieldMetadataUpdateCollection: (Partial<ComputedPartialFieldMetadata> & {
|
||||||
id: string;
|
id: string;
|
||||||
})[] = [];
|
})[] = [];
|
||||||
private readonly _fieldMetadataDeleteCollection: FieldMetadataEntity[] = [];
|
private readonly _fieldMetadataDeleteCollection: FieldMetadataEntity[] = [];
|
||||||
@ -67,11 +68,11 @@ export class WorkspaceSyncStorage {
|
|||||||
return this._relationMetadataDeleteCollection;
|
return this._relationMetadataDeleteCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
addCreateObjectMetadata(object: PartialObjectMetadata) {
|
addCreateObjectMetadata(object: ComputedPartialObjectMetadata) {
|
||||||
this._objectMetadataCreateCollection.push(object);
|
this._objectMetadataCreateCollection.push(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
addUpdateObjectMetadata(object: Partial<PartialObjectMetadata>) {
|
addUpdateObjectMetadata(object: Partial<ComputedPartialObjectMetadata>) {
|
||||||
this._objectMetadataUpdateCollection.push(object);
|
this._objectMetadataUpdateCollection.push(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,12 +80,12 @@ export class WorkspaceSyncStorage {
|
|||||||
this._objectMetadataDeleteCollection.push(object);
|
this._objectMetadataDeleteCollection.push(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
addCreateFieldMetadata(field: PartialFieldMetadata) {
|
addCreateFieldMetadata(field: ComputedPartialFieldMetadata) {
|
||||||
this._fieldMetadataCreateCollection.push(field);
|
this._fieldMetadataCreateCollection.push(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
addUpdateFieldMetadata(
|
addUpdateFieldMetadata(
|
||||||
field: Partial<PartialFieldMetadata> & { id: string },
|
field: Partial<ComputedPartialFieldMetadata> & { id: string },
|
||||||
) {
|
) {
|
||||||
this._fieldMetadataUpdateCollection.push(field);
|
this._fieldMetadataUpdateCollection.push(field);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
import {
|
||||||
|
ComputedPartialObjectMetadata,
|
||||||
|
PartialObjectMetadata,
|
||||||
|
} from 'src/workspace/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
||||||
|
import { ComputedPartialFieldMetadata } from 'src/workspace/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||||
|
|
||||||
|
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
||||||
|
import { generateTargetColumnMap } from 'src/metadata/field-metadata/utils/generate-target-column-map.util';
|
||||||
|
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||||
|
|
||||||
|
export const computeStandardObject = (
|
||||||
|
standardObjectMetadata: PartialObjectMetadata,
|
||||||
|
originalObjectMetadata: ObjectMetadataEntity,
|
||||||
|
customObjectMetadataCollection: ObjectMetadataEntity[] = [],
|
||||||
|
): ComputedPartialObjectMetadata => {
|
||||||
|
const fields: ComputedPartialFieldMetadata[] = [];
|
||||||
|
|
||||||
|
for (const partialFieldMetadata of standardObjectMetadata.fields) {
|
||||||
|
if ('paramsFactory' in partialFieldMetadata) {
|
||||||
|
// Compute standard fields of custom object
|
||||||
|
for (const customObjectMetadata of customObjectMetadataCollection) {
|
||||||
|
const { paramsFactory, ...rest } = partialFieldMetadata;
|
||||||
|
const { joinColumn, ...data } = paramsFactory(customObjectMetadata);
|
||||||
|
|
||||||
|
// Relation
|
||||||
|
fields.push({
|
||||||
|
...data,
|
||||||
|
...rest,
|
||||||
|
defaultValue: null,
|
||||||
|
targetColumnMap: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Foreign key
|
||||||
|
fields.push({
|
||||||
|
...rest,
|
||||||
|
name: joinColumn,
|
||||||
|
type: FieldMetadataType.UUID,
|
||||||
|
label: `${data.label} ID (foreign key)`,
|
||||||
|
description: `${data.description} id foreign key`,
|
||||||
|
defaultValue: null,
|
||||||
|
icon: undefined,
|
||||||
|
targetColumnMap: generateTargetColumnMap(
|
||||||
|
FieldMetadataType.UUID,
|
||||||
|
rest.isCustom,
|
||||||
|
joinColumn,
|
||||||
|
),
|
||||||
|
isSystem: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const labelText =
|
||||||
|
typeof partialFieldMetadata.label === 'function'
|
||||||
|
? partialFieldMetadata.label(originalObjectMetadata)
|
||||||
|
: partialFieldMetadata.label;
|
||||||
|
const descriptionText =
|
||||||
|
typeof partialFieldMetadata.description === 'function'
|
||||||
|
? partialFieldMetadata.description(originalObjectMetadata)
|
||||||
|
: partialFieldMetadata.description;
|
||||||
|
|
||||||
|
fields.push({
|
||||||
|
...partialFieldMetadata,
|
||||||
|
label: labelText,
|
||||||
|
description: descriptionText,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...standardObjectMetadata,
|
||||||
|
fields,
|
||||||
|
};
|
||||||
|
};
|
@ -13,6 +13,7 @@ import { workspaceSyncMetadataComparators } from 'src/workspace/workspace-sync-m
|
|||||||
import { WorkspaceMetadataUpdaterService } from 'src/workspace/workspace-sync-metadata/services/workspace-metadata-updater.service';
|
import { WorkspaceMetadataUpdaterService } from 'src/workspace/workspace-sync-metadata/services/workspace-metadata-updater.service';
|
||||||
import { WorkspaceSyncObjectMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-object-metadata.service';
|
import { WorkspaceSyncObjectMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-object-metadata.service';
|
||||||
import { WorkspaceSyncRelationMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-relation-metadata.service';
|
import { WorkspaceSyncRelationMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-relation-metadata.service';
|
||||||
|
import { WorkspaceSyncFieldMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-field-metadata.service';
|
||||||
import { WorkspaceMigrationBuilderModule } from 'src/workspace/workspace-migration-builder/workspace-migration-builder.module';
|
import { WorkspaceMigrationBuilderModule } from 'src/workspace/workspace-migration-builder/workspace-migration-builder.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@ -36,6 +37,7 @@ import { WorkspaceMigrationBuilderModule } from 'src/workspace/workspace-migrati
|
|||||||
WorkspaceMetadataUpdaterService,
|
WorkspaceMetadataUpdaterService,
|
||||||
WorkspaceSyncObjectMetadataService,
|
WorkspaceSyncObjectMetadataService,
|
||||||
WorkspaceSyncRelationMetadataService,
|
WorkspaceSyncRelationMetadataService,
|
||||||
|
WorkspaceSyncFieldMetadataService,
|
||||||
WorkspaceSyncMetadataService,
|
WorkspaceSyncMetadataService,
|
||||||
],
|
],
|
||||||
exports: [WorkspaceSyncMetadataService],
|
exports: [WorkspaceSyncMetadataService],
|
||||||
|
@ -9,9 +9,14 @@ import { WorkspaceMigrationRunnerService } from 'src/workspace/workspace-migrati
|
|||||||
import { FeatureFlagFactory } from 'src/workspace/workspace-sync-metadata/factories/feature-flags.factory';
|
import { FeatureFlagFactory } from 'src/workspace/workspace-sync-metadata/factories/feature-flags.factory';
|
||||||
import { WorkspaceSyncObjectMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-object-metadata.service';
|
import { WorkspaceSyncObjectMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-object-metadata.service';
|
||||||
import { WorkspaceSyncRelationMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-relation-metadata.service';
|
import { WorkspaceSyncRelationMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-relation-metadata.service';
|
||||||
|
import { WorkspaceSyncFieldMetadataService } from 'src/workspace/workspace-sync-metadata/services/workspace-sync-field-metadata.service';
|
||||||
import { WorkspaceSyncStorage } from 'src/workspace/workspace-sync-metadata/storage/workspace-sync.storage';
|
import { WorkspaceSyncStorage } from 'src/workspace/workspace-sync-metadata/storage/workspace-sync.storage';
|
||||||
import { WorkspaceMigrationEntity } from 'src/metadata/workspace-migration/workspace-migration.entity';
|
import { WorkspaceMigrationEntity } from 'src/metadata/workspace-migration/workspace-migration.entity';
|
||||||
|
|
||||||
|
interface SynchronizeOptions {
|
||||||
|
applyChanges?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkspaceSyncMetadataService {
|
export class WorkspaceSyncMetadataService {
|
||||||
private readonly logger = new Logger(WorkspaceSyncMetadataService.name);
|
private readonly logger = new Logger(WorkspaceSyncMetadataService.name);
|
||||||
@ -23,6 +28,7 @@ export class WorkspaceSyncMetadataService {
|
|||||||
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
||||||
private readonly workspaceSyncObjectMetadataService: WorkspaceSyncObjectMetadataService,
|
private readonly workspaceSyncObjectMetadataService: WorkspaceSyncObjectMetadataService,
|
||||||
private readonly workspaceSyncRelationMetadataService: WorkspaceSyncRelationMetadataService,
|
private readonly workspaceSyncRelationMetadataService: WorkspaceSyncRelationMetadataService,
|
||||||
|
private readonly workspaceSyncFieldMetadataService: WorkspaceSyncFieldMetadataService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,9 +39,9 @@ export class WorkspaceSyncMetadataService {
|
|||||||
* @param dataSourceId
|
* @param dataSourceId
|
||||||
* @param workspaceId
|
* @param workspaceId
|
||||||
*/
|
*/
|
||||||
public async syncStandardObjectsAndFieldsMetadata(
|
public async synchronize(
|
||||||
context: WorkspaceSyncContext,
|
context: WorkspaceSyncContext,
|
||||||
options: { applyChanges?: boolean } = { applyChanges: true },
|
options: SynchronizeOptions = { applyChanges: true },
|
||||||
): Promise<{
|
): Promise<{
|
||||||
workspaceMigrations: WorkspaceMigrationEntity[];
|
workspaceMigrations: WorkspaceMigrationEntity[];
|
||||||
storage: WorkspaceSyncStorage;
|
storage: WorkspaceSyncStorage;
|
||||||
@ -62,6 +68,7 @@ export class WorkspaceSyncMetadataService {
|
|||||||
|
|
||||||
this.logger.log('Syncing standard objects and fields metadata');
|
this.logger.log('Syncing standard objects and fields metadata');
|
||||||
|
|
||||||
|
// 1 - Sync standard objects
|
||||||
const workspaceObjectMigrations =
|
const workspaceObjectMigrations =
|
||||||
await this.workspaceSyncObjectMetadataService.synchronize(
|
await this.workspaceSyncObjectMetadataService.synchronize(
|
||||||
context,
|
context,
|
||||||
@ -70,6 +77,16 @@ export class WorkspaceSyncMetadataService {
|
|||||||
workspaceFeatureFlagsMap,
|
workspaceFeatureFlagsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 2 - Sync standard fields on custom objects
|
||||||
|
const workspaceFieldMigrations =
|
||||||
|
await this.workspaceSyncFieldMetadataService.synchronize(
|
||||||
|
context,
|
||||||
|
manager,
|
||||||
|
storage,
|
||||||
|
workspaceFeatureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3 - Sync standard relations on standard and custom objects
|
||||||
const workspaceRelationMigrations =
|
const workspaceRelationMigrations =
|
||||||
await this.workspaceSyncRelationMetadataService.synchronize(
|
await this.workspaceSyncRelationMetadataService.synchronize(
|
||||||
context,
|
context,
|
||||||
@ -81,6 +98,7 @@ export class WorkspaceSyncMetadataService {
|
|||||||
// Save workspace migrations into the database
|
// Save workspace migrations into the database
|
||||||
workspaceMigrations = await workspaceMigrationRepository.save([
|
workspaceMigrations = await workspaceMigrationRepository.save([
|
||||||
...workspaceObjectMigrations,
|
...workspaceObjectMigrations,
|
||||||
|
...workspaceFieldMigrations,
|
||||||
...workspaceRelationMigrations,
|
...workspaceRelationMigrations,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user