Files
twenty/packages/twenty-server/src/engine/api/common/common-query-runners/common-update-one-query-runner.service.ts
T
BugIsGod 8005b35b56 Fix relation connect where failing on mixed-case email and URL (#18605)
Related to issue #17711 
Follow-up to PR #17774  which fixed the frontend link normalization only
## Summary
- Normalize `primaryEmail` (lowercase) and `primaryLinkUrl` in relation
`connect.where` composite values
- Applied in both frontend spreadsheet import and backend
`DataArgProcessorService` to cover all entry points (UI import, GraphQL
API)

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
2026-03-19 17:56:26 +00:00

116 lines
4.0 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { msg } from '@lingui/core/macro';
import { type ObjectRecord } from 'twenty-shared/types';
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
import { CommonUpdateManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-update-many-query-runner.service';
import {
CommonQueryRunnerException,
CommonQueryRunnerExceptionCode,
} from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
import { CommonBaseQueryRunnerContext } from 'src/engine/api/common/types/common-base-query-runner-context.type';
import { CommonExtendedQueryRunnerContext } from 'src/engine/api/common/types/common-extended-query-runner-context.type';
import {
CommonExtendedInput,
CommonInput,
CommonQueryNames,
UpdateOneQueryArgs,
} from 'src/engine/api/common/types/common-query-args.type';
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
@Injectable()
export class CommonUpdateOneQueryRunnerService extends CommonBaseQueryRunnerService<
UpdateOneQueryArgs,
ObjectRecord
> {
constructor(
private readonly commonUpdateManyQueryRunnerService: CommonUpdateManyQueryRunnerService,
) {
super();
}
protected readonly operationName = CommonQueryNames.UPDATE_ONE;
async run(
args: CommonExtendedInput<UpdateOneQueryArgs>,
queryRunnerContext: CommonExtendedQueryRunnerContext,
): Promise<ObjectRecord> {
const result = await this.commonUpdateManyQueryRunnerService.run(
{
...args,
filter: { id: { eq: args.id } },
},
queryRunnerContext,
);
if (!result || result.length === 0) {
throw new CommonQueryRunnerException(
'Record not found',
CommonQueryRunnerExceptionCode.RECORD_NOT_FOUND,
{
userFriendlyMessage: msg`This record does not exist or has been deleted.`,
},
);
}
return result[0];
}
async computeArgs(
args: CommonInput<UpdateOneQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<UpdateOneQueryArgs>> {
const {
authContext,
flatObjectMetadata,
flatFieldMetadataMaps,
flatObjectMetadataMaps,
} = queryRunnerContext;
return {
...args,
data: (
await this.dataArgProcessor.process({
partialRecordInputs: [args.data],
authContext,
flatObjectMetadata,
flatFieldMetadataMaps,
flatObjectMetadataMaps,
shouldBackfillPositionIfUndefined: false,
})
)[0],
};
}
async processQueryResult(
queryResult: ObjectRecord,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord> {
return this.commonResultGettersService.processRecord(
queryResult,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
async validate(
args: CommonInput<UpdateOneQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<void> {
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(flatObjectMetadata);
assertIsValidUuid(args.id);
}
}