diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts index 097ba73dd1..07243cb6df 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts @@ -12,7 +12,6 @@ import { type DestroyManyResolverArgs } from 'src/engine/api/graphql/workspace-r import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { buildColumnsToReturn } from 'src/engine/api/graphql/graphql-query-runner/utils/build-columns-to-return'; -import { computeTableName } from 'src/engine/utils/compute-table-name.util'; @Injectable() export class GraphqlQueryDestroyManyResolverService extends GraphqlQueryBaseResolverService< @@ -31,14 +30,9 @@ export class GraphqlQueryDestroyManyResolverService extends GraphqlQueryBaseReso objectMetadataItemWithFieldMaps.nameSingular, ); - const tableName = computeTableName( - objectMetadataItemWithFieldMaps.nameSingular, - objectMetadataItemWithFieldMaps.isCustom, - ); - executionArgs.graphqlQueryParser.applyFilterToBuilder( queryBuilder, - tableName, + objectMetadataItemWithFieldMaps.nameSingular, executionArgs.args.filter, ); diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts index 6e72b03167..f603d099c7 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts @@ -7,6 +7,7 @@ import { type ObjectLiteral, } from 'typeorm'; import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; +import { type WhereClause } from 'typeorm/query-builder/WhereClause'; import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; import { type WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; @@ -23,8 +24,10 @@ import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repositor import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder'; import { type WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder'; import { type WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-update-query-builder'; +import { applyTableAliasOnWhereCondition } from 'src/engine/twenty-orm/utils/apply-table-alias-on-where-condition'; import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util'; import { getObjectMetadataFromEntityTarget } from 'src/engine/twenty-orm/utils/get-object-metadata-from-entity-target.util'; +import { computeTableName } from 'src/engine/utils/compute-table-name.util'; export class WorkspaceDeleteQueryBuilder< T extends ObjectLiteral, @@ -89,13 +92,25 @@ export class WorkspaceDeleteQueryBuilder< this.featureFlagMap, ); + const tableName = computeTableName( + objectMetadata.nameSingular, + objectMetadata.isCustom, + ); + eventSelectQueryBuilder.expressionMap.wheres = this.expressionMap.wheres; + eventSelectQueryBuilder.expressionMap.aliases = this.expressionMap.aliases; eventSelectQueryBuilder.setParameters(this.getParameters()); const before = await eventSelectQueryBuilder.getOne(); + this.expressionMap.wheres = applyTableAliasOnWhereCondition({ + condition: this.expressionMap.wheres, + tableName, + aliasName: objectMetadata.nameSingular, + }) as WhereClause[]; + const result = await super.execute(); const formattedResult = formatResult( diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/apply-table-alias-on-where-condition.util.spec.ts b/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/apply-table-alias-on-where-condition.util.spec.ts new file mode 100644 index 0000000000..4c30ffb2c0 --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/apply-table-alias-on-where-condition.util.spec.ts @@ -0,0 +1,132 @@ +import { type WhereClauseCondition } from 'typeorm/query-builder/WhereClause'; + +import { applyTableAliasOnWhereCondition } from 'src/engine/twenty-orm/utils/apply-table-alias-on-where-condition'; + +describe('applyTableAliasOnWhereCondition', () => { + const tableName = '_listing'; + const aliasName = 'listing'; + + describe('when processing simple where conditions with string conditions', () => { + it('should replace alias name with table name in string condition', () => { + const condition: WhereClauseCondition = [ + { + type: 'simple', + condition: `${aliasName}.id = :id`, + }, + ]; + + const result = applyTableAliasOnWhereCondition({ + condition, + tableName, + aliasName, + }); + + expect(result).toEqual([ + { + type: 'simple', + condition: `${tableName}.id = :id`, + }, + ]); + }); + + it('should replace alias name with table name in array condition and wrapping operator condition', () => { + const condition: WhereClauseCondition = [ + { + type: 'simple', + condition: { + operator: 'brackets', + condition: [ + { + type: 'simple', + condition: `"${aliasName}"."id" IN (:...id8oi6y)`, + }, + ], + }, + }, + ]; + + const result = applyTableAliasOnWhereCondition({ + condition, + tableName, + aliasName, + }); + + expect(result).toEqual([ + { + type: 'simple', + condition: { + operator: 'brackets', + condition: [ + { + type: 'simple', + condition: `"${tableName}"."id" IN (:...id8oi6y)`, + }, + ], + }, + }, + ]); + }); + + it('should replace alias name with table name in object condition', () => { + const condition: WhereClauseCondition = { + parameters: ['id'], + operator: 'equal', + }; + + const result = applyTableAliasOnWhereCondition({ + condition, + tableName, + aliasName, + }); + + expect(result).toEqual({ + operator: 'equal', + parameters: ['id'], + }); + }); + + it('should replace alias name with table name in string condition without alias name', () => { + const condition: WhereClauseCondition = [ + { + type: 'simple', + condition: `id = :id`, + }, + ]; + + const result = applyTableAliasOnWhereCondition({ + condition, + tableName, + aliasName, + }); + + expect(result).toEqual([ + { + type: 'simple', + condition: `id = :id`, + }, + ]); + }); + + it('should replace alias name with table name in string condition without quotes', () => { + const condition: WhereClauseCondition = [ + { + type: 'simple', + condition: `${aliasName}."id" = :id`, + }, + ]; + + const result = applyTableAliasOnWhereCondition({ + condition, + tableName, + aliasName, + }); + + expect(result).toEqual([ + { + type: 'simple', + condition: `${tableName}."id" = :id`, + }, + ]); + }); + }); +}); diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/apply-table-alias-on-where-condition.ts b/packages/twenty-server/src/engine/twenty-orm/utils/apply-table-alias-on-where-condition.ts new file mode 100644 index 0000000000..29c04407d1 --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/utils/apply-table-alias-on-where-condition.ts @@ -0,0 +1,61 @@ +import { isArray, isObject, isString } from '@sniptt/guards'; +import { + type WhereClause, + type WhereClauseCondition, +} from 'typeorm/query-builder/WhereClause'; + +type ApplyTableAliasOnWhereConditionParams = { + condition: WhereClauseCondition; + tableName: string; + aliasName: string; +}; + +export const applyTableAliasOnWhereCondition = ({ + condition, + tableName, + aliasName, +}: ApplyTableAliasOnWhereConditionParams): WhereClauseCondition => { + if (isString(condition)) { + const conditionParts = condition.split('.'); + + if (conditionParts.length === 1) { + return condition; + } + + const [tableNamePart, ...rest] = conditionParts; + + return `${tableNamePart.replace(aliasName, tableName)}.${rest.join('.')}`; + } + + if (isArray(condition)) { + return condition.map((where: WhereClause) => { + return { + ...where, + condition: applyTableAliasOnWhereCondition({ + condition: where.condition, + tableName, + aliasName, + }), + }; + }); + } + + if (isObject(condition)) { + if ('condition' in condition) { + return { + ...condition, + condition: applyTableAliasOnWhereCondition({ + condition: condition.condition, + tableName, + aliasName, + }), + }; + } + + if ('operator' in condition) { + return condition; + } + } + + return condition; +};