@prisma-next/driver-postgres 0.4.0-dev.9 → 0.4.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/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +75 -9
- package/dist/runtime.mjs.map +1 -1
- package/package.json +9 -9
- package/src/exports/runtime.ts +42 -1
- package/src/postgres-driver.ts +71 -12
package/dist/runtime.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/postgres-driver.ts","../src/exports/runtime.ts"],"sourcesContent":[],"mappings":";;;;;KAsBY,sBAAsB,iBAAiB,kBAAkB,cAAc;KAEvE,eAAA;;EAFA,SAAA,GAAA,EAAW,MAAA;CAAW,GAAA;EAAiB,SAAA,IAAA,EAAA,QAAA;EAAgC,SAAA,IAAA,EAIrC,IAJqC;CAAd,GAAA;EAAa,SAAA,IAAA,EAAA,UAAA;EAEtE,SAAA,MAAA,EAGsC,MAHvB;AAK3B,CAAA;AAKU,UALO,qBAAA,CAKc;EACD,SAAA,SAAA,CAAA,EAAA,MAAA;EAAmB,SAAA,QAAA,CAAA,EAAA,OAAA;;UADvC,qBAAA,CAE+B;EAG7B,SAAA,OAAA,EAAA;YAJkB;;UAAmB;ECjBrC,CAAA;EAAwB,SAAA,MAAA,CAAA,EDkBhB,qBClBgB,GAAA,SAAA;;AAClC,KDoBU,2BAAA,GAA8B,ICpBxC,CDoB6C,qBCpB7C,EAAA,SAAA,CAAA;;;KADU,qBAAA,GAAwB,2CAClC,UAAU;
|
|
1
|
+
{"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/postgres-driver.ts","../src/exports/runtime.ts"],"sourcesContent":[],"mappings":";;;;;KAsBY,sBAAsB,iBAAiB,kBAAkB,cAAc;KAEvE,eAAA;;EAFA,SAAA,GAAA,EAAW,MAAA;CAAW,GAAA;EAAiB,SAAA,IAAA,EAAA,QAAA;EAAgC,SAAA,IAAA,EAIrC,IAJqC;CAAd,GAAA;EAAa,SAAA,IAAA,EAAA,UAAA;EAEtE,SAAA,MAAA,EAGsC,MAHvB;AAK3B,CAAA;AAKU,UALO,qBAAA,CAKc;EACD,SAAA,SAAA,CAAA,EAAA,MAAA;EAAmB,SAAA,QAAA,CAAA,EAAA,OAAA;;UADvC,qBAAA,CAE+B;EAG7B,SAAA,OAAA,EAAA;YAJkB;;UAAmB;ECjBrC,CAAA;EAAwB,SAAA,MAAA,CAAA,EDkBhB,qBClBgB,GAAA,SAAA;;AAClC,KDoBU,2BAAA,GAA8B,ICpBxC,CDoB6C,qBCpB7C,EAAA,SAAA,CAAA;;;KADU,qBAAA,GAAwB,2CAClC,UAAU;cAsKN,iCAAiC,2CAGrC,6BACA"}
|
package/dist/runtime.mjs
CHANGED
|
@@ -92,10 +92,12 @@ var PostgresQueryable = class {
|
|
|
92
92
|
var PostgresConnectionImpl = class extends PostgresQueryable {
|
|
93
93
|
#connection;
|
|
94
94
|
#onRelease;
|
|
95
|
-
|
|
95
|
+
#onDestroy;
|
|
96
|
+
constructor(connection, options, onRelease, onDestroy) {
|
|
96
97
|
super(options);
|
|
97
98
|
this.#connection = connection;
|
|
98
99
|
this.#onRelease = onRelease;
|
|
100
|
+
this.#onDestroy = onDestroy;
|
|
99
101
|
}
|
|
100
102
|
acquireClient() {
|
|
101
103
|
return Promise.resolve(this.#connection);
|
|
@@ -108,9 +110,25 @@ var PostgresConnectionImpl = class extends PostgresQueryable {
|
|
|
108
110
|
return new PostgresTransactionImpl(this.#connection, this.options);
|
|
109
111
|
}
|
|
110
112
|
async release() {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
const conn = this.#connection;
|
|
114
|
+
if ("release" in conn) conn.release();
|
|
115
|
+
const onRelease = this.#onRelease;
|
|
113
116
|
this.#onRelease = void 0;
|
|
117
|
+
this.#onDestroy = void 0;
|
|
118
|
+
onRelease?.();
|
|
119
|
+
}
|
|
120
|
+
async destroy(reason) {
|
|
121
|
+
const onDestroy = this.#onDestroy;
|
|
122
|
+
const onRelease = this.#onRelease;
|
|
123
|
+
this.#onDestroy = void 0;
|
|
124
|
+
this.#onRelease = void 0;
|
|
125
|
+
const conn = this.#connection;
|
|
126
|
+
if ("release" in conn) {
|
|
127
|
+
const releaseArg = reason instanceof Error ? reason : /* @__PURE__ */ new Error("Connection destroyed");
|
|
128
|
+
conn.release(releaseArg);
|
|
129
|
+
}
|
|
130
|
+
if (onDestroy) await onDestroy(reason);
|
|
131
|
+
else onRelease?.();
|
|
114
132
|
}
|
|
115
133
|
};
|
|
116
134
|
var PostgresTransactionImpl = class extends PostgresQueryable {
|
|
@@ -181,7 +199,13 @@ var PostgresDirectDriverImpl = class extends PostgresQueryable {
|
|
|
181
199
|
async acquireConnection() {
|
|
182
200
|
const releaseLease = await this.#connectionMutex.lock();
|
|
183
201
|
try {
|
|
184
|
-
return new PostgresConnectionImpl(await this.acquireClient(), this.options, releaseLease)
|
|
202
|
+
return new PostgresConnectionImpl(await this.acquireClient(), this.options, releaseLease, async () => {
|
|
203
|
+
try {
|
|
204
|
+
await this.#closeWhileHoldingLease();
|
|
205
|
+
} finally {
|
|
206
|
+
releaseLease();
|
|
207
|
+
}
|
|
208
|
+
});
|
|
185
209
|
} catch (error) {
|
|
186
210
|
releaseLease();
|
|
187
211
|
throw error;
|
|
@@ -190,14 +214,17 @@ var PostgresDirectDriverImpl = class extends PostgresQueryable {
|
|
|
190
214
|
async close() {
|
|
191
215
|
const releaseLease = await this.#connectionMutex.lock();
|
|
192
216
|
try {
|
|
193
|
-
|
|
194
|
-
this.#closed = true;
|
|
195
|
-
await this.directClient.end();
|
|
196
|
-
this.#connected = false;
|
|
217
|
+
await this.#closeWhileHoldingLease();
|
|
197
218
|
} finally {
|
|
198
219
|
releaseLease();
|
|
199
220
|
}
|
|
200
221
|
}
|
|
222
|
+
async #closeWhileHoldingLease() {
|
|
223
|
+
if (this.#closed) return;
|
|
224
|
+
this.#closed = true;
|
|
225
|
+
await this.directClient.end();
|
|
226
|
+
this.#connected = false;
|
|
227
|
+
}
|
|
201
228
|
async acquireClient() {
|
|
202
229
|
if (this.#connected) return this.directClient;
|
|
203
230
|
if (this.#connectPromise !== void 0) {
|
|
@@ -301,7 +328,46 @@ var PostgresUnboundDriverImpl = class {
|
|
|
301
328
|
this.#closed = false;
|
|
302
329
|
}
|
|
303
330
|
async acquireConnection() {
|
|
304
|
-
|
|
331
|
+
const delegate = this.#requireDelegate();
|
|
332
|
+
const connection = await delegate.acquireConnection();
|
|
333
|
+
return this.#wrapConnection(connection, delegate);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Wraps an acquired connection so that teardown paths which close the
|
|
337
|
+
* underlying delegate (notably `destroy()` on a pgClient binding, where
|
|
338
|
+
* the single socket means a destroyed connection invalidates the driver)
|
|
339
|
+
* also reset our own `#delegate` reference. Without this, a failed
|
|
340
|
+
* transaction rollback would leave the outer unbound wrapper reporting
|
|
341
|
+
* `connected` while routing subsequent work to an already-ended delegate.
|
|
342
|
+
*/
|
|
343
|
+
#wrapConnection(connection, delegate) {
|
|
344
|
+
const syncDelegateState = () => {
|
|
345
|
+
if (this.#delegate === delegate && delegate.state === "closed") {
|
|
346
|
+
this.#delegate = null;
|
|
347
|
+
this.#closed = true;
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
const wrapped = {
|
|
351
|
+
beginTransaction: connection.beginTransaction.bind(connection),
|
|
352
|
+
execute: connection.execute.bind(connection),
|
|
353
|
+
query: connection.query.bind(connection),
|
|
354
|
+
release: async () => {
|
|
355
|
+
try {
|
|
356
|
+
await connection.release();
|
|
357
|
+
} finally {
|
|
358
|
+
syncDelegateState();
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
destroy: async (reason) => {
|
|
362
|
+
try {
|
|
363
|
+
await connection.destroy(reason);
|
|
364
|
+
} finally {
|
|
365
|
+
syncDelegateState();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
if (connection.explain) wrapped.explain = connection.explain.bind(connection);
|
|
370
|
+
return wrapped;
|
|
305
371
|
}
|
|
306
372
|
async close() {
|
|
307
373
|
const delegate = this.#delegate;
|
package/dist/runtime.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.mjs","names":["#queue","releaseLock: (() => void) | undefined","#connection","#onRelease","#closed","#connectionMutex","#connected","#connectPromise","error: unknown","#cursorOpts","#delegate","#closed","#requireDelegate","postgresRuntimeDriverDescriptor: RuntimeDriverDescriptor<\n 'sql',\n 'postgres',\n PostgresDriverCreateOptions,\n PostgresRuntimeDriver\n>"],"sources":["../src/callback-to-promise.ts","../src/postgres-driver.ts","../src/exports/runtime.ts"],"sourcesContent":["/**\n * Wraps a Node-style callback function into a Promise.\n * Supports both (err) => void and (err, result) => void patterns.\n */\nexport function callbackToPromise(\n fn: (callback: (err: Error | null | undefined) => void) => void,\n): Promise<void>;\nexport function callbackToPromise<T>(\n fn: (callback: (err: Error | null | undefined, result: T) => void) => void,\n): Promise<T>;\nexport function callbackToPromise<T = void>(\n fn: (callback: (err: Error | null | undefined, result?: T) => void) => void,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n fn((err, result) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(result as T);\n });\n });\n}\n","import type {\n SqlConnection,\n SqlDriver,\n SqlDriverState,\n SqlExecuteRequest,\n SqlExplainResult,\n SqlQueryable,\n SqlQueryResult,\n SqlTransaction,\n} from '@prisma-next/sql-relational-core/ast';\nimport type {\n Client,\n QueryResult as PgQueryResult,\n PoolClient,\n Pool as PoolType,\n QueryResultRow,\n} from 'pg';\nimport { Pool } from 'pg';\nimport Cursor from 'pg-cursor';\nimport { callbackToPromise } from './callback-to-promise';\nimport { isAlreadyConnectedError, isPostgresError, normalizePgError } from './normalize-error';\n\nexport type QueryResult<T extends QueryResultRow = QueryResultRow> = PgQueryResult<T>;\n\nexport type PostgresBinding =\n | { readonly kind: 'url'; readonly url: string }\n | { readonly kind: 'pgPool'; readonly pool: PoolType }\n | { readonly kind: 'pgClient'; readonly client: Client };\n\nexport interface PostgresCursorOptions {\n readonly batchSize?: number;\n readonly disabled?: boolean;\n}\n\ninterface PostgresDriverOptions {\n readonly connect: { client: Client } | { pool: PoolType };\n readonly cursor?: PostgresCursorOptions | undefined;\n}\n\nexport type PostgresDriverCreateOptions = Omit<PostgresDriverOptions, 'connect'>;\n\nconst DEFAULT_BATCH_SIZE = 100;\n\ntype ConnectionOptions =\n | { readonly cursorDisabled: true }\n | { readonly cursorBatchSize: number; readonly cursorDisabled: false };\n\nclass AsyncMutex {\n #queue = Promise.resolve();\n\n async lock(): Promise<() => void> {\n const previous = this.#queue;\n let releaseLock: (() => void) | undefined;\n this.#queue = new Promise<void>((resolve) => {\n releaseLock = resolve;\n });\n await previous;\n return () => {\n releaseLock?.();\n releaseLock = undefined;\n };\n }\n}\n\nabstract class PostgresQueryable<C extends PoolClient | Client = PoolClient | Client>\n implements SqlQueryable\n{\n abstract acquireClient(): Promise<C>;\n abstract releaseClient(client: C): Promise<void>;\n\n protected readonly options: ConnectionOptions;\n\n constructor(options: ConnectionOptions) {\n this.options = options;\n }\n\n async *execute<Row = Record<string, unknown>>(request: SqlExecuteRequest): AsyncIterable<Row> {\n const client = await this.acquireClient();\n try {\n if (!this.options.cursorDisabled) {\n try {\n for await (const row of this.executeWithCursor(\n client,\n request.sql,\n request.params,\n this.options.cursorBatchSize,\n )) {\n yield row as Row;\n }\n return;\n } catch (cursorError) {\n if (!(cursorError instanceof Error)) {\n throw cursorError;\n }\n // Check if this is a pg error - if so, normalize and throw\n // Otherwise, fall back to buffered mode for cursor-specific errors\n if (isPostgresError(cursorError)) {\n throw normalizePgError(cursorError);\n }\n // Not a pg error - cursor-specific error, fall back to buffered mode\n }\n }\n\n for await (const row of this.executeBuffered(client, request.sql, request.params)) {\n yield row as Row;\n }\n } catch (error) {\n throw normalizePgError(error);\n } finally {\n await this.releaseClient(client);\n }\n }\n\n async explain(request: SqlExecuteRequest): Promise<SqlExplainResult> {\n // SQL is generated by Prisma Next planners (or validated raw paths), so\n // EXPLAIN prefixing preserves the same statement semantics.\n const text = `EXPLAIN (FORMAT JSON) ${request.sql}`;\n const client = await this.acquireClient();\n try {\n const result = await client\n .query(text, request.params as unknown[] | undefined)\n .catch(rethrowNormalizedError);\n return { rows: result.rows as ReadonlyArray<Record<string, unknown>> };\n } finally {\n await this.releaseClient(client);\n }\n }\n\n async query<Row = Record<string, unknown>>(\n sql: string,\n params?: readonly unknown[],\n ): Promise<SqlQueryResult<Row>> {\n const client = await this.acquireClient();\n try {\n const result = await client\n .query(sql, params as unknown[] | undefined)\n .catch(rethrowNormalizedError);\n return result as unknown as SqlQueryResult<Row>;\n } finally {\n await this.releaseClient(client);\n }\n }\n\n private async *executeWithCursor(\n client: PoolClient | Client,\n sql: string,\n params: readonly unknown[] | undefined,\n cursorBatchSize: number,\n ): AsyncIterable<Record<string, unknown>> {\n const cursor = client.query(new Cursor(sql, params as unknown[] | undefined));\n\n try {\n while (true) {\n const rows = await readCursor(cursor, cursorBatchSize);\n if (rows.length === 0) {\n break;\n }\n\n for (const row of rows) {\n yield row;\n }\n }\n } finally {\n await closeCursor(cursor);\n }\n }\n\n private async *executeBuffered(\n client: PoolClient | Client,\n sql: string,\n params: readonly unknown[] | undefined,\n ): AsyncIterable<Record<string, unknown>> {\n const result = await client.query(sql, params as unknown[] | undefined);\n for (const row of result.rows as Record<string, unknown>[]) {\n yield row;\n }\n }\n}\n\nclass PostgresConnectionImpl extends PostgresQueryable implements SqlConnection {\n #connection: PoolClient | Client;\n #onRelease: (() => void) | undefined;\n\n constructor(connection: PoolClient | Client, options: ConnectionOptions, onRelease?: () => void) {\n super(options);\n this.#connection = connection;\n this.#onRelease = onRelease;\n }\n\n override acquireClient(): Promise<PoolClient | Client> {\n return Promise.resolve(this.#connection);\n }\n\n override releaseClient(_client: PoolClient | Client): Promise<void> {\n return Promise.resolve();\n }\n\n async beginTransaction(): Promise<SqlTransaction> {\n await this.#connection.query('BEGIN').catch(rethrowNormalizedError);\n return new PostgresTransactionImpl(this.#connection, this.options);\n }\n\n async release(): Promise<void> {\n if ('release' in this.#connection) {\n this.#connection.release();\n }\n this.#onRelease?.();\n this.#onRelease = undefined;\n }\n}\n\nclass PostgresTransactionImpl extends PostgresQueryable implements SqlTransaction {\n #connection: PoolClient | Client;\n\n constructor(connection: PoolClient | Client, options: ConnectionOptions) {\n super(options);\n this.#connection = connection;\n }\n\n override acquireClient(): Promise<PoolClient | Client> {\n return Promise.resolve(this.#connection);\n }\n\n override releaseClient(_client: PoolClient | Client): Promise<void> {\n return Promise.resolve();\n }\n\n async commit(): Promise<void> {\n await this.#connection.query('COMMIT').catch(rethrowNormalizedError);\n }\n\n async rollback(): Promise<void> {\n await this.#connection.query('ROLLBACK').catch(rethrowNormalizedError);\n }\n}\n\nclass PostgresPoolDriverImpl\n extends PostgresQueryable<PoolClient>\n implements SqlDriver<PostgresBinding>\n{\n private readonly pool: PoolType;\n #closed = false;\n\n constructor(options: PostgresDriverOptions & { connect: { pool: PoolType } }) {\n super({\n cursorBatchSize: options.cursor?.batchSize ?? DEFAULT_BATCH_SIZE,\n cursorDisabled: options.cursor?.disabled ?? false,\n });\n this.pool = options.connect.pool;\n }\n\n get state(): SqlDriverState {\n return this.#closed ? 'closed' : 'connected';\n }\n\n // Bound drivers are created via createBoundDriverFromBinding with pool already\n // configured; connect is intentionally no-op.\n async connect(_binding: PostgresBinding): Promise<void> {}\n\n async acquireConnection(): Promise<SqlConnection> {\n const client = await this.acquireClient();\n return new PostgresConnectionImpl(client, this.options);\n }\n\n async close(): Promise<void> {\n if (this.#closed) {\n return;\n }\n this.#closed = true;\n await this.pool.end();\n }\n\n async acquireClient(): Promise<PoolClient> {\n return this.pool.connect();\n }\n\n async releaseClient(client: PoolClient): Promise<void> {\n client.release();\n }\n}\n\nclass PostgresDirectDriverImpl\n extends PostgresQueryable<Client>\n implements SqlDriver<PostgresBinding>\n{\n private readonly directClient: Client;\n readonly #connectionMutex = new AsyncMutex();\n #closed = false;\n #connected = false;\n #connectPromise: Promise<void> | undefined;\n\n constructor(options: PostgresDriverOptions & { connect: { client: Client } }) {\n super({\n cursorBatchSize: options.cursor?.batchSize ?? DEFAULT_BATCH_SIZE,\n cursorDisabled: options.cursor?.disabled ?? false,\n });\n this.directClient = options.connect.client;\n }\n\n get state(): SqlDriverState {\n return this.#closed ? 'closed' : 'connected';\n }\n\n // Bound drivers are created via createBoundDriverFromBinding with client already\n // configured; connect is intentionally no-op.\n async connect(_binding: PostgresBinding): Promise<void> {}\n\n async acquireConnection(): Promise<SqlConnection> {\n const releaseLease = await this.#connectionMutex.lock();\n try {\n const client = await this.acquireClient();\n return new PostgresConnectionImpl(client, this.options, releaseLease);\n } catch (error) {\n releaseLease();\n throw error;\n }\n }\n\n async close(): Promise<void> {\n const releaseLease = await this.#connectionMutex.lock();\n try {\n if (this.#closed) {\n return;\n }\n this.#closed = true;\n await this.directClient.end();\n this.#connected = false;\n } finally {\n releaseLease();\n }\n }\n\n async acquireClient(): Promise<Client> {\n if (this.#connected) {\n return this.directClient;\n }\n if (this.#connectPromise !== undefined) {\n await this.#connectPromise;\n return this.directClient;\n }\n\n this.#connectPromise = (async () => {\n try {\n await this.directClient.connect();\n } catch (error: unknown) {\n if (!isAlreadyConnectedError(error)) {\n throw error;\n }\n } finally {\n this.#connectPromise = undefined;\n }\n this.#connected = true;\n })();\n await this.#connectPromise;\n\n return this.directClient;\n }\n\n async releaseClient(_client: Client): Promise<void> {}\n}\n\nexport function createBoundDriverFromBinding(\n binding: PostgresBinding,\n cursorOpts: PostgresDriverCreateOptions['cursor'],\n): SqlDriver<PostgresBinding> {\n switch (binding.kind) {\n case 'url': {\n const pool = new Pool({\n connectionString: binding.url,\n connectionTimeoutMillis: 20_000,\n idleTimeoutMillis: 30_000,\n });\n return new PostgresPoolDriverImpl({\n connect: { pool },\n cursor: cursorOpts,\n });\n }\n case 'pgPool':\n return new PostgresPoolDriverImpl({\n connect: { pool: binding.pool },\n cursor: cursorOpts,\n });\n case 'pgClient':\n return new PostgresDirectDriverImpl({\n connect: { client: binding.client },\n cursor: cursorOpts,\n });\n }\n}\n\nfunction readCursor<Row>(cursor: Cursor<Row>, size: number): Promise<Row[]> {\n return callbackToPromise<Row[]>((cb) => {\n cursor.read(size, (err, rows) => cb(err, rows));\n });\n}\n\nfunction closeCursor(cursor: Cursor<unknown>): Promise<void> {\n return callbackToPromise((cb) => cursor.close(cb));\n}\n\nfunction rethrowNormalizedError(error: unknown): never {\n throw normalizePgError(error);\n}\n","import type {\n RuntimeDriverDescriptor,\n RuntimeDriverInstance,\n} from '@prisma-next/framework-components/execution';\nimport type {\n SqlConnection,\n SqlDriver,\n SqlExecuteRequest,\n SqlExplainResult,\n SqlQueryResult,\n} from '@prisma-next/sql-relational-core/ast';\nimport { postgresDriverDescriptorMeta } from '../core/descriptor-meta';\nimport {\n createBoundDriverFromBinding,\n type PostgresBinding,\n type PostgresDriverCreateOptions,\n} from '../postgres-driver';\n\nexport type PostgresRuntimeDriver = RuntimeDriverInstance<'sql', 'postgres'> &\n SqlDriver<PostgresBinding>;\n\nconst USE_BEFORE_CONNECT_MESSAGE =\n 'Postgres driver not connected. Call connect(binding) before acquireConnection or execute.';\nconst ALREADY_CONNECTED_MESSAGE =\n 'Postgres driver already connected. Call close() before reconnecting with a new binding.';\n\ninterface DriverRuntimeError extends Error {\n readonly code: 'DRIVER.NOT_CONNECTED' | 'DRIVER.ALREADY_CONNECTED';\n readonly category: 'RUNTIME';\n readonly severity: 'error';\n readonly details?: Record<string, unknown>;\n}\n\nfunction driverError(\n code: DriverRuntimeError['code'],\n message: string,\n details?: Record<string, unknown>,\n): DriverRuntimeError {\n const error = new Error(message) as DriverRuntimeError;\n Object.defineProperty(error, 'name', {\n value: 'RuntimeError',\n configurable: true,\n });\n return Object.assign(error, {\n code,\n category: 'RUNTIME' as const,\n severity: 'error' as const,\n message,\n details,\n });\n}\n\nfunction unboundExecute<Row>(): AsyncIterable<Row> {\n return {\n [Symbol.asyncIterator]() {\n return {\n async next() {\n throw driverError('DRIVER.NOT_CONNECTED', USE_BEFORE_CONNECT_MESSAGE);\n },\n };\n },\n };\n}\n\nclass PostgresUnboundDriverImpl implements PostgresRuntimeDriver {\n readonly familyId = 'sql' as const;\n readonly targetId = 'postgres' as const;\n\n #delegate: SqlDriver<PostgresBinding> | null = null;\n #closed = false;\n #cursorOpts: PostgresDriverCreateOptions['cursor'];\n\n constructor(cursorOpts?: PostgresDriverCreateOptions['cursor']) {\n this.#cursorOpts = cursorOpts;\n }\n\n get state(): 'unbound' | 'connected' | 'closed' {\n if (this.#delegate !== null) {\n return 'connected';\n }\n if (this.#closed) {\n return 'closed';\n }\n return 'unbound';\n }\n\n #requireDelegate(): SqlDriver<PostgresBinding> {\n const delegate = this.#delegate;\n if (delegate === null) {\n throw driverError('DRIVER.NOT_CONNECTED', USE_BEFORE_CONNECT_MESSAGE);\n }\n return delegate;\n }\n\n async connect(binding: PostgresBinding): Promise<void> {\n if (this.#delegate !== null) {\n throw driverError('DRIVER.ALREADY_CONNECTED', ALREADY_CONNECTED_MESSAGE, {\n bindingKind: binding.kind,\n });\n }\n this.#delegate = createBoundDriverFromBinding(binding, this.#cursorOpts);\n this.#closed = false;\n }\n\n async acquireConnection(): Promise<SqlConnection> {\n const delegate = this.#requireDelegate();\n return delegate.acquireConnection();\n }\n\n async close(): Promise<void> {\n const delegate = this.#delegate;\n if (delegate !== null) {\n this.#delegate = null;\n await delegate.close();\n }\n this.#closed = true;\n }\n\n execute<Row = Record<string, unknown>>(request: SqlExecuteRequest): AsyncIterable<Row> {\n const delegate = this.#delegate;\n if (delegate === null) {\n return unboundExecute<Row>();\n }\n return delegate.execute<Row>(request);\n }\n\n async explain(request: SqlExecuteRequest): Promise<SqlExplainResult> {\n const delegate = this.#requireDelegate();\n const explain = delegate.explain;\n if (explain === undefined) {\n throw driverError('DRIVER.NOT_CONNECTED', USE_BEFORE_CONNECT_MESSAGE);\n }\n return explain.call(delegate, request);\n }\n\n async query<Row = Record<string, unknown>>(\n sql: string,\n params?: readonly unknown[],\n ): Promise<SqlQueryResult<Row>> {\n const delegate = this.#requireDelegate();\n return delegate.query<Row>(sql, params);\n }\n}\n\nconst postgresRuntimeDriverDescriptor: RuntimeDriverDescriptor<\n 'sql',\n 'postgres',\n PostgresDriverCreateOptions,\n PostgresRuntimeDriver\n> = {\n ...postgresDriverDescriptorMeta,\n create(options?: PostgresDriverCreateOptions): PostgresRuntimeDriver {\n return new PostgresUnboundDriverImpl(options?.cursor);\n },\n};\n\nexport default postgresRuntimeDriverDescriptor;\nexport type {\n PostgresBinding,\n PostgresDriverCreateOptions,\n QueryResult,\n} from '../postgres-driver';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runtime.mjs","names":["#queue","releaseLock: (() => void) | undefined","#connection","#onRelease","#onDestroy","releaseArg: Error","#closed","#connectionMutex","#closeWhileHoldingLease","#connected","#connectPromise","error: unknown","#cursorOpts","#delegate","#closed","#requireDelegate","#wrapConnection","wrapped: SqlConnection","postgresRuntimeDriverDescriptor: RuntimeDriverDescriptor<\n 'sql',\n 'postgres',\n PostgresDriverCreateOptions,\n PostgresRuntimeDriver\n>"],"sources":["../src/callback-to-promise.ts","../src/postgres-driver.ts","../src/exports/runtime.ts"],"sourcesContent":["/**\n * Wraps a Node-style callback function into a Promise.\n * Supports both (err) => void and (err, result) => void patterns.\n */\nexport function callbackToPromise(\n fn: (callback: (err: Error | null | undefined) => void) => void,\n): Promise<void>;\nexport function callbackToPromise<T>(\n fn: (callback: (err: Error | null | undefined, result: T) => void) => void,\n): Promise<T>;\nexport function callbackToPromise<T = void>(\n fn: (callback: (err: Error | null | undefined, result?: T) => void) => void,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n fn((err, result) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(result as T);\n });\n });\n}\n","import type {\n SqlConnection,\n SqlDriver,\n SqlDriverState,\n SqlExecuteRequest,\n SqlExplainResult,\n SqlQueryable,\n SqlQueryResult,\n SqlTransaction,\n} from '@prisma-next/sql-relational-core/ast';\nimport type {\n Client,\n QueryResult as PgQueryResult,\n PoolClient,\n Pool as PoolType,\n QueryResultRow,\n} from 'pg';\nimport { Pool } from 'pg';\nimport Cursor from 'pg-cursor';\nimport { callbackToPromise } from './callback-to-promise';\nimport { isAlreadyConnectedError, isPostgresError, normalizePgError } from './normalize-error';\n\nexport type QueryResult<T extends QueryResultRow = QueryResultRow> = PgQueryResult<T>;\n\nexport type PostgresBinding =\n | { readonly kind: 'url'; readonly url: string }\n | { readonly kind: 'pgPool'; readonly pool: PoolType }\n | { readonly kind: 'pgClient'; readonly client: Client };\n\nexport interface PostgresCursorOptions {\n readonly batchSize?: number;\n readonly disabled?: boolean;\n}\n\ninterface PostgresDriverOptions {\n readonly connect: { client: Client } | { pool: PoolType };\n readonly cursor?: PostgresCursorOptions | undefined;\n}\n\nexport type PostgresDriverCreateOptions = Omit<PostgresDriverOptions, 'connect'>;\n\nconst DEFAULT_BATCH_SIZE = 100;\n\ntype ConnectionOptions =\n | { readonly cursorDisabled: true }\n | { readonly cursorBatchSize: number; readonly cursorDisabled: false };\n\nclass AsyncMutex {\n #queue = Promise.resolve();\n\n async lock(): Promise<() => void> {\n const previous = this.#queue;\n let releaseLock: (() => void) | undefined;\n this.#queue = new Promise<void>((resolve) => {\n releaseLock = resolve;\n });\n await previous;\n return () => {\n releaseLock?.();\n releaseLock = undefined;\n };\n }\n}\n\nabstract class PostgresQueryable<C extends PoolClient | Client = PoolClient | Client>\n implements SqlQueryable\n{\n abstract acquireClient(): Promise<C>;\n abstract releaseClient(client: C): Promise<void>;\n\n protected readonly options: ConnectionOptions;\n\n constructor(options: ConnectionOptions) {\n this.options = options;\n }\n\n async *execute<Row = Record<string, unknown>>(request: SqlExecuteRequest): AsyncIterable<Row> {\n const client = await this.acquireClient();\n try {\n if (!this.options.cursorDisabled) {\n try {\n for await (const row of this.executeWithCursor(\n client,\n request.sql,\n request.params,\n this.options.cursorBatchSize,\n )) {\n yield row as Row;\n }\n return;\n } catch (cursorError) {\n if (!(cursorError instanceof Error)) {\n throw cursorError;\n }\n // Check if this is a pg error - if so, normalize and throw\n // Otherwise, fall back to buffered mode for cursor-specific errors\n if (isPostgresError(cursorError)) {\n throw normalizePgError(cursorError);\n }\n // Not a pg error - cursor-specific error, fall back to buffered mode\n }\n }\n\n for await (const row of this.executeBuffered(client, request.sql, request.params)) {\n yield row as Row;\n }\n } catch (error) {\n throw normalizePgError(error);\n } finally {\n await this.releaseClient(client);\n }\n }\n\n async explain(request: SqlExecuteRequest): Promise<SqlExplainResult> {\n // SQL is generated by Prisma Next planners (or validated raw paths), so\n // EXPLAIN prefixing preserves the same statement semantics.\n const text = `EXPLAIN (FORMAT JSON) ${request.sql}`;\n const client = await this.acquireClient();\n try {\n const result = await client\n .query(text, request.params as unknown[] | undefined)\n .catch(rethrowNormalizedError);\n return { rows: result.rows as ReadonlyArray<Record<string, unknown>> };\n } finally {\n await this.releaseClient(client);\n }\n }\n\n async query<Row = Record<string, unknown>>(\n sql: string,\n params?: readonly unknown[],\n ): Promise<SqlQueryResult<Row>> {\n const client = await this.acquireClient();\n try {\n const result = await client\n .query(sql, params as unknown[] | undefined)\n .catch(rethrowNormalizedError);\n return result as unknown as SqlQueryResult<Row>;\n } finally {\n await this.releaseClient(client);\n }\n }\n\n private async *executeWithCursor(\n client: PoolClient | Client,\n sql: string,\n params: readonly unknown[] | undefined,\n cursorBatchSize: number,\n ): AsyncIterable<Record<string, unknown>> {\n const cursor = client.query(new Cursor(sql, params as unknown[] | undefined));\n\n try {\n while (true) {\n const rows = await readCursor(cursor, cursorBatchSize);\n if (rows.length === 0) {\n break;\n }\n\n for (const row of rows) {\n yield row;\n }\n }\n } finally {\n await closeCursor(cursor);\n }\n }\n\n private async *executeBuffered(\n client: PoolClient | Client,\n sql: string,\n params: readonly unknown[] | undefined,\n ): AsyncIterable<Record<string, unknown>> {\n const result = await client.query(sql, params as unknown[] | undefined);\n for (const row of result.rows as Record<string, unknown>[]) {\n yield row;\n }\n }\n}\n\nclass PostgresConnectionImpl extends PostgresQueryable implements SqlConnection {\n #connection: PoolClient | Client;\n #onRelease: (() => void) | undefined;\n #onDestroy: ((reason: unknown) => Promise<void> | void) | undefined;\n\n constructor(\n connection: PoolClient | Client,\n options: ConnectionOptions,\n onRelease?: () => void,\n onDestroy?: (reason: unknown) => Promise<void> | void,\n ) {\n super(options);\n this.#connection = connection;\n this.#onRelease = onRelease;\n this.#onDestroy = onDestroy;\n }\n\n override acquireClient(): Promise<PoolClient | Client> {\n return Promise.resolve(this.#connection);\n }\n\n override releaseClient(_client: PoolClient | Client): Promise<void> {\n return Promise.resolve();\n }\n\n async beginTransaction(): Promise<SqlTransaction> {\n await this.#connection.query('BEGIN').catch(rethrowNormalizedError);\n return new PostgresTransactionImpl(this.#connection, this.options);\n }\n\n async release(): Promise<void> {\n const conn = this.#connection;\n if ('release' in conn) {\n conn.release();\n }\n const onRelease = this.#onRelease;\n this.#onRelease = undefined;\n this.#onDestroy = undefined;\n onRelease?.();\n }\n\n async destroy(reason?: unknown): Promise<void> {\n const onDestroy = this.#onDestroy;\n const onRelease = this.#onRelease;\n this.#onDestroy = undefined;\n this.#onRelease = undefined;\n\n const conn = this.#connection;\n if ('release' in conn) {\n // Pass a truthy Error to pg's PoolClient.release so the pool evicts the\n // client instead of returning it for reuse. A connection that reaches\n // destroy() is in an indeterminate state (failed rollback/commit, etc.)\n // and must not be handed back to another caller. The Error value is\n // surfaced on pg-pool's 'release' event as advisory context; pg-pool\n // itself only uses its truthiness for the eviction decision.\n const releaseArg: Error =\n reason instanceof Error ? reason : new Error('Connection destroyed');\n conn.release(releaseArg);\n }\n\n if (onDestroy) {\n await onDestroy(reason);\n } else {\n onRelease?.();\n }\n }\n}\n\nclass PostgresTransactionImpl extends PostgresQueryable implements SqlTransaction {\n #connection: PoolClient | Client;\n\n constructor(connection: PoolClient | Client, options: ConnectionOptions) {\n super(options);\n this.#connection = connection;\n }\n\n override acquireClient(): Promise<PoolClient | Client> {\n return Promise.resolve(this.#connection);\n }\n\n override releaseClient(_client: PoolClient | Client): Promise<void> {\n return Promise.resolve();\n }\n\n async commit(): Promise<void> {\n await this.#connection.query('COMMIT').catch(rethrowNormalizedError);\n }\n\n async rollback(): Promise<void> {\n await this.#connection.query('ROLLBACK').catch(rethrowNormalizedError);\n }\n}\n\nclass PostgresPoolDriverImpl\n extends PostgresQueryable<PoolClient>\n implements SqlDriver<PostgresBinding>\n{\n private readonly pool: PoolType;\n #closed = false;\n\n constructor(options: PostgresDriverOptions & { connect: { pool: PoolType } }) {\n super({\n cursorBatchSize: options.cursor?.batchSize ?? DEFAULT_BATCH_SIZE,\n cursorDisabled: options.cursor?.disabled ?? false,\n });\n this.pool = options.connect.pool;\n }\n\n get state(): SqlDriverState {\n return this.#closed ? 'closed' : 'connected';\n }\n\n // Bound drivers are created via createBoundDriverFromBinding with pool already\n // configured; connect is intentionally no-op.\n async connect(_binding: PostgresBinding): Promise<void> {}\n\n async acquireConnection(): Promise<SqlConnection> {\n const client = await this.acquireClient();\n return new PostgresConnectionImpl(client, this.options);\n }\n\n async close(): Promise<void> {\n if (this.#closed) {\n return;\n }\n this.#closed = true;\n await this.pool.end();\n }\n\n async acquireClient(): Promise<PoolClient> {\n return this.pool.connect();\n }\n\n async releaseClient(client: PoolClient): Promise<void> {\n client.release();\n }\n}\n\nclass PostgresDirectDriverImpl\n extends PostgresQueryable<Client>\n implements SqlDriver<PostgresBinding>\n{\n private readonly directClient: Client;\n readonly #connectionMutex = new AsyncMutex();\n #closed = false;\n #connected = false;\n #connectPromise: Promise<void> | undefined;\n\n constructor(options: PostgresDriverOptions & { connect: { client: Client } }) {\n super({\n cursorBatchSize: options.cursor?.batchSize ?? DEFAULT_BATCH_SIZE,\n cursorDisabled: options.cursor?.disabled ?? false,\n });\n this.directClient = options.connect.client;\n }\n\n get state(): SqlDriverState {\n return this.#closed ? 'closed' : 'connected';\n }\n\n // Bound drivers are created via createBoundDriverFromBinding with client already\n // configured; connect is intentionally no-op.\n async connect(_binding: PostgresBinding): Promise<void> {}\n\n async acquireConnection(): Promise<SqlConnection> {\n const releaseLease = await this.#connectionMutex.lock();\n try {\n const client = await this.acquireClient();\n return new PostgresConnectionImpl(\n client,\n this.options,\n releaseLease,\n // A direct driver has a single underlying socket, so a destroyed\n // connection means the driver itself is no longer usable. Tear down\n // the driver while still holding the lease so that any\n // acquireConnection() queued on #connectionMutex only observes the\n // driver after .end() has completed and #closed is set — preventing\n // a concurrent caller from reusing a socket that is already being\n // closed. The lease is released in a finally so a failing .end()\n // cannot leave the mutex permanently held.\n async () => {\n try {\n await this.#closeWhileHoldingLease();\n } finally {\n releaseLease();\n }\n },\n );\n } catch (error) {\n releaseLease();\n throw error;\n }\n }\n\n async close(): Promise<void> {\n const releaseLease = await this.#connectionMutex.lock();\n try {\n await this.#closeWhileHoldingLease();\n } finally {\n releaseLease();\n }\n }\n\n async #closeWhileHoldingLease(): Promise<void> {\n if (this.#closed) {\n return;\n }\n this.#closed = true;\n await this.directClient.end();\n this.#connected = false;\n }\n\n async acquireClient(): Promise<Client> {\n if (this.#connected) {\n return this.directClient;\n }\n if (this.#connectPromise !== undefined) {\n await this.#connectPromise;\n return this.directClient;\n }\n\n this.#connectPromise = (async () => {\n try {\n await this.directClient.connect();\n } catch (error: unknown) {\n if (!isAlreadyConnectedError(error)) {\n throw error;\n }\n } finally {\n this.#connectPromise = undefined;\n }\n this.#connected = true;\n })();\n await this.#connectPromise;\n\n return this.directClient;\n }\n\n async releaseClient(_client: Client): Promise<void> {}\n}\n\nexport function createBoundDriverFromBinding(\n binding: PostgresBinding,\n cursorOpts: PostgresDriverCreateOptions['cursor'],\n): SqlDriver<PostgresBinding> {\n switch (binding.kind) {\n case 'url': {\n const pool = new Pool({\n connectionString: binding.url,\n connectionTimeoutMillis: 20_000,\n idleTimeoutMillis: 30_000,\n });\n return new PostgresPoolDriverImpl({\n connect: { pool },\n cursor: cursorOpts,\n });\n }\n case 'pgPool':\n return new PostgresPoolDriverImpl({\n connect: { pool: binding.pool },\n cursor: cursorOpts,\n });\n case 'pgClient':\n return new PostgresDirectDriverImpl({\n connect: { client: binding.client },\n cursor: cursorOpts,\n });\n }\n}\n\nfunction readCursor<Row>(cursor: Cursor<Row>, size: number): Promise<Row[]> {\n return callbackToPromise<Row[]>((cb) => {\n cursor.read(size, (err, rows) => cb(err, rows));\n });\n}\n\nfunction closeCursor(cursor: Cursor<unknown>): Promise<void> {\n return callbackToPromise((cb) => cursor.close(cb));\n}\n\nfunction rethrowNormalizedError(error: unknown): never {\n throw normalizePgError(error);\n}\n","import type {\n RuntimeDriverDescriptor,\n RuntimeDriverInstance,\n} from '@prisma-next/framework-components/execution';\nimport type {\n SqlConnection,\n SqlDriver,\n SqlExecuteRequest,\n SqlExplainResult,\n SqlQueryResult,\n} from '@prisma-next/sql-relational-core/ast';\nimport { postgresDriverDescriptorMeta } from '../core/descriptor-meta';\nimport {\n createBoundDriverFromBinding,\n type PostgresBinding,\n type PostgresDriverCreateOptions,\n} from '../postgres-driver';\n\nexport type PostgresRuntimeDriver = RuntimeDriverInstance<'sql', 'postgres'> &\n SqlDriver<PostgresBinding>;\n\nconst USE_BEFORE_CONNECT_MESSAGE =\n 'Postgres driver not connected. Call connect(binding) before acquireConnection or execute.';\nconst ALREADY_CONNECTED_MESSAGE =\n 'Postgres driver already connected. Call close() before reconnecting with a new binding.';\n\ninterface DriverRuntimeError extends Error {\n readonly code: 'DRIVER.NOT_CONNECTED' | 'DRIVER.ALREADY_CONNECTED';\n readonly category: 'RUNTIME';\n readonly severity: 'error';\n readonly details?: Record<string, unknown>;\n}\n\nfunction driverError(\n code: DriverRuntimeError['code'],\n message: string,\n details?: Record<string, unknown>,\n): DriverRuntimeError {\n const error = new Error(message) as DriverRuntimeError;\n Object.defineProperty(error, 'name', {\n value: 'RuntimeError',\n configurable: true,\n });\n return Object.assign(error, {\n code,\n category: 'RUNTIME' as const,\n severity: 'error' as const,\n message,\n details,\n });\n}\n\nfunction unboundExecute<Row>(): AsyncIterable<Row> {\n return {\n [Symbol.asyncIterator]() {\n return {\n async next() {\n throw driverError('DRIVER.NOT_CONNECTED', USE_BEFORE_CONNECT_MESSAGE);\n },\n };\n },\n };\n}\n\nclass PostgresUnboundDriverImpl implements PostgresRuntimeDriver {\n readonly familyId = 'sql' as const;\n readonly targetId = 'postgres' as const;\n\n #delegate: SqlDriver<PostgresBinding> | null = null;\n #closed = false;\n #cursorOpts: PostgresDriverCreateOptions['cursor'];\n\n constructor(cursorOpts?: PostgresDriverCreateOptions['cursor']) {\n this.#cursorOpts = cursorOpts;\n }\n\n get state(): 'unbound' | 'connected' | 'closed' {\n if (this.#delegate !== null) {\n return 'connected';\n }\n if (this.#closed) {\n return 'closed';\n }\n return 'unbound';\n }\n\n #requireDelegate(): SqlDriver<PostgresBinding> {\n const delegate = this.#delegate;\n if (delegate === null) {\n throw driverError('DRIVER.NOT_CONNECTED', USE_BEFORE_CONNECT_MESSAGE);\n }\n return delegate;\n }\n\n async connect(binding: PostgresBinding): Promise<void> {\n if (this.#delegate !== null) {\n throw driverError('DRIVER.ALREADY_CONNECTED', ALREADY_CONNECTED_MESSAGE, {\n bindingKind: binding.kind,\n });\n }\n this.#delegate = createBoundDriverFromBinding(binding, this.#cursorOpts);\n this.#closed = false;\n }\n\n async acquireConnection(): Promise<SqlConnection> {\n const delegate = this.#requireDelegate();\n const connection = await delegate.acquireConnection();\n return this.#wrapConnection(connection, delegate);\n }\n\n /**\n * Wraps an acquired connection so that teardown paths which close the\n * underlying delegate (notably `destroy()` on a pgClient binding, where\n * the single socket means a destroyed connection invalidates the driver)\n * also reset our own `#delegate` reference. Without this, a failed\n * transaction rollback would leave the outer unbound wrapper reporting\n * `connected` while routing subsequent work to an already-ended delegate.\n */\n #wrapConnection(connection: SqlConnection, delegate: SqlDriver<PostgresBinding>): SqlConnection {\n const syncDelegateState = (): void => {\n if (this.#delegate === delegate && delegate.state === 'closed') {\n this.#delegate = null;\n this.#closed = true;\n }\n };\n const wrapped: SqlConnection = {\n beginTransaction: connection.beginTransaction.bind(connection),\n execute: connection.execute.bind(connection),\n query: connection.query.bind(connection),\n release: async () => {\n try {\n await connection.release();\n } finally {\n syncDelegateState();\n }\n },\n destroy: async (reason?: unknown) => {\n try {\n await connection.destroy(reason);\n } finally {\n syncDelegateState();\n }\n },\n };\n if (connection.explain) {\n wrapped.explain = connection.explain.bind(connection);\n }\n return wrapped;\n }\n\n async close(): Promise<void> {\n const delegate = this.#delegate;\n if (delegate !== null) {\n this.#delegate = null;\n await delegate.close();\n }\n this.#closed = true;\n }\n\n execute<Row = Record<string, unknown>>(request: SqlExecuteRequest): AsyncIterable<Row> {\n const delegate = this.#delegate;\n if (delegate === null) {\n return unboundExecute<Row>();\n }\n return delegate.execute<Row>(request);\n }\n\n async explain(request: SqlExecuteRequest): Promise<SqlExplainResult> {\n const delegate = this.#requireDelegate();\n const explain = delegate.explain;\n if (explain === undefined) {\n throw driverError('DRIVER.NOT_CONNECTED', USE_BEFORE_CONNECT_MESSAGE);\n }\n return explain.call(delegate, request);\n }\n\n async query<Row = Record<string, unknown>>(\n sql: string,\n params?: readonly unknown[],\n ): Promise<SqlQueryResult<Row>> {\n const delegate = this.#requireDelegate();\n return delegate.query<Row>(sql, params);\n }\n}\n\nconst postgresRuntimeDriverDescriptor: RuntimeDriverDescriptor<\n 'sql',\n 'postgres',\n PostgresDriverCreateOptions,\n PostgresRuntimeDriver\n> = {\n ...postgresDriverDescriptorMeta,\n create(options?: PostgresDriverCreateOptions): PostgresRuntimeDriver {\n return new PostgresUnboundDriverImpl(options?.cursor);\n },\n};\n\nexport default postgresRuntimeDriverDescriptor;\nexport type {\n PostgresBinding,\n PostgresDriverCreateOptions,\n QueryResult,\n} from '../postgres-driver';\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/driver-postgres",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"arktype": "^2.0.0",
|
|
8
8
|
"pg": "8.16.3",
|
|
9
9
|
"pg-cursor": "^2.10.5",
|
|
10
|
-
"@prisma-next/
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/
|
|
13
|
-
"@prisma-next/
|
|
14
|
-
"@prisma-next/
|
|
15
|
-
"@prisma-next/sql-operations": "0.4.
|
|
16
|
-
"@prisma-next/sql-relational-core": "0.4.
|
|
17
|
-
"@prisma-next/utils": "0.4.
|
|
10
|
+
"@prisma-next/errors": "0.4.2",
|
|
11
|
+
"@prisma-next/sql-contract": "0.4.2",
|
|
12
|
+
"@prisma-next/framework-components": "0.4.2",
|
|
13
|
+
"@prisma-next/contract": "0.4.2",
|
|
14
|
+
"@prisma-next/sql-errors": "0.4.2",
|
|
15
|
+
"@prisma-next/sql-operations": "0.4.2",
|
|
16
|
+
"@prisma-next/sql-relational-core": "0.4.2",
|
|
17
|
+
"@prisma-next/utils": "0.4.2"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/pg": "8.16.0",
|
package/src/exports/runtime.ts
CHANGED
|
@@ -104,7 +104,48 @@ class PostgresUnboundDriverImpl implements PostgresRuntimeDriver {
|
|
|
104
104
|
|
|
105
105
|
async acquireConnection(): Promise<SqlConnection> {
|
|
106
106
|
const delegate = this.#requireDelegate();
|
|
107
|
-
|
|
107
|
+
const connection = await delegate.acquireConnection();
|
|
108
|
+
return this.#wrapConnection(connection, delegate);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Wraps an acquired connection so that teardown paths which close the
|
|
113
|
+
* underlying delegate (notably `destroy()` on a pgClient binding, where
|
|
114
|
+
* the single socket means a destroyed connection invalidates the driver)
|
|
115
|
+
* also reset our own `#delegate` reference. Without this, a failed
|
|
116
|
+
* transaction rollback would leave the outer unbound wrapper reporting
|
|
117
|
+
* `connected` while routing subsequent work to an already-ended delegate.
|
|
118
|
+
*/
|
|
119
|
+
#wrapConnection(connection: SqlConnection, delegate: SqlDriver<PostgresBinding>): SqlConnection {
|
|
120
|
+
const syncDelegateState = (): void => {
|
|
121
|
+
if (this.#delegate === delegate && delegate.state === 'closed') {
|
|
122
|
+
this.#delegate = null;
|
|
123
|
+
this.#closed = true;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const wrapped: SqlConnection = {
|
|
127
|
+
beginTransaction: connection.beginTransaction.bind(connection),
|
|
128
|
+
execute: connection.execute.bind(connection),
|
|
129
|
+
query: connection.query.bind(connection),
|
|
130
|
+
release: async () => {
|
|
131
|
+
try {
|
|
132
|
+
await connection.release();
|
|
133
|
+
} finally {
|
|
134
|
+
syncDelegateState();
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
destroy: async (reason?: unknown) => {
|
|
138
|
+
try {
|
|
139
|
+
await connection.destroy(reason);
|
|
140
|
+
} finally {
|
|
141
|
+
syncDelegateState();
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
if (connection.explain) {
|
|
146
|
+
wrapped.explain = connection.explain.bind(connection);
|
|
147
|
+
}
|
|
148
|
+
return wrapped;
|
|
108
149
|
}
|
|
109
150
|
|
|
110
151
|
async close(): Promise<void> {
|
package/src/postgres-driver.ts
CHANGED
|
@@ -180,11 +180,18 @@ abstract class PostgresQueryable<C extends PoolClient | Client = PoolClient | Cl
|
|
|
180
180
|
class PostgresConnectionImpl extends PostgresQueryable implements SqlConnection {
|
|
181
181
|
#connection: PoolClient | Client;
|
|
182
182
|
#onRelease: (() => void) | undefined;
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
#onDestroy: ((reason: unknown) => Promise<void> | void) | undefined;
|
|
184
|
+
|
|
185
|
+
constructor(
|
|
186
|
+
connection: PoolClient | Client,
|
|
187
|
+
options: ConnectionOptions,
|
|
188
|
+
onRelease?: () => void,
|
|
189
|
+
onDestroy?: (reason: unknown) => Promise<void> | void,
|
|
190
|
+
) {
|
|
185
191
|
super(options);
|
|
186
192
|
this.#connection = connection;
|
|
187
193
|
this.#onRelease = onRelease;
|
|
194
|
+
this.#onDestroy = onDestroy;
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
override acquireClient(): Promise<PoolClient | Client> {
|
|
@@ -201,11 +208,40 @@ class PostgresConnectionImpl extends PostgresQueryable implements SqlConnection
|
|
|
201
208
|
}
|
|
202
209
|
|
|
203
210
|
async release(): Promise<void> {
|
|
204
|
-
|
|
205
|
-
|
|
211
|
+
const conn = this.#connection;
|
|
212
|
+
if ('release' in conn) {
|
|
213
|
+
conn.release();
|
|
206
214
|
}
|
|
207
|
-
this.#onRelease
|
|
215
|
+
const onRelease = this.#onRelease;
|
|
216
|
+
this.#onRelease = undefined;
|
|
217
|
+
this.#onDestroy = undefined;
|
|
218
|
+
onRelease?.();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async destroy(reason?: unknown): Promise<void> {
|
|
222
|
+
const onDestroy = this.#onDestroy;
|
|
223
|
+
const onRelease = this.#onRelease;
|
|
224
|
+
this.#onDestroy = undefined;
|
|
208
225
|
this.#onRelease = undefined;
|
|
226
|
+
|
|
227
|
+
const conn = this.#connection;
|
|
228
|
+
if ('release' in conn) {
|
|
229
|
+
// Pass a truthy Error to pg's PoolClient.release so the pool evicts the
|
|
230
|
+
// client instead of returning it for reuse. A connection that reaches
|
|
231
|
+
// destroy() is in an indeterminate state (failed rollback/commit, etc.)
|
|
232
|
+
// and must not be handed back to another caller. The Error value is
|
|
233
|
+
// surfaced on pg-pool's 'release' event as advisory context; pg-pool
|
|
234
|
+
// itself only uses its truthiness for the eviction decision.
|
|
235
|
+
const releaseArg: Error =
|
|
236
|
+
reason instanceof Error ? reason : new Error('Connection destroyed');
|
|
237
|
+
conn.release(releaseArg);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (onDestroy) {
|
|
241
|
+
await onDestroy(reason);
|
|
242
|
+
} else {
|
|
243
|
+
onRelease?.();
|
|
244
|
+
}
|
|
209
245
|
}
|
|
210
246
|
}
|
|
211
247
|
|
|
@@ -309,7 +345,26 @@ class PostgresDirectDriverImpl
|
|
|
309
345
|
const releaseLease = await this.#connectionMutex.lock();
|
|
310
346
|
try {
|
|
311
347
|
const client = await this.acquireClient();
|
|
312
|
-
return new PostgresConnectionImpl(
|
|
348
|
+
return new PostgresConnectionImpl(
|
|
349
|
+
client,
|
|
350
|
+
this.options,
|
|
351
|
+
releaseLease,
|
|
352
|
+
// A direct driver has a single underlying socket, so a destroyed
|
|
353
|
+
// connection means the driver itself is no longer usable. Tear down
|
|
354
|
+
// the driver while still holding the lease so that any
|
|
355
|
+
// acquireConnection() queued on #connectionMutex only observes the
|
|
356
|
+
// driver after .end() has completed and #closed is set — preventing
|
|
357
|
+
// a concurrent caller from reusing a socket that is already being
|
|
358
|
+
// closed. The lease is released in a finally so a failing .end()
|
|
359
|
+
// cannot leave the mutex permanently held.
|
|
360
|
+
async () => {
|
|
361
|
+
try {
|
|
362
|
+
await this.#closeWhileHoldingLease();
|
|
363
|
+
} finally {
|
|
364
|
+
releaseLease();
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
);
|
|
313
368
|
} catch (error) {
|
|
314
369
|
releaseLease();
|
|
315
370
|
throw error;
|
|
@@ -319,17 +374,21 @@ class PostgresDirectDriverImpl
|
|
|
319
374
|
async close(): Promise<void> {
|
|
320
375
|
const releaseLease = await this.#connectionMutex.lock();
|
|
321
376
|
try {
|
|
322
|
-
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
this.#closed = true;
|
|
326
|
-
await this.directClient.end();
|
|
327
|
-
this.#connected = false;
|
|
377
|
+
await this.#closeWhileHoldingLease();
|
|
328
378
|
} finally {
|
|
329
379
|
releaseLease();
|
|
330
380
|
}
|
|
331
381
|
}
|
|
332
382
|
|
|
383
|
+
async #closeWhileHoldingLease(): Promise<void> {
|
|
384
|
+
if (this.#closed) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
this.#closed = true;
|
|
388
|
+
await this.directClient.end();
|
|
389
|
+
this.#connected = false;
|
|
390
|
+
}
|
|
391
|
+
|
|
333
392
|
async acquireClient(): Promise<Client> {
|
|
334
393
|
if (this.#connected) {
|
|
335
394
|
return this.directClient;
|