@typed-sql/postgres 1.0.0-rc.0 → 2.0.0-rc.1
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 +130 -0
- package/README.md +57 -65
- package/dist/packages/postgres/src/bulk.d.ts +30 -0
- package/dist/packages/postgres/src/bulk.d.ts.map +1 -0
- package/dist/packages/postgres/src/bulk.js +228 -0
- package/dist/packages/postgres/src/bulk.js.map +1 -0
- package/dist/packages/postgres/src/index.d.ts +5 -1
- package/dist/packages/postgres/src/index.d.ts.map +1 -1
- package/dist/packages/postgres/src/index.js +17 -4
- package/dist/packages/postgres/src/index.js.map +1 -1
- package/dist/packages/postgres/src/pg.d.ts +68 -4
- package/dist/packages/postgres/src/pg.d.ts.map +1 -1
- package/dist/packages/postgres/src/pg.js +458 -14
- package/dist/packages/postgres/src/pg.js.map +1 -1
- package/dist/packages/postgres/src/prepared.d.ts +20 -0
- package/dist/packages/postgres/src/prepared.d.ts.map +1 -0
- package/dist/packages/postgres/src/prepared.js +47 -0
- package/dist/packages/postgres/src/prepared.js.map +1 -0
- package/dist/packages/postgres/src/provider.d.ts +2 -1
- package/dist/packages/postgres/src/provider.d.ts.map +1 -1
- package/dist/packages/postgres/src/provider.js +3 -1
- package/dist/packages/postgres/src/provider.js.map +1 -1
- package/dist/packages/postgres/src/resolver.d.ts.map +1 -1
- package/dist/packages/postgres/src/resolver.js +11 -1
- package/dist/packages/postgres/src/resolver.js.map +1 -1
- package/dist/packages/postgres/src/routing.d.ts +22 -0
- package/dist/packages/postgres/src/routing.d.ts.map +1 -0
- package/dist/packages/postgres/src/routing.js +70 -0
- package/dist/packages/postgres/src/routing.js.map +1 -0
- package/dist/packages/postgres/src/runtime.d.ts +34 -3
- package/dist/packages/postgres/src/runtime.d.ts.map +1 -1
- package/dist/packages/postgres/src/runtime.js +923 -22
- package/dist/packages/postgres/src/runtime.js.map +1 -1
- package/dist/packages/postgres/src/semantics.d.ts +5 -0
- package/dist/packages/postgres/src/semantics.d.ts.map +1 -0
- package/dist/packages/postgres/src/semantics.js +211 -0
- package/dist/packages/postgres/src/semantics.js.map +1 -0
- package/dist/packages/postgres/src/stream.d.ts +34 -0
- package/dist/packages/postgres/src/stream.d.ts.map +1 -0
- package/dist/packages/postgres/src/stream.js +124 -0
- package/dist/packages/postgres/src/stream.js.map +1 -0
- package/dist/packages/postgres/src/version.d.ts +2 -0
- package/dist/packages/postgres/src/version.d.ts.map +1 -0
- package/dist/packages/postgres/src/version.js +2 -0
- package/dist/packages/postgres/src/version.js.map +1 -0
- package/package.json +4 -4
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
var _a;
|
|
2
|
-
import {
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { adapterCapabilities, assertExecutionCapabilities, createAdapterCapabilityResolver, databaseErrorCompletion, hasQueryResultValidator, observeQueryStream, QueryCardinalityError, queryResultValidationSource, renderQuery, runControlledExecution, startDatabaseObservation, validateQueryResultRows, validateQueryResultStream, } from "@typed-sql/core";
|
|
4
|
+
import { createPostgresCopyCapability, postgresCopy } from "./bulk.js";
|
|
5
|
+
import { createPostgresPreparedQueryState, preparePostgresQuery, } from "./prepared.js";
|
|
6
|
+
import { PostgresQueryStream, validatePostgresStreamBatchSize } from "./stream.js";
|
|
3
7
|
import { defaultPostgresTypePolicy } from "./type-policy.js";
|
|
8
|
+
import { POSTGRES_DIALECT_VERSION } from "./version.js";
|
|
4
9
|
const defaultPolicy = defaultPostgresTypePolicy;
|
|
10
|
+
const emptyBatchResults = Object.freeze([]);
|
|
11
|
+
function createPostgresObservationState(observer) {
|
|
12
|
+
return { observer, fingerprints: observer === undefined ? undefined : new WeakMap() };
|
|
13
|
+
}
|
|
14
|
+
function postgresQueryFingerprint(state, query) {
|
|
15
|
+
const key = query;
|
|
16
|
+
const cached = state.fingerprints?.get(key);
|
|
17
|
+
if (cached !== undefined)
|
|
18
|
+
return cached;
|
|
19
|
+
const text = renderQuery(query, postgresRenderer).text;
|
|
20
|
+
const fingerprint = `sha256:${createHash("sha256")
|
|
21
|
+
.update(`postgres\0${POSTGRES_DIALECT_VERSION}\0${text}`)
|
|
22
|
+
.digest("hex")}`;
|
|
23
|
+
state.fingerprints?.set(key, fingerprint);
|
|
24
|
+
return fingerprint;
|
|
25
|
+
}
|
|
5
26
|
const oids = {
|
|
6
27
|
int8: 20,
|
|
7
28
|
date: 1082,
|
|
@@ -121,61 +142,941 @@ class PostgresDatabaseImplementation {
|
|
|
121
142
|
#client;
|
|
122
143
|
#parsers;
|
|
123
144
|
#ownsPool;
|
|
145
|
+
#prepared;
|
|
146
|
+
#observation;
|
|
124
147
|
#transactionDepth;
|
|
125
|
-
|
|
148
|
+
#transactionScopeOpen = true;
|
|
149
|
+
#transactionOperationFailed = false;
|
|
150
|
+
#transactionOperationError;
|
|
151
|
+
#transactionState;
|
|
152
|
+
#transactionExecutes = new Set();
|
|
153
|
+
#transactionStreams = new Set();
|
|
154
|
+
executionCapabilities;
|
|
155
|
+
[adapterCapabilities];
|
|
156
|
+
constructor(pool, client, parsers, ownsPool, depth, prepared, observation, transactionState = {
|
|
157
|
+
activeBatch: undefined,
|
|
158
|
+
activeCopy: undefined,
|
|
159
|
+
activeExecutes: new Set(),
|
|
160
|
+
activePipeline: undefined,
|
|
161
|
+
activeStreams: new Set(),
|
|
162
|
+
discardLease: false,
|
|
163
|
+
leaseReleased: false,
|
|
164
|
+
firstDatabaseOperationError: undefined,
|
|
165
|
+
unsafe: false,
|
|
166
|
+
unsafeDepth: undefined,
|
|
167
|
+
unsafeError: undefined,
|
|
168
|
+
valid: true,
|
|
169
|
+
}) {
|
|
126
170
|
this.#pool = pool;
|
|
127
171
|
this.#client = client;
|
|
128
172
|
this.#parsers = parsers;
|
|
129
173
|
this.#ownsPool = ownsPool;
|
|
130
174
|
this.#transactionDepth = depth;
|
|
175
|
+
this.#prepared = prepared;
|
|
176
|
+
this.#observation = observation;
|
|
177
|
+
this.#transactionState = transactionState;
|
|
178
|
+
this.executionCapabilities = Object.freeze({
|
|
179
|
+
cancellation: pool.executionCapabilities?.cancellation ?? false,
|
|
180
|
+
deadlines: pool.executionCapabilities?.deadlines ?? false,
|
|
181
|
+
});
|
|
182
|
+
const copyTransport = {
|
|
183
|
+
copyFrom: (statement, chunks, options) => this.#copyFrom(statement, chunks, options),
|
|
184
|
+
copyTo: (statement, options) => this.#copyTo(statement, options),
|
|
185
|
+
};
|
|
186
|
+
this[adapterCapabilities] = createAdapterCapabilityResolver(pool.ensureCopy === undefined ? [] : [[postgresCopy, createPostgresCopyCapability(copyTransport)]]);
|
|
131
187
|
}
|
|
132
188
|
async execute(query) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
189
|
+
if (this.#observation.observer === undefined) {
|
|
190
|
+
return this.#validateRows(query, await this.#executeUnobserved(query));
|
|
191
|
+
}
|
|
192
|
+
return this.#observeQuery(query, "many", async () => this.#validateRows(query, await this.#executeUnobserved(query)));
|
|
193
|
+
}
|
|
194
|
+
async #executeUnobserved(query) {
|
|
195
|
+
this.#assertTransactionScopeOpen();
|
|
196
|
+
this.#rejectOperationDuringTransactionStream("execute another query");
|
|
197
|
+
this.#rejectOperationDuringTransactionBatch("execute another query");
|
|
198
|
+
this.#rejectOperationDuringTransactionCopy("execute another query");
|
|
199
|
+
this.#rejectOperationDuringTransactionPipeline("execute another query");
|
|
200
|
+
const config = this.#queryConfig(query);
|
|
201
|
+
let operation;
|
|
202
|
+
try {
|
|
203
|
+
operation = (this.#client ?? this.#pool).query(config);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
this.#recordTransactionOperationFailure(error);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
if (this.#client !== undefined) {
|
|
210
|
+
this.#transactionExecutes.add(operation);
|
|
211
|
+
this.#transactionState.activeExecutes.add(operation);
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const result = await operation;
|
|
215
|
+
return result.rows;
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
this.#recordTransactionOperationFailure(error);
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
this.#transactionExecutes.delete(operation);
|
|
223
|
+
this.#transactionState.activeExecutes.delete(operation);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async all(query, options) {
|
|
227
|
+
if (this.#observation.observer === undefined) {
|
|
228
|
+
return this.#validateRows(query, await this.#allUnobserved(query, options));
|
|
229
|
+
}
|
|
230
|
+
return this.#observeQuery(query, "many", async () => this.#validateRows(query, await this.#allUnobserved(query, options)));
|
|
231
|
+
}
|
|
232
|
+
async #allUnobserved(query, options) {
|
|
233
|
+
if (options === undefined || (options.signal === undefined && options.deadline === undefined))
|
|
234
|
+
return this.#executeUnobserved(query);
|
|
235
|
+
assertExecutionCapabilities(this.executionCapabilities, options);
|
|
236
|
+
this.#assertTransactionScopeOpen();
|
|
237
|
+
this.#rejectOperationDuringTransactionStream("execute another query");
|
|
238
|
+
this.#rejectOperationDuringTransactionBatch("execute another query");
|
|
239
|
+
this.#rejectOperationDuringTransactionCopy("execute another query");
|
|
240
|
+
this.#rejectOperationDuringTransactionPipeline("execute another query");
|
|
241
|
+
if (options.signal?.aborted || (options.deadline !== undefined && Number(options.deadline) <= Date.now())) {
|
|
242
|
+
return runControlledExecution(options, async () => [], () => undefined);
|
|
243
|
+
}
|
|
244
|
+
if (this.#client === undefined) {
|
|
245
|
+
const client = await this.#pool.connect();
|
|
246
|
+
let discarded = false;
|
|
247
|
+
try {
|
|
248
|
+
return await this.#executeControlledOn(client, query, options, (error) => {
|
|
249
|
+
client.release(error);
|
|
250
|
+
discarded = true;
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
if (!discarded)
|
|
255
|
+
client.release();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const client = this.#client;
|
|
259
|
+
const operation = this.#executeControlledOn(client, query, options, (error) => {
|
|
260
|
+
this.#transactionState.discardLease = true;
|
|
261
|
+
this.#markTransactionStateUnsafe(error);
|
|
262
|
+
try {
|
|
263
|
+
client.release(error);
|
|
264
|
+
this.#transactionState.leaseReleased = true;
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
/* The transaction finalizer also owns lease cleanup. */
|
|
268
|
+
}
|
|
138
269
|
});
|
|
270
|
+
this.#transactionExecutes.add(operation);
|
|
271
|
+
this.#transactionState.activeExecutes.add(operation);
|
|
272
|
+
try {
|
|
273
|
+
return await operation;
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
this.#recordTransactionOperationFailure(error);
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
finally {
|
|
280
|
+
this.#transactionExecutes.delete(operation);
|
|
281
|
+
this.#transactionState.activeExecutes.delete(operation);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async #executeControlledOn(client, query, options, cancel) {
|
|
285
|
+
const result = await runControlledExecution(options, () => client.query(this.#queryConfig(query)), cancel);
|
|
139
286
|
return result.rows;
|
|
140
287
|
}
|
|
141
|
-
async
|
|
142
|
-
if (this.#
|
|
143
|
-
|
|
288
|
+
async one(query, options) {
|
|
289
|
+
if (this.#observation.observer === undefined) {
|
|
290
|
+
const rows = await this.#validateRows(query, await this.#allUnobserved(query, options));
|
|
291
|
+
if (rows.length !== 1)
|
|
292
|
+
throw new QueryCardinalityError("one", rows.length);
|
|
293
|
+
return rows[0];
|
|
294
|
+
}
|
|
295
|
+
const rows = await this.#observeQuery(query, "one", async () => {
|
|
296
|
+
const result = await this.#validateRows(query, await this.#allUnobserved(query, options));
|
|
297
|
+
if (result.length !== 1)
|
|
298
|
+
throw new QueryCardinalityError("one", result.length);
|
|
299
|
+
return result;
|
|
300
|
+
});
|
|
301
|
+
return rows[0];
|
|
302
|
+
}
|
|
303
|
+
async maybeOne(query, options) {
|
|
304
|
+
if (this.#observation.observer === undefined) {
|
|
305
|
+
const rows = await this.#validateRows(query, await this.#allUnobserved(query, options));
|
|
306
|
+
if (rows.length > 1)
|
|
307
|
+
throw new QueryCardinalityError("maybeOne", rows.length);
|
|
308
|
+
return rows[0];
|
|
309
|
+
}
|
|
310
|
+
const rows = await this.#observeQuery(query, "maybeOne", async () => {
|
|
311
|
+
const result = await this.#validateRows(query, await this.#allUnobserved(query, options));
|
|
312
|
+
if (result.length > 1)
|
|
313
|
+
throw new QueryCardinalityError("maybeOne", result.length);
|
|
314
|
+
return result;
|
|
315
|
+
});
|
|
316
|
+
return rows[0];
|
|
317
|
+
}
|
|
318
|
+
async #observeQuery(query, cardinality, operation) {
|
|
319
|
+
if (this.#observation.observer === undefined)
|
|
320
|
+
return operation();
|
|
321
|
+
const observation = startDatabaseObservation(this.#observation.observer, {
|
|
322
|
+
kind: "query",
|
|
323
|
+
dialect: "postgres",
|
|
324
|
+
grammarVersion: POSTGRES_DIALECT_VERSION,
|
|
325
|
+
transactionDepth: this.#transactionDepth,
|
|
326
|
+
fingerprint: postgresQueryFingerprint(this.#observation, query),
|
|
327
|
+
cardinality,
|
|
328
|
+
prepared: this.#prepared.queries.has(queryResultValidationSource(query)),
|
|
329
|
+
});
|
|
330
|
+
if (observation === undefined)
|
|
331
|
+
return operation();
|
|
332
|
+
try {
|
|
333
|
+
const rows = await observation.run(operation);
|
|
334
|
+
observation.end({ status: "success", rowCount: rows.length });
|
|
335
|
+
return rows;
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
observation.end(databaseErrorCompletion(error), error);
|
|
339
|
+
throw error;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async batch(queries) {
|
|
343
|
+
if (queries.length === 0)
|
|
344
|
+
return emptyBatchResults;
|
|
345
|
+
if (this.#observation.observer === undefined) {
|
|
346
|
+
return this.#validateBatch(queries, await this.#batchUnobserved(queries));
|
|
347
|
+
}
|
|
348
|
+
return this.#observeGroup("batch", queries, async () => this.#validateBatch(queries, await this.#batchUnobserved(queries)));
|
|
349
|
+
}
|
|
350
|
+
async #batchUnobserved(queries) {
|
|
351
|
+
this.#assertTransactionScopeOpen();
|
|
352
|
+
this.#rejectOperationDuringTransactionStream("execute a query batch");
|
|
353
|
+
this.#rejectOperationDuringTransactionBatch("execute another query batch");
|
|
354
|
+
this.#rejectOperationDuringTransactionCopy("execute a query batch");
|
|
355
|
+
this.#rejectOperationDuringTransactionPipeline("execute a query batch");
|
|
356
|
+
if (queries.length === 0)
|
|
357
|
+
return emptyBatchResults;
|
|
358
|
+
const querySnapshot = [...queries];
|
|
359
|
+
if (this.#client !== undefined) {
|
|
360
|
+
const operation = this.#executeBatch(this.#client, querySnapshot);
|
|
361
|
+
this.#transactionState.activeBatch = operation;
|
|
362
|
+
try {
|
|
363
|
+
return await operation;
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
this.#recordTransactionOperationFailure(error);
|
|
367
|
+
throw error;
|
|
368
|
+
}
|
|
369
|
+
finally {
|
|
370
|
+
if (this.#transactionState.activeBatch === operation)
|
|
371
|
+
this.#transactionState.activeBatch = undefined;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
144
374
|
const client = await this.#pool.connect();
|
|
375
|
+
let results;
|
|
145
376
|
try {
|
|
146
|
-
await client
|
|
147
|
-
const result = await fn(new _a(this.#pool, client, this.#parsers, false, 1));
|
|
148
|
-
await client.query("COMMIT");
|
|
149
|
-
return result;
|
|
377
|
+
results = await this.#executeBatch(client, querySnapshot);
|
|
150
378
|
}
|
|
151
379
|
catch (error) {
|
|
152
380
|
try {
|
|
153
|
-
|
|
381
|
+
client.release(error instanceof Error ? error : true);
|
|
154
382
|
}
|
|
155
383
|
catch {
|
|
156
|
-
/* Preserve the
|
|
384
|
+
/* Preserve the first query failure. */
|
|
157
385
|
}
|
|
158
386
|
throw error;
|
|
159
387
|
}
|
|
160
|
-
|
|
388
|
+
client.release();
|
|
389
|
+
return results;
|
|
390
|
+
}
|
|
391
|
+
async pipeline(queries) {
|
|
392
|
+
if (queries.length === 0)
|
|
393
|
+
return emptyBatchResults;
|
|
394
|
+
if (this.#observation.observer === undefined) {
|
|
395
|
+
return this.#validateBatch(queries, await this.#pipelineUnobserved(queries));
|
|
396
|
+
}
|
|
397
|
+
return this.#observeGroup("pipeline", queries, async () => this.#validateBatch(queries, await this.#pipelineUnobserved(queries)));
|
|
398
|
+
}
|
|
399
|
+
async #pipelineUnobserved(queries) {
|
|
400
|
+
this.#assertTransactionScopeOpen();
|
|
401
|
+
this.#rejectOperationDuringTransactionStream("execute a query pipeline");
|
|
402
|
+
this.#rejectOperationDuringTransactionBatch("execute a query pipeline");
|
|
403
|
+
this.#rejectOperationDuringTransactionCopy("execute a query pipeline");
|
|
404
|
+
this.#rejectOperationDuringTransactionExecute("execute a query pipeline");
|
|
405
|
+
this.#rejectOperationDuringTransactionPipeline("execute another query pipeline");
|
|
406
|
+
if (queries.length === 0)
|
|
407
|
+
return emptyBatchResults;
|
|
408
|
+
const configs = [...queries].map((value) => this.#queryConfig(value));
|
|
409
|
+
if (this.#client !== undefined) {
|
|
410
|
+
this.#assertPipelineClient(this.#client);
|
|
411
|
+
const operation = this.#executePipeline(this.#client, configs);
|
|
412
|
+
this.#transactionState.activePipeline = operation;
|
|
413
|
+
try {
|
|
414
|
+
return await operation;
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
this.#recordTransactionOperationFailure(error);
|
|
418
|
+
throw error;
|
|
419
|
+
}
|
|
420
|
+
finally {
|
|
421
|
+
if (this.#transactionState.activePipeline === operation)
|
|
422
|
+
this.#transactionState.activePipeline = undefined;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const client = await this.#pool.connect();
|
|
426
|
+
try {
|
|
427
|
+
this.#assertPipelineClient(client);
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
try {
|
|
431
|
+
client.release();
|
|
432
|
+
}
|
|
433
|
+
catch {
|
|
434
|
+
/* Preserve the missing pipeline-capability error. */
|
|
435
|
+
}
|
|
436
|
+
throw error;
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
const results = await this.#executePipeline(client, configs);
|
|
161
440
|
client.release();
|
|
441
|
+
return results;
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
try {
|
|
445
|
+
client.release(error instanceof Error ? error : true);
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
/* Preserve the first pipeline failure. */
|
|
449
|
+
}
|
|
450
|
+
throw error;
|
|
162
451
|
}
|
|
163
452
|
}
|
|
453
|
+
async #observeGroup(kind, queries, operation) {
|
|
454
|
+
if (this.#observation.observer === undefined)
|
|
455
|
+
return operation();
|
|
456
|
+
const fingerprints = Object.freeze([...queries].map((query) => postgresQueryFingerprint(this.#observation, query)));
|
|
457
|
+
const observation = startDatabaseObservation(this.#observation.observer, {
|
|
458
|
+
kind,
|
|
459
|
+
dialect: "postgres",
|
|
460
|
+
grammarVersion: POSTGRES_DIALECT_VERSION,
|
|
461
|
+
transactionDepth: this.#transactionDepth,
|
|
462
|
+
fingerprints,
|
|
463
|
+
size: queries.length,
|
|
464
|
+
});
|
|
465
|
+
if (observation === undefined)
|
|
466
|
+
return operation();
|
|
467
|
+
try {
|
|
468
|
+
const results = await observation.run(operation);
|
|
469
|
+
observation.end({ status: "success" });
|
|
470
|
+
return results;
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
observation.end(databaseErrorCompletion(error), error);
|
|
474
|
+
throw error;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
stream(query, options = {}) {
|
|
478
|
+
this.#assertTransactionScopeOpen();
|
|
479
|
+
this.#rejectOperationDuringTransactionStream("start another query stream");
|
|
480
|
+
this.#rejectOperationDuringTransactionBatch("start a query stream");
|
|
481
|
+
this.#rejectOperationDuringTransactionCopy("start a query stream");
|
|
482
|
+
this.#rejectOperationDuringTransactionPipeline("start a query stream");
|
|
483
|
+
const batchSize = validatePostgresStreamBatchSize(options.batchSize);
|
|
484
|
+
const config = this.#queryConfig(query);
|
|
485
|
+
let exposedStream;
|
|
486
|
+
const stream = new PostgresQueryStream({
|
|
487
|
+
batchSize,
|
|
488
|
+
start: async () => {
|
|
489
|
+
await this.#pool.ensureCursor?.();
|
|
490
|
+
const client = this.#client ?? (await this.#pool.connect());
|
|
491
|
+
const release = this.#client === undefined
|
|
492
|
+
? (cleanupError) => client.release(cleanupError === undefined ? undefined : cleanupError instanceof Error ? cleanupError : true)
|
|
493
|
+
: undefined;
|
|
494
|
+
if (client.openCursor === undefined) {
|
|
495
|
+
try {
|
|
496
|
+
release?.();
|
|
497
|
+
}
|
|
498
|
+
catch {
|
|
499
|
+
/* The missing-capability failure remains primary. */
|
|
500
|
+
}
|
|
501
|
+
throw new Error("PostgreSQL streaming requires the application-owned pg-cursor package. Install it with: pnpm add pg-cursor");
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
const cursor = await client.openCursor(config);
|
|
505
|
+
return { cursor: cursor, ...(release === undefined ? {} : { release }) };
|
|
506
|
+
}
|
|
507
|
+
catch (error) {
|
|
508
|
+
this.#recordTransactionOperationFailure(error);
|
|
509
|
+
try {
|
|
510
|
+
release?.(error);
|
|
511
|
+
}
|
|
512
|
+
catch {
|
|
513
|
+
/* Preserve cursor creation or optional-dependency failures. */
|
|
514
|
+
}
|
|
515
|
+
throw error;
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
...(this.#client === undefined
|
|
519
|
+
? {}
|
|
520
|
+
: {
|
|
521
|
+
onStart: () => {
|
|
522
|
+
this.#assertTransactionScopeOpen();
|
|
523
|
+
this.#rejectOperationDuringTransactionStream("start another query stream");
|
|
524
|
+
this.#rejectOperationDuringTransactionBatch("start a query stream");
|
|
525
|
+
this.#rejectOperationDuringTransactionCopy("start a query stream");
|
|
526
|
+
this.#rejectOperationDuringTransactionPipeline("start a query stream");
|
|
527
|
+
this.#transactionState.activeStreams.add(exposedStream);
|
|
528
|
+
},
|
|
529
|
+
onClose: () => {
|
|
530
|
+
this.#transactionState.activeStreams.delete(exposedStream);
|
|
531
|
+
this.#transactionStreams.delete(exposedStream);
|
|
532
|
+
},
|
|
533
|
+
onError: (error) => this.#recordTransactionOperationFailure(error),
|
|
534
|
+
}),
|
|
535
|
+
});
|
|
536
|
+
const validatedStream = hasQueryResultValidator(query)
|
|
537
|
+
? validateQueryResultStream(query, stream, postgresQueryFingerprint(this.#observation, query))
|
|
538
|
+
: stream;
|
|
539
|
+
exposedStream =
|
|
540
|
+
this.#observation.observer === undefined
|
|
541
|
+
? validatedStream
|
|
542
|
+
: observeQueryStream(validatedStream, this.#observation.observer, {
|
|
543
|
+
kind: "stream",
|
|
544
|
+
dialect: "postgres",
|
|
545
|
+
grammarVersion: POSTGRES_DIALECT_VERSION,
|
|
546
|
+
transactionDepth: this.#transactionDepth,
|
|
547
|
+
fingerprint: postgresQueryFingerprint(this.#observation, query),
|
|
548
|
+
prepared: this.#prepared.queries.has(queryResultValidationSource(query)),
|
|
549
|
+
});
|
|
550
|
+
if (this.#client !== undefined)
|
|
551
|
+
this.#transactionStreams.add(exposedStream);
|
|
552
|
+
return exposedStream;
|
|
553
|
+
}
|
|
554
|
+
async #validateRows(query, rows) {
|
|
555
|
+
if (!hasQueryResultValidator(query))
|
|
556
|
+
return rows;
|
|
557
|
+
return validateQueryResultRows(query, rows, postgresQueryFingerprint(this.#observation, query));
|
|
558
|
+
}
|
|
559
|
+
async #validateBatch(queries, results) {
|
|
560
|
+
let validated;
|
|
561
|
+
const queryList = queries;
|
|
562
|
+
const resultList = results;
|
|
563
|
+
for (let index = 0; index < queryList.length; index += 1) {
|
|
564
|
+
const query = queryList[index];
|
|
565
|
+
if (!hasQueryResultValidator(query))
|
|
566
|
+
continue;
|
|
567
|
+
validated ??= [...resultList];
|
|
568
|
+
validated[index] = await validateQueryResultRows(query, resultList[index], postgresQueryFingerprint(this.#observation, query));
|
|
569
|
+
}
|
|
570
|
+
return (validated ?? results);
|
|
571
|
+
}
|
|
572
|
+
async #copyFrom(statement, chunks, options) {
|
|
573
|
+
assertExecutionCapabilities(this.executionCapabilities, options);
|
|
574
|
+
this.#assertTransactionScopeOpen();
|
|
575
|
+
this.#rejectOperationDuringTransactionStream("start COPY FROM");
|
|
576
|
+
this.#rejectOperationDuringTransactionBatch("start COPY FROM");
|
|
577
|
+
this.#rejectOperationDuringTransactionCopy("start another COPY operation");
|
|
578
|
+
this.#rejectOperationDuringTransactionExecute("start COPY FROM");
|
|
579
|
+
this.#rejectOperationDuringTransactionPipeline("start COPY FROM");
|
|
580
|
+
await this.#pool.ensureCopy?.();
|
|
581
|
+
const client = this.#client ?? (await this.#pool.connect());
|
|
582
|
+
let sink;
|
|
583
|
+
const operation = runControlledExecution(options, async () => {
|
|
584
|
+
if (client.openCopyFrom === undefined) {
|
|
585
|
+
throw new Error("PostgreSQL COPY requires the application-owned pg-copy-streams package. Install it with: pnpm add pg-copy-streams");
|
|
586
|
+
}
|
|
587
|
+
sink = await client.openCopyFrom(statement);
|
|
588
|
+
try {
|
|
589
|
+
for await (const chunk of chunks)
|
|
590
|
+
await sink.write(chunk);
|
|
591
|
+
await sink.finish();
|
|
592
|
+
}
|
|
593
|
+
catch (error) {
|
|
594
|
+
try {
|
|
595
|
+
await sink.abort(error);
|
|
596
|
+
}
|
|
597
|
+
catch {
|
|
598
|
+
/* Preserve the producer or database failure. */
|
|
599
|
+
}
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
}, (error) => {
|
|
603
|
+
void sink?.abort(error).catch(() => undefined);
|
|
604
|
+
});
|
|
605
|
+
if (this.#client !== undefined)
|
|
606
|
+
this.#transactionState.activeCopy = operation;
|
|
607
|
+
try {
|
|
608
|
+
await operation;
|
|
609
|
+
if (this.#client === undefined)
|
|
610
|
+
client.release();
|
|
611
|
+
}
|
|
612
|
+
catch (error) {
|
|
613
|
+
this.#recordTransactionOperationFailure(error);
|
|
614
|
+
if (this.#client === undefined) {
|
|
615
|
+
try {
|
|
616
|
+
client.release(error instanceof Error ? error : true);
|
|
617
|
+
}
|
|
618
|
+
catch {
|
|
619
|
+
/* Preserve the COPY failure. */
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
throw error;
|
|
623
|
+
}
|
|
624
|
+
finally {
|
|
625
|
+
if (this.#transactionState.activeCopy === operation)
|
|
626
|
+
this.#transactionState.activeCopy = undefined;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
#copyTo(statement, options) {
|
|
630
|
+
assertExecutionCapabilities(this.executionCapabilities, options);
|
|
631
|
+
this.#assertTransactionScopeOpen();
|
|
632
|
+
this.#rejectOperationDuringTransactionStream("start COPY TO");
|
|
633
|
+
this.#rejectOperationDuringTransactionBatch("start COPY TO");
|
|
634
|
+
this.#rejectOperationDuringTransactionCopy("start COPY TO");
|
|
635
|
+
this.#rejectOperationDuringTransactionPipeline("start COPY TO");
|
|
636
|
+
let exposedStream;
|
|
637
|
+
const stream = new PostgresQueryStream({
|
|
638
|
+
batchSize: 1,
|
|
639
|
+
start: async () => {
|
|
640
|
+
await this.#pool.ensureCopy?.();
|
|
641
|
+
const client = this.#client ?? (await this.#pool.connect());
|
|
642
|
+
const release = this.#client === undefined
|
|
643
|
+
? (cleanupError) => client.release(cleanupError === undefined ? undefined : cleanupError instanceof Error ? cleanupError : true)
|
|
644
|
+
: undefined;
|
|
645
|
+
if (client.openCopyTo === undefined) {
|
|
646
|
+
try {
|
|
647
|
+
release?.();
|
|
648
|
+
}
|
|
649
|
+
catch {
|
|
650
|
+
/* The missing optional dependency remains primary. */
|
|
651
|
+
}
|
|
652
|
+
throw new Error("PostgreSQL COPY requires the application-owned pg-copy-streams package. Install it with: pnpm add pg-copy-streams");
|
|
653
|
+
}
|
|
654
|
+
try {
|
|
655
|
+
const source = await client.openCopyTo(statement);
|
|
656
|
+
return {
|
|
657
|
+
cursor: {
|
|
658
|
+
async read() {
|
|
659
|
+
const result = await runControlledExecution(options, () => source.next(), (error) => {
|
|
660
|
+
void source.abort(error).catch(() => undefined);
|
|
661
|
+
});
|
|
662
|
+
return result.done === true ? [] : [result.value];
|
|
663
|
+
},
|
|
664
|
+
close: () => source.close(),
|
|
665
|
+
},
|
|
666
|
+
...(release === undefined ? {} : { release }),
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
catch (error) {
|
|
670
|
+
this.#recordTransactionOperationFailure(error);
|
|
671
|
+
try {
|
|
672
|
+
release?.(error);
|
|
673
|
+
}
|
|
674
|
+
catch {
|
|
675
|
+
/* Preserve source creation or optional-dependency failures. */
|
|
676
|
+
}
|
|
677
|
+
throw error;
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
...(this.#client === undefined
|
|
681
|
+
? {}
|
|
682
|
+
: {
|
|
683
|
+
onStart: () => {
|
|
684
|
+
this.#assertTransactionScopeOpen();
|
|
685
|
+
this.#rejectOperationDuringTransactionStream("start COPY TO");
|
|
686
|
+
this.#rejectOperationDuringTransactionBatch("start COPY TO");
|
|
687
|
+
this.#rejectOperationDuringTransactionCopy("start COPY TO");
|
|
688
|
+
this.#rejectOperationDuringTransactionPipeline("start COPY TO");
|
|
689
|
+
this.#transactionState.activeStreams.add(exposedStream);
|
|
690
|
+
},
|
|
691
|
+
onClose: () => {
|
|
692
|
+
this.#transactionState.activeStreams.delete(exposedStream);
|
|
693
|
+
this.#transactionStreams.delete(exposedStream);
|
|
694
|
+
},
|
|
695
|
+
onError: (error) => this.#recordTransactionOperationFailure(error),
|
|
696
|
+
}),
|
|
697
|
+
});
|
|
698
|
+
exposedStream = stream;
|
|
699
|
+
if (this.#client !== undefined)
|
|
700
|
+
this.#transactionStreams.add(exposedStream);
|
|
701
|
+
return exposedStream;
|
|
702
|
+
}
|
|
703
|
+
prepare(statementName, factory) {
|
|
704
|
+
this.#assertTransactionScopeOpen();
|
|
705
|
+
return preparePostgresQuery(this.#prepared, postgresRenderer, statementName, factory);
|
|
706
|
+
}
|
|
707
|
+
async transaction(fn) {
|
|
708
|
+
if (this.#observation.observer === undefined)
|
|
709
|
+
return this.#transactionUnobserved(fn);
|
|
710
|
+
const observation = startDatabaseObservation(this.#observation.observer, {
|
|
711
|
+
kind: "transaction",
|
|
712
|
+
dialect: "postgres",
|
|
713
|
+
grammarVersion: POSTGRES_DIALECT_VERSION,
|
|
714
|
+
transactionDepth: this.#transactionDepth + 1,
|
|
715
|
+
});
|
|
716
|
+
if (observation === undefined)
|
|
717
|
+
return this.#transactionUnobserved(fn);
|
|
718
|
+
try {
|
|
719
|
+
const result = await observation.run(() => this.#transactionUnobserved(fn));
|
|
720
|
+
observation.end({ status: "success" });
|
|
721
|
+
return result;
|
|
722
|
+
}
|
|
723
|
+
catch (error) {
|
|
724
|
+
observation.end(databaseErrorCompletion(error), error);
|
|
725
|
+
throw error;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
async #transactionUnobserved(fn) {
|
|
729
|
+
this.#assertTransactionScopeOpen();
|
|
730
|
+
this.#rejectOperationDuringTransactionStream("start a nested transaction");
|
|
731
|
+
this.#rejectOperationDuringTransactionBatch("start a nested transaction");
|
|
732
|
+
this.#rejectOperationDuringTransactionCopy("start a nested transaction");
|
|
733
|
+
this.#rejectOperationDuringTransactionPipeline("start a nested transaction");
|
|
734
|
+
if (this.#client !== undefined)
|
|
735
|
+
return this.#nestedTransaction(fn);
|
|
736
|
+
const client = await this.#pool.connect();
|
|
737
|
+
const scope = new _a(this.#pool, client, this.#parsers, false, 1, this.#prepared, this.#observation, {
|
|
738
|
+
activeBatch: undefined,
|
|
739
|
+
activeCopy: undefined,
|
|
740
|
+
activeExecutes: new Set(),
|
|
741
|
+
activePipeline: undefined,
|
|
742
|
+
activeStreams: new Set(),
|
|
743
|
+
discardLease: false,
|
|
744
|
+
leaseReleased: false,
|
|
745
|
+
firstDatabaseOperationError: undefined,
|
|
746
|
+
unsafe: false,
|
|
747
|
+
unsafeDepth: undefined,
|
|
748
|
+
unsafeError: undefined,
|
|
749
|
+
valid: true,
|
|
750
|
+
});
|
|
751
|
+
let result;
|
|
752
|
+
try {
|
|
753
|
+
try {
|
|
754
|
+
await client.query("BEGIN");
|
|
755
|
+
}
|
|
756
|
+
catch (error) {
|
|
757
|
+
scope.#recordTransactionOperationFailure(error);
|
|
758
|
+
throw error;
|
|
759
|
+
}
|
|
760
|
+
try {
|
|
761
|
+
result = await fn(scope);
|
|
762
|
+
}
|
|
763
|
+
finally {
|
|
764
|
+
scope.#transactionScopeOpen = false;
|
|
765
|
+
scope.#transactionState.valid = false;
|
|
766
|
+
}
|
|
767
|
+
scope.#throwIfTransactionCannotCommit();
|
|
768
|
+
await scope.#rejectLeakedTransactionWork();
|
|
769
|
+
try {
|
|
770
|
+
await client.query("COMMIT");
|
|
771
|
+
}
|
|
772
|
+
catch (error) {
|
|
773
|
+
scope.#recordTransactionOperationFailure(error);
|
|
774
|
+
throw error;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
catch (error) {
|
|
778
|
+
scope.#transactionScopeOpen = false;
|
|
779
|
+
scope.#transactionState.valid = false;
|
|
780
|
+
await scope.#settleTransactionExecutesPreservingError();
|
|
781
|
+
await scope.#closeTransactionStreamsPreservingError();
|
|
782
|
+
await scope.#settleTransactionPipelinePreservingError();
|
|
783
|
+
await scope.#settleTransactionBatchPreservingError();
|
|
784
|
+
await scope.#settleTransactionCopyPreservingError();
|
|
785
|
+
if (!scope.#transactionState.leaseReleased) {
|
|
786
|
+
try {
|
|
787
|
+
await client.query("ROLLBACK");
|
|
788
|
+
}
|
|
789
|
+
catch (cleanupError) {
|
|
790
|
+
scope.#markTransactionStateUnsafe(cleanupError);
|
|
791
|
+
/* Preserve the original error. */
|
|
792
|
+
}
|
|
793
|
+
try {
|
|
794
|
+
client.release(scope.#transactionLeaseReleaseError());
|
|
795
|
+
}
|
|
796
|
+
catch {
|
|
797
|
+
/* Preserve the original error. */
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
throw error;
|
|
801
|
+
}
|
|
802
|
+
client.release(scope.#transactionLeaseReleaseError());
|
|
803
|
+
return result;
|
|
804
|
+
}
|
|
164
805
|
async #nestedTransaction(fn) {
|
|
165
806
|
const client = this.#client;
|
|
166
807
|
const depth = this.#transactionDepth + 1;
|
|
167
808
|
const savepoint = `typed_sql_${depth}`;
|
|
168
|
-
await client.query(`SAVEPOINT ${savepoint}`);
|
|
169
809
|
try {
|
|
170
|
-
|
|
171
|
-
|
|
810
|
+
await client.query(`SAVEPOINT ${savepoint}`);
|
|
811
|
+
}
|
|
812
|
+
catch (error) {
|
|
813
|
+
this.#recordTransactionOperationFailure(error);
|
|
814
|
+
throw error;
|
|
815
|
+
}
|
|
816
|
+
const scope = new _a(this.#pool, client, this.#parsers, false, depth, this.#prepared, this.#observation, this.#transactionState);
|
|
817
|
+
try {
|
|
818
|
+
let result;
|
|
819
|
+
try {
|
|
820
|
+
result = await fn(scope);
|
|
821
|
+
}
|
|
822
|
+
finally {
|
|
823
|
+
scope.#transactionScopeOpen = false;
|
|
824
|
+
}
|
|
825
|
+
if (!scope.#transactionState.valid) {
|
|
826
|
+
throw new Error("The parent PostgreSQL transaction scope ended before its nested transaction completed");
|
|
827
|
+
}
|
|
828
|
+
scope.#throwIfTransactionCannotCommit();
|
|
829
|
+
await scope.#rejectLeakedTransactionWork();
|
|
830
|
+
try {
|
|
831
|
+
await client.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
832
|
+
}
|
|
833
|
+
catch (error) {
|
|
834
|
+
scope.#recordTransactionOperationFailure(error);
|
|
835
|
+
throw error;
|
|
836
|
+
}
|
|
172
837
|
return result;
|
|
173
838
|
}
|
|
174
839
|
catch (error) {
|
|
175
|
-
await
|
|
840
|
+
await scope.#settleTransactionExecutesPreservingError();
|
|
841
|
+
await scope.#closeTransactionStreamsPreservingError();
|
|
842
|
+
await scope.#settleTransactionPipelinePreservingError();
|
|
843
|
+
await scope.#settleTransactionBatchPreservingError();
|
|
844
|
+
await scope.#settleTransactionCopyPreservingError();
|
|
845
|
+
if (scope.#transactionState.valid && !scope.#transactionState.leaseReleased) {
|
|
846
|
+
try {
|
|
847
|
+
await client.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
848
|
+
scope.#recoverTransactionStateAfterSavepoint(depth);
|
|
849
|
+
}
|
|
850
|
+
catch (cleanupError) {
|
|
851
|
+
scope.#markTransactionStateUnsafe(cleanupError);
|
|
852
|
+
/* Preserve the original callback, query, or release error. */
|
|
853
|
+
}
|
|
854
|
+
}
|
|
176
855
|
throw error;
|
|
177
856
|
}
|
|
178
857
|
}
|
|
858
|
+
#queryConfig(query) {
|
|
859
|
+
const prepared = this.#prepared.queries.get(queryResultValidationSource(query));
|
|
860
|
+
const rendered = prepared?.rendered ?? renderQuery(query, postgresRenderer);
|
|
861
|
+
return {
|
|
862
|
+
...(prepared === undefined ? {} : { name: prepared.statementName }),
|
|
863
|
+
text: rendered.text,
|
|
864
|
+
values: rendered.values.map(encodeValue),
|
|
865
|
+
types: this.#parsers,
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
async #executeBatch(client, queries) {
|
|
869
|
+
const results = [];
|
|
870
|
+
for (const value of queries) {
|
|
871
|
+
this.#assertTransactionScopeOpen();
|
|
872
|
+
const query = value;
|
|
873
|
+
const result = await client.query(this.#queryConfig(query));
|
|
874
|
+
results.push(result.rows);
|
|
875
|
+
}
|
|
876
|
+
return results;
|
|
877
|
+
}
|
|
878
|
+
async #executePipeline(client, configs) {
|
|
879
|
+
const operations = [];
|
|
880
|
+
let dispatchFailed = false;
|
|
881
|
+
let dispatchError;
|
|
882
|
+
for (const config of configs) {
|
|
883
|
+
try {
|
|
884
|
+
operations.push(client.query(config));
|
|
885
|
+
}
|
|
886
|
+
catch (error) {
|
|
887
|
+
dispatchFailed = true;
|
|
888
|
+
dispatchError = error;
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
const settlements = await Promise.allSettled(operations);
|
|
893
|
+
if (dispatchFailed)
|
|
894
|
+
throw dispatchError;
|
|
895
|
+
const results = [];
|
|
896
|
+
for (const settlement of settlements) {
|
|
897
|
+
if (settlement.status === "rejected")
|
|
898
|
+
throw settlement.reason;
|
|
899
|
+
results.push(settlement.value.rows);
|
|
900
|
+
}
|
|
901
|
+
return results;
|
|
902
|
+
}
|
|
903
|
+
#assertPipelineClient(client) {
|
|
904
|
+
if (client.pipeline !== true) {
|
|
905
|
+
throw new Error("PostgreSQL query pipelining requires pg 8.23.0 or newer and pipeline mode. Create the application-owned Pool with { pipeline: true }");
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
async #rejectLeakedTransactionWork() {
|
|
909
|
+
const leakedStreams = this.#transactionStreams.size > 0 || this.#transactionState.activeStreams.size > 0;
|
|
910
|
+
const leakedExecutes = this.#transactionExecutes.size > 0 || this.#transactionState.activeExecutes.size > 0;
|
|
911
|
+
const leakedPipeline = this.#transactionState.activePipeline !== undefined;
|
|
912
|
+
const leakedBatch = this.#transactionState.activeBatch !== undefined;
|
|
913
|
+
const leakedCopy = this.#transactionState.activeCopy !== undefined;
|
|
914
|
+
if (!leakedStreams && !leakedExecutes && !leakedPipeline && !leakedBatch && !leakedCopy)
|
|
915
|
+
return;
|
|
916
|
+
await this.#settleTransactionExecutesPreservingError();
|
|
917
|
+
await this.#closeTransactionStreamsPreservingError();
|
|
918
|
+
await this.#settleTransactionPipelinePreservingError();
|
|
919
|
+
await this.#settleTransactionBatchPreservingError();
|
|
920
|
+
await this.#settleTransactionCopyPreservingError();
|
|
921
|
+
if (leakedExecutes) {
|
|
922
|
+
throw new Error("A PostgreSQL transaction callback returned before an execute operation completed; await execute before returning");
|
|
923
|
+
}
|
|
924
|
+
if (leakedBatch) {
|
|
925
|
+
throw new Error("A PostgreSQL transaction callback returned before its query batch completed; await the batch before returning");
|
|
926
|
+
}
|
|
927
|
+
if (leakedPipeline) {
|
|
928
|
+
throw new Error("A PostgreSQL transaction callback returned before its query pipeline completed; await the pipeline before returning");
|
|
929
|
+
}
|
|
930
|
+
if (leakedCopy) {
|
|
931
|
+
throw new Error("A PostgreSQL transaction callback returned before its COPY operation completed; await COPY before returning");
|
|
932
|
+
}
|
|
933
|
+
throw new Error("A PostgreSQL transaction callback returned before all query streams were completed or closed");
|
|
934
|
+
}
|
|
935
|
+
async #settleTransactionExecutesPreservingError() {
|
|
936
|
+
const operations = new Set([...this.#transactionExecutes, ...this.#transactionState.activeExecutes]);
|
|
937
|
+
for (const operation of operations) {
|
|
938
|
+
try {
|
|
939
|
+
await operation;
|
|
940
|
+
}
|
|
941
|
+
catch {
|
|
942
|
+
/* The callback or transaction misuse error remains primary. */
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
async #closeTransactionStreamsPreservingError() {
|
|
947
|
+
const streams = new Set([...this.#transactionStreams, ...this.#transactionState.activeStreams]);
|
|
948
|
+
for (const stream of streams) {
|
|
949
|
+
try {
|
|
950
|
+
await stream.close();
|
|
951
|
+
}
|
|
952
|
+
catch {
|
|
953
|
+
/* The callback or transaction misuse error remains primary. */
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
async #settleTransactionBatchPreservingError() {
|
|
958
|
+
const operation = this.#transactionState.activeBatch;
|
|
959
|
+
if (operation === undefined)
|
|
960
|
+
return;
|
|
961
|
+
try {
|
|
962
|
+
await operation;
|
|
963
|
+
}
|
|
964
|
+
catch {
|
|
965
|
+
/* The callback or transaction misuse error remains primary. */
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
async #settleTransactionPipelinePreservingError() {
|
|
969
|
+
const operation = this.#transactionState.activePipeline;
|
|
970
|
+
if (operation === undefined)
|
|
971
|
+
return;
|
|
972
|
+
try {
|
|
973
|
+
await operation;
|
|
974
|
+
}
|
|
975
|
+
catch {
|
|
976
|
+
/* The callback or transaction misuse error remains primary. */
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
async #settleTransactionCopyPreservingError() {
|
|
980
|
+
const operation = this.#transactionState.activeCopy;
|
|
981
|
+
if (operation === undefined)
|
|
982
|
+
return;
|
|
983
|
+
try {
|
|
984
|
+
await operation;
|
|
985
|
+
}
|
|
986
|
+
catch {
|
|
987
|
+
/* The callback or transaction misuse error remains primary. */
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
#rejectOperationDuringTransactionStream(operation) {
|
|
991
|
+
if (this.#client !== undefined && this.#transactionState.activeStreams.size > 0) {
|
|
992
|
+
throw new Error(`Cannot ${operation} while a PostgreSQL transaction query stream is still open; complete or close the stream first`);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
#rejectOperationDuringTransactionBatch(operation) {
|
|
996
|
+
if (this.#client !== undefined && this.#transactionState.activeBatch !== undefined) {
|
|
997
|
+
throw new Error(`Cannot ${operation} while a PostgreSQL transaction query batch is still running; await the batch first`);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
#rejectOperationDuringTransactionCopy(operation) {
|
|
1001
|
+
if (this.#client !== undefined && this.#transactionState.activeCopy !== undefined) {
|
|
1002
|
+
throw new Error(`Cannot ${operation} while a PostgreSQL transaction COPY operation is still running; await COPY first`);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
#rejectOperationDuringTransactionExecute(operation) {
|
|
1006
|
+
if (this.#client !== undefined && this.#transactionState.activeExecutes.size > 0) {
|
|
1007
|
+
throw new Error(`Cannot ${operation} while a PostgreSQL transaction execute operation is still running; await execute first`);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
#rejectOperationDuringTransactionPipeline(operation) {
|
|
1011
|
+
if (this.#client !== undefined && this.#transactionState.activePipeline !== undefined) {
|
|
1012
|
+
throw new Error(`Cannot ${operation} while a PostgreSQL transaction query pipeline is still running; await the pipeline first`);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
#recordTransactionOperationFailure(error) {
|
|
1016
|
+
if (this.#client === undefined)
|
|
1017
|
+
return;
|
|
1018
|
+
if (!this.#transactionOperationFailed) {
|
|
1019
|
+
this.#transactionOperationFailed = true;
|
|
1020
|
+
this.#transactionOperationError = error;
|
|
1021
|
+
}
|
|
1022
|
+
this.#markTransactionStateUnsafe(error);
|
|
1023
|
+
}
|
|
1024
|
+
#markTransactionStateUnsafe(error) {
|
|
1025
|
+
if (!this.#transactionState.discardLease) {
|
|
1026
|
+
this.#transactionState.discardLease = true;
|
|
1027
|
+
this.#transactionState.firstDatabaseOperationError = error;
|
|
1028
|
+
}
|
|
1029
|
+
if (!this.#transactionState.unsafe ||
|
|
1030
|
+
this.#transactionState.unsafeDepth === undefined ||
|
|
1031
|
+
this.#transactionDepth < this.#transactionState.unsafeDepth) {
|
|
1032
|
+
this.#transactionState.unsafe = true;
|
|
1033
|
+
this.#transactionState.unsafeDepth = this.#transactionDepth;
|
|
1034
|
+
this.#transactionState.unsafeError = error;
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
#recoverTransactionStateAfterSavepoint(depth) {
|
|
1038
|
+
if (this.#transactionState.unsafeDepth === undefined || this.#transactionState.unsafeDepth < depth)
|
|
1039
|
+
return;
|
|
1040
|
+
this.#transactionState.unsafe = false;
|
|
1041
|
+
this.#transactionState.unsafeDepth = undefined;
|
|
1042
|
+
this.#transactionState.unsafeError = undefined;
|
|
1043
|
+
}
|
|
1044
|
+
#transactionLeaseReleaseError() {
|
|
1045
|
+
if (!this.#transactionState.discardLease)
|
|
1046
|
+
return undefined;
|
|
1047
|
+
return this.#transactionState.firstDatabaseOperationError instanceof Error
|
|
1048
|
+
? this.#transactionState.firstDatabaseOperationError
|
|
1049
|
+
: true;
|
|
1050
|
+
}
|
|
1051
|
+
#throwIfTransactionCannotCommit() {
|
|
1052
|
+
if (this.#transactionOperationFailed) {
|
|
1053
|
+
if (this.#transactionOperationError !== undefined)
|
|
1054
|
+
throw this.#transactionOperationError;
|
|
1055
|
+
throw new Error("A PostgreSQL transaction operation failed and the transaction cannot be committed");
|
|
1056
|
+
}
|
|
1057
|
+
if (this.#transactionState.unsafe) {
|
|
1058
|
+
throw new Error("The PostgreSQL transaction connection did not complete recovery and cannot be committed", {
|
|
1059
|
+
cause: this.#transactionState.unsafeError,
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
#assertTransactionScopeOpen() {
|
|
1064
|
+
if (this.#client === undefined)
|
|
1065
|
+
return;
|
|
1066
|
+
if (!this.#transactionScopeOpen || !this.#transactionState.valid) {
|
|
1067
|
+
throw new Error("This PostgreSQL transaction scope has ended and can no longer be used");
|
|
1068
|
+
}
|
|
1069
|
+
if (this.#transactionOperationFailed) {
|
|
1070
|
+
throw new Error("This PostgreSQL transaction scope cannot continue after a database operation failed", {
|
|
1071
|
+
cause: this.#transactionOperationError,
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
if (this.#transactionState.unsafe) {
|
|
1075
|
+
throw new Error("The PostgreSQL transaction cannot continue until its failed operation is rolled back", {
|
|
1076
|
+
cause: this.#transactionState.unsafeError,
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
179
1080
|
async close() {
|
|
180
1081
|
if (this.#client !== undefined)
|
|
181
1082
|
throw new Error("Cannot close a database from inside a transaction");
|
|
@@ -185,6 +1086,6 @@ class PostgresDatabaseImplementation {
|
|
|
185
1086
|
}
|
|
186
1087
|
_a = PostgresDatabaseImplementation;
|
|
187
1088
|
export function createPostgresDatabase(options) {
|
|
188
|
-
return new PostgresDatabaseImplementation(options.pool, undefined, createPostgresTypeParsers(options.typePolicy ?? defaultPolicy, options.decimal, options.fallbackTypeParsers), options.ownsPool ?? false, 0);
|
|
1089
|
+
return new PostgresDatabaseImplementation(options.pool, undefined, createPostgresTypeParsers(options.typePolicy ?? defaultPolicy, options.decimal, options.fallbackTypeParsers), options.ownsPool ?? false, 0, createPostgresPreparedQueryState(), createPostgresObservationState(options.observer));
|
|
189
1090
|
}
|
|
190
1091
|
//# sourceMappingURL=runtime.js.map
|