Update store on data model mutation (#18684)
- enrich SSE events with relations - remove queries from sse metadata events - on sse event, manage store - on object/field metadata changes, manage store TODO left: - fix other metadata items --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions <github-actions@twenty.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@@ -10,7 +10,6 @@ import { type IndexMetadataInterface } from 'src/engine/metadata-modules/index-m
|
||||
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
|
||||
import { type IDataloaders } from 'src/engine/dataloaders/dataloader.interface';
|
||||
import { filterMorphRelationDuplicateFields } from 'src/engine/dataloaders/utils/filter-morph-relation-duplicate-fields.util';
|
||||
import { pickMorphGroupSurvivor } from 'src/engine/dataloaders/utils/pick-morph-group-survivor.util';
|
||||
import { FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/field-metadata/constants/field-metadata-standard-overrides-properties.constant';
|
||||
import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
|
||||
import { RelationDTO } from 'src/engine/metadata-modules/field-metadata/dtos/relation.dto';
|
||||
@@ -21,11 +20,10 @@ import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findManyFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findAllOthersMorphRelationFlatFieldMetadatasOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-all-others-morph-relation-flat-field-metadatas-or-throw.util';
|
||||
import { fromFlatFieldMetadataToFieldMetadataDto } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-flat-field-metadata-to-field-metadata-dto.util';
|
||||
import { fromMorphOrRelationFlatFieldMetadataToRelationDto } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-morph-or-relation-flat-field-metadata-to-relation-dto.util';
|
||||
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
|
||||
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
|
||||
import { resolveMorphRelationsFromFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/resolve-morph-relations-from-flat-field-metadata.util';
|
||||
import { resolveRelationFromFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/resolve-relation-from-flat-field-metadata.util';
|
||||
import { fromFlatObjectMetadataToObjectMetadataDto } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-to-object-metadata-dto.util';
|
||||
import { getMorphNameFromMorphFieldMetadataName } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-morph-name-from-morph-field-metadata-name.util';
|
||||
import { fromFlatViewFieldGroupToViewFieldGroupDto } from 'src/engine/metadata-modules/view-field-group/utils/from-flat-view-field-group-to-view-field-group-dto.util';
|
||||
@@ -158,7 +156,6 @@ export class DataloaderService {
|
||||
private createRelationLoader() {
|
||||
return new DataLoader<RelationLoaderPayload, RelationDTO | null>(
|
||||
async (dataLoaderParams: RelationLoaderPayload[]) => {
|
||||
const relationDtos: Array<RelationDTO | null> = [];
|
||||
const workspaceId = dataLoaderParams[0].workspaceId;
|
||||
const { flatFieldMetadataMaps, flatObjectMetadataMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
@@ -168,7 +165,7 @@ export class DataloaderService {
|
||||
},
|
||||
);
|
||||
|
||||
for (const { fieldMetadataId } of dataLoaderParams) {
|
||||
return dataLoaderParams.map(({ fieldMetadataId }) => {
|
||||
const sourceFlatFieldMetadata =
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: fieldMetadataId,
|
||||
@@ -181,85 +178,15 @@ export class DataloaderService {
|
||||
FieldMetadataType.RELATION,
|
||||
)
|
||||
) {
|
||||
relationDtos.push(null);
|
||||
continue;
|
||||
return null;
|
||||
}
|
||||
|
||||
const sourceFlatObjectMetadata =
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: sourceFlatFieldMetadata.objectMetadataId,
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const targetFlatFieldMetadata =
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId:
|
||||
sourceFlatFieldMetadata.relationTargetFieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isMorphOrRelationFlatFieldMetadata(targetFlatFieldMetadata)) {
|
||||
relationDtos.push(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
const targetFlatObjectMetadata =
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: targetFlatFieldMetadata.objectMetadataId,
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
if (
|
||||
isFlatFieldMetadataOfType(
|
||||
targetFlatFieldMetadata,
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
)
|
||||
) {
|
||||
const morphNameFromMorphFieldMetadataName =
|
||||
getMorphNameFromMorphFieldMetadataName({
|
||||
morphRelationFlatFieldMetadata: targetFlatFieldMetadata,
|
||||
nameSingular: sourceFlatObjectMetadata.nameSingular,
|
||||
namePlural: sourceFlatObjectMetadata.namePlural,
|
||||
});
|
||||
|
||||
const allMorphFlatFieldMetadatas = [
|
||||
targetFlatFieldMetadata,
|
||||
...findAllOthersMorphRelationFlatFieldMetadatasOrThrow({
|
||||
flatFieldMetadata: targetFlatFieldMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata: targetFlatObjectMetadata,
|
||||
}),
|
||||
];
|
||||
|
||||
const survivorMorphField = pickMorphGroupSurvivor(
|
||||
allMorphFlatFieldMetadatas,
|
||||
);
|
||||
|
||||
relationDtos.push(
|
||||
fromMorphOrRelationFlatFieldMetadataToRelationDto({
|
||||
sourceFlatFieldMetadata,
|
||||
sourceFlatObjectMetadata,
|
||||
targetFlatFieldMetadata: {
|
||||
...survivorMorphField,
|
||||
name: morphNameFromMorphFieldMetadataName,
|
||||
},
|
||||
targetFlatObjectMetadata,
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
relationDtos.push(
|
||||
fromMorphOrRelationFlatFieldMetadataToRelationDto({
|
||||
sourceFlatFieldMetadata,
|
||||
targetFlatFieldMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
sourceFlatObjectMetadata,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return relationDtos;
|
||||
return resolveRelationFromFlatFieldMetadata({
|
||||
sourceFlatFieldMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -275,9 +202,8 @@ export class DataloaderService {
|
||||
flatMapsKeys: ['flatFieldMetadataMaps', 'flatObjectMetadataMaps'],
|
||||
},
|
||||
);
|
||||
const relationDtos: Array<RelationDTO[] | null> = [];
|
||||
|
||||
for (const { fieldMetadataId } of dataLoaderParams) {
|
||||
return dataLoaderParams.map(({ fieldMetadataId }) => {
|
||||
const morphFlatFieldMetadata =
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: fieldMetadataId,
|
||||
@@ -290,70 +216,15 @@ export class DataloaderService {
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
)
|
||||
) {
|
||||
relationDtos.push(null);
|
||||
continue;
|
||||
return null;
|
||||
}
|
||||
|
||||
const sourceFlatObjectMetadata =
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
flatEntityId: morphFlatFieldMetadata.objectMetadataId,
|
||||
});
|
||||
|
||||
const relatedMorphFlatFieldMetadatas =
|
||||
findAllOthersMorphRelationFlatFieldMetadatasOrThrow({
|
||||
flatFieldMetadata: morphFlatFieldMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata: sourceFlatObjectMetadata,
|
||||
});
|
||||
const allMorphFlatFieldMetadatas = [
|
||||
return resolveMorphRelationsFromFlatFieldMetadata({
|
||||
morphFlatFieldMetadata,
|
||||
...relatedMorphFlatFieldMetadatas,
|
||||
];
|
||||
|
||||
relationDtos.push(
|
||||
allMorphFlatFieldMetadatas.flatMap((sourceFlatFieldMetadata) => {
|
||||
const targetFlatFieldMetadata =
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId:
|
||||
sourceFlatFieldMetadata.relationTargetFieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (
|
||||
!isMorphOrRelationFlatFieldMetadata(targetFlatFieldMetadata)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const targetFlatObjectMetadata =
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId:
|
||||
sourceFlatFieldMetadata.relationTargetObjectMetadataId,
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const morphNameFromMorphFieldMetadataName =
|
||||
getMorphNameFromMorphFieldMetadataName({
|
||||
morphRelationFlatFieldMetadata: sourceFlatFieldMetadata,
|
||||
nameSingular: targetFlatObjectMetadata.nameSingular,
|
||||
namePlural: targetFlatObjectMetadata.namePlural,
|
||||
});
|
||||
|
||||
return fromMorphOrRelationFlatFieldMetadataToRelationDto({
|
||||
sourceFlatFieldMetadata: {
|
||||
...sourceFlatFieldMetadata,
|
||||
name: morphNameFromMorphFieldMetadataName,
|
||||
},
|
||||
targetFlatFieldMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
sourceFlatObjectMetadata,
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return relationDtos;
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { RelationDTO } from 'src/engine/metadata-modules/field-metadata/dtos/relation.dto';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { findAllOthersMorphRelationFlatFieldMetadatasOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-all-others-morph-relation-flat-field-metadatas-or-throw.util';
|
||||
import { fromMorphOrRelationFlatFieldMetadataToRelationDto } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-morph-or-relation-flat-field-metadata-to-relation-dto.util';
|
||||
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { getMorphNameFromMorphFieldMetadataName } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-morph-name-from-morph-field-metadata-name.util';
|
||||
|
||||
type ResolveMorphRelationsFromFlatFieldMetadataArgs = {
|
||||
morphFlatFieldMetadata: FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
};
|
||||
|
||||
export const resolveMorphRelationsFromFlatFieldMetadata = ({
|
||||
morphFlatFieldMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
}: ResolveMorphRelationsFromFlatFieldMetadataArgs): RelationDTO[] => {
|
||||
const sourceFlatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
flatEntityId: morphFlatFieldMetadata.objectMetadataId,
|
||||
});
|
||||
|
||||
const relatedMorphFlatFieldMetadatas =
|
||||
findAllOthersMorphRelationFlatFieldMetadatasOrThrow({
|
||||
flatFieldMetadata: morphFlatFieldMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata: sourceFlatObjectMetadata,
|
||||
});
|
||||
|
||||
const allMorphFlatFieldMetadatas = [
|
||||
morphFlatFieldMetadata,
|
||||
...relatedMorphFlatFieldMetadatas,
|
||||
];
|
||||
|
||||
return allMorphFlatFieldMetadatas.flatMap((sourceFlatFieldMetadata) => {
|
||||
const targetFlatFieldMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: sourceFlatFieldMetadata.relationTargetFieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isMorphOrRelationFlatFieldMetadata(targetFlatFieldMetadata)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const targetFlatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: sourceFlatFieldMetadata.relationTargetObjectMetadataId,
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const morphNameFromMorphFieldMetadataName =
|
||||
getMorphNameFromMorphFieldMetadataName({
|
||||
morphRelationFlatFieldMetadata: sourceFlatFieldMetadata,
|
||||
nameSingular: targetFlatObjectMetadata.nameSingular,
|
||||
namePlural: targetFlatObjectMetadata.namePlural,
|
||||
});
|
||||
|
||||
return fromMorphOrRelationFlatFieldMetadataToRelationDto({
|
||||
sourceFlatFieldMetadata: {
|
||||
...sourceFlatFieldMetadata,
|
||||
name: morphNameFromMorphFieldMetadataName,
|
||||
},
|
||||
targetFlatFieldMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
sourceFlatObjectMetadata,
|
||||
});
|
||||
});
|
||||
};
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { pickMorphGroupSurvivor } from 'src/engine/dataloaders/utils/pick-morph-group-survivor.util';
|
||||
import { RelationDTO } from 'src/engine/metadata-modules/field-metadata/dtos/relation.dto';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { findAllOthersMorphRelationFlatFieldMetadatasOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-all-others-morph-relation-flat-field-metadatas-or-throw.util';
|
||||
import { fromMorphOrRelationFlatFieldMetadataToRelationDto } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-morph-or-relation-flat-field-metadata-to-relation-dto.util';
|
||||
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
|
||||
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { getMorphNameFromMorphFieldMetadataName } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-morph-name-from-morph-field-metadata-name.util';
|
||||
|
||||
type ResolveRelationFromFlatFieldMetadataArgs = {
|
||||
sourceFlatFieldMetadata: FlatFieldMetadata<FieldMetadataType.RELATION>;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
};
|
||||
|
||||
export const resolveRelationFromFlatFieldMetadata = ({
|
||||
sourceFlatFieldMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
}: ResolveRelationFromFlatFieldMetadataArgs): RelationDTO | null => {
|
||||
const sourceFlatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: sourceFlatFieldMetadata.objectMetadataId,
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const targetFlatFieldMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: sourceFlatFieldMetadata.relationTargetFieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isMorphOrRelationFlatFieldMetadata(targetFlatFieldMetadata)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const targetFlatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: targetFlatFieldMetadata.objectMetadataId,
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
if (
|
||||
isFlatFieldMetadataOfType(
|
||||
targetFlatFieldMetadata,
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
)
|
||||
) {
|
||||
const morphNameFromMorphFieldMetadataName =
|
||||
getMorphNameFromMorphFieldMetadataName({
|
||||
morphRelationFlatFieldMetadata: targetFlatFieldMetadata,
|
||||
nameSingular: sourceFlatObjectMetadata.nameSingular,
|
||||
namePlural: sourceFlatObjectMetadata.namePlural,
|
||||
});
|
||||
|
||||
const allMorphFlatFieldMetadatas = [
|
||||
targetFlatFieldMetadata,
|
||||
...findAllOthersMorphRelationFlatFieldMetadatasOrThrow({
|
||||
flatFieldMetadata: targetFlatFieldMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata: targetFlatObjectMetadata,
|
||||
}),
|
||||
];
|
||||
|
||||
const survivorMorphField = pickMorphGroupSurvivor(
|
||||
allMorphFlatFieldMetadatas,
|
||||
);
|
||||
|
||||
return fromMorphOrRelationFlatFieldMetadataToRelationDto({
|
||||
sourceFlatFieldMetadata,
|
||||
sourceFlatObjectMetadata,
|
||||
targetFlatFieldMetadata: {
|
||||
...survivorMorphField,
|
||||
name: morphNameFromMorphFieldMetadataName,
|
||||
},
|
||||
targetFlatObjectMetadata,
|
||||
});
|
||||
}
|
||||
|
||||
return fromMorphOrRelationFlatFieldMetadataToRelationDto({
|
||||
sourceFlatFieldMetadata,
|
||||
targetFlatFieldMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
sourceFlatObjectMetadata,
|
||||
});
|
||||
};
|
||||
@@ -12,15 +12,6 @@ export class ObjectRecordEventWithQueryIdsDTO {
|
||||
objectRecordEvent: ObjectRecordEventDTO;
|
||||
}
|
||||
|
||||
@ObjectType('MetadataEventWithQueryIds')
|
||||
export class MetadataEventWithQueryIdsDTO {
|
||||
@Field(() => [String])
|
||||
queryIds: string[];
|
||||
|
||||
@Field(() => MetadataEventDTO)
|
||||
metadataEvent: MetadataEventDTO;
|
||||
}
|
||||
|
||||
@ObjectType('EventSubscription')
|
||||
export class EventSubscriptionDTO {
|
||||
@Field(() => String)
|
||||
@@ -29,6 +20,6 @@ export class EventSubscriptionDTO {
|
||||
@Field(() => [ObjectRecordEventWithQueryIdsDTO])
|
||||
objectRecordEventsWithQueryIds: ObjectRecordEventWithQueryIdsDTO[];
|
||||
|
||||
@Field(() => [MetadataEventWithQueryIdsDTO])
|
||||
metadataEventsWithQueryIds: MetadataEventWithQueryIdsDTO[];
|
||||
@Field(() => [MetadataEventDTO])
|
||||
metadataEvents: MetadataEventDTO[];
|
||||
}
|
||||
|
||||
@@ -6,8 +6,5 @@ export type EventStreamPayload = {
|
||||
queryIds: string[];
|
||||
objectRecordEvent: ObjectRecordSubscriptionEvent;
|
||||
}[];
|
||||
metadataEventsWithQueryIds: {
|
||||
queryIds: string[];
|
||||
metadataEvent: MetadataEvent;
|
||||
}[];
|
||||
metadataEvents: MetadataEvent[];
|
||||
};
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
|
||||
import { resolveMorphRelationsFromFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/resolve-morph-relations-from-flat-field-metadata.util';
|
||||
import { resolveRelationFromFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/resolve-relation-from-flat-field-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
type EnrichFieldMetadataEventArgs = {
|
||||
record: Record<string, unknown>;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
};
|
||||
|
||||
export const enrichFieldMetadataEventWithRelations = ({
|
||||
record,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
}: EnrichFieldMetadataEventArgs): Record<string, unknown> => {
|
||||
const flatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: record.id as string,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatFieldMetadata)) {
|
||||
return record;
|
||||
}
|
||||
|
||||
try {
|
||||
if (
|
||||
isFlatFieldMetadataOfType(flatFieldMetadata, FieldMetadataType.RELATION)
|
||||
) {
|
||||
const relation = resolveRelationFromFlatFieldMetadata({
|
||||
sourceFlatFieldMetadata: flatFieldMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
return isDefined(relation) ? { ...record, relation } : record;
|
||||
}
|
||||
|
||||
if (
|
||||
isFlatFieldMetadataOfType(
|
||||
flatFieldMetadata,
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
)
|
||||
) {
|
||||
const morphRelations = resolveMorphRelationsFromFlatFieldMetadata({
|
||||
morphFlatFieldMetadata: flatFieldMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
return { ...record, morphRelations };
|
||||
}
|
||||
} catch {
|
||||
return record;
|
||||
}
|
||||
|
||||
return record;
|
||||
};
|
||||
+2
-2
@@ -90,7 +90,7 @@ export class WorkspaceEventEmitterResolver {
|
||||
return {
|
||||
eventStreamId: variables.eventStreamId,
|
||||
objectRecordEventsWithQueryIds: payload.objectRecordEventsWithQueryIds,
|
||||
metadataEventsWithQueryIds: payload.metadataEventsWithQueryIds,
|
||||
metadataEvents: payload.metadataEvents,
|
||||
};
|
||||
},
|
||||
})
|
||||
@@ -143,7 +143,7 @@ export class WorkspaceEventEmitterResolver {
|
||||
return wrapAsyncIteratorWithLifecycle(iterator, {
|
||||
initialValue: {
|
||||
objectRecordEventsWithQueryIds: [],
|
||||
metadataEventsWithQueryIds: [],
|
||||
metadataEvents: [],
|
||||
},
|
||||
onHeartbeat: () =>
|
||||
this.eventStreamService.refreshEventStreamTTL({
|
||||
|
||||
+61
-18
@@ -31,6 +31,7 @@ import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/typ
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { enrichFieldMetadataEventWithRelations } from 'src/engine/workspace-event-emitter/utils/enrich-field-metadata-event-with-relations.util';
|
||||
import { UserWorkspaceRoleMap } from 'src/engine/metadata-modules/role-target/types/user-workspace-role-map';
|
||||
import { type FlatRowLevelPermissionPredicateGroupMaps } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group-maps.type';
|
||||
import { type FlatRowLevelPermissionPredicateMaps } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-maps.type';
|
||||
@@ -130,23 +131,29 @@ export class WorkspaceEventEmitterService {
|
||||
? await this.fetchObjectRecordStreamContext(workspaceId)
|
||||
: undefined;
|
||||
|
||||
const enrichedMetadataEventBatch = isMetadata
|
||||
? await this.enrichFieldMetadataEventsWithRelations(
|
||||
eventBatch as MetadataEventBatch,
|
||||
)
|
||||
: undefined;
|
||||
|
||||
for (const [streamChannelId, streamData] of streamsData) {
|
||||
if (!isDefined(streamData)) {
|
||||
streamIdsToRemove.push(streamChannelId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Object.keys(streamData.queries).length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isMetadata) {
|
||||
if (isMetadata && isDefined(enrichedMetadataEventBatch)) {
|
||||
await this.processMetadataStreamEvents(
|
||||
streamChannelId,
|
||||
streamData,
|
||||
eventBatch as MetadataEventBatch,
|
||||
enrichedMetadataEventBatch,
|
||||
);
|
||||
} else {
|
||||
} else if (!isMetadata) {
|
||||
if (Object.keys(streamData.queries).length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isDefined(objectRecordStreamContext)) {
|
||||
continue;
|
||||
}
|
||||
@@ -186,19 +193,14 @@ export class WorkspaceEventEmitterService {
|
||||
return;
|
||||
}
|
||||
|
||||
const metadataEventsWithQueryIds = metadataEventBatch.events.map(
|
||||
(metadataEvent) => ({
|
||||
queryIds: [] as string[],
|
||||
metadataEvent: {
|
||||
...metadataEvent,
|
||||
updatedCollectionHash: metadataEventBatch.updatedCollectionHash,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const metadataEvents = metadataEventBatch.events.map((metadataEvent) => ({
|
||||
...metadataEvent,
|
||||
updatedCollectionHash: metadataEventBatch.updatedCollectionHash,
|
||||
}));
|
||||
|
||||
const payload: EventStreamPayload = {
|
||||
objectRecordEventsWithQueryIds: [],
|
||||
metadataEventsWithQueryIds,
|
||||
metadataEvents,
|
||||
};
|
||||
|
||||
await this.subscriptionService.publishToEventStream({
|
||||
@@ -208,6 +210,47 @@ export class WorkspaceEventEmitterService {
|
||||
});
|
||||
}
|
||||
|
||||
private async enrichFieldMetadataEventsWithRelations(
|
||||
metadataEventBatch: MetadataEventBatch,
|
||||
): Promise<MetadataEventBatch> {
|
||||
if (metadataEventBatch.metadataName !== 'fieldMetadata') {
|
||||
return metadataEventBatch;
|
||||
}
|
||||
|
||||
const { flatFieldMetadataMaps, flatObjectMetadataMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId: metadataEventBatch.workspaceId,
|
||||
flatMapsKeys: ['flatFieldMetadataMaps', 'flatObjectMetadataMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const enrichedEvents = metadataEventBatch.events.map((event) => {
|
||||
if (
|
||||
!('after' in event.properties) ||
|
||||
!isDefined(event.properties.after)
|
||||
) {
|
||||
return event;
|
||||
}
|
||||
|
||||
const enrichedAfter = enrichFieldMetadataEventWithRelations({
|
||||
record: event.properties.after as Record<string, unknown>,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
return {
|
||||
...event,
|
||||
properties: {
|
||||
...event.properties,
|
||||
after: enrichedAfter,
|
||||
},
|
||||
} as typeof event;
|
||||
});
|
||||
|
||||
return { ...metadataEventBatch, events: enrichedEvents };
|
||||
}
|
||||
|
||||
private async processObjectRecordStreamEvents(
|
||||
streamChannelId: string,
|
||||
streamData: EventStreamData,
|
||||
@@ -315,7 +358,7 @@ export class WorkspaceEventEmitterService {
|
||||
|
||||
const payload: EventStreamPayload = {
|
||||
objectRecordEventsWithQueryIds: matchedEvents,
|
||||
metadataEventsWithQueryIds: [],
|
||||
metadataEvents: [],
|
||||
};
|
||||
|
||||
await this.subscriptionService.publishToEventStream({
|
||||
|
||||
Reference in New Issue
Block a user