@prisma/orm-target-postgres 8.0.0-rc.4-dev.7 → 8.0.0-rc.4-dev.8

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.
@@ -0,0 +1,645 @@
1
+ import { i as postgresDriverDescriptorMeta, n as isPostgresError, r as normalizePgError, t as isAlreadyConnectedError } from "./normalize-error-CNjgVO71-CLlZ3CuJ.mjs";
2
+ import { blindCast } from "@prisma/orm-framework/utils/casts";
3
+ import { suppressIdleConnectionErrors, suppressIdleConnectionErrors as suppressIdleConnectionErrors$1 } from "@prisma/orm-framework/utils/suppress-idle-connection-errors";
4
+ import { Pool } from "pg";
5
+ import Cursor from "pg-cursor";
6
+ //#region ../../../3-targets/7-drivers/postgres/dist/runtime.mjs
7
+ function driverError(code, message, details) {
8
+ const error = new Error(message);
9
+ Object.defineProperty(error, "name", {
10
+ value: "RuntimeError",
11
+ configurable: true
12
+ });
13
+ return details === void 0 ? Object.assign(error, {
14
+ code,
15
+ category: "DRIVER",
16
+ severity: "error"
17
+ }) : Object.assign(error, {
18
+ code,
19
+ category: "DRIVER",
20
+ severity: "error",
21
+ details
22
+ });
23
+ }
24
+ function callbackToPromise(fn) {
25
+ return new Promise((resolve, reject) => {
26
+ fn((err, result) => {
27
+ if (err) {
28
+ reject(err);
29
+ return;
30
+ }
31
+ resolve(result);
32
+ });
33
+ });
34
+ }
35
+ let nextNamedPortalId = 1;
36
+ /** Streaming cursor for a server-side named prepared statement. */
37
+ var NamedCursor = class extends Cursor {
38
+ name;
39
+ constructor(opts) {
40
+ super(opts.text, [...opts.values], opts.config);
41
+ this.name = opts.name;
42
+ this.submit = this.submitNamed;
43
+ }
44
+ submitNamed(connection) {
45
+ const self = this;
46
+ const conn = connection;
47
+ self.state = "submitted";
48
+ self.connection = conn;
49
+ self._portal = `np_${nextNamedPortalId++}`;
50
+ if (!conn.parsedStatements[this.name]) {
51
+ const parseMessage = {
52
+ text: self.text,
53
+ name: this.name,
54
+ types: []
55
+ };
56
+ conn.parse(parseMessage, true);
57
+ }
58
+ const bindMessage = {
59
+ portal: self._portal,
60
+ statement: this.name,
61
+ values: self.values ?? []
62
+ };
63
+ conn.bind(bindMessage, true);
64
+ conn.describe({
65
+ type: "P",
66
+ name: self._portal
67
+ }, true);
68
+ conn.flush();
69
+ if (self._conf.types) self._result._getTypeParser = self._conf.types.getTypeParser;
70
+ conn.once("noData", self._ifNoData);
71
+ conn.once("rowDescription", self._rowDescription);
72
+ }
73
+ };
74
+ const DEFAULT_BATCH_SIZE = 100;
75
+ const DEFAULT_PREPARED_STATEMENTS = true;
76
+ function createHandleAllocator() {
77
+ let next = 1;
78
+ return { mint: () => `pn_${next++}` };
79
+ }
80
+ function buildConnectionOptions(options) {
81
+ return {
82
+ ...options.cursor?.disabled ? { cursorDisabled: true } : {
83
+ cursorBatchSize: options.cursor?.batchSize ?? DEFAULT_BATCH_SIZE,
84
+ cursorDisabled: false
85
+ },
86
+ preparedStatementsEnabled: options.preparedStatements ?? DEFAULT_PREPARED_STATEMENTS,
87
+ handleAllocator: createHandleAllocator()
88
+ };
89
+ }
90
+ function isStalePreparedStatementError(error) {
91
+ if (!(error instanceof Error) || !("code" in error) || typeof error.code !== "string") return false;
92
+ const code = error.code;
93
+ return code === "26000" || code === "0A000";
94
+ }
95
+ var AsyncMutex = class {
96
+ #queue = Promise.resolve();
97
+ async lock() {
98
+ const previous = this.#queue;
99
+ let releaseLock;
100
+ this.#queue = new Promise((resolve) => {
101
+ releaseLock = resolve;
102
+ });
103
+ await previous;
104
+ return () => {
105
+ releaseLock?.();
106
+ releaseLock = void 0;
107
+ };
108
+ }
109
+ };
110
+ const clientQueryLocks = /* @__PURE__ */ new WeakMap();
111
+ function acquireClientQueryLock(client) {
112
+ let mutex = clientQueryLocks.get(client);
113
+ if (mutex === void 0) {
114
+ mutex = new AsyncMutex();
115
+ clientQueryLocks.set(client, mutex);
116
+ }
117
+ return mutex.lock();
118
+ }
119
+ var PostgresQueryable = class {
120
+ options;
121
+ constructor(options) {
122
+ this.options = options;
123
+ }
124
+ async *query(request) {
125
+ try {
126
+ const preparedStatementHandle = request.preparedStatementHandle;
127
+ if (preparedStatementHandle === void 0 || !this.options.preparedStatementsEnabled) {
128
+ yield* this.runQuery(request);
129
+ return;
130
+ }
131
+ const name = this.preparedStatementName(preparedStatementHandle);
132
+ yield* this.withStaleHandleStreamRetry(preparedStatementHandle, name, (name) => this.runQuery(request, name));
133
+ } catch (error) {
134
+ throw normalizePgError(error);
135
+ }
136
+ }
137
+ async execute(request) {
138
+ try {
139
+ const preparedStatementHandle = request.preparedStatementHandle;
140
+ if (preparedStatementHandle === void 0 || !this.options.preparedStatementsEnabled) return await this.runExecute(request);
141
+ const name = this.preparedStatementName(preparedStatementHandle);
142
+ return await this.withStaleHandleRetry(preparedStatementHandle, name, (name) => this.runExecute(request, name));
143
+ } catch (error) {
144
+ throw normalizePgError(error);
145
+ }
146
+ }
147
+ preparedStatementName(handle) {
148
+ const existingName = handle.get();
149
+ if (typeof existingName === "string") return existingName;
150
+ const mintedName = this.options.handleAllocator.mint();
151
+ handle.set(mintedName);
152
+ return mintedName;
153
+ }
154
+ async withStaleHandleRetry(preparedStatementHandle, name, attempt) {
155
+ try {
156
+ return await attempt(name);
157
+ } catch (error) {
158
+ if (!isStalePreparedStatementError(error)) throw error;
159
+ const retryName = this.options.handleAllocator.mint();
160
+ preparedStatementHandle.set(retryName);
161
+ try {
162
+ return await attempt(retryName);
163
+ } catch (retryError) {
164
+ throw prepareFailedError(retryError, retryName);
165
+ }
166
+ }
167
+ }
168
+ async *withStaleHandleStreamRetry(preparedStatementHandle, name, attempt) {
169
+ const stream = await this.withStaleHandleRetry(preparedStatementHandle, name, async (name) => {
170
+ const iterator = attempt(name)[Symbol.asyncIterator]();
171
+ return {
172
+ iterator,
173
+ first: await iterator.next()
174
+ };
175
+ });
176
+ if (stream.first.done) return;
177
+ let streamCompleted = false;
178
+ try {
179
+ yield stream.first.value;
180
+ while (true) {
181
+ const next = await stream.iterator.next();
182
+ if (next.done) {
183
+ streamCompleted = true;
184
+ return;
185
+ }
186
+ yield next.value;
187
+ }
188
+ } finally {
189
+ if (!streamCompleted) await stream.iterator.return?.();
190
+ }
191
+ }
192
+ async runExecute(request, name) {
193
+ const client = await this.acquireClient();
194
+ try {
195
+ const releaseLock = await acquireClientQueryLock(client);
196
+ try {
197
+ return { affectedRows: (await client.query({
198
+ name,
199
+ text: request.sql,
200
+ values: blindCast(request.params ?? [])
201
+ })).rowCount ?? 0 };
202
+ } finally {
203
+ releaseLock();
204
+ }
205
+ } finally {
206
+ await this.releaseClient(client);
207
+ }
208
+ }
209
+ inExplicitTransaction() {
210
+ return false;
211
+ }
212
+ async *runQuery(request, name) {
213
+ const client = await this.acquireClient();
214
+ try {
215
+ if (!this.options.cursorDisabled) {
216
+ const releaseLock = await acquireClientQueryLock(client);
217
+ try {
218
+ for await (const row of this.streamWithPortalProtection(client, request, this.options.cursorBatchSize, name)) yield blindCast(row);
219
+ return;
220
+ } catch (cursorError) {
221
+ if (!(cursorError instanceof Error) || isPostgresError(cursorError)) throw cursorError;
222
+ } finally {
223
+ releaseLock();
224
+ }
225
+ }
226
+ for await (const row of this.executeBuffered(client, request.sql, request.params, name)) yield blindCast(row);
227
+ } finally {
228
+ await this.releaseClient(client);
229
+ }
230
+ }
231
+ async explain(request) {
232
+ const text = `EXPLAIN (FORMAT JSON) ${request.sql}`;
233
+ const client = await this.acquireClient();
234
+ try {
235
+ const releaseLock = await acquireClientQueryLock(client);
236
+ try {
237
+ return { rows: blindCast((await client.query(text, request.params === void 0 ? void 0 : [...request.params]).catch(rethrowNormalizedError)).rows) };
238
+ } finally {
239
+ releaseLock();
240
+ }
241
+ } finally {
242
+ await this.releaseClient(client);
243
+ }
244
+ }
245
+ async *streamWithPortalProtection(client, request, cursorBatchSize, name) {
246
+ if (this.inExplicitTransaction()) {
247
+ yield* this.executeWithCursor(client, request.sql, request.params, cursorBatchSize, name);
248
+ return;
249
+ }
250
+ await client.query("BEGIN");
251
+ let streamFailed = false;
252
+ try {
253
+ yield* this.executeWithCursor(client, request.sql, request.params, cursorBatchSize, name);
254
+ } catch (error) {
255
+ streamFailed = true;
256
+ throw error;
257
+ } finally {
258
+ await this.commitStreamSpan(client, streamFailed);
259
+ }
260
+ }
261
+ async commitStreamSpan(client, streamFailed) {
262
+ try {
263
+ await client.query("COMMIT");
264
+ } catch (commitError) {
265
+ if (!streamFailed) throw commitError;
266
+ }
267
+ }
268
+ async *executeWithCursor(client, sql, params, cursorBatchSize, name) {
269
+ const values = blindCast(params ?? []);
270
+ const cursor = client.query(name === void 0 ? new Cursor(sql, values) : new NamedCursor({
271
+ name,
272
+ text: sql,
273
+ values
274
+ }));
275
+ try {
276
+ while (true) {
277
+ const rows = await readCursor(cursor, cursorBatchSize);
278
+ if (rows.length === 0) break;
279
+ for (const row of rows) yield row;
280
+ }
281
+ } finally {
282
+ await closeCursor(cursor);
283
+ }
284
+ }
285
+ async *executeBuffered(client, sql, params, name) {
286
+ const config = {
287
+ name,
288
+ text: sql,
289
+ values: blindCast(params ?? [])
290
+ };
291
+ const releaseLock = await acquireClientQueryLock(client);
292
+ let result;
293
+ try {
294
+ result = await client.query(config);
295
+ } finally {
296
+ releaseLock();
297
+ }
298
+ for (const row of blindCast(result.rows)) yield row;
299
+ }
300
+ };
301
+ var PostgresConnectionImpl = class extends PostgresQueryable {
302
+ #connection;
303
+ #onRelease;
304
+ #onDestroy;
305
+ #txState;
306
+ constructor(connection, options, onRelease, onDestroy, txState) {
307
+ super(options);
308
+ this.#connection = connection;
309
+ this.#onRelease = onRelease;
310
+ this.#onDestroy = onDestroy;
311
+ this.#txState = txState ?? { open: false };
312
+ }
313
+ acquireClient() {
314
+ return Promise.resolve(this.#connection);
315
+ }
316
+ releaseClient(_client) {
317
+ return Promise.resolve();
318
+ }
319
+ inExplicitTransaction() {
320
+ return this.#txState.open;
321
+ }
322
+ async beginTransaction() {
323
+ const releaseLock = await acquireClientQueryLock(this.#connection);
324
+ try {
325
+ await this.#connection.query("BEGIN").catch(rethrowNormalizedError);
326
+ } finally {
327
+ releaseLock();
328
+ }
329
+ this.#txState.open = true;
330
+ return new PostgresTransactionImpl(this.#connection, this.options, () => {
331
+ this.#txState.open = false;
332
+ });
333
+ }
334
+ async release() {
335
+ const conn = this.#connection;
336
+ if ("release" in conn) conn.release();
337
+ const onRelease = this.#onRelease;
338
+ this.#onRelease = void 0;
339
+ this.#onDestroy = void 0;
340
+ onRelease?.();
341
+ }
342
+ async destroy(reason) {
343
+ const onDestroy = this.#onDestroy;
344
+ const onRelease = this.#onRelease;
345
+ this.#onDestroy = void 0;
346
+ this.#onRelease = void 0;
347
+ const conn = this.#connection;
348
+ if ("release" in conn) {
349
+ const releaseArg = reason instanceof Error ? reason : /* @__PURE__ */ new Error("Connection destroyed");
350
+ conn.release(releaseArg);
351
+ }
352
+ if (onDestroy) await onDestroy(reason);
353
+ else onRelease?.();
354
+ }
355
+ };
356
+ var PostgresTransactionImpl = class extends PostgresQueryable {
357
+ #connection;
358
+ #onSettled;
359
+ constructor(connection, options, onSettled) {
360
+ super(options);
361
+ this.#connection = connection;
362
+ this.#onSettled = onSettled;
363
+ }
364
+ acquireClient() {
365
+ return Promise.resolve(this.#connection);
366
+ }
367
+ releaseClient(_client) {
368
+ return Promise.resolve();
369
+ }
370
+ inExplicitTransaction() {
371
+ return true;
372
+ }
373
+ #settle() {
374
+ const onSettled = this.#onSettled;
375
+ this.#onSettled = void 0;
376
+ onSettled?.();
377
+ }
378
+ async commit() {
379
+ const releaseLock = await acquireClientQueryLock(this.#connection);
380
+ try {
381
+ await this.#connection.query("COMMIT").catch(rethrowNormalizedError);
382
+ } finally {
383
+ releaseLock();
384
+ this.#settle();
385
+ }
386
+ }
387
+ async rollback() {
388
+ const releaseLock = await acquireClientQueryLock(this.#connection);
389
+ try {
390
+ await this.#connection.query("ROLLBACK").catch(rethrowNormalizedError);
391
+ } finally {
392
+ releaseLock();
393
+ this.#settle();
394
+ }
395
+ }
396
+ };
397
+ var PostgresPoolDriverImpl = class extends PostgresQueryable {
398
+ pool;
399
+ #closed = false;
400
+ constructor(options) {
401
+ super(buildConnectionOptions(options));
402
+ this.pool = options.connect.pool;
403
+ }
404
+ get state() {
405
+ return this.#closed ? "closed" : "connected";
406
+ }
407
+ async connect(_binding) {}
408
+ async acquireConnection() {
409
+ return new PostgresConnectionImpl(await this.acquireClient(), this.options);
410
+ }
411
+ async close() {
412
+ if (this.#closed) return;
413
+ this.#closed = true;
414
+ await this.pool.end();
415
+ }
416
+ async acquireClient() {
417
+ return suppressIdleConnectionErrors(await this.pool.connect());
418
+ }
419
+ async releaseClient(client) {
420
+ client.release();
421
+ }
422
+ };
423
+ var PostgresDirectDriverImpl = class extends PostgresQueryable {
424
+ directClient;
425
+ #connectionMutex = new AsyncMutex();
426
+ #closed = false;
427
+ #connected = false;
428
+ #connectPromise;
429
+ #txState = { open: false };
430
+ constructor(options) {
431
+ super(buildConnectionOptions(options));
432
+ this.directClient = options.connect.client;
433
+ this.directClient.on("error", () => {
434
+ this.#closed = true;
435
+ this.#connected = false;
436
+ });
437
+ }
438
+ inExplicitTransaction() {
439
+ return this.#txState.open;
440
+ }
441
+ get state() {
442
+ return this.#closed ? "closed" : "connected";
443
+ }
444
+ async connect(_binding) {}
445
+ async acquireConnection() {
446
+ const releaseLease = await this.#connectionMutex.lock();
447
+ try {
448
+ return new PostgresConnectionImpl(await this.acquireClient(), this.options, releaseLease, async () => {
449
+ try {
450
+ await this.#closeWhileHoldingLease();
451
+ } finally {
452
+ releaseLease();
453
+ }
454
+ }, this.#txState);
455
+ } catch (error) {
456
+ releaseLease();
457
+ throw error;
458
+ }
459
+ }
460
+ async close() {
461
+ const releaseLease = await this.#connectionMutex.lock();
462
+ try {
463
+ await this.#closeWhileHoldingLease();
464
+ } finally {
465
+ releaseLease();
466
+ }
467
+ }
468
+ async #closeWhileHoldingLease() {
469
+ if (this.#closed) return;
470
+ this.#closed = true;
471
+ await this.directClient.end();
472
+ this.#connected = false;
473
+ }
474
+ async acquireClient() {
475
+ if (this.#closed) throw driverError("DRIVER.NOT_CONNECTED", "Postgres connection lost or closed. Create a new client to reconnect.");
476
+ if (this.#connected) return this.directClient;
477
+ if (this.#connectPromise !== void 0) {
478
+ await this.#connectPromise;
479
+ return this.directClient;
480
+ }
481
+ this.#connectPromise = (async () => {
482
+ try {
483
+ await this.directClient.connect();
484
+ } catch (error) {
485
+ if (!isAlreadyConnectedError(error)) throw error;
486
+ } finally {
487
+ this.#connectPromise = void 0;
488
+ }
489
+ this.#connected = true;
490
+ })();
491
+ await this.#connectPromise;
492
+ return this.directClient;
493
+ }
494
+ async releaseClient(_client) {}
495
+ };
496
+ function createBoundDriverFromBinding(binding, cursorOpts, extraOpts) {
497
+ const preparedStatements = extraOpts?.preparedStatements;
498
+ switch (binding.kind) {
499
+ case "url": return new PostgresPoolDriverImpl({
500
+ connect: { pool: suppressIdleConnectionErrors(new Pool({
501
+ connectionString: binding.url,
502
+ connectionTimeoutMillis: 2e4,
503
+ idleTimeoutMillis: 3e4
504
+ })) },
505
+ cursor: cursorOpts,
506
+ preparedStatements
507
+ });
508
+ case "pgPool": return new PostgresPoolDriverImpl({
509
+ connect: { pool: suppressIdleConnectionErrors(binding.pool) },
510
+ cursor: cursorOpts,
511
+ preparedStatements
512
+ });
513
+ case "pgClient": return new PostgresDirectDriverImpl({
514
+ connect: { client: suppressIdleConnectionErrors(binding.client) },
515
+ cursor: cursorOpts,
516
+ preparedStatements
517
+ });
518
+ }
519
+ }
520
+ function readCursor(cursor, size) {
521
+ return callbackToPromise((cb) => {
522
+ cursor.read(size, (err, rows) => cb(err, rows));
523
+ });
524
+ }
525
+ function closeCursor(cursor) {
526
+ return callbackToPromise((cb) => cursor.close(cb));
527
+ }
528
+ function rethrowNormalizedError(error) {
529
+ throw normalizePgError(error);
530
+ }
531
+ function prepareFailedError(retryError, handle) {
532
+ const cause = normalizePgError(retryError);
533
+ return Object.assign(driverError("DRIVER.PREPARE_FAILED", `Prepared statement failed again after re-preparing with a fresh handle: ${cause.message}`, { handle }), { cause });
534
+ }
535
+ const USE_BEFORE_CONNECT_MESSAGE = "Postgres driver not connected. Call connect(binding) before acquireConnection or execute.";
536
+ const ALREADY_CONNECTED_MESSAGE = "Postgres driver already connected. Call close() before reconnecting with a new binding.";
537
+ function unboundQuery() {
538
+ return { [Symbol.asyncIterator]() {
539
+ return { async next() {
540
+ throw driverError("DRIVER.NOT_CONNECTED", USE_BEFORE_CONNECT_MESSAGE);
541
+ } };
542
+ } };
543
+ }
544
+ var PostgresUnboundDriverImpl = class {
545
+ familyId = "sql";
546
+ targetId = "postgres";
547
+ #delegate = null;
548
+ #closed = false;
549
+ #cursorOpts;
550
+ #preparedStatements;
551
+ constructor(options) {
552
+ this.#cursorOpts = options?.cursor;
553
+ this.#preparedStatements = options?.preparedStatements;
554
+ }
555
+ get state() {
556
+ if (this.#delegate !== null) return "connected";
557
+ if (this.#closed) return "closed";
558
+ return "unbound";
559
+ }
560
+ #requireDelegate() {
561
+ const delegate = this.#delegate;
562
+ if (delegate === null) throw driverError("DRIVER.NOT_CONNECTED", USE_BEFORE_CONNECT_MESSAGE);
563
+ return delegate;
564
+ }
565
+ async connect(binding) {
566
+ if (this.#delegate !== null) throw driverError("DRIVER.ALREADY_CONNECTED", ALREADY_CONNECTED_MESSAGE, { bindingKind: binding.kind });
567
+ this.#delegate = createBoundDriverFromBinding(binding, this.#cursorOpts, { preparedStatements: this.#preparedStatements });
568
+ this.#closed = false;
569
+ }
570
+ async acquireConnection() {
571
+ const delegate = this.#requireDelegate();
572
+ const connection = await delegate.acquireConnection();
573
+ return this.#wrapConnection(connection, delegate);
574
+ }
575
+ /**
576
+ * Wraps an acquired connection so that teardown paths which close the
577
+ * underlying delegate (notably `destroy()` on a pgClient binding, where
578
+ * the single socket means a destroyed connection invalidates the driver)
579
+ * also reset our own `#delegate` reference. Without this, a failed
580
+ * transaction rollback would leave the outer unbound wrapper reporting
581
+ * `connected` while routing subsequent work to an already-ended delegate.
582
+ */
583
+ #wrapConnection(connection, delegate) {
584
+ const syncDelegateState = () => {
585
+ if (this.#delegate === delegate && delegate.state === "closed") {
586
+ this.#delegate = null;
587
+ this.#closed = true;
588
+ }
589
+ };
590
+ const wrapped = {
591
+ beginTransaction: connection.beginTransaction.bind(connection),
592
+ query: connection.query.bind(connection),
593
+ execute: connection.execute.bind(connection),
594
+ release: async () => {
595
+ try {
596
+ await connection.release();
597
+ } finally {
598
+ syncDelegateState();
599
+ }
600
+ },
601
+ destroy: async (reason) => {
602
+ try {
603
+ await connection.destroy(reason);
604
+ } finally {
605
+ syncDelegateState();
606
+ }
607
+ }
608
+ };
609
+ if (connection.explain) wrapped.explain = connection.explain.bind(connection);
610
+ return wrapped;
611
+ }
612
+ async close() {
613
+ const delegate = this.#delegate;
614
+ if (delegate !== null) {
615
+ this.#delegate = null;
616
+ await delegate.close();
617
+ }
618
+ this.#closed = true;
619
+ }
620
+ query(request) {
621
+ const delegate = this.#delegate;
622
+ return delegate === null ? unboundQuery() : delegate.query(request);
623
+ }
624
+ async execute(request) {
625
+ const delegate = this.#delegate;
626
+ if (delegate === null) throw driverError("DRIVER.NOT_CONNECTED", USE_BEFORE_CONNECT_MESSAGE);
627
+ return delegate.execute(request);
628
+ }
629
+ async explain(request) {
630
+ const delegate = this.#requireDelegate();
631
+ const explain = delegate.explain;
632
+ if (explain === void 0) throw driverError("DRIVER.NOT_CONNECTED", USE_BEFORE_CONNECT_MESSAGE);
633
+ return explain.call(delegate, request);
634
+ }
635
+ };
636
+ const postgresRuntimeDriverDescriptor = {
637
+ ...postgresDriverDescriptorMeta,
638
+ create(options) {
639
+ return new PostgresUnboundDriverImpl(options);
640
+ }
641
+ };
642
+ //#endregion
643
+ export { suppressIdleConnectionErrors$1 as n, postgresRuntimeDriverDescriptor as t };
644
+
645
+ //# sourceMappingURL=runtime-C-Hh2m1R.mjs.map