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

Refactored query result getter handlers to support recursivity #8497

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

Conversation

lucasbordeau
Copy link
Contributor

@lucasbordeau lucasbordeau commented Nov 14, 2024

The QueryResultGettersFactory that is called on every query return to was called only on the first level of relations because recursivity wasn't implemented.

In this PR I implement recursivity and add some typing for the possible forms a GraphQL query field can take.

This PR will fix any issue we have with pictures that were losing their token (here for person.avatarUrl)

Fixes #8425
Fixes #8498

Copy link

github-actions bot commented Nov 14, 2024

TODOs/FIXMEs:

  • // TODO: find a way to prevent conflict between handlers executing logic on object relations: packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/query-result-getters.factory.ts
  • // TODO: computing this by taking the opposite of the current object metadata id: packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/query-result-getters.factory.ts
  • // TODO: this is a code smell trying to guess whether it's a relative path or not: packages/twenty-ui/src/utilities/image/getImageAbsoluteURI.ts

Generated by 🚫 dangerJS against c298be7

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 refactors query result getter handlers to support recursive processing of nested data structures, with improvements to image handling and metadata caching.

  • Added recursive processing in QueryResultGettersFactory to handle nested relations, connections, and record arrays
  • Introduced type guards in isResultAConnection.ts to safely check query result shapes
  • Added objectMetadataMap parameter to queryResultGettersFactory.create() for metadata-aware processing
  • Enhanced LogExecutionTime decorator with optional labels for better observability
  • Improved caching with new getWorkspaceObjectMetadataMap method in WorkspaceMetadataCacheService

11 file(s) reviewed, 7 comment(s)
Edit PR Review Bot Settings | Greptile

async handle(
person: PersonWorkspaceEntity,
workspaceId: string,
): Promise<PersonWorkspaceEntity> {
console.log('PersonQueryResultGetterHandler.handle');

if (!person.id || !person?.avatarUrl) {
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Optional chaining (?.) is redundant here since person.id is already checked

async handle(
person: PersonWorkspaceEntity,
workspaceId: string,
): Promise<PersonWorkspaceEntity> {
console.log('PersonQueryResultGetterHandler.handle');
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Consider removing this console.log or replacing with proper logger since execution time is already being logged via decorator

Comment on lines 174 to 182
const objectRecordProcessedWithoutRelationFields = await handler.handle(
record,
workspaceId,
);

const newRecord = {
...objectRecordProcessedWithoutRelationFields,
...relationFieldsProcessedMap,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Handler results are being overridden by relationFieldsProcessedMap spread. This could cause loss of handler-specific processing for relation fields.

Comment on lines 54 to 59
async processConnection(
connection: IConnection<ObjectRecord>,
objectMetadataItemId: string,
objectMetadataMap: ObjectMetadataMap,
workspaceId: string,
): Promise<any> {
Copy link
Contributor

Choose a reason for hiding this comment

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

style: processConnection returns Promise while having strongly typed input parameters. Consider using concrete return type.

export const isPossibleFieldValueAConnection = (
result: PossibleQueryResultFieldValue,
): result is IConnection<ObjectRecord, IEdge<ObjectRecord>> => {
return isDefined((result as any).edges);
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Using (result as any).edges bypasses type safety. Consider checking if result is an object first with typeof result === 'object' && result !== null

/**
* A decorator function that logs the execution time of the decorated method.
*
* @returns The modified property descriptor with the execution time logging functionality.
*/
export function LogExecutionTime() {
export function LogExecutionTime(label?: string | undefined) {
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 type annotation string | undefined is redundant when using optional parameter syntax ?

@@ -21,7 +23,11 @@ export function LogExecutionTime() {
const end = performance.now();
const executionTime = end - start;

logger.log(`Execution time: ${executionTime.toFixed(2)}ms`);
if (isDefined(label)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: isDefined() will return true for empty strings - consider using a more strict check like label?.length > 0

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.

Attachment creation signed token bug Can't upload a record image
3 participants