@aventara/prisma7-adapter 1.0.0-rc.13 → 1.0.0-rc.14

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @aventara/prisma7-adapter
2
2
 
3
+ ## 1.0.0-rc.14
4
+
5
+ ### Patch Changes
6
+
7
+ - 28688e4: On SQLite (`@prisma/adapter-better-sqlite3`), a plain operation or `ctx.$sql` that gives up waiting for the connection another request's transaction holds still answers `A3002`, and its diagnostic now says so: how many milliseconds it waited, the `maxWait` that ran out (the adapter's `transactionOptions.maxWait`, or else the PrismaClient's, 2000 ms unless set on the client), and that it never ran. A transaction that fails to open for another reason, such as an unsupported isolation level, keeps its usual diagnostic. Before, the diagnostic said the call's transaction "was no longer open", which named the wrong cause. Raise the adapter's `transactionOptions.maxWait`, or keep the transaction that holds the connection shorter.
8
+ - Updated dependencies [1c5eaa3]
9
+ - @aventara/core@1.0.0-rc.14
10
+
3
11
  ## 1.0.0-rc.13
4
12
 
5
13
  ### Patch Changes
package/README.md CHANGED
@@ -101,7 +101,8 @@ connection without waiting, so a plain call made meanwhile would run inside the
101
101
  see its uncommitted rows and roll back with it. With that driver, an operation that is not part of a
102
102
  transaction, and a `ctx.$sql` that is not, each run in a `$transaction` of their own that holds only that
103
103
  call. They wait on the driver's own lock, so operations and transactions queue for the connection and run
104
- one at a time. `transactionOptions` apply to the wait: past `maxWait` the operation answers `A3002`, and
104
+ one at a time. `transactionOptions` apply to the wait: past `maxWait` the operation answers `A3002`, its
105
+ diagnostic says how long it waited for the connection another request's transaction held, and
105
106
  `timeout` limits a single plain operation too. `@prisma/adapter-pg` checks a connection of its own out of
106
107
  the pool for each transaction, and D1 runs none, so both stay as they were. Calls made on the Prisma client
107
108
  directly, outside Aventara, are not covered.
@@ -66,6 +66,21 @@ export declare function classifyPrismaError(error: unknown, operation: Pick<AvOp
66
66
  export declare function classifyPrismaStatementError(error: unknown): PrismaErrorClassification;
67
67
  /** The deliberate failure an `outcome` classification stands for. */
68
68
  export declare function prismaOutcomeFailure(code: AvOperationErrorCode): AvError;
69
+ /**
70
+ * Whether a failure to open a transaction has the structure of the `maxWait`
71
+ * acquisition timeout: `P2028` with an empty `meta`.
72
+ */
73
+ export declare function isPrismaAcquisitionTimeout(error: unknown): boolean;
74
+ /**
75
+ * `A3002` for a plain call on a one-connection driver that gave up waiting for
76
+ * the connection another request's transaction held: its own transaction never
77
+ * opened, so `OUTCOME_MESSAGES`' "no longer open" text would name the wrong
78
+ * cause. Diagnostics only, like every `A3xxx` text here.
79
+ */
80
+ export declare function prismaConnectionWaitFailure(facts: {
81
+ readonly waitedMs: number;
82
+ readonly maxWait: number | undefined;
83
+ }): AvError;
69
84
  /** The `A2004` a value the database refused answers: one issue at the arguments (or the value in them) saying what was refused. */
70
85
  export declare function prismaValueFailure(refusal: PrismaValueRefusal, path?: PrismaArgumentPath): AvError;
71
86
  /** The `A2004` a nested write that writes its relation back answers: `V1012` at `path`. */
@@ -127,6 +127,18 @@ export function prismaOutcomeFailure(code) {
127
127
  message: OUTCOME_MESSAGES[code] ?? "The operation could not be completed.",
128
128
  });
129
129
  }
130
+ export function isPrismaAcquisitionTimeout(error) {
131
+ const facts = readPrismaError(error);
132
+ return facts.code === "P2028" && facts.metaKeys.length === 0;
133
+ }
134
+ export function prismaConnectionWaitFailure(facts) {
135
+ const limit = facts.maxWait === undefined
136
+ ? "the PrismaClient's maxWait (2000 ms unless set on the client)"
137
+ : `the adapter's maxWait (${facts.maxWait} ms)`;
138
+ return new AvError("A3002", {
139
+ message: `This call waited ${Math.round(facts.waitedMs)} ms for the SQLite connection, which another request's transaction held, and gave up when ${limit} ran out: it never ran and wrote nothing. Raise the adapter's transactionOptions.maxWait, or keep the transaction that holds the connection shorter.`,
140
+ });
141
+ }
130
142
  export function prismaValueFailure(refusal, path = []) {
131
143
  const { code, message } = DATABASE_REFUSALS[refusal];
132
144
  return new AvError("A2004", {
@@ -1,5 +1,5 @@
1
1
  import { emitAdapterWarning } from "../adapter-warning.emitter.js";
2
- import { classifyPrismaStatementError, prismaOutcomeFailure, } from "../errors/error.normalizer.js";
2
+ import { classifyPrismaStatementError, isPrismaAcquisitionTimeout, prismaConnectionWaitFailure, prismaOutcomeFailure, } from "../errors/error.normalizer.js";
3
3
  const TRANSACTION_JOINED_WARNING = "AVENTARA_PRISMA_SQLITE_TRANSACTION_JOINED";
4
4
  const warnedJoins = new Set();
5
5
  function warnJoined(call) {
@@ -40,7 +40,9 @@ export function createSharedConnectionRouter(dependencies) {
40
40
  return work(joined.client);
41
41
  }
42
42
  let thrownByWork = false;
43
+ let started = false;
43
44
  const run = async (transactional) => {
45
+ started = true;
44
46
  try {
45
47
  return await within(transactional, () => work(transactional));
46
48
  }
@@ -50,6 +52,7 @@ export function createSharedConnectionRouter(dependencies) {
50
52
  }
51
53
  };
52
54
  const options = dependencies.transactionOptions;
55
+ const waitedFrom = performance.now();
53
56
  try {
54
57
  return await (options === undefined
55
58
  ? dependencies.client.$transaction(run)
@@ -61,7 +64,14 @@ export function createSharedConnectionRouter(dependencies) {
61
64
  }
62
65
  const classification = classifyPrismaStatementError(error);
63
66
  if (classification.kind === "outcome") {
64
- throw prismaOutcomeFailure(classification.code);
67
+ const waitedMs = performance.now() - waitedFrom;
68
+ const maxWait = options?.maxWait;
69
+ const waitedOut = !started &&
70
+ isPrismaAcquisitionTimeout(error) &&
71
+ (maxWait === undefined || waitedMs + 1 >= maxWait);
72
+ throw waitedOut
73
+ ? prismaConnectionWaitFailure({ waitedMs, maxWait })
74
+ : prismaOutcomeFailure(classification.code);
65
75
  }
66
76
  throw error;
67
77
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aventara/prisma7-adapter",
3
- "version": "1.0.0-rc.13",
3
+ "version": "1.0.0-rc.14",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "The Prisma 7 adapter for Aventara.",
6
6
  "type": "module",
@@ -30,7 +30,7 @@
30
30
  "CHANGELOG.md"
31
31
  ],
32
32
  "dependencies": {
33
- "@aventara/core": "1.0.0-rc.13"
33
+ "@aventara/core": "1.0.0-rc.14"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@prisma/adapter-better-sqlite3": "^7.10.1",