@lokalise/prisma-utils 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/errors/cockroachdbError.js +5 -1
- package/dist/errors/index.js +4 -1
- package/dist/errors/prismaError.js +14 -9
- package/dist/index.js +9 -3
- package/dist/isolation_level/isolationLevel.js +2 -1
- package/dist/prismaClientFactory.js +7 -3
- package/dist/prismaTransaction.js +16 -13
- package/dist/types.d.ts +1 -1
- package/dist/types.js +4 -1
- package/package.json +2 -10
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isCockroachDBRetryTransaction = void 0;
|
|
1
4
|
/**
|
|
2
5
|
* https://www.cockroachlabs.com/docs/stable/transaction-retry-error-reference#:~:text=To%20indicate%20that%20a%20transaction,the%20string%20%22restart%20transaction%22%20.
|
|
3
6
|
*
|
|
@@ -9,9 +12,10 @@ const COCKROACHDB_RETRY_TRANSACTION_CODE = '40001';
|
|
|
9
12
|
*
|
|
10
13
|
* @param error
|
|
11
14
|
*/
|
|
12
|
-
|
|
15
|
+
const isCockroachDBRetryTransaction = (error) => {
|
|
13
16
|
const meta = error.meta;
|
|
14
17
|
if (!meta)
|
|
15
18
|
return false;
|
|
16
19
|
return meta.code === COCKROACHDB_RETRY_TRANSACTION_CODE;
|
|
17
20
|
};
|
|
21
|
+
exports.isCockroachDBRetryTransaction = isCockroachDBRetryTransaction;
|
package/dist/errors/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PRISMA_SERVER_CLOSED_CONNECTION_ERROR = exports.PRISMA_TRANSACTION_ERROR = exports.PRISMA_UNIQUE_CONSTRAINT_ERROR = exports.PRISMA_SERIALIZATION_ERROR = exports.PRISMA_NOT_FOUND_ERROR = exports.isPrismaTransactionClosedError = exports.isPrismaClientKnownRequestError = void 0;
|
|
4
|
+
const node_core_1 = require("@lokalise/node-core");
|
|
2
5
|
/**
|
|
3
6
|
* What is checked?
|
|
4
7
|
* 1. error is defined and not null
|
|
@@ -6,35 +9,37 @@ import { isError } from '@lokalise/node-core';
|
|
|
6
9
|
* 3. error contains the field code which is a string
|
|
7
10
|
* 4. code starts by `P` ([doc](https://www.prisma.io/docs/reference/api-reference/error-reference#error-codes))
|
|
8
11
|
*/
|
|
9
|
-
|
|
10
|
-
isError(error) &&
|
|
12
|
+
const isPrismaClientKnownRequestError = (error) => !!error &&
|
|
13
|
+
(0, node_core_1.isError)(error) &&
|
|
11
14
|
'code' in error &&
|
|
12
15
|
typeof error.code === 'string' &&
|
|
13
16
|
error.code.startsWith('P');
|
|
14
|
-
|
|
17
|
+
exports.isPrismaClientKnownRequestError = isPrismaClientKnownRequestError;
|
|
18
|
+
const isPrismaTransactionClosedError = (error) => error.code === exports.PRISMA_TRANSACTION_ERROR &&
|
|
15
19
|
error.message.toLowerCase().includes('transaction already closed');
|
|
20
|
+
exports.isPrismaTransactionClosedError = isPrismaTransactionClosedError;
|
|
16
21
|
/**
|
|
17
22
|
* Prisma error code P2025 indicates that the operation failed because it depends on one or more
|
|
18
23
|
* records that were required but not found
|
|
19
24
|
*/
|
|
20
|
-
|
|
25
|
+
exports.PRISMA_NOT_FOUND_ERROR = 'P2025';
|
|
21
26
|
/**
|
|
22
27
|
* Prisma error code P2034 indicates a serialization error and that the transaction must be retried.
|
|
23
28
|
* A different error code would indicate that an internal state error happened and that
|
|
24
29
|
* the cluster itself is experiencing an issue which requires intervention
|
|
25
30
|
*/
|
|
26
|
-
|
|
31
|
+
exports.PRISMA_SERIALIZATION_ERROR = 'P2034';
|
|
27
32
|
/**
|
|
28
33
|
* Prisma error code P2002 indicates that the operation failed because a unique constraint was
|
|
29
34
|
* violated. This can happen if you try to create a record with a unique field that already exists
|
|
30
35
|
*/
|
|
31
|
-
|
|
36
|
+
exports.PRISMA_UNIQUE_CONSTRAINT_ERROR = 'P2002';
|
|
32
37
|
/**
|
|
33
38
|
* Prisma error code P2028 indicates a transaction API error, essentially a placeholder for errors that do not fit into
|
|
34
39
|
* a more specific category. You should look into the error message for more details
|
|
35
40
|
*/
|
|
36
|
-
|
|
41
|
+
exports.PRISMA_TRANSACTION_ERROR = 'P2028';
|
|
37
42
|
/**
|
|
38
43
|
* Prisma error code P1017 indicates that the connection to the database server was prematurely terminated by the server
|
|
39
44
|
*/
|
|
40
|
-
|
|
45
|
+
exports.PRISMA_SERVER_CLOSED_CONNECTION_ERROR = 'P1017';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prismaClientFactory = exports.prismaTransaction = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
tslib_1.__exportStar(require("./errors"), exports);
|
|
6
|
+
var prismaTransaction_1 = require("./prismaTransaction");
|
|
7
|
+
Object.defineProperty(exports, "prismaTransaction", { enumerable: true, get: function () { return prismaTransaction_1.prismaTransaction; } });
|
|
8
|
+
var prismaClientFactory_1 = require("./prismaClientFactory");
|
|
9
|
+
Object.defineProperty(exports, "prismaClientFactory", { enumerable: true, get: function () { return prismaClientFactory_1.prismaClientFactory; } });
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prismaClientFactory = void 0;
|
|
4
|
+
const client_1 = require("@prisma/client");
|
|
2
5
|
const defaultOptions = {
|
|
3
6
|
transactionOptions: { isolationLevel: 'ReadCommitted' },
|
|
4
7
|
};
|
|
5
|
-
|
|
8
|
+
const prismaClientFactory = (options = {}) => {
|
|
6
9
|
options.transactionOptions = {
|
|
7
10
|
...defaultOptions.transactionOptions,
|
|
8
11
|
...options.transactionOptions,
|
|
9
12
|
};
|
|
10
13
|
//@ts-expect-error - ReadCommitted is not accepted by Prisma atm
|
|
11
|
-
return new PrismaClient(options);
|
|
14
|
+
return new client_1.PrismaClient(options);
|
|
12
15
|
};
|
|
16
|
+
exports.prismaClientFactory = prismaClientFactory;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prismaTransaction = void 0;
|
|
4
|
+
const promises_1 = require("node:timers/promises");
|
|
5
|
+
const node_core_1 = require("@lokalise/node-core");
|
|
6
|
+
const cockroachdbError_1 = require("./errors/cockroachdbError");
|
|
7
|
+
const prismaError_1 = require("./errors/prismaError");
|
|
5
8
|
const DEFAULT_OPTIONS = {
|
|
6
9
|
retriesAllowed: 2, // first try + 2 retries = 3 tries
|
|
7
10
|
dbDriver: 'CockroachDb',
|
|
@@ -19,13 +22,13 @@ const DEFAULT_OPTIONS = {
|
|
|
19
22
|
* @param {PrismaTransactionOptions | PrismaTransactionBasicOptions} options transaction configuration
|
|
20
23
|
* @return {Promise<PrismaTransactionReturnType<T>>}
|
|
21
24
|
*/
|
|
22
|
-
|
|
25
|
+
exports.prismaTransaction = (async (prisma, arg, options) => {
|
|
23
26
|
let optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
24
27
|
let result = undefined;
|
|
25
28
|
let retries = 0;
|
|
26
29
|
do {
|
|
27
30
|
if (retries > 0) {
|
|
28
|
-
await setTimeout(calculateRetryDelay(retries, optionsWithDefaults.baseRetryDelayMs, optionsWithDefaults.maxRetryDelayMs));
|
|
31
|
+
await (0, promises_1.setTimeout)(calculateRetryDelay(retries, optionsWithDefaults.baseRetryDelayMs, optionsWithDefaults.maxRetryDelayMs));
|
|
29
32
|
}
|
|
30
33
|
result = await executeTransactionTry(prisma, arg, optionsWithDefaults);
|
|
31
34
|
if (result.result)
|
|
@@ -34,7 +37,7 @@ export const prismaTransaction = (async (prisma, arg, options) => {
|
|
|
34
37
|
if (!retryAllowed)
|
|
35
38
|
break;
|
|
36
39
|
if (retryAllowed === 'increase-timeout') {
|
|
37
|
-
optionsWithDefaults = deepClone(optionsWithDefaults);
|
|
40
|
+
optionsWithDefaults = (0, node_core_1.deepClone)(optionsWithDefaults);
|
|
38
41
|
optionsWithDefaults.timeout = Math.min(optionsWithDefaults.timeout * 2, optionsWithDefaults.maxTimeout);
|
|
39
42
|
}
|
|
40
43
|
retries++;
|
|
@@ -58,22 +61,22 @@ const calculateRetryDelay = (retries, baseRetryDelayMs, maxDelayMs) => {
|
|
|
58
61
|
return Math.min(expDelay, maxDelayMs);
|
|
59
62
|
};
|
|
60
63
|
const PrismaCodesToRetry = [
|
|
61
|
-
PRISMA_SERIALIZATION_ERROR,
|
|
62
|
-
PRISMA_SERVER_CLOSED_CONNECTION_ERROR,
|
|
63
|
-
PRISMA_TRANSACTION_ERROR,
|
|
64
|
+
prismaError_1.PRISMA_SERIALIZATION_ERROR,
|
|
65
|
+
prismaError_1.PRISMA_SERVER_CLOSED_CONNECTION_ERROR,
|
|
66
|
+
prismaError_1.PRISMA_TRANSACTION_ERROR,
|
|
64
67
|
];
|
|
65
68
|
const isRetryAllowed = (result, dbDriver) => {
|
|
66
|
-
if (isPrismaClientKnownRequestError(result.error)) {
|
|
69
|
+
if ((0, prismaError_1.isPrismaClientKnownRequestError)(result.error)) {
|
|
67
70
|
const error = result.error;
|
|
68
71
|
// in case transaction is closed (timeout), retry increasing the timeout
|
|
69
72
|
// this should be the first check as the code error is PRISMA_TRANSACTION_ERROR covered also in the next check
|
|
70
|
-
if (isPrismaTransactionClosedError(error))
|
|
73
|
+
if ((0, prismaError_1.isPrismaTransactionClosedError)(error))
|
|
71
74
|
return 'increase-timeout';
|
|
72
75
|
// retry if the error code is in the list of codes to retry
|
|
73
76
|
if (PrismaCodesToRetry.includes(error.code))
|
|
74
77
|
return true;
|
|
75
78
|
// retry if the error is a CockroachDB retry transaction error
|
|
76
|
-
if (dbDriver === 'CockroachDb' && isCockroachDBRetryTransaction(error))
|
|
79
|
+
if (dbDriver === 'CockroachDb' && (0, cockroachdbError_1.isCockroachDBRetryTransaction)(error))
|
|
77
80
|
return true;
|
|
78
81
|
}
|
|
79
82
|
return false;
|
package/dist/types.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export type PrismaTransactionClient<P> = Omit<P, runtime.ITXClientDenyList>;
|
|
|
22
22
|
export type PrismaTransactionFn<T, P> = (prisma: PrismaTransactionClient<P>) => Promise<T>;
|
|
23
23
|
export type PrismaTransactionReturnType<T> = Either<unknown, T | runtime.Types.Utils.UnwrapTuple<Prisma.PrismaPromise<unknown>[]>>;
|
|
24
24
|
/**
|
|
25
|
-
* If we try to use `Omit<Prisma.PrismaClientOptions['transactionOptions']
|
|
25
|
+
* If we try to use `Omit<Prisma.PrismaClientOptions['transactionOptions'], 'isolationLevel'>` to override isolationLevel
|
|
26
26
|
* we start to get lint errors about maxWait and timeout not being part of the transactionOptions type.
|
|
27
27
|
*
|
|
28
28
|
* for that reason, and as this is a temporal solution in the meantime Prisma includes ReadCommitted as a valid isolation
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lokalise/prisma-utils",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"type": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
|
+
"type": "commonjs",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"files": ["dist", "README.md", "LICENSE.md"],
|
|
7
7
|
"main": "./dist/index.cjs",
|
|
8
|
-
"module": "./dist/index.js",
|
|
9
8
|
"types": "./dist/index.d.ts",
|
|
10
9
|
"homepage": "https://github.com/lokalise/shared-ts-libs",
|
|
11
10
|
"repository": {
|
|
12
11
|
"type": "git",
|
|
13
12
|
"url": "git://github.com/lokalise/shared-ts-libs.git"
|
|
14
13
|
},
|
|
15
|
-
"exports": {
|
|
16
|
-
".": {
|
|
17
|
-
"types": "./dist/index.d.ts",
|
|
18
|
-
"require": "./dist/index.cjs",
|
|
19
|
-
"import": "./dist/index.js"
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
14
|
"scripts": {
|
|
23
15
|
"build": "rimraf dist && npm run db:update-client && tsc",
|
|
24
16
|
"dev": "vite watch",
|