Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create RelationMetadataV2 #9691

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

magrinj
Copy link
Member

@magrinj magrinj commented Jan 16, 2025

This PR is creating RelationMetadataV2 in order to refactor relations smoothly.

Fix twentyhq/core-team-issues#237

@magrinj magrinj marked this pull request as ready for review January 16, 2025 15:01
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This PR introduces RelationMetadataV2 to smoothly transition from 'from/to' to 'source/target' naming in relation metadata, with significant structural changes to support improved relationship handling between objects.

  • Added new RelationMetadataV2Entity with source/target naming and proper TypeORM decorators in /packages/twenty-server/src/engine/metadata-modules/relation-metadata-v2/relation-metadata-v2.entity.ts
  • Created migration 1737037997641-createRelationMetadataV2.ts to set up new table structure with appropriate constraints and foreign keys
  • Implemented comprehensive RelationMetadataV2Service with CRUD operations, validation, and workspace-specific metadata handling
  • Added proper exception handling through RelationMetadataV2Exception and GraphQL error mapping
  • Note: relation-to-delete-v2.ts still uses old 'from/to' naming convention and needs updating

19 file(s) reviewed, 32 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +111 to +115
@OneToOne(
() => RelationMetadataV2Entity,
(relation: RelationMetadataV2Entity) => relation.sourceFieldMetadata,
)
sourceRelationMetadata: Relation<RelationMetadataV2Entity>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Missing @joincolumn decorator for OneToOne relationship. This could cause issues with foreign key mapping.

Comment on lines +117 to +121
@OneToOne(
() => RelationMetadataV2Entity,
(relation: RelationMetadataV2Entity) => relation.targetFieldMetadata,
)
targetRelationMetadata: Relation<RelationMetadataV2Entity>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Missing @joincolumn decorator for OneToOne relationship. This could cause issues with foreign key mapping.


public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TYPE "metadata"."relationMetadataV2_ondeleteaction_enum" AS ENUM('CASCADE', 'RESTRICT', 'SET_NULL', 'NO_ACTION')`);
await queryRunner.query(`CREATE TABLE "metadata"."relationMetadataV2" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "relationType" character varying NOT NULL, "onDeleteAction" "metadata"."relationMetadataV2_ondeleteaction_enum" NOT NULL DEFAULT 'SET_NULL', "workspaceId" uuid NOT NULL, "sourceObjectMetadataId" uuid NOT NULL, "targetObjectMetadataId" uuid NOT NULL, "sourceFieldMetadataId" uuid NOT NULL, "targetFieldMetadataId" uuid NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), CONSTRAINT "REL_c73d1e4657f79a6ec346e00916" UNIQUE ("sourceFieldMetadataId"), CONSTRAINT "REL_74afbb10c407038ec790eb5f8e" UNIQUE ("targetFieldMetadataId"), CONSTRAINT "PK_46973b622a2907b5a9a2d3f3db8" PRIMARY KEY ("id"))`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: relationType is defined as character varying without length limit - consider adding a maximum length constraint for data integrity

Comment on lines 11 to 12
await queryRunner.query(`ALTER TABLE "metadata"."relationMetadataV2" ADD CONSTRAINT "FK_c73d1e4657f79a6ec346e00916b" FOREIGN KEY ("sourceFieldMetadataId") REFERENCES "metadata"."fieldMetadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "metadata"."relationMetadataV2" ADD CONSTRAINT "FK_74afbb10c407038ec790eb5f8e5" FOREIGN KEY ("targetFieldMetadataId") REFERENCES "metadata"."fieldMetadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: sourceFieldMetadataId and targetFieldMetadataId have NO ACTION on delete - this could lead to orphaned relations if fields are deleted. Consider using CASCADE

Comment on lines +73 to +74
@HideField()
workspaceId: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: workspaceId lacks validation decorators (@IsUUID, @isnotempty) despite being required in the service

Comment on lines +1 to +14
export type RelationToDeleteV2 = {
id: string;
fromFieldMetadataId: string;
toFieldMetadataId: string;
fromFieldMetadataName: string;
toFieldMetadataName: string;
fromObjectMetadataId: string;
toObjectMetadataId: string;
fromObjectName: string;
toObjectName: string;
toFieldMetadataIsCustom: boolean;
toObjectMetadataIsCustom: boolean;
direction: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: All 'from/to' prefixes should be renamed to 'source/target' to match the PR requirements

toObjectName: string;
toFieldMetadataIsCustom: boolean;
toObjectMetadataIsCustom: boolean;
direction: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: The 'direction' field type should be an enum or union type to restrict possible values

Comment on lines +11 to +12
toFieldMetadataIsCustom: boolean;
toObjectMetadataIsCustom: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Only checking 'to' side for custom flags - should also check 'from/source' side for consistency

Comment on lines +21 to +23
case RelationMetadataV2ExceptionCode.FOREIGN_KEY_NOT_FOUND:
default:
throw new InternalServerError(error.message);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: FOREIGN_KEY_NOT_FOUND case falls through to default. Consider handling it separately if it needs different error handling than InternalServerError.

}
}

throw error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Re-throwing raw errors could expose sensitive information. Consider wrapping non-RelationMetadataV2Exceptions in InternalServerError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[RelationMetadata] - Create RelationMetadataV2
1 participant