-
Notifications
You must be signed in to change notification settings - Fork 7.5k
Expand file tree
/
Copy pathcompute-twenty-orm-exception.ts
More file actions
82 lines (72 loc) · 2.93 KB
/
Copy pathcompute-twenty-orm-exception.ts
File metadata and controls
82 lines (72 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import { msg } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { QueryFailedError, QueryRunnerAlreadyReleasedError } from 'typeorm';
import { type WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
import { POSTGRESQL_ERROR_CODES } from 'src/engine/api/graphql/workspace-query-runner/constants/postgres-error-codes.constants';
import { handleDuplicateKeyError } from 'src/engine/api/graphql/workspace-query-runner/utils/handle-duplicate-key-error.util';
import { PostgresException } from 'src/engine/api/graphql/workspace-query-runner/utils/postgres-exception';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import {
TwentyORMException,
TwentyORMExceptionCode,
} from 'src/engine/twenty-orm/exceptions/twenty-orm.exception';
interface QueryFailedErrorWithCode extends QueryFailedError {
code?: string;
}
export const computeTwentyORMException = async (
error: Error,
objectMetadata?: FlatObjectMetadata,
entityManager?: WorkspaceEntityManager,
internalContext?: WorkspaceInternalContext,
): Promise<Error | TwentyORMException> => {
// A released query runner means the underlying connection was torn down
// mid-flight (e.g. node-postgres `query_timeout` destroying the pooled
// connection during a transaction). It is transient, so we surface it as a
// retryable error rather than an opaque failure.
if (error instanceof QueryRunnerAlreadyReleasedError) {
return new TwentyORMException(
error.message,
TwentyORMExceptionCode.QUERY_RUNNER_RELEASED,
);
}
if (error instanceof QueryFailedError) {
if (error.message.includes('Query read timeout')) {
return new TwentyORMException(
'Query read timeout',
TwentyORMExceptionCode.QUERY_READ_TIMEOUT,
{
userFriendlyMessage: msg`We are experiencing a temporary issue with our database. Please try again later.`,
},
);
}
const errorCode = (error as QueryFailedErrorWithCode).code;
if (
errorCode === POSTGRESQL_ERROR_CODES.UNIQUE_VIOLATION &&
isDefined(objectMetadata) &&
isDefined(entityManager) &&
isDefined(internalContext)
) {
return await handleDuplicateKeyError(
error,
objectMetadata,
internalContext,
entityManager,
);
}
if (errorCode === POSTGRESQL_ERROR_CODES.INVALID_TEXT_REPRESENTATION) {
return new TwentyORMException(
error.message, // safe and useful
TwentyORMExceptionCode.INVALID_INPUT,
);
}
if (
isDefined(errorCode) &&
Object.values(POSTGRESQL_ERROR_CODES).includes(errorCode)
) {
throw new PostgresException('Data validation error.', errorCode);
}
throw error;
}
return error;
};