feat: manually implement joinColumn (#6022)

This PR introduce a new decorator named `@WorkspaceJoinColumn`, the goal
of this one is to manually declare the join columns inside the workspace
entities, so we don't have to rely on `ObjectRecord` type.

This decorator can be used that way:

```typescript
  @WorkspaceRelation({
    standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.company,
    type: RelationMetadataType.MANY_TO_ONE,
    label: 'Company',
    description: 'ActivityTarget company',
    icon: 'IconBuildingSkyscraper',
    inverseSideTarget: () => CompanyWorkspaceEntity,
    inverseSideFieldKey: 'activityTargets',
  })
  @WorkspaceIsNullable()
  company: Relation<CompanyWorkspaceEntity> | null;

  // The argument is the name of the relation above
  @WorkspaceJoinColumn('company')
  companyId: string | null;
```
This commit is contained in:
Jérémy M
2024-06-27 11:41:22 +02:00
committed by GitHub
parent 7eb69a78ef
commit 95c5602a4e
64 changed files with 427 additions and 243 deletions

View File

@ -31,9 +31,7 @@ export class TimelineCalendarEventService {
const calendarEventIds = await this.calendarEventRepository.find({ const calendarEventIds = await this.calendarEventRepository.find({
where: { where: {
calendarEventParticipants: { calendarEventParticipants: {
person: { personId: Any(personIds),
id: Any(personIds),
},
}, },
}, },
select: { select: {
@ -81,8 +79,8 @@ export class TimelineCalendarEventService {
const participants = event.calendarEventParticipants.map( const participants = event.calendarEventParticipants.map(
(participant) => ({ (participant) => ({
calendarEventId: event.id, calendarEventId: event.id,
personId: participant.person?.id ?? null, personId: participant.personId ?? null,
workspaceMemberId: participant.workspaceMember?.id ?? null, workspaceMemberId: participant.workspaceMemberId ?? null,
firstName: firstName:
participant.person?.name?.firstName || participant.person?.name?.firstName ||
participant.workspaceMember?.name.firstName || participant.workspaceMember?.name.firstName ||
@ -135,9 +133,7 @@ export class TimelineCalendarEventService {
): Promise<TimelineCalendarEventsWithTotal> { ): Promise<TimelineCalendarEventsWithTotal> {
const personIds = await this.personRepository.find({ const personIds = await this.personRepository.find({
where: { where: {
company: { companyId,
id: companyId,
},
}, },
select: { select: {
id: true, id: true,

View File

@ -12,7 +12,6 @@ import { TypeORMService } from 'src/database/typeorm/typeorm.service';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
export class UserService extends TypeOrmQueryService<User> { export class UserService extends TypeOrmQueryService<User> {
@ -113,8 +112,7 @@ export class UserService extends TypeOrmQueryService<User> {
`SELECT * FROM ${dataSourceMetadata.schema}."workspaceMember"`, `SELECT * FROM ${dataSourceMetadata.schema}."workspaceMember"`,
); );
const workspaceMember = workspaceMembers.filter( const workspaceMember = workspaceMembers.filter(
(member: ObjectRecord<WorkspaceMemberWorkspaceEntity>) => (member: WorkspaceMemberWorkspaceEntity) => member.userId === userId,
member.userId === userId,
)?.[0]; )?.[0];
assert(workspaceMember, 'WorkspaceMember not found'); assert(workspaceMember, 'WorkspaceMember not found');

View File

@ -0,0 +1,13 @@
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
export function WorkspaceJoinColumn(
relationPropertyKey: string,
): PropertyDecorator {
return (object, propertyKey) => {
metadataArgsStorage.addJoinColumns({
target: object.constructor,
relationName: relationPropertyKey,
joinColumn: propertyKey.toString(),
});
};
}

View File

@ -8,35 +8,19 @@ import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args
import { TypedReflect } from 'src/utils/typed-reflect'; import { TypedReflect } from 'src/utils/typed-reflect';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
interface WorkspaceBaseRelationOptions<TType, TClass> { interface WorkspaceRelationOptions<TClass> {
standardId: string; standardId: string;
label: string | ((objectMetadata: ObjectMetadataEntity) => string); label: string | ((objectMetadata: ObjectMetadataEntity) => string);
description?: string | ((objectMetadata: ObjectMetadataEntity) => string); description?: string | ((objectMetadata: ObjectMetadataEntity) => string);
icon?: string; icon?: string;
type: TType; type: RelationMetadataType;
inverseSideTarget: () => ObjectType<TClass>; inverseSideTarget: () => ObjectType<TClass>;
inverseSideFieldKey?: keyof TClass; inverseSideFieldKey?: keyof TClass;
onDelete?: RelationOnDeleteAction; onDelete?: RelationOnDeleteAction;
} }
export interface WorkspaceManyToOneRelationOptions<TClass>
extends WorkspaceBaseRelationOptions<
RelationMetadataType.MANY_TO_ONE | RelationMetadataType.ONE_TO_ONE,
TClass
> {
joinColumn?: string;
}
export interface WorkspaceOtherRelationOptions<TClass>
extends WorkspaceBaseRelationOptions<
RelationMetadataType.ONE_TO_MANY | RelationMetadataType.MANY_TO_MANY,
TClass
> {}
export function WorkspaceRelation<TClass extends object>( export function WorkspaceRelation<TClass extends object>(
options: options: WorkspaceRelationOptions<TClass>,
| WorkspaceManyToOneRelationOptions<TClass>
| WorkspaceOtherRelationOptions<TClass>,
): PropertyDecorator { ): PropertyDecorator {
return (object, propertyKey) => { return (object, propertyKey) => {
const isPrimary = const isPrimary =
@ -63,14 +47,6 @@ export function WorkspaceRelation<TClass extends object>(
propertyKey.toString(), propertyKey.toString(),
); );
let joinColumn: string | undefined;
if ('joinColumn' in options) {
joinColumn = options.joinColumn
? options.joinColumn
: `${propertyKey.toString()}Id`;
}
metadataArgsStorage.addRelations({ metadataArgsStorage.addRelations({
target: object.constructor, target: object.constructor,
standardId: options.standardId, standardId: options.standardId,
@ -82,7 +58,6 @@ export function WorkspaceRelation<TClass extends object>(
inverseSideTarget: options.inverseSideTarget, inverseSideTarget: options.inverseSideTarget,
inverseSideFieldKey: options.inverseSideFieldKey as string | undefined, inverseSideFieldKey: options.inverseSideFieldKey as string | undefined,
onDelete: options.onDelete, onDelete: options.onDelete,
joinColumn,
isPrimary, isPrimary,
isNullable, isNullable,
isSystem, isSystem,

View File

@ -4,6 +4,7 @@ import { ColumnType, EntitySchemaColumnOptions } from 'typeorm';
import { WorkspaceFieldMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-field-metadata-args.interface'; import { WorkspaceFieldMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-field-metadata-args.interface';
import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface'; import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface';
import { WorkspaceJoinColumnsMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface';
import { fieldMetadataTypeToColumnType } from 'src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util'; import { fieldMetadataTypeToColumnType } from 'src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util';
import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-enum-field-metadata-type.util'; import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-enum-field-metadata-type.util';
@ -12,6 +13,7 @@ import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-me
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
import { compositeTypeDefintions } from 'src/engine/metadata-modules/field-metadata/composite-types'; import { compositeTypeDefintions } from 'src/engine/metadata-modules/field-metadata/composite-types';
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { getJoinColumn } from 'src/engine/twenty-orm/utils/get-join-column.util';
type EntitySchemaColumnMap = { type EntitySchemaColumnMap = {
[key: string]: EntitySchemaColumnOptions; [key: string]: EntitySchemaColumnOptions;
@ -22,6 +24,7 @@ export class EntitySchemaColumnFactory {
create( create(
fieldMetadataArgsCollection: WorkspaceFieldMetadataArgs[], fieldMetadataArgsCollection: WorkspaceFieldMetadataArgs[],
relationMetadataArgsCollection: WorkspaceRelationMetadataArgs[], relationMetadataArgsCollection: WorkspaceRelationMetadataArgs[],
joinColumnsMetadataArgsCollection: WorkspaceJoinColumnsMetadataArgs[],
): EntitySchemaColumnMap { ): EntitySchemaColumnMap {
let entitySchemaColumnMap: EntitySchemaColumnMap = {}; let entitySchemaColumnMap: EntitySchemaColumnMap = {};
@ -56,9 +59,14 @@ export class EntitySchemaColumnFactory {
}; };
for (const relationMetadataArgs of relationMetadataArgsCollection) { for (const relationMetadataArgs of relationMetadataArgsCollection) {
if (relationMetadataArgs.joinColumn) { const joinColumn = getJoinColumn(
entitySchemaColumnMap[relationMetadataArgs.joinColumn] = { joinColumnsMetadataArgsCollection,
name: relationMetadataArgs.joinColumn, relationMetadataArgs,
);
if (joinColumn) {
entitySchemaColumnMap[joinColumn] = {
name: joinColumn,
type: 'uuid', type: 'uuid',
nullable: relationMetadataArgs.isNullable, nullable: relationMetadataArgs.isNullable,
}; };

View File

@ -4,9 +4,11 @@ import { EntitySchemaRelationOptions } from 'typeorm';
import { RelationType } from 'typeorm/metadata/types/RelationTypes'; import { RelationType } from 'typeorm/metadata/types/RelationTypes';
import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface'; import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface';
import { WorkspaceJoinColumnsMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface';
import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util'; import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { getJoinColumn } from 'src/engine/twenty-orm/utils/get-join-column.util';
type EntitySchemaRelationMap = { type EntitySchemaRelationMap = {
[key: string]: EntitySchemaRelationOptions; [key: string]: EntitySchemaRelationOptions;
@ -18,6 +20,7 @@ export class EntitySchemaRelationFactory {
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
target: Function, target: Function,
relationMetadataArgsCollection: WorkspaceRelationMetadataArgs[], relationMetadataArgsCollection: WorkspaceRelationMetadataArgs[],
joinColumnsMetadataArgsCollection: WorkspaceJoinColumnsMetadataArgs[],
): EntitySchemaRelationMap { ): EntitySchemaRelationMap {
const entitySchemaRelationMap: EntitySchemaRelationMap = {}; const entitySchemaRelationMap: EntitySchemaRelationMap = {};
@ -27,16 +30,19 @@ export class EntitySchemaRelationFactory {
const oppositeObjectName = convertClassNameToObjectMetadataName( const oppositeObjectName = convertClassNameToObjectMetadataName(
oppositeTarget.name, oppositeTarget.name,
); );
const relationType = this.getRelationType(relationMetadataArgs); const relationType = this.getRelationType(relationMetadataArgs);
const joinColumn = getJoinColumn(
joinColumnsMetadataArgsCollection,
relationMetadataArgs,
);
entitySchemaRelationMap[relationMetadataArgs.name] = { entitySchemaRelationMap[relationMetadataArgs.name] = {
type: relationType, type: relationType,
target: oppositeObjectName, target: oppositeObjectName,
inverseSide: relationMetadataArgs.inverseSideFieldKey ?? objectName, inverseSide: relationMetadataArgs.inverseSideFieldKey ?? objectName,
joinColumn: relationMetadataArgs.joinColumn joinColumn: joinColumn
? { ? {
name: relationMetadataArgs.joinColumn, name: joinColumn,
} }
: undefined, : undefined,
}; };

View File

@ -23,17 +23,21 @@ export class EntitySchemaFactory {
const fieldMetadataArgsCollection = const fieldMetadataArgsCollection =
metadataArgsStorage.filterFields(target); metadataArgsStorage.filterFields(target);
const joinColumnsMetadataArgsCollection =
metadataArgsStorage.filterJoinColumns(target);
const relationMetadataArgsCollection = const relationMetadataArgsCollection =
metadataArgsStorage.filterRelations(target); metadataArgsStorage.filterRelations(target);
const columns = this.entitySchemaColumnFactory.create( const columns = this.entitySchemaColumnFactory.create(
fieldMetadataArgsCollection, fieldMetadataArgsCollection,
relationMetadataArgsCollection, relationMetadataArgsCollection,
joinColumnsMetadataArgsCollection,
); );
const relations = this.entitySchemaRelationFactory.create( const relations = this.entitySchemaRelationFactory.create(
target, target,
relationMetadataArgsCollection, relationMetadataArgsCollection,
joinColumnsMetadataArgsCollection,
); );
const entitySchema = new EntitySchema({ const entitySchema = new EntitySchema({

View File

@ -0,0 +1,17 @@
export interface WorkspaceJoinColumnsMetadataArgs {
/**
* Class to which relation is applied.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
readonly target: Function;
/**
* Relation name.
*/
readonly relationName: string;
/**
* Relation label.
*/
readonly joinColumn: string;
}

View File

@ -62,11 +62,6 @@ export interface WorkspaceRelationMetadataArgs {
*/ */
readonly onDelete?: RelationOnDeleteAction; readonly onDelete?: RelationOnDeleteAction;
/**
* Relation join column.
*/
readonly joinColumn?: string;
/** /**
* Is primary field. * Is primary field.
*/ */

View File

@ -6,6 +6,7 @@ import { WorkspaceEntityMetadataArgs } from 'src/engine/twenty-orm/interfaces/wo
import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface'; import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface';
import { WorkspaceExtendedEntityMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-extended-entity-metadata-args.interface'; import { WorkspaceExtendedEntityMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-extended-entity-metadata-args.interface';
import { WorkspaceIndexMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-index-metadata-args.interface'; import { WorkspaceIndexMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-index-metadata-args.interface';
import { WorkspaceJoinColumnsMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface';
export class MetadataArgsStorage { export class MetadataArgsStorage {
private readonly entities: WorkspaceEntityMetadataArgs[] = []; private readonly entities: WorkspaceEntityMetadataArgs[] = [];
@ -15,6 +16,7 @@ export class MetadataArgsStorage {
private readonly dynamicRelations: WorkspaceDynamicRelationMetadataArgs[] = private readonly dynamicRelations: WorkspaceDynamicRelationMetadataArgs[] =
[]; [];
private readonly indexes: WorkspaceIndexMetadataArgs[] = []; private readonly indexes: WorkspaceIndexMetadataArgs[] = [];
private readonly joinColumns: WorkspaceJoinColumnsMetadataArgs[] = [];
addEntities(...entities: WorkspaceEntityMetadataArgs[]): void { addEntities(...entities: WorkspaceEntityMetadataArgs[]): void {
this.entities.push(...entities); this.entities.push(...entities);
@ -44,6 +46,10 @@ export class MetadataArgsStorage {
this.dynamicRelations.push(...dynamicRelations); this.dynamicRelations.push(...dynamicRelations);
} }
addJoinColumns(...joinColumns: WorkspaceJoinColumnsMetadataArgs[]): void {
this.joinColumns.push(...joinColumns);
}
filterEntities( filterEntities(
target: Function | string, target: Function | string,
): WorkspaceEntityMetadataArgs | undefined; ): WorkspaceEntityMetadataArgs | undefined;
@ -123,6 +129,20 @@ export class MetadataArgsStorage {
return this.filterByTarget(this.dynamicRelations, target); return this.filterByTarget(this.dynamicRelations, target);
} }
filterJoinColumns(
target: Function | string,
): WorkspaceJoinColumnsMetadataArgs[];
filterJoinColumns(
target: (Function | string)[],
): WorkspaceJoinColumnsMetadataArgs[];
filterJoinColumns(
target: (Function | string) | (Function | string)[],
): WorkspaceJoinColumnsMetadataArgs[] {
return this.filterByTarget(this.joinColumns, target);
}
protected filterByTarget<T extends { target: Function | string }>( protected filterByTarget<T extends { target: Function | string }>(
array: T[], array: T[],
target: (Function | string) | (Function | string)[], target: (Function | string) | (Function | string)[],

View File

@ -0,0 +1,87 @@
import { WorkspaceJoinColumnsMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface';
import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
export const getJoinColumn = (
joinColumnsMetadataArgsCollection: WorkspaceJoinColumnsMetadataArgs[],
relationMetadataArgs: WorkspaceRelationMetadataArgs,
opposite = false,
): string | null => {
if (
relationMetadataArgs.type === RelationMetadataType.ONE_TO_MANY ||
relationMetadataArgs.type === RelationMetadataType.MANY_TO_MANY
) {
return null;
}
const inverseSideTarget = relationMetadataArgs.inverseSideTarget();
const inverseSideJoinColumnsMetadataArgsCollection =
metadataArgsStorage.filterJoinColumns(inverseSideTarget);
const filteredJoinColumnsMetadataArgsCollection =
joinColumnsMetadataArgsCollection.filter(
(joinColumnsMetadataArgs) =>
joinColumnsMetadataArgs.relationName === relationMetadataArgs.name,
);
const oppositeFilteredJoinColumnsMetadataArgsCollection =
inverseSideJoinColumnsMetadataArgsCollection.filter(
(joinColumnsMetadataArgs) =>
joinColumnsMetadataArgs.relationName === relationMetadataArgs.name,
);
if (
filteredJoinColumnsMetadataArgsCollection.length > 0 &&
oppositeFilteredJoinColumnsMetadataArgsCollection.length > 0
) {
throw new Error(
`Join column for ${relationMetadataArgs.name} relation is present on both sides`,
);
}
// If we're in a ONE_TO_ONE relation and there are no join columns, we need to find the join column on the inverse side
if (
relationMetadataArgs.type === RelationMetadataType.ONE_TO_ONE &&
filteredJoinColumnsMetadataArgsCollection.length === 0 &&
!opposite
) {
const inverseSideRelationMetadataArgsCollection =
metadataArgsStorage.filterRelations(inverseSideTarget);
const inverseSideRelationMetadataArgs =
inverseSideRelationMetadataArgsCollection.find(
(inverseSideRelationMetadataArgs) =>
inverseSideRelationMetadataArgs.inverseSideFieldKey ===
relationMetadataArgs.name,
);
if (!inverseSideRelationMetadataArgs) {
throw new Error(
`Inverse side join column of relation ${relationMetadataArgs.name} is missing`,
);
}
return getJoinColumn(
inverseSideJoinColumnsMetadataArgsCollection,
inverseSideRelationMetadataArgs,
// Avoid infinite recursion
true,
);
}
// Check if there are multiple join columns for the relation
if (filteredJoinColumnsMetadataArgsCollection.length > 1) {
throw new Error(
`Multiple join columns found for relation ${relationMetadataArgs.name}`,
);
}
const joinColumnsMetadataArgs = filteredJoinColumnsMetadataArgsCollection[0];
if (!joinColumnsMetadataArgs) {
throw new Error(
`Join column is missing for relation ${relationMetadataArgs.name}`,
);
}
return joinColumnsMetadataArgs.joinColumn;
};

View File

@ -16,6 +16,7 @@ import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { createDeterministicUuid } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util'; import { createDeterministicUuid } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util';
import { getJoinColumn } from 'src/engine/twenty-orm/utils/get-join-column.util';
@Injectable() @Injectable()
export class StandardFieldFactory { export class StandardFieldFactory {
@ -139,6 +140,14 @@ export class StandardFieldFactory {
const foreignKeyStandardId = createDeterministicUuid( const foreignKeyStandardId = createDeterministicUuid(
workspaceRelationMetadataArgs.standardId, workspaceRelationMetadataArgs.standardId,
); );
const joinColumnMetadataArgsCollection =
metadataArgsStorage.filterJoinColumns(
workspaceRelationMetadataArgs.target,
);
const joinColumn = getJoinColumn(
joinColumnMetadataArgsCollection,
workspaceRelationMetadataArgs,
);
if ( if (
isGatedAndNotEnabled( isGatedAndNotEnabled(
@ -149,11 +158,11 @@ export class StandardFieldFactory {
return []; return [];
} }
if (workspaceRelationMetadataArgs.joinColumn) { if (joinColumn) {
fieldMetadataCollection.push({ fieldMetadataCollection.push({
type: FieldMetadataType.UUID, type: FieldMetadataType.UUID,
standardId: foreignKeyStandardId, standardId: foreignKeyStandardId,
name: workspaceRelationMetadataArgs.joinColumn, name: joinColumn,
label: `${workspaceRelationMetadataArgs.label} id (foreign key)`, label: `${workspaceRelationMetadataArgs.label} id (foreign key)`,
description: `${workspaceRelationMetadataArgs.description} id foreign key`, description: `${workspaceRelationMetadataArgs.description} id foreign key`,
icon: workspaceRelationMetadataArgs.icon, icon: workspaceRelationMetadataArgs.icon,

View File

@ -1,20 +0,0 @@
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
type RelationKeys<T> = {
[K in keyof T]: NonNullable<T[K]> extends BaseWorkspaceEntity ? K : never;
}[keyof T];
type ForeignKeyMap<T> = {
[K in RelationKeys<T> as `${K & string}Id`]: string;
};
type RecursiveObjectRecord<T> = {
[P in keyof T]: NonNullable<T[P]> extends BaseWorkspaceEntity
? ObjectRecord<NonNullable<T[P]>> & ForeignKeyMap<NonNullable<T[P]>>
: T[P];
};
// TODO: We should get rid of that it's causing too much issues
// Some relations can be null or undefined because they're not mendatory and other cannot
// This utility type put as defined all the joinColumn, so it's not well typed
export type ObjectRecord<T> = RecursiveObjectRecord<T> & ForeignKeyMap<T>;

View File

@ -14,6 +14,7 @@ import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/works
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.activityTarget, standardId: STANDARD_OBJECT_IDS.activityTarget,
@ -31,52 +32,60 @@ export class ActivityTargetWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Activity', label: 'Activity',
description: 'ActivityTarget activity', description: 'ActivityTarget activity',
icon: 'IconNotes', icon: 'IconNotes',
joinColumn: 'activityId',
inverseSideTarget: () => ActivityWorkspaceEntity, inverseSideTarget: () => ActivityWorkspaceEntity,
inverseSideFieldKey: 'activityTargets', inverseSideFieldKey: 'activityTargets',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
activity: Relation<ActivityWorkspaceEntity> | null; activity: Relation<ActivityWorkspaceEntity> | null;
@WorkspaceJoinColumn('activity')
activityId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.person, standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.person,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Person', label: 'Person',
description: 'ActivityTarget person', description: 'ActivityTarget person',
icon: 'IconUser', icon: 'IconUser',
joinColumn: 'personId',
inverseSideTarget: () => PersonWorkspaceEntity, inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'activityTargets', inverseSideFieldKey: 'activityTargets',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null; person: Relation<PersonWorkspaceEntity> | null;
@WorkspaceJoinColumn('person')
personId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.company, standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.company,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Company', label: 'Company',
description: 'ActivityTarget company', description: 'ActivityTarget company',
icon: 'IconBuildingSkyscraper', icon: 'IconBuildingSkyscraper',
joinColumn: 'companyId',
inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'activityTargets', inverseSideFieldKey: 'activityTargets',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null; company: Relation<CompanyWorkspaceEntity> | null;
@WorkspaceJoinColumn('company')
companyId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.opportunity, standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.opportunity,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Opportunity', label: 'Opportunity',
description: 'ActivityTarget opportunity', description: 'ActivityTarget opportunity',
icon: 'IconTargetArrow', icon: 'IconTargetArrow',
joinColumn: 'opportunityId',
inverseSideTarget: () => OpportunityWorkspaceEntity, inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'activityTargets', inverseSideFieldKey: 'activityTargets',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
opportunity: Relation<OpportunityWorkspaceEntity> | null; opportunity: Relation<OpportunityWorkspaceEntity> | null;
@WorkspaceJoinColumn('opportunity')
opportunityId: string | null;
@WorkspaceDynamicRelation({ @WorkspaceDynamicRelation({
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
argsFactory: (oppositeObjectMetadata) => ({ argsFactory: (oppositeObjectMetadata) => ({

View File

@ -17,6 +17,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.activity, standardId: STANDARD_OBJECT_IDS.activity,
@ -131,11 +132,13 @@ export class ActivityWorkspaceEntity extends BaseWorkspaceEntity {
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'authoredActivities', inverseSideFieldKey: 'authoredActivities',
onDelete: RelationOnDeleteAction.SET_NULL, onDelete: RelationOnDeleteAction.SET_NULL,
joinColumn: 'authorId',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
author: Relation<WorkspaceMemberWorkspaceEntity> | null; author: Relation<WorkspaceMemberWorkspaceEntity> | null;
@WorkspaceJoinColumn('author')
authorId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: ACTIVITY_STANDARD_FIELD_IDS.assignee, standardId: ACTIVITY_STANDARD_FIELD_IDS.assignee,
label: 'Assignee', label: 'Assignee',
@ -145,8 +148,10 @@ export class ActivityWorkspaceEntity extends BaseWorkspaceEntity {
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'assignedActivities', inverseSideFieldKey: 'assignedActivities',
onDelete: RelationOnDeleteAction.SET_NULL, onDelete: RelationOnDeleteAction.SET_NULL,
joinColumn: 'assigneeId',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
assignee: Relation<WorkspaceMemberWorkspaceEntity> | null; assignee: Relation<WorkspaceMemberWorkspaceEntity> | null;
@WorkspaceJoinColumn('assignee')
assigneeId: string | null;
} }

View File

@ -11,6 +11,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.comment, standardId: STANDARD_OBJECT_IDS.comment,
@ -37,21 +38,25 @@ export class CommentWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Author', label: 'Author',
description: 'Comment author', description: 'Comment author',
icon: 'IconCircleUser', icon: 'IconCircleUser',
joinColumn: 'authorId',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'authoredComments', inverseSideFieldKey: 'authoredComments',
}) })
author: Relation<WorkspaceMemberWorkspaceEntity>; author: Relation<WorkspaceMemberWorkspaceEntity>;
@WorkspaceJoinColumn('author')
authorId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: COMMENT_STANDARD_FIELD_IDS.activity, standardId: COMMENT_STANDARD_FIELD_IDS.activity,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Activity', label: 'Activity',
description: 'Comment activity', description: 'Comment activity',
icon: 'IconNotes', icon: 'IconNotes',
joinColumn: 'activityId',
inverseSideTarget: () => ActivityWorkspaceEntity, inverseSideTarget: () => ActivityWorkspaceEntity,
inverseSideFieldKey: 'comments', inverseSideFieldKey: 'comments',
}) })
activity: Relation<ActivityWorkspaceEntity>; activity: Relation<ActivityWorkspaceEntity>;
@WorkspaceJoinColumn('activity')
activityId: string;
} }

View File

@ -18,6 +18,7 @@ import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metad
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator'; import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.attachment, standardId: STANDARD_OBJECT_IDS.attachment,
@ -63,64 +64,74 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Author', label: 'Author',
description: 'Attachment author', description: 'Attachment author',
icon: 'IconCircleUser', icon: 'IconCircleUser',
joinColumn: 'authorId',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'authoredAttachments', inverseSideFieldKey: 'authoredAttachments',
}) })
author: Relation<WorkspaceMemberWorkspaceEntity>; author: Relation<WorkspaceMemberWorkspaceEntity>;
@WorkspaceJoinColumn('author')
authorId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: ATTACHMENT_STANDARD_FIELD_IDS.activity, standardId: ATTACHMENT_STANDARD_FIELD_IDS.activity,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Activity', label: 'Activity',
description: 'Attachment activity', description: 'Attachment activity',
icon: 'IconNotes', icon: 'IconNotes',
joinColumn: 'activityId',
inverseSideTarget: () => ActivityWorkspaceEntity, inverseSideTarget: () => ActivityWorkspaceEntity,
inverseSideFieldKey: 'attachments', inverseSideFieldKey: 'attachments',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
activity: Relation<ActivityWorkspaceEntity> | null; activity: Relation<ActivityWorkspaceEntity> | null;
@WorkspaceJoinColumn('activity')
activityId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: ATTACHMENT_STANDARD_FIELD_IDS.person, standardId: ATTACHMENT_STANDARD_FIELD_IDS.person,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Person', label: 'Person',
description: 'Attachment person', description: 'Attachment person',
icon: 'IconUser', icon: 'IconUser',
joinColumn: 'personId',
inverseSideTarget: () => PersonWorkspaceEntity, inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'attachments', inverseSideFieldKey: 'attachments',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null; person: Relation<PersonWorkspaceEntity> | null;
@WorkspaceJoinColumn('person')
personId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: ATTACHMENT_STANDARD_FIELD_IDS.company, standardId: ATTACHMENT_STANDARD_FIELD_IDS.company,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Company', label: 'Company',
description: 'Attachment company', description: 'Attachment company',
icon: 'IconBuildingSkyscraper', icon: 'IconBuildingSkyscraper',
joinColumn: 'companyId',
inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'attachments', inverseSideFieldKey: 'attachments',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null; company: Relation<CompanyWorkspaceEntity> | null;
@WorkspaceJoinColumn('company')
companyId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: ATTACHMENT_STANDARD_FIELD_IDS.opportunity, standardId: ATTACHMENT_STANDARD_FIELD_IDS.opportunity,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Opportunity', label: 'Opportunity',
description: 'Attachment opportunity', description: 'Attachment opportunity',
icon: 'IconBuildingSkyscraper', icon: 'IconBuildingSkyscraper',
joinColumn: 'opportunityId',
inverseSideTarget: () => OpportunityWorkspaceEntity, inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'attachments', inverseSideFieldKey: 'attachments',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
opportunity: Relation<OpportunityWorkspaceEntity> | null; opportunity: Relation<OpportunityWorkspaceEntity> | null;
@WorkspaceJoinColumn('opportunity')
opportunityId: string | null;
@WorkspaceDynamicRelation({ @WorkspaceDynamicRelation({
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
argsFactory: (oppositeObjectMetadata) => ({ argsFactory: (oppositeObjectMetadata) => ({

View File

@ -70,12 +70,9 @@ export class BlocklistItemDeleteCalendarEventsJob {
const calendarChannels = await this.calendarChannelRepository.find({ const calendarChannels = await this.calendarChannelRepository.find({
where: { where: {
connectedAccount: { connectedAccount: {
accountOwner: { accountOwnerId: workspaceMemberId,
id: workspaceMemberId,
},
}, },
}, },
relations: ['connectedAccount.accountOwner'],
}); });
const calendarChannelIds = calendarChannels.map(({ id }) => id); const calendarChannelIds = calendarChannels.map(({ id }) => id);
@ -88,9 +85,7 @@ export class BlocklistItemDeleteCalendarEventsJob {
handle: isHandleDomain ? ILike(`%${handle}`) : handle, handle: isHandleDomain ? ILike(`%${handle}`) : handle,
}, },
calendarChannelEventAssociations: { calendarChannelEventAssociations: {
calendarChannel: { calendarChannelId: Any(calendarChannelIds),
id: Any(calendarChannelIds),
},
}, },
}, },
}); });

View File

@ -72,9 +72,7 @@ export class CalendarCreateCompanyAndContactAfterSyncJob {
where: { where: {
calendarEvent: { calendarEvent: {
calendarChannelEventAssociations: { calendarChannelEventAssociations: {
calendarChannel: { calendarChannelId,
id: calendarChannelId,
},
}, },
calendarEventParticipants: { calendarEventParticipants: {
person: IsNull(), person: IsNull(),

View File

@ -10,7 +10,6 @@ import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/work
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity';
import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository'; import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository';
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
@Injectable() @Injectable()
export class CalendarEventParticipantListener { export class CalendarEventParticipantListener {
@ -26,7 +25,7 @@ export class CalendarEventParticipantListener {
public async handleCalendarEventParticipantMatchedEvent(payload: { public async handleCalendarEventParticipantMatchedEvent(payload: {
workspaceId: string; workspaceId: string;
workspaceMemberId: string; workspaceMemberId: string;
calendarEventParticipants: ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]; calendarEventParticipants: CalendarEventParticipantWorkspaceEntity[];
}): Promise<void> { }): Promise<void> {
const calendarEventParticipants = payload.calendarEventParticipants ?? []; const calendarEventParticipants = payload.calendarEventParticipants ?? [];

View File

@ -34,9 +34,7 @@ export class CalendarEventFindManyPreQueryHook
const calendarChannelCalendarEventAssociations = const calendarChannelCalendarEventAssociations =
await this.calendarChannelEventAssociationRepository.find({ await this.calendarChannelEventAssociationRepository.find({
where: { where: {
calendarEvent: { calendarEventId: payload?.filter?.id?.eq,
id: payload?.filter?.id?.eq,
},
}, },
relations: ['calendarChannel.connectedAccount'], relations: ['calendarChannel.connectedAccount'],
}); });

View File

@ -35,9 +35,7 @@ export class CalendarEventFindOnePreQueryHook
const calendarChannelCalendarEventAssociations = const calendarChannelCalendarEventAssociations =
await this.calendarChannelEventAssociationRepository.find({ await this.calendarChannelEventAssociationRepository.find({
where: { where: {
calendarEvent: { calendarEventId: payload?.filter?.id?.eq,
id: payload?.filter?.id?.eq,
},
}, },
relations: ['calendarChannel.connectedAccount'], relations: ['calendarChannel.connectedAccount'],
}); });

View File

@ -11,7 +11,6 @@ import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/c
import { CalendarEventParticipant } from 'src/modules/calendar/types/calendar-event'; import { CalendarEventParticipant } from 'src/modules/calendar/types/calendar-event';
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity';
import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
@ -28,10 +27,10 @@ export class CalendarEventParticipantService {
) {} ) {}
public async updateCalendarEventParticipantsAfterPeopleCreation( public async updateCalendarEventParticipantsAfterPeopleCreation(
createdPeople: ObjectRecord<PersonWorkspaceEntity>[], createdPeople: PersonWorkspaceEntity[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]> { ): Promise<CalendarEventParticipantWorkspaceEntity[]> {
const participants = await this.calendarEventParticipantRepository.find({ const participants = await this.calendarEventParticipantRepository.find({
where: { where: {
handle: Any(createdPeople.map((person) => person.email)), handle: Any(createdPeople.map((person) => person.email)),
@ -88,7 +87,7 @@ export class CalendarEventParticipantService {
calendarEventParticipants: CalendarEventParticipant[], calendarEventParticipants: CalendarEventParticipant[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]> { ): Promise<CalendarEventParticipantWorkspaceEntity[]> {
if (calendarEventParticipants.length === 0) { if (calendarEventParticipants.length === 0) {
return []; return [];
} }

View File

@ -37,7 +37,6 @@ import {
} from 'src/modules/connected-account/auto-companies-and-contacts-creation/jobs/create-company-and-contact.job'; } from 'src/modules/connected-account/auto-companies-and-contacts-creation/jobs/create-company-and-contact.job';
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { isDefined } from 'src/utils/is-defined'; import { isDefined } from 'src/utils/is-defined';
import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource'; import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
import { InjectWorkspaceDatasource } from 'src/engine/twenty-orm/decorators/inject-workspace-datasource.decorator'; import { InjectWorkspaceDatasource } from 'src/engine/twenty-orm/decorators/inject-workspace-datasource.decorator';
@ -416,7 +415,7 @@ export class GoogleCalendarSyncService {
eventExternalId: string; eventExternalId: string;
calendarChannelId: string; calendarChannelId: string;
}[], }[],
connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, connectedAccount: ConnectedAccountWorkspaceEntity,
calendarChannel: CalendarChannelWorkspaceEntity, calendarChannel: CalendarChannelWorkspaceEntity,
workspaceId: string, workspaceId: string,
): Promise<void> { ): Promise<void> {
@ -431,7 +430,7 @@ export class GoogleCalendarSyncService {
let startTime: number; let startTime: number;
let endTime: number; let endTime: number;
const savedCalendarEventParticipantsToEmit: ObjectRecord<CalendarEventParticipantWorkspaceEntity>[] = const savedCalendarEventParticipantsToEmit: CalendarEventParticipantWorkspaceEntity[] =
[]; [];
try { try {
@ -496,13 +495,11 @@ export class GoogleCalendarSyncService {
const existingCalendarEventParticipants = const existingCalendarEventParticipants =
await this.calendarEventParticipantsRepository.find({ await this.calendarEventParticipantsRepository.find({
where: { where: {
calendarEvent: { calendarEventId: Any(
id: Any( participantsToUpdate
participantsToUpdate .map((participant) => participant.calendarEventId)
.map((participant) => participant.calendarEventId) .filter(isDefined),
.filter(isDefined), ),
),
},
}, },
}); });

View File

@ -12,6 +12,7 @@ import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metad
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.calendarChannelEventAssociation, standardId: STANDARD_OBJECT_IDS.calendarChannelEventAssociation,
@ -41,12 +42,14 @@ export class CalendarChannelEventAssociationWorkspaceEntity extends BaseWorkspac
label: 'Channel ID', label: 'Channel ID',
description: 'Channel ID', description: 'Channel ID',
icon: 'IconCalendar', icon: 'IconCalendar',
joinColumn: 'calendarChannelId',
inverseSideTarget: () => CalendarChannelWorkspaceEntity, inverseSideTarget: () => CalendarChannelWorkspaceEntity,
inverseSideFieldKey: 'calendarChannelEventAssociations', inverseSideFieldKey: 'calendarChannelEventAssociations',
}) })
calendarChannel: Relation<CalendarChannelWorkspaceEntity>; calendarChannel: Relation<CalendarChannelWorkspaceEntity>;
@WorkspaceJoinColumn('calendarChannel')
calendarChannelId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: standardId:
CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS.calendarEvent, CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS.calendarEvent,
@ -54,9 +57,11 @@ export class CalendarChannelEventAssociationWorkspaceEntity extends BaseWorkspac
label: 'Event ID', label: 'Event ID',
description: 'Event ID', description: 'Event ID',
icon: 'IconCalendar', icon: 'IconCalendar',
joinColumn: 'calendarEventId',
inverseSideTarget: () => CalendarEventWorkspaceEntity, inverseSideTarget: () => CalendarEventWorkspaceEntity,
inverseSideFieldKey: 'calendarChannelEventAssociations', inverseSideFieldKey: 'calendarChannelEventAssociations',
}) })
calendarEvent: Relation<CalendarEventWorkspaceEntity>; calendarEvent: Relation<CalendarEventWorkspaceEntity>;
@WorkspaceJoinColumn('calendarEvent')
calendarEventId: string;
} }

View File

@ -16,6 +16,7 @@ import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/work
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
export enum CalendarChannelVisibility { export enum CalendarChannelVisibility {
METADATA = 'METADATA', METADATA = 'METADATA',
@ -231,12 +232,12 @@ export class CalendarChannelWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Connected Account', label: 'Connected Account',
description: 'Connected Account', description: 'Connected Account',
icon: 'IconUserCircle', icon: 'IconUserCircle',
joinColumn: 'connectedAccountId',
inverseSideTarget: () => ConnectedAccountWorkspaceEntity, inverseSideTarget: () => ConnectedAccountWorkspaceEntity,
inverseSideFieldKey: 'calendarChannels', inverseSideFieldKey: 'calendarChannels',
}) })
connectedAccount: Relation<ConnectedAccountWorkspaceEntity>; connectedAccount: Relation<ConnectedAccountWorkspaceEntity>;
@WorkspaceJoinColumn('connectedAccount')
connectedAccountId: string; connectedAccountId: string;
@WorkspaceRelation({ @WorkspaceRelation({

View File

@ -14,6 +14,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
export enum CalendarEventParticipantResponseStatus { export enum CalendarEventParticipantResponseStatus {
NEEDS_ACTION = 'NEEDS_ACTION', NEEDS_ACTION = 'NEEDS_ACTION',
@ -103,35 +104,41 @@ export class CalendarEventParticipantWorkspaceEntity extends BaseWorkspaceEntity
label: 'Event ID', label: 'Event ID',
description: 'Event ID', description: 'Event ID',
icon: 'IconCalendar', icon: 'IconCalendar',
joinColumn: 'calendarEventId',
inverseSideTarget: () => CalendarEventWorkspaceEntity, inverseSideTarget: () => CalendarEventWorkspaceEntity,
inverseSideFieldKey: 'calendarEventParticipants', inverseSideFieldKey: 'calendarEventParticipants',
}) })
calendarEvent: Relation<CalendarEventWorkspaceEntity>; calendarEvent: Relation<CalendarEventWorkspaceEntity>;
@WorkspaceJoinColumn('calendarEvent')
calendarEventId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.person, standardId: CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.person,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Person', label: 'Person',
description: 'Person', description: 'Person',
icon: 'IconUser', icon: 'IconUser',
joinColumn: 'personId',
inverseSideTarget: () => PersonWorkspaceEntity, inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'calendarEventParticipants', inverseSideFieldKey: 'calendarEventParticipants',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null; person: Relation<PersonWorkspaceEntity> | null;
@WorkspaceJoinColumn('person')
personId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.workspaceMember, standardId: CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.workspaceMember,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Workspace Member', label: 'Workspace Member',
description: 'Workspace Member', description: 'Workspace Member',
icon: 'IconUser', icon: 'IconUser',
joinColumn: 'workspaceMemberId',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'calendarEventParticipants', inverseSideFieldKey: 'calendarEventParticipants',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null; workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null;
@WorkspaceJoinColumn('workspaceMember')
workspaceMemberId: string | null;
} }

View File

@ -1,9 +1,8 @@
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity';
import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
export type CalendarEvent = Omit< export type CalendarEvent = Omit<
ObjectRecord<CalendarEventWorkspaceEntity>, CalendarEventWorkspaceEntity,
| 'createdAt' | 'createdAt'
| 'updatedAt' | 'updatedAt'
| 'calendarChannelEventAssociations' | 'calendarChannelEventAssociations'
@ -15,7 +14,7 @@ export type CalendarEvent = Omit<
}; };
export type CalendarEventParticipant = Omit< export type CalendarEventParticipant = Omit<
ObjectRecord<CalendarEventParticipantWorkspaceEntity>, CalendarEventParticipantWorkspaceEntity,
| 'id' | 'id'
| 'createdAt' | 'createdAt'
| 'updatedAt' | 'updatedAt'

View File

@ -22,6 +22,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.company, standardId: STANDARD_OBJECT_IDS.company,
@ -143,7 +144,6 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
description: description:
'Your team member responsible for managing the company account', 'Your team member responsible for managing the company account',
icon: 'IconUserCircle', icon: 'IconUserCircle',
joinColumn: 'accountOwnerId',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'accountOwnerForCompanies', inverseSideFieldKey: 'accountOwnerForCompanies',
onDelete: RelationOnDeleteAction.SET_NULL, onDelete: RelationOnDeleteAction.SET_NULL,
@ -151,6 +151,9 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceIsNullable() @WorkspaceIsNullable()
accountOwner: Relation<WorkspaceMemberWorkspaceEntity> | null; accountOwner: Relation<WorkspaceMemberWorkspaceEntity> | null;
@WorkspaceJoinColumn('accountOwner')
accountOwnerId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: COMPANY_STANDARD_FIELD_IDS.activityTargets, standardId: COMPANY_STANDARD_FIELD_IDS.activityTargets,
type: RelationMetadataType.ONE_TO_MANY, type: RelationMetadataType.ONE_TO_MANY,

View File

@ -7,7 +7,6 @@ import { PersonRepository } from 'src/modules/person/repositories/person.reposit
import { getFirstNameAndLastNameFromHandleAndDisplayName } from 'src/modules/calendar-messaging-participant/utils/get-first-name-and-last-name-from-handle-and-display-name.util'; import { getFirstNameAndLastNameFromHandleAndDisplayName } from 'src/modules/calendar-messaging-participant/utils/get-first-name-and-last-name-from-handle-and-display-name.util';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
type ContactToCreate = { type ContactToCreate = {
handle: string; handle: string;
@ -55,7 +54,7 @@ export class CreateContactService {
contactsToCreate: ContactToCreate[], contactsToCreate: ContactToCreate[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<PersonWorkspaceEntity>[]> { ): Promise<PersonWorkspaceEntity[]> {
if (contactsToCreate.length === 0) return []; if (contactsToCreate.length === 0) return [];
const formattedContacts = this.formatContacts(contactsToCreate); const formattedContacts = this.formatContacts(contactsToCreate);

View File

@ -17,7 +17,6 @@ import { getUniqueContactsAndHandles } from 'src/modules/connected-account/auto-
import { Contacts } from 'src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type'; import { Contacts } from 'src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type';
import { CalendarEventParticipantService } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service'; import { CalendarEventParticipantService } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service';
import { filterOutContactsFromCompanyOrWorkspace } from 'src/modules/connected-account/auto-companies-and-contacts-creation/utils/filter-out-contacts-from-company-or-workspace.util'; import { filterOutContactsFromCompanyOrWorkspace } from 'src/modules/connected-account/auto-companies-and-contacts-creation/utils/filter-out-contacts-from-company-or-workspace.util';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { MessagingMessageParticipantService } from 'src/modules/messaging/common/services/messaging-message-participant.service'; import { MessagingMessageParticipantService } from 'src/modules/messaging/common/services/messaging-message-participant.service';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity';
@ -46,7 +45,7 @@ export class CreateCompanyAndContactService {
contactsToCreate: Contacts, contactsToCreate: Contacts,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<PersonWorkspaceEntity>[]> { ): Promise<PersonWorkspaceEntity[]> {
if (!contactsToCreate || contactsToCreate.length === 0) { if (!contactsToCreate || contactsToCreate.length === 0) {
return []; return [];
} }
@ -136,9 +135,8 @@ export class CreateCompanyAndContactService {
contactsToCreate: Contacts, contactsToCreate: Contacts,
workspaceId: string, workspaceId: string,
) { ) {
let updatedMessageParticipants: ObjectRecord<MessageParticipantWorkspaceEntity>[] = let updatedMessageParticipants: MessageParticipantWorkspaceEntity[] = [];
[]; let updatedCalendarEventParticipants: CalendarEventParticipantWorkspaceEntity[] =
let updatedCalendarEventParticipants: ObjectRecord<CalendarEventParticipantWorkspaceEntity>[] =
[]; [];
await this.workspaceDataSource?.transaction( await this.workspaceDataSource?.transaction(

View File

@ -1,12 +1,11 @@
import { getDomainNameFromHandle } from 'src/modules/calendar-messaging-participant/utils/get-domain-name-from-handle.util'; import { getDomainNameFromHandle } from 'src/modules/calendar-messaging-participant/utils/get-domain-name-from-handle.util';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { Contacts } from 'src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type'; import { Contacts } from 'src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type';
export function filterOutContactsFromCompanyOrWorkspace( export function filterOutContactsFromCompanyOrWorkspace(
contacts: Contacts, contacts: Contacts,
selfHandle: string, selfHandle: string,
workspaceMembers: ObjectRecord<WorkspaceMemberWorkspaceEntity>[], workspaceMembers: WorkspaceMemberWorkspaceEntity[],
): Contacts { ): Contacts {
const selfDomainName = getDomainNameFromHandle(selfHandle); const selfDomainName = getDomainNameFromHandle(selfHandle);

View File

@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm'; import { EntityManager } from 'typeorm';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity';
@Injectable() @Injectable()
@ -16,7 +15,7 @@ export class BlocklistRepository {
id: string, id: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<BlocklistWorkspaceEntity> | null> { ): Promise<BlocklistWorkspaceEntity | null> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -39,7 +38,7 @@ export class BlocklistRepository {
workspaceMemberId: string, workspaceMemberId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<BlocklistWorkspaceEntity>[]> { ): Promise<BlocklistWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -56,7 +55,7 @@ export class BlocklistRepository {
handle: string, handle: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<BlocklistWorkspaceEntity>[]> { ): Promise<BlocklistWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);

View File

@ -4,7 +4,6 @@ import { EntityManager } from 'typeorm';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
@Injectable() @Injectable()
export class ConnectedAccountRepository { export class ConnectedAccountRepository {
@ -15,7 +14,7 @@ export class ConnectedAccountRepository {
public async getAll( public async getAll(
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[]> { ): Promise<ConnectedAccountWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -31,7 +30,7 @@ export class ConnectedAccountRepository {
connectedAccountIds: string[], connectedAccountIds: string[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[]> { ): Promise<ConnectedAccountWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -47,7 +46,7 @@ export class ConnectedAccountRepository {
workspaceMemberId: string, workspaceMemberId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[] | undefined> { ): Promise<ConnectedAccountWorkspaceEntity[] | undefined> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -66,7 +65,7 @@ export class ConnectedAccountRepository {
userId: string, userId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[] | undefined> { ): Promise<ConnectedAccountWorkspaceEntity[] | undefined> {
const schemaExists = const schemaExists =
await this.workspaceDataSourceService.checkSchemaExists(workspaceId); await this.workspaceDataSourceService.checkSchemaExists(workspaceId);
@ -102,7 +101,7 @@ export class ConnectedAccountRepository {
workspaceMemberId: string, workspaceMemberId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[] | undefined> { ): Promise<ConnectedAccountWorkspaceEntity[] | undefined> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -119,7 +118,7 @@ export class ConnectedAccountRepository {
public async create( public async create(
connectedAccount: Pick< connectedAccount: Pick<
ObjectRecord<ConnectedAccountWorkspaceEntity>, ConnectedAccountWorkspaceEntity,
| 'id' | 'id'
| 'handle' | 'handle'
| 'provider' | 'provider'
@ -129,7 +128,7 @@ export class ConnectedAccountRepository {
>, >,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>> { ): Promise<ConnectedAccountWorkspaceEntity> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -170,7 +169,7 @@ export class ConnectedAccountRepository {
connectedAccountId: string, connectedAccountId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity> | undefined> { ): Promise<ConnectedAccountWorkspaceEntity | undefined> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -189,7 +188,7 @@ export class ConnectedAccountRepository {
connectedAccountId: string, connectedAccountId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>> { ): Promise<ConnectedAccountWorkspaceEntity> {
const connectedAccount = await this.getById( const connectedAccount = await this.getById(
connectedAccountId, connectedAccountId,
workspaceId, workspaceId,
@ -293,7 +292,7 @@ export class ConnectedAccountRepository {
public async getConnectedAccountOrThrow( public async getConnectedAccountOrThrow(
workspaceId: string, workspaceId: string,
connectedAccountId: string, connectedAccountId: string,
): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>> { ): Promise<ConnectedAccountWorkspaceEntity> {
const connectedAccount = await this.getById( const connectedAccount = await this.getById(
connectedAccountId, connectedAccountId,
workspaceId, workspaceId,

View File

@ -11,6 +11,7 @@ import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/work
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.blocklist, standardId: STANDARD_OBJECT_IDS.blocklist,
@ -38,9 +39,11 @@ export class BlocklistWorkspaceEntity extends BaseWorkspaceEntity {
label: 'WorkspaceMember', label: 'WorkspaceMember',
description: 'WorkspaceMember', description: 'WorkspaceMember',
icon: 'IconCircleUser', icon: 'IconCircleUser',
joinColumn: 'workspaceMemberId',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'blocklist', inverseSideFieldKey: 'blocklist',
}) })
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>; workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>;
@WorkspaceJoinColumn('workspaceMember')
workspaceMemberId: string;
} }

View File

@ -17,6 +17,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
export enum ConnectedAccountProvider { export enum ConnectedAccountProvider {
GOOGLE = 'google', GOOGLE = 'google',
@ -94,12 +95,12 @@ export class ConnectedAccountWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Account Owner', label: 'Account Owner',
description: 'Account Owner', description: 'Account Owner',
icon: 'IconUserCircle', icon: 'IconUserCircle',
joinColumn: 'accountOwnerId',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'connectedAccounts', inverseSideFieldKey: 'connectedAccounts',
}) })
accountOwner: Relation<WorkspaceMemberWorkspaceEntity>; accountOwner: Relation<WorkspaceMemberWorkspaceEntity>;
@WorkspaceJoinColumn('accountOwner')
accountOwnerId: string; accountOwnerId: string;
@WorkspaceRelation({ @WorkspaceRelation({

View File

@ -17,6 +17,7 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator'; import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.favorite, standardId: STANDARD_OBJECT_IDS.favorite,
@ -46,51 +47,59 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Workspace Member', label: 'Workspace Member',
description: 'Favorite workspace member', description: 'Favorite workspace member',
icon: 'IconCircleUser', icon: 'IconCircleUser',
joinColumn: 'workspaceMemberId',
inverseSideFieldKey: 'favorites', inverseSideFieldKey: 'favorites',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
}) })
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>; workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>;
@WorkspaceJoinColumn('workspaceMember')
workspaceMemberId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: FAVORITE_STANDARD_FIELD_IDS.person, standardId: FAVORITE_STANDARD_FIELD_IDS.person,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Person', label: 'Person',
description: 'Favorite person', description: 'Favorite person',
icon: 'IconUser', icon: 'IconUser',
joinColumn: 'personId',
inverseSideTarget: () => PersonWorkspaceEntity, inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'favorites', inverseSideFieldKey: 'favorites',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null; person: Relation<PersonWorkspaceEntity> | null;
@WorkspaceJoinColumn('person')
personId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: FAVORITE_STANDARD_FIELD_IDS.company, standardId: FAVORITE_STANDARD_FIELD_IDS.company,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Company', label: 'Company',
description: 'Favorite company', description: 'Favorite company',
icon: 'IconBuildingSkyscraper', icon: 'IconBuildingSkyscraper',
joinColumn: 'companyId',
inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'favorites', inverseSideFieldKey: 'favorites',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null; company: Relation<CompanyWorkspaceEntity> | null;
@WorkspaceJoinColumn('company')
companyId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: FAVORITE_STANDARD_FIELD_IDS.opportunity, standardId: FAVORITE_STANDARD_FIELD_IDS.opportunity,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Opportunity', label: 'Opportunity',
description: 'Favorite opportunity', description: 'Favorite opportunity',
icon: 'IconTargetArrow', icon: 'IconTargetArrow',
joinColumn: 'opportunityId',
inverseSideTarget: () => OpportunityWorkspaceEntity, inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'favorites', inverseSideFieldKey: 'favorites',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
opportunity: Relation<OpportunityWorkspaceEntity> | null; opportunity: Relation<OpportunityWorkspaceEntity> | null;
@WorkspaceJoinColumn('opportunity')
opportunityId: string;
@WorkspaceDynamicRelation({ @WorkspaceDynamicRelation({
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
argsFactory: (oppositeObjectMetadata) => ({ argsFactory: (oppositeObjectMetadata) => ({

View File

@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm'; import { EntityManager } from 'typeorm';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
@Injectable() @Injectable()
@ -17,7 +16,7 @@ export class MessageChannelMessageAssociationRepository {
messageChannelId: string, messageChannelId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -130,7 +129,7 @@ export class MessageChannelMessageAssociationRepository {
messageChannelIds: string[], messageChannelIds: string[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -183,7 +182,7 @@ export class MessageChannelMessageAssociationRepository {
messageThreadExternalIds: string[], messageThreadExternalIds: string[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -200,7 +199,7 @@ export class MessageChannelMessageAssociationRepository {
messageThreadExternalId: string, messageThreadExternalId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity> | null> { ): Promise<MessageChannelMessageAssociationWorkspaceEntity | null> {
const existingMessageChannelMessageAssociations = const existingMessageChannelMessageAssociations =
await this.getByMessageThreadExternalIds( await this.getByMessageThreadExternalIds(
[messageThreadExternalId], [messageThreadExternalId],
@ -222,7 +221,7 @@ export class MessageChannelMessageAssociationRepository {
messageIds: string[], messageIds: string[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -239,7 +238,7 @@ export class MessageChannelMessageAssociationRepository {
messageThreadId: string, messageThreadId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);

View File

@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm'; import { EntityManager } from 'typeorm';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { import {
MessageChannelWorkspaceEntity, MessageChannelWorkspaceEntity,
MessageChannelSyncStatus, MessageChannelSyncStatus,
@ -18,7 +17,7 @@ export class MessageChannelRepository {
public async create( public async create(
messageChannel: Pick< messageChannel: Pick<
ObjectRecord<MessageChannelWorkspaceEntity>, MessageChannelWorkspaceEntity,
| 'id' | 'id'
| 'connectedAccountId' | 'connectedAccountId'
| 'type' | 'type'
@ -72,7 +71,7 @@ export class MessageChannelRepository {
public async getAll( public async getAll(
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelWorkspaceEntity>[]> { ): Promise<MessageChannelWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -88,7 +87,7 @@ export class MessageChannelRepository {
connectedAccountId: string, connectedAccountId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelWorkspaceEntity>[]> { ): Promise<MessageChannelWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -103,7 +102,7 @@ export class MessageChannelRepository {
public async getFirstByConnectedAccountIdOrFail( public async getFirstByConnectedAccountIdOrFail(
connectedAccountId: string, connectedAccountId: string,
workspaceId: string, workspaceId: string,
): Promise<ObjectRecord<MessageChannelWorkspaceEntity>> { ): Promise<MessageChannelWorkspaceEntity> {
const messageChannel = await this.getFirstByConnectedAccountId( const messageChannel = await this.getFirstByConnectedAccountId(
connectedAccountId, connectedAccountId,
workspaceId, workspaceId,
@ -122,7 +121,7 @@ export class MessageChannelRepository {
connectedAccountId: string, connectedAccountId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelWorkspaceEntity> | undefined> { ): Promise<MessageChannelWorkspaceEntity | undefined> {
const messageChannels = await this.getByConnectedAccountId( const messageChannels = await this.getByConnectedAccountId(
connectedAccountId, connectedAccountId,
workspaceId, workspaceId,
@ -136,7 +135,7 @@ export class MessageChannelRepository {
ids: string[], ids: string[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelWorkspaceEntity>[]> { ): Promise<MessageChannelWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -152,7 +151,7 @@ export class MessageChannelRepository {
id: string, id: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelWorkspaceEntity>> { ): Promise<MessageChannelWorkspaceEntity> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -171,7 +170,7 @@ export class MessageChannelRepository {
workspaceMemberId: string, workspaceMemberId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageChannelWorkspaceEntity>[]> { ): Promise<MessageChannelWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);

View File

@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm'; import { EntityManager } from 'typeorm';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
import { ParticipantWithId } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message'; import { ParticipantWithId } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message';
@ -17,7 +16,7 @@ export class MessageParticipantRepository {
handles: string[], handles: string[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageParticipantWorkspaceEntity>[]> { ): Promise<MessageParticipantWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);

View File

@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm'; import { EntityManager } from 'typeorm';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
@Injectable() @Injectable()
@ -40,7 +39,7 @@ export class MessageRepository {
headerMessageId: string, headerMessageId: string,
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageWorkspaceEntity> | null> { ): Promise<MessageWorkspaceEntity | null> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -62,7 +61,7 @@ export class MessageRepository {
messageIds: string[], messageIds: string[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageWorkspaceEntity>[]> { ): Promise<MessageWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -94,7 +93,7 @@ export class MessageRepository {
messageThreadIds: string[], messageThreadIds: string[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageWorkspaceEntity>[]> { ): Promise<MessageWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);

View File

@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common';
import snakeCase from 'lodash.snakecase'; import snakeCase from 'lodash.snakecase';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service'; import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
@ -36,7 +35,7 @@ export class MessagingErrorHandlingService {
public async handleGmailError( public async handleGmailError(
error: GmailError, error: GmailError,
syncStep: SyncStep, syncStep: SyncStep,
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
workspaceId: string, workspaceId: string,
): Promise<void> { ): Promise<void> {
const { code, reason } = error; const { code, reason } = error;
@ -156,7 +155,7 @@ export class MessagingErrorHandlingService {
private async handleRateLimitExceeded( private async handleRateLimitExceeded(
error: GmailError, error: GmailError,
syncStep: SyncStep, syncStep: SyncStep,
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
workspaceId: string, workspaceId: string,
): Promise<void> { ): Promise<void> {
await this.messagingTelemetryService.track({ await this.messagingTelemetryService.track({
@ -190,7 +189,7 @@ export class MessagingErrorHandlingService {
private async handleInsufficientPermissions( private async handleInsufficientPermissions(
error: GmailError, error: GmailError,
syncStep: SyncStep, syncStep: SyncStep,
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
workspaceId: string, workspaceId: string,
): Promise<void> { ): Promise<void> {
await this.messagingTelemetryService.track({ await this.messagingTelemetryService.track({
@ -221,7 +220,7 @@ export class MessagingErrorHandlingService {
private async handleNotFound( private async handleNotFound(
error: GmailError, error: GmailError,
syncStep: SyncStep, syncStep: SyncStep,
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
workspaceId: string, workspaceId: string,
): Promise<void> { ): Promise<void> {
if (syncStep === 'messages-import') { if (syncStep === 'messages-import') {
@ -288,7 +287,7 @@ export class MessagingErrorHandlingService {
} }
private async throttle( private async throttle(
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
workspaceId: string, workspaceId: string,
): Promise<void> { ): Promise<void> {
await this.messageChannelRepository.incrementThrottleFailureCount( await this.messageChannelRepository.incrementThrottleFailureCount(

View File

@ -9,7 +9,6 @@ import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/perso
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util';
import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { MessageParticipantRepository } from 'src/modules/messaging/common/repositories/message-participant.repository'; import { MessageParticipantRepository } from 'src/modules/messaging/common/repositories/message-participant.repository';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
import { ParticipantWithMessageId } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message'; import { ParticipantWithMessageId } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message';
@ -29,10 +28,10 @@ export class MessagingMessageParticipantService {
) {} ) {}
public async updateMessageParticipantsAfterPeopleCreation( public async updateMessageParticipantsAfterPeopleCreation(
createdPeople: ObjectRecord<PersonWorkspaceEntity>[], createdPeople: PersonWorkspaceEntity[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageParticipantWorkspaceEntity>[]> { ): Promise<MessageParticipantWorkspaceEntity[]> {
const participants = await this.messageParticipantRepository.getByHandles( const participants = await this.messageParticipantRepository.getByHandles(
createdPeople.map((person) => person.email), createdPeople.map((person) => person.email),
workspaceId, workspaceId,
@ -87,7 +86,7 @@ export class MessagingMessageParticipantService {
participants: ParticipantWithMessageId[], participants: ParticipantWithMessageId[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<MessageParticipantWorkspaceEntity>[]> { ): Promise<MessageParticipantWorkspaceEntity[]> {
if (!participants) return []; if (!participants) return [];
const dataSourceSchema = const dataSourceSchema =

View File

@ -4,7 +4,6 @@ import { DataSource, EntityManager } from 'typeorm';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
@ -39,7 +38,7 @@ export class MessagingMessageService {
public async saveMessagesWithinTransaction( public async saveMessagesWithinTransaction(
messages: GmailMessage[], messages: GmailMessage[],
connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, connectedAccount: ConnectedAccountWorkspaceEntity,
gmailMessageChannelId: string, gmailMessageChannelId: string,
workspaceId: string, workspaceId: string,
transactionManager: EntityManager, transactionManager: EntityManager,
@ -68,6 +67,12 @@ export class MessagingMessageService {
transactionManager, transactionManager,
); );
if (!savedOrExistingMessageThreadId) {
throw new Error(
`No message thread found for message ${message.headerMessageId} in workspace ${workspaceId} in saveMessages`,
);
}
const savedOrExistingMessageId = const savedOrExistingMessageId =
await this.saveMessageOrReturnExistingMessage( await this.saveMessageOrReturnExistingMessage(
message, message,
@ -99,7 +104,7 @@ export class MessagingMessageService {
public async saveMessages( public async saveMessages(
messages: GmailMessage[], messages: GmailMessage[],
workspaceDataSource: DataSource, workspaceDataSource: DataSource,
connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, connectedAccount: ConnectedAccountWorkspaceEntity,
gmailMessageChannelId: string, gmailMessageChannelId: string,
workspaceId: string, workspaceId: string,
): Promise<Map<string, string>> { ): Promise<Map<string, string>> {
@ -153,6 +158,12 @@ export class MessagingMessageService {
manager, manager,
); );
if (!savedOrExistingMessageThreadId) {
throw new Error(
`No message thread found for message ${message.headerMessageId} in workspace ${workspaceId} in saveMessages`,
);
}
const savedOrExistingMessageId = const savedOrExistingMessageId =
await this.saveMessageOrReturnExistingMessage( await this.saveMessageOrReturnExistingMessage(
message, message,
@ -191,7 +202,7 @@ export class MessagingMessageService {
private async saveMessageOrReturnExistingMessage( private async saveMessageOrReturnExistingMessage(
message: GmailMessage, message: GmailMessage,
messageThreadId: string, messageThreadId: string,
connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, connectedAccount: ConnectedAccountWorkspaceEntity,
workspaceId: string, workspaceId: string,
manager: EntityManager, manager: EntityManager,
): Promise<string> { ): Promise<string> {

View File

@ -7,7 +7,6 @@ import { EntityManager, Repository } from 'typeorm';
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { import {
CreateCompanyAndContactJobData, CreateCompanyAndContactJobData,
@ -43,8 +42,8 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService {
async saveMessagesAndEnqueueContactCreationJob( async saveMessagesAndEnqueueContactCreationJob(
messagesToSave: GmailMessage[], messagesToSave: GmailMessage[],
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, connectedAccount: ConnectedAccountWorkspaceEntity,
workspaceId: string, workspaceId: string,
) { ) {
const workspaceDataSource = const workspaceDataSource =
@ -62,8 +61,7 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService {
const isContactCreationForSentAndReceivedEmailsEnabled = const isContactCreationForSentAndReceivedEmailsEnabled =
isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag?.value; isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag?.value;
let savedMessageParticipants: ObjectRecord<MessageParticipantWorkspaceEntity>[] = let savedMessageParticipants: MessageParticipantWorkspaceEntity[] = [];
[];
const participantsWithMessageId = await workspaceDataSource?.transaction( const participantsWithMessageId = await workspaceDataSource?.transaction(
async (transactionManager: EntityManager) => { async (transactionManager: EntityManager) => {

View File

@ -14,6 +14,7 @@ import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metad
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity';
import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.messageChannelMessageAssociation, standardId: STANDARD_OBJECT_IDS.messageChannelMessageAssociation,
@ -55,26 +56,30 @@ export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspa
label: 'Message Channel Id', label: 'Message Channel Id',
description: 'Message Channel Id', description: 'Message Channel Id',
icon: 'IconHash', icon: 'IconHash',
joinColumn: 'messageChannelId',
inverseSideTarget: () => MessageChannelWorkspaceEntity, inverseSideTarget: () => MessageChannelWorkspaceEntity,
inverseSideFieldKey: 'messageChannelMessageAssociations', inverseSideFieldKey: 'messageChannelMessageAssociations',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
messageChannel: Relation<MessageChannelWorkspaceEntity> | null; messageChannel: Relation<MessageChannelWorkspaceEntity> | null;
@WorkspaceJoinColumn('messageChannel')
messageChannelId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.message, standardId: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.message,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Message Id', label: 'Message Id',
description: 'Message Id', description: 'Message Id',
icon: 'IconHash', icon: 'IconHash',
joinColumn: 'messageId',
inverseSideTarget: () => MessageWorkspaceEntity, inverseSideTarget: () => MessageWorkspaceEntity,
inverseSideFieldKey: 'messageChannelMessageAssociations', inverseSideFieldKey: 'messageChannelMessageAssociations',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
message: Relation<MessageWorkspaceEntity> | null; message: Relation<MessageWorkspaceEntity> | null;
@WorkspaceJoinColumn('message')
messageId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: standardId:
MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageThread, MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageThread,
@ -82,10 +87,12 @@ export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspa
label: 'Message Thread Id', label: 'Message Thread Id',
description: 'Message Thread Id', description: 'Message Thread Id',
icon: 'IconHash', icon: 'IconHash',
joinColumn: 'messageThreadId',
inverseSideTarget: () => MessageThreadWorkspaceEntity, inverseSideTarget: () => MessageThreadWorkspaceEntity,
inverseSideFieldKey: 'messageChannelMessageAssociations', inverseSideFieldKey: 'messageChannelMessageAssociations',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
messageThread: Relation<MessageThreadWorkspaceEntity> | null; messageThread: Relation<MessageThreadWorkspaceEntity> | null;
@WorkspaceJoinColumn('messageThread')
messageThreadId: string;
} }

View File

@ -16,6 +16,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
export enum MessageChannelSyncStatus { export enum MessageChannelSyncStatus {
// TO BE DEPRECATED // TO BE DEPRECATED
@ -300,11 +301,12 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Connected Account', label: 'Connected Account',
description: 'Connected Account', description: 'Connected Account',
icon: 'IconUserCircle', icon: 'IconUserCircle',
joinColumn: 'connectedAccountId',
inverseSideTarget: () => ConnectedAccountWorkspaceEntity, inverseSideTarget: () => ConnectedAccountWorkspaceEntity,
inverseSideFieldKey: 'messageChannels', inverseSideFieldKey: 'messageChannels',
}) })
connectedAccount: Relation<ConnectedAccountWorkspaceEntity>; connectedAccount: Relation<ConnectedAccountWorkspaceEntity>;
@WorkspaceJoinColumn('connectedAccount')
connectedAccountId: string; connectedAccountId: string;
@WorkspaceRelation({ @WorkspaceRelation({

View File

@ -14,6 +14,7 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.messageParticipant, standardId: STANDARD_OBJECT_IDS.messageParticipant,
@ -66,35 +67,41 @@ export class MessageParticipantWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Message', label: 'Message',
description: 'Message', description: 'Message',
icon: 'IconMessage', icon: 'IconMessage',
joinColumn: 'messageId',
inverseSideTarget: () => MessageWorkspaceEntity, inverseSideTarget: () => MessageWorkspaceEntity,
inverseSideFieldKey: 'messageParticipants', inverseSideFieldKey: 'messageParticipants',
}) })
message: Relation<MessageWorkspaceEntity>; message: Relation<MessageWorkspaceEntity>;
@WorkspaceJoinColumn('message')
messageId: string;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.person, standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.person,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Person', label: 'Person',
description: 'Person', description: 'Person',
icon: 'IconUser', icon: 'IconUser',
joinColumn: 'personId',
inverseSideTarget: () => PersonWorkspaceEntity, inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'messageParticipants', inverseSideFieldKey: 'messageParticipants',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null; person: Relation<PersonWorkspaceEntity> | null;
@WorkspaceJoinColumn('person')
personId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.workspaceMember, standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.workspaceMember,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Workspace Member', label: 'Workspace Member',
description: 'Workspace member', description: 'Workspace member',
icon: 'IconCircleUser', icon: 'IconCircleUser',
joinColumn: 'workspaceMemberId',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'messageParticipants', inverseSideFieldKey: 'messageParticipants',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null; workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null;
@WorkspaceJoinColumn('workspaceMember')
workspaceMemberId: string | null;
} }

View File

@ -17,6 +17,7 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.message, standardId: STANDARD_OBJECT_IDS.message,
@ -86,7 +87,6 @@ export class MessageWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Message Thread Id', label: 'Message Thread Id',
description: 'Message Thread Id', description: 'Message Thread Id',
icon: 'IconHash', icon: 'IconHash',
joinColumn: 'messageThreadId',
inverseSideTarget: () => MessageThreadWorkspaceEntity, inverseSideTarget: () => MessageThreadWorkspaceEntity,
inverseSideFieldKey: 'messages', inverseSideFieldKey: 'messages',
onDelete: RelationOnDeleteAction.CASCADE, onDelete: RelationOnDeleteAction.CASCADE,
@ -94,6 +94,9 @@ export class MessageWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceIsNullable() @WorkspaceIsNullable()
messageThread: Relation<MessageThreadWorkspaceEntity> | null; messageThread: Relation<MessageThreadWorkspaceEntity> | null;
@WorkspaceJoinColumn('messageThread')
messageThreadId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: MESSAGE_STANDARD_FIELD_IDS.messageParticipants, standardId: MESSAGE_STANDARD_FIELD_IDS.messageParticipants,
type: RelationMetadataType.ONE_TO_MANY, type: RelationMetadataType.ONE_TO_MANY,

View File

@ -9,7 +9,6 @@ import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decora
import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
@ -50,8 +49,8 @@ export class MessagingGmailFullMessageListFetchService {
) {} ) {}
public async processMessageListFetch( public async processMessageListFetch(
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, connectedAccount: ConnectedAccountWorkspaceEntity,
workspaceId: string, workspaceId: string,
) { ) {
await this.messagingChannelSyncStatusService.markAsMessagesListFetchOngoing( await this.messagingChannelSyncStatusService.markAsMessagesListFetchOngoing(

View File

@ -4,7 +4,6 @@ import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/s
import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator'; import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator';
import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum';
import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service'; import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service';
import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
@ -44,8 +43,8 @@ export class MessagingGmailMessagesImportService {
) {} ) {}
async processMessageBatchImport( async processMessageBatchImport(
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, connectedAccount: ConnectedAccountWorkspaceEntity,
workspaceId: string, workspaceId: string,
) { ) {
if ( if (
@ -185,7 +184,7 @@ export class MessagingGmailMessagesImportService {
} }
private async trackMessageImportCompleted( private async trackMessageImportCompleted(
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
workspaceId: string, workspaceId: string,
) { ) {
await this.messagingTelemetryService.track({ await this.messagingTelemetryService.track({

View File

@ -7,7 +7,6 @@ import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/s
import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service';
import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator'; import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator';
import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
@ -41,8 +40,8 @@ export class MessagingGmailPartialMessageListFetchService {
) {} ) {}
public async processMessageListFetch( public async processMessageListFetch(
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, messageChannel: MessageChannelWorkspaceEntity,
connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, connectedAccount: ConnectedAccountWorkspaceEntity,
workspaceId: string, workspaceId: string,
): Promise<void> { ): Promise<void> {
await this.messagingChannelSyncStatusService.markAsMessagesListFetchOngoing( await this.messagingChannelSyncStatusService.markAsMessagesListFetchOngoing(

View File

@ -9,7 +9,6 @@ import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repos
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository'; import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository';
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
@Injectable() @Injectable()
@ -26,7 +25,7 @@ export class MessageParticipantListener {
public async handleMessageParticipantMatched(payload: { public async handleMessageParticipantMatched(payload: {
workspaceId: string; workspaceId: string;
workspaceMemberId: string; workspaceMemberId: string;
messageParticipants: ObjectRecord<MessageParticipantWorkspaceEntity>[]; messageParticipants: MessageParticipantWorkspaceEntity[];
}): Promise<void> { }): Promise<void> {
const messageParticipants = payload.messageParticipants ?? []; const messageParticipants = payload.messageParticipants ?? [];

View File

@ -21,6 +21,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.opportunity, standardId: STANDARD_OBJECT_IDS.opportunity,
@ -110,7 +111,6 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Point of Contact', label: 'Point of Contact',
description: 'Opportunity point of contact', description: 'Opportunity point of contact',
icon: 'IconUser', icon: 'IconUser',
joinColumn: 'pointOfContactId',
inverseSideTarget: () => PersonWorkspaceEntity, inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'pointOfContactForOpportunities', inverseSideFieldKey: 'pointOfContactForOpportunities',
onDelete: RelationOnDeleteAction.SET_NULL, onDelete: RelationOnDeleteAction.SET_NULL,
@ -118,13 +118,15 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceIsNullable() @WorkspaceIsNullable()
pointOfContact: Relation<PersonWorkspaceEntity> | null; pointOfContact: Relation<PersonWorkspaceEntity> | null;
@WorkspaceJoinColumn('pointOfContact')
pointOfContactId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: OPPORTUNITY_STANDARD_FIELD_IDS.company, standardId: OPPORTUNITY_STANDARD_FIELD_IDS.company,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Company', label: 'Company',
description: 'Opportunity company', description: 'Opportunity company',
icon: 'IconBuildingSkyscraper', icon: 'IconBuildingSkyscraper',
joinColumn: 'companyId',
inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'opportunities', inverseSideFieldKey: 'opportunities',
onDelete: RelationOnDeleteAction.SET_NULL, onDelete: RelationOnDeleteAction.SET_NULL,
@ -132,6 +134,9 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceIsNullable() @WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null; company: Relation<CompanyWorkspaceEntity> | null;
@WorkspaceJoinColumn('company')
companyId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: OPPORTUNITY_STANDARD_FIELD_IDS.favorites, standardId: OPPORTUNITY_STANDARD_FIELD_IDS.favorites,
type: RelationMetadataType.ONE_TO_MANY, type: RelationMetadataType.ONE_TO_MANY,

View File

@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm'; import { EntityManager } from 'typeorm';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util';
@ -17,7 +16,7 @@ export class PersonRepository {
emails: string[], emails: string[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<PersonWorkspaceEntity>[]> { ): Promise<PersonWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -56,7 +55,7 @@ export class PersonRepository {
}[], }[],
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<PersonWorkspaceEntity>[]> { ): Promise<PersonWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);

View File

@ -23,6 +23,7 @@ import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.person, standardId: STANDARD_OBJECT_IDS.person,
@ -127,13 +128,15 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Company', label: 'Company',
description: 'Contacts company', description: 'Contacts company',
icon: 'IconBuildingSkyscraper', icon: 'IconBuildingSkyscraper',
joinColumn: 'companyId',
inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'people', inverseSideFieldKey: 'people',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null; company: Relation<CompanyWorkspaceEntity> | null;
@WorkspaceJoinColumn('company')
companyId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: PERSON_STANDARD_FIELD_IDS.pointOfContactForOpportunities, standardId: PERSON_STANDARD_FIELD_IDS.pointOfContactForOpportunities,
type: RelationMetadataType.ONE_TO_MANY, type: RelationMetadataType.ONE_TO_MANY,

View File

@ -11,6 +11,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.auditLog, standardId: STANDARD_OBJECT_IDS.auditLog,
@ -86,10 +87,12 @@ export class AuditLogWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Workspace Member', label: 'Workspace Member',
description: 'Event workspace member', description: 'Event workspace member',
icon: 'IconCircleUser', icon: 'IconCircleUser',
joinColumn: 'workspaceMemberId',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'auditLogs', inverseSideFieldKey: 'auditLogs',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null; workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null;
@WorkspaceJoinColumn('workspaceMember')
workspaceMemberId: string | null;
} }

View File

@ -17,6 +17,7 @@ import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator'; import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.timelineActivity, standardId: STANDARD_OBJECT_IDS.timelineActivity,
@ -95,52 +96,60 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
label: 'Workspace Member', label: 'Workspace Member',
description: 'Event workspace member', description: 'Event workspace member',
icon: 'IconCircleUser', icon: 'IconCircleUser',
joinColumn: 'workspaceMemberId',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities', inverseSideFieldKey: 'timelineActivities',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null; workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null;
@WorkspaceJoinColumn('workspaceMember')
workspaceMemberId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.person, standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.person,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Person', label: 'Person',
description: 'Event person', description: 'Event person',
icon: 'IconUser', icon: 'IconUser',
joinColumn: 'personId',
inverseSideTarget: () => PersonWorkspaceEntity, inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities', inverseSideFieldKey: 'timelineActivities',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null; person: Relation<PersonWorkspaceEntity> | null;
@WorkspaceJoinColumn('person')
personId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.company, standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.company,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Company', label: 'Company',
description: 'Event company', description: 'Event company',
icon: 'IconBuildingSkyscraper', icon: 'IconBuildingSkyscraper',
joinColumn: 'companyId',
inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities', inverseSideFieldKey: 'timelineActivities',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null; company: Relation<CompanyWorkspaceEntity> | null;
@WorkspaceJoinColumn('company')
companyId: string | null;
@WorkspaceRelation({ @WorkspaceRelation({
standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.opportunity, standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.opportunity,
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
label: 'Opportunity', label: 'Opportunity',
description: 'Event opportunity', description: 'Event opportunity',
icon: 'IconTargetArrow', icon: 'IconTargetArrow',
joinColumn: 'opportunityId',
inverseSideTarget: () => OpportunityWorkspaceEntity, inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities', inverseSideFieldKey: 'timelineActivities',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
opportunity: Relation<OpportunityWorkspaceEntity> | null; opportunity: Relation<OpportunityWorkspaceEntity> | null;
@WorkspaceJoinColumn('opportunity')
opportunityId: string | null;
@WorkspaceDynamicRelation({ @WorkspaceDynamicRelation({
type: RelationMetadataType.MANY_TO_ONE, type: RelationMetadataType.MANY_TO_ONE,
argsFactory: (oppositeObjectMetadata) => ({ argsFactory: (oppositeObjectMetadata) => ({

View File

@ -10,6 +10,7 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re
import { VIEW_FIELD_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { VIEW_FIELD_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids';
import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.workspace-entity'; import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.workspace-entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.viewField, standardId: STANDARD_OBJECT_IDS.viewField,
@ -69,8 +70,10 @@ export class ViewFieldWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconLayoutCollage', icon: 'IconLayoutCollage',
inverseSideTarget: () => ViewWorkspaceEntity, inverseSideTarget: () => ViewWorkspaceEntity,
inverseSideFieldKey: 'viewFields', inverseSideFieldKey: 'viewFields',
joinColumn: 'viewId',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
view?: ViewWorkspaceEntity | null; view?: ViewWorkspaceEntity | null;
@WorkspaceJoinColumn('view')
viewId: string | null;
} }

View File

@ -12,6 +12,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.viewFilter, standardId: STANDARD_OBJECT_IDS.viewFilter,
@ -63,10 +64,12 @@ export class ViewFilterWorkspaceEntity extends BaseWorkspaceEntity {
label: 'View', label: 'View',
description: 'View Filter related view', description: 'View Filter related view',
icon: 'IconLayoutCollage', icon: 'IconLayoutCollage',
joinColumn: 'viewId',
inverseSideTarget: () => ViewWorkspaceEntity, inverseSideTarget: () => ViewWorkspaceEntity,
inverseSideFieldKey: 'viewFilters', inverseSideFieldKey: 'viewFilters',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
view: Relation<ViewWorkspaceEntity> | null; view: Relation<ViewWorkspaceEntity> | null;
@WorkspaceJoinColumn('view')
viewId: string | null;
} }

View File

@ -12,6 +12,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@WorkspaceEntity({ @WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.viewSort, standardId: STANDARD_OBJECT_IDS.viewSort,
@ -48,10 +49,12 @@ export class ViewSortWorkspaceEntity extends BaseWorkspaceEntity {
label: 'View', label: 'View',
description: 'View Sort related view', description: 'View Sort related view',
icon: 'IconLayoutCollage', icon: 'IconLayoutCollage',
joinColumn: 'viewId',
inverseSideTarget: () => ViewWorkspaceEntity, inverseSideTarget: () => ViewWorkspaceEntity,
inverseSideFieldKey: 'viewSorts', inverseSideFieldKey: 'viewSorts',
}) })
@WorkspaceIsNullable() @WorkspaceIsNullable()
view: Relation<ViewWorkspaceEntity> | null; view: Relation<ViewWorkspaceEntity> | null;
@WorkspaceJoinColumn('view')
viewId: string | null;
} }

View File

@ -27,15 +27,11 @@ export class WorkspaceMemberDeleteOnePreQueryHook
const authorId = payload.id; const authorId = payload.id;
await this.attachmentRepository.delete({ await this.attachmentRepository.delete({
author: { authorId,
id: authorId,
},
}); });
await this.commentRepository.delete({ await this.commentRepository.delete({
author: { authorId,
id: authorId,
},
}); });
} }
} }

View File

@ -4,7 +4,6 @@ import { EntityManager } from 'typeorm';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
@Injectable() @Injectable()
export class WorkspaceMemberRepository { export class WorkspaceMemberRepository {
@ -15,7 +14,7 @@ export class WorkspaceMemberRepository {
public async getByIds( public async getByIds(
userIds: string[], userIds: string[],
workspaceId: string, workspaceId: string,
): Promise<ObjectRecord<WorkspaceMemberWorkspaceEntity>[]> { ): Promise<WorkspaceMemberWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -45,7 +44,7 @@ export class WorkspaceMemberRepository {
public async getByIdOrFail( public async getByIdOrFail(
userId: string, userId: string,
workspaceId: string, workspaceId: string,
): Promise<ObjectRecord<WorkspaceMemberWorkspaceEntity>> { ): Promise<WorkspaceMemberWorkspaceEntity> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);
@ -68,7 +67,7 @@ export class WorkspaceMemberRepository {
public async getAllByWorkspaceId( public async getAllByWorkspaceId(
workspaceId: string, workspaceId: string,
transactionManager?: EntityManager, transactionManager?: EntityManager,
): Promise<ObjectRecord<WorkspaceMemberWorkspaceEntity>[]> { ): Promise<WorkspaceMemberWorkspaceEntity[]> {
const dataSourceSchema = const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId); this.workspaceDataSourceService.getSchemaName(workspaceId);

View File

@ -8,7 +8,6 @@ export interface ReflectMetadataTypeMap {
['workspace:is-system-metadata-args']: true; ['workspace:is-system-metadata-args']: true;
['workspace:is-audit-logged-metadata-args']: false; ['workspace:is-audit-logged-metadata-args']: false;
['workspace:is-primary-field-metadata-args']: true; ['workspace:is-primary-field-metadata-args']: true;
['workspace:join-column']: true;
} }
export class TypedReflect { export class TypedReflect {