@steadybrew/postgresjs 4.3.0 → 4.4.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/README.md +18 -2
- package/cf/src/connection.js +59 -19
- package/cf/src/errors.js +8 -0
- package/cf/src/index.js +61 -34
- package/cf/src/subscribe.js +127 -47
- package/cjs/src/connection.js +59 -19
- package/cjs/src/errors.js +8 -0
- package/cjs/src/index.js +61 -34
- package/cjs/src/subscribe.js +127 -47
- package/package.json +1 -1
- package/src/connection.js +59 -19
- package/src/errors.js +8 -0
- package/src/index.js +61 -34
- package/src/subscribe.js +127 -47
- package/types/index.d.ts +9 -9
package/src/connection.js
CHANGED
|
@@ -5,7 +5,7 @@ import Stream from 'stream'
|
|
|
5
5
|
import { performance } from 'perf_hooks'
|
|
6
6
|
|
|
7
7
|
import { stringify, handleValue, addArrayType } from './types.js'
|
|
8
|
-
import { Errors } from './errors.js'
|
|
8
|
+
import { Errors, callback } from './errors.js'
|
|
9
9
|
import Result from './result.js'
|
|
10
10
|
import Queue from './queue.js'
|
|
11
11
|
import clampedTimeout from './timeout.js'
|
|
@@ -13,7 +13,7 @@ import { SSLRequest, tlsConfig, cancelRequest } from './transport.js'
|
|
|
13
13
|
import { Query, CLOSE } from './query.js'
|
|
14
14
|
import b from './bytes.js'
|
|
15
15
|
|
|
16
|
-
export
|
|
16
|
+
export { Connection }
|
|
17
17
|
|
|
18
18
|
let uid = 1
|
|
19
19
|
|
|
@@ -26,6 +26,8 @@ const Sync = b().S().end()
|
|
|
26
26
|
const Phase = { Closed: 0, Backoff: 1, Connecting: 2, Initializing: 3, Ready: 4, Draining: 5, Closing: 6 }
|
|
27
27
|
const phaseNames = Object.keys(Phase)
|
|
28
28
|
|
|
29
|
+
const endsAbortedState = /^\s*(rollback|abort)\b/i
|
|
30
|
+
|
|
29
31
|
const retryRoutines = new Set([
|
|
30
32
|
'FetchPreparedStatement',
|
|
31
33
|
'RevalidateCachedQuery',
|
|
@@ -110,6 +112,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
110
112
|
, chunk = null
|
|
111
113
|
, nonce = null
|
|
112
114
|
, query = null
|
|
115
|
+
, barrier = null
|
|
113
116
|
, final = null
|
|
114
117
|
|
|
115
118
|
const check = globalThis[Symbol.for('postgres.js:check')]
|
|
@@ -224,6 +227,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
224
227
|
owner: null,
|
|
225
228
|
get active() { return query ? 1 : 0 },
|
|
226
229
|
get pipelined() { return sent.length },
|
|
230
|
+
get accepting() { return accepting() },
|
|
231
|
+
get copying() { return stream !== null },
|
|
232
|
+
get copyHeld() { return stream !== null && !stream.writableEnded },
|
|
227
233
|
get acquiring() { return acquisition && !acquisition.owner.cancelled ? 1 : 0 },
|
|
228
234
|
count: 0,
|
|
229
235
|
id
|
|
@@ -268,8 +274,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
268
274
|
return !query && sent.length === 0
|
|
269
275
|
}
|
|
270
276
|
|
|
277
|
+
function accepting() {
|
|
278
|
+
return !query || (!barrier && sent.length < max_pipeline)
|
|
279
|
+
}
|
|
280
|
+
|
|
271
281
|
function backoffMs() {
|
|
272
|
-
return (
|
|
282
|
+
return backoffSeconds(backoff, options.shared.retries) * 1000
|
|
273
283
|
}
|
|
274
284
|
|
|
275
285
|
function standbyPass() {
|
|
@@ -446,7 +456,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
446
456
|
queryError(pending, err)
|
|
447
457
|
pending.cancelled && pending.cancelled.resolve()
|
|
448
458
|
}
|
|
449
|
-
query = results = errorResponse = chunk = nextWriteTimer = null
|
|
459
|
+
query = results = errorResponse = chunk = nextWriteTimer = barrier = null
|
|
450
460
|
result = new Result()
|
|
451
461
|
rows = 0
|
|
452
462
|
nonce = serverSignature = null
|
|
@@ -510,8 +520,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
510
520
|
}
|
|
511
521
|
|
|
512
522
|
function submit(q) {
|
|
513
|
-
if (stream)
|
|
514
|
-
|
|
523
|
+
if (stream) {
|
|
524
|
+
queryError(q, Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy'))
|
|
525
|
+
return true
|
|
526
|
+
}
|
|
515
527
|
|
|
516
528
|
if (q.cancelled)
|
|
517
529
|
return true
|
|
@@ -525,17 +537,21 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
525
537
|
: (query = q, query.active = true)
|
|
526
538
|
|
|
527
539
|
build(q)
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
540
|
+
const written = write(toBuffer(q))
|
|
541
|
+
if (q.describeFirst || q.cursorFn || mayCopy(q))
|
|
542
|
+
barrier = q
|
|
543
|
+
return written && accepting()
|
|
532
544
|
} catch (error) {
|
|
533
545
|
sent.remove(q) || write(Sync)
|
|
534
546
|
queryError(q, error)
|
|
535
|
-
return
|
|
547
|
+
return accepting()
|
|
536
548
|
}
|
|
537
549
|
}
|
|
538
550
|
|
|
551
|
+
function mayCopy(q) {
|
|
552
|
+
return q.options.simple && /\bcopy\b/i.test(q.string)
|
|
553
|
+
}
|
|
554
|
+
|
|
539
555
|
function toBuffer(q) {
|
|
540
556
|
if (q.parameters.length >= 65534)
|
|
541
557
|
throw Errors.generic('MAX_PARAMETERS_EXCEEDED', 'Max number of parameters (65534) exceeded')
|
|
@@ -594,7 +610,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
594
610
|
? statements[q.signature]
|
|
595
611
|
: { string, types, name: q.prepare ? statementId + statementCount++ : '' }
|
|
596
612
|
|
|
597
|
-
typeof options.debug === 'function' && options.debug
|
|
613
|
+
typeof options.debug === 'function' && callback(options.debug, id, string, parameters, types)
|
|
598
614
|
}
|
|
599
615
|
|
|
600
616
|
function write(x, fn) {
|
|
@@ -765,18 +781,21 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
765
781
|
backendParameters[k] = v
|
|
766
782
|
if (options.parameters[k] !== v) {
|
|
767
783
|
options.parameters[k] = v
|
|
768
|
-
onparameter
|
|
784
|
+
callback(onparameter, k, v)
|
|
769
785
|
}
|
|
770
786
|
}
|
|
771
787
|
|
|
772
|
-
function ReadyForQuery() {
|
|
788
|
+
function ReadyForQuery(x) {
|
|
789
|
+
query === barrier && (barrier = null)
|
|
773
790
|
if (query) {
|
|
774
791
|
if (errorResponse) {
|
|
775
792
|
if (query.initialization)
|
|
776
793
|
return dispatch('initFailed', errorResponse)
|
|
794
|
+
query.prepared && retryRoutines.has(errorResponse.routine) && delete statements[query.signature]
|
|
777
795
|
query.retried
|
|
778
796
|
? errored(query.retried)
|
|
779
|
-
: query.prepared && retryRoutines.has(errorResponse.routine) && query.owner === connection.owner
|
|
797
|
+
: query.prepared && retryRoutines.has(errorResponse.routine) && query.owner === connection.owner && !barrier
|
|
798
|
+
&& (x[5] !== 69 || endsAbortedState.test(query.string))
|
|
780
799
|
? retry(query, errorResponse)
|
|
781
800
|
: errored(errorResponse)
|
|
782
801
|
} else {
|
|
@@ -1059,7 +1078,6 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1059
1078
|
}
|
|
1060
1079
|
|
|
1061
1080
|
function retry(q, error) {
|
|
1062
|
-
delete statements[q.signature]
|
|
1063
1081
|
q.retried = error
|
|
1064
1082
|
execute(q)
|
|
1065
1083
|
}
|
|
@@ -1070,7 +1088,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1070
1088
|
|
|
1071
1089
|
let index = 9
|
|
1072
1090
|
while (x[index++] !== 0);
|
|
1073
|
-
|
|
1091
|
+
callback(
|
|
1092
|
+
onnotify,
|
|
1074
1093
|
x.toString('utf8', 9, index - 1),
|
|
1075
1094
|
x.toString('utf8', index, x.length - 1)
|
|
1076
1095
|
)
|
|
@@ -1116,6 +1135,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1116
1135
|
}
|
|
1117
1136
|
})
|
|
1118
1137
|
query.resolve(stream)
|
|
1138
|
+
connection.owner && connection.owner.next()
|
|
1119
1139
|
}
|
|
1120
1140
|
|
|
1121
1141
|
function CopyOutResponse() {
|
|
@@ -1123,6 +1143,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1123
1143
|
read() { socket.resume() }
|
|
1124
1144
|
})
|
|
1125
1145
|
query.resolve(stream)
|
|
1146
|
+
connection.owner && connection.owner.next()
|
|
1126
1147
|
}
|
|
1127
1148
|
|
|
1128
1149
|
/* c8 ignore next 3 */
|
|
@@ -1145,6 +1166,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1145
1166
|
}
|
|
1146
1167
|
})
|
|
1147
1168
|
query.resolve(stream)
|
|
1169
|
+
connection.owner && connection.owner.next()
|
|
1148
1170
|
}
|
|
1149
1171
|
|
|
1150
1172
|
function CopyData(x) {
|
|
@@ -1157,10 +1179,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1157
1179
|
}
|
|
1158
1180
|
|
|
1159
1181
|
function NoticeResponse(x) {
|
|
1182
|
+
if (onnotice === false)
|
|
1183
|
+
return
|
|
1184
|
+
|
|
1160
1185
|
onnotice
|
|
1161
|
-
? onnotice
|
|
1186
|
+
? callback(onnotice, parseError(x))
|
|
1162
1187
|
: console.log(parseError(x)) // eslint-disable-line
|
|
1163
|
-
|
|
1164
1188
|
}
|
|
1165
1189
|
|
|
1166
1190
|
/* c8 ignore next 3 */
|
|
@@ -1311,3 +1335,19 @@ function timer(fn, seconds) {
|
|
|
1311
1335
|
fn.apply(null, args)
|
|
1312
1336
|
}
|
|
1313
1337
|
}
|
|
1338
|
+
|
|
1339
|
+
export function defaultBackoff(retries) {
|
|
1340
|
+
return (0.5 + Math.random() / 2) * Math.min(3 ** retries / 100, 20)
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
export function backoffSeconds(backoff, retries) {
|
|
1344
|
+
if (typeof backoff !== 'function')
|
|
1345
|
+
return backoff
|
|
1346
|
+
|
|
1347
|
+
try {
|
|
1348
|
+
return backoff(retries)
|
|
1349
|
+
} catch (e) {
|
|
1350
|
+
callback(() => { throw e })
|
|
1351
|
+
return defaultBackoff(retries)
|
|
1352
|
+
}
|
|
1353
|
+
}
|
package/src/errors.js
CHANGED
package/src/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
Parameter,
|
|
9
9
|
Identifier,
|
|
10
10
|
Builder,
|
|
11
|
+
escapeIdentifier,
|
|
11
12
|
toPascal,
|
|
12
13
|
pascal,
|
|
13
14
|
toCamel,
|
|
@@ -19,12 +20,12 @@ import {
|
|
|
19
20
|
fromKebab
|
|
20
21
|
} from './types.js'
|
|
21
22
|
|
|
22
|
-
import Connection from './connection.js'
|
|
23
|
+
import { Connection, defaultBackoff } from './connection.js'
|
|
23
24
|
import { cancelRequest } from './transport.js'
|
|
24
25
|
import clampedTimeout from './timeout.js'
|
|
25
26
|
import { Query, CLOSE } from './query.js'
|
|
26
27
|
import Queue from './queue.js'
|
|
27
|
-
import { Errors, PostgresError } from './errors.js'
|
|
28
|
+
import { Errors, PostgresError, callback } from './errors.js'
|
|
28
29
|
import Subscribe from './subscribe.js'
|
|
29
30
|
import largeObject from './large.js'
|
|
30
31
|
|
|
@@ -218,7 +219,7 @@ function Postgres(a, b) {
|
|
|
218
219
|
})
|
|
219
220
|
},
|
|
220
221
|
onnotify(c, x) {
|
|
221
|
-
c in listen.channels && listen.channels[c].listeners.forEach(l => l.fn
|
|
222
|
+
c in listen.channels && listen.channels[c].listeners.forEach(l => callback(l.fn, x))
|
|
222
223
|
}
|
|
223
224
|
}))
|
|
224
225
|
|
|
@@ -228,7 +229,7 @@ function Postgres(a, b) {
|
|
|
228
229
|
if (exists) {
|
|
229
230
|
channels[name].listeners.push(listener)
|
|
230
231
|
const result = await channels[name].result
|
|
231
|
-
listener.onlisten
|
|
232
|
+
callback(listener.onlisten)
|
|
232
233
|
return { state: result.state, unlisten }
|
|
233
234
|
}
|
|
234
235
|
|
|
@@ -236,7 +237,7 @@ function Postgres(a, b) {
|
|
|
236
237
|
sql.unsafe('"' + name.replace(/"/g, '""') + '"')
|
|
237
238
|
}`, listeners: [listener] }
|
|
238
239
|
const result = await channels[name].result
|
|
239
|
-
listener.onlisten
|
|
240
|
+
callback(listener.onlisten)
|
|
240
241
|
return { state: result.state, unlisten }
|
|
241
242
|
|
|
242
243
|
async function unlisten() {
|
|
@@ -272,7 +273,9 @@ function Postgres(a, b) {
|
|
|
272
273
|
const query = { reserve: c => resolve(own(c, l)), reject }
|
|
273
274
|
closed.length
|
|
274
275
|
? connect(closed.shift(), query)
|
|
275
|
-
:
|
|
276
|
+
: allHeldByCopy()
|
|
277
|
+
? reject(copyInProgress())
|
|
278
|
+
: queries.push(query)
|
|
276
279
|
})
|
|
277
280
|
return l
|
|
278
281
|
}
|
|
@@ -294,9 +297,9 @@ function Postgres(a, b) {
|
|
|
294
297
|
function send(l, q, expected = Lease.Active) {
|
|
295
298
|
const c = l.connection
|
|
296
299
|
l.state === expected
|
|
297
|
-
? c.queue
|
|
298
|
-
? (q
|
|
299
|
-
:
|
|
300
|
+
? c.copying || (c.queue !== full && c.accepting)
|
|
301
|
+
? c.execute(q) || move(c, full)
|
|
302
|
+
: (move(c, full), q.queue = l.queue, l.queue.push(q))
|
|
300
303
|
: q.reject(leaseError(l.state))
|
|
301
304
|
}
|
|
302
305
|
|
|
@@ -352,14 +355,16 @@ function Postgres(a, b) {
|
|
|
352
355
|
}
|
|
353
356
|
|
|
354
357
|
async function finish(statement) {
|
|
358
|
+
let result
|
|
355
359
|
l.state = Lease.Settling
|
|
356
360
|
try {
|
|
357
|
-
await statement(Sql(q => send(l, q, Lease.Settling)))
|
|
361
|
+
result = await statement(Sql(q => send(l, q, Lease.Settling)))
|
|
358
362
|
} catch (e) {
|
|
359
363
|
settle(l, Lease.Discarded)
|
|
360
364
|
throw e
|
|
361
365
|
}
|
|
362
366
|
settle(l, Lease.Released)
|
|
367
|
+
return result
|
|
363
368
|
}
|
|
364
369
|
|
|
365
370
|
async function scope(fn, name) {
|
|
@@ -374,7 +379,7 @@ function Postgres(a, b) {
|
|
|
374
379
|
let uncaughtError
|
|
375
380
|
, result
|
|
376
381
|
|
|
377
|
-
name && await sql
|
|
382
|
+
name && await sql.unsafe('savepoint ' + escapeIdentifier(name))
|
|
378
383
|
try {
|
|
379
384
|
result = await new Promise((resolve, reject) => {
|
|
380
385
|
const x = fn(sql)
|
|
@@ -385,8 +390,8 @@ function Postgres(a, b) {
|
|
|
385
390
|
throw uncaughtError
|
|
386
391
|
} catch (e) {
|
|
387
392
|
l.state === Lease.Active && await (name
|
|
388
|
-
? sql
|
|
389
|
-
: finish(final => final
|
|
393
|
+
? sql.unsafe('rollback to ' + escapeIdentifier(name))
|
|
394
|
+
: finish(final => final.unsafe('rollback'))
|
|
390
395
|
)
|
|
391
396
|
throw e instanceof PostgresError && e.code === '25P02' && uncaughtError || e
|
|
392
397
|
}
|
|
@@ -394,10 +399,18 @@ function Postgres(a, b) {
|
|
|
394
399
|
if (l.state !== Lease.Active)
|
|
395
400
|
throw l.error || leaseError(l.state)
|
|
396
401
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
402
|
+
if (!name) {
|
|
403
|
+
const done = await finish(final => prepare
|
|
404
|
+
? final.unsafe('prepare transaction ' + prepare)
|
|
405
|
+
: final.unsafe('commit')
|
|
406
|
+
)
|
|
407
|
+
if (done.command === 'ROLLBACK') {
|
|
408
|
+
throw Object.assign(
|
|
409
|
+
Errors.generic('TRANSACTION_ROLLED_BACK', 'The server rolled the transaction back instead of committing it'),
|
|
410
|
+
uncaughtError && { cause: uncaughtError }
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
}
|
|
401
414
|
|
|
402
415
|
return result
|
|
403
416
|
|
|
@@ -426,14 +439,6 @@ function Postgres(a, b) {
|
|
|
426
439
|
return c
|
|
427
440
|
}
|
|
428
441
|
|
|
429
|
-
function callback(fn, ...args) {
|
|
430
|
-
try {
|
|
431
|
-
fn && fn(...args)
|
|
432
|
-
} catch (e) {
|
|
433
|
-
queueMicrotask(() => { throw e })
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
442
|
function json(x) {
|
|
438
443
|
return new Parameter(x, 3802)
|
|
439
444
|
}
|
|
@@ -456,9 +461,32 @@ function Postgres(a, b) {
|
|
|
456
461
|
if (closed.length)
|
|
457
462
|
return connect(closed.shift(), query)
|
|
458
463
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
464
|
+
const c = takeBusy()
|
|
465
|
+
c
|
|
466
|
+
? go(c, query)
|
|
467
|
+
: allHeldByCopy()
|
|
468
|
+
? query.reject(copyInProgress())
|
|
469
|
+
: queries.push(query)
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function allHeldByCopy() {
|
|
473
|
+
return connections.every(c => c.copyHeld)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function copyInProgress() {
|
|
477
|
+
return Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy')
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function takeBusy() {
|
|
481
|
+
while (busy.length) {
|
|
482
|
+
const c = busy.shift()
|
|
483
|
+
if (c.accepting)
|
|
484
|
+
return c
|
|
485
|
+
|
|
486
|
+
move(c, full)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return null
|
|
462
490
|
}
|
|
463
491
|
|
|
464
492
|
function takeOpen() {
|
|
@@ -545,6 +573,9 @@ function Postgres(a, b) {
|
|
|
545
573
|
if (initial && initial.reserve)
|
|
546
574
|
return initial.reserve(c)
|
|
547
575
|
|
|
576
|
+
if (!initial && !c.accepting)
|
|
577
|
+
return move(c, full)
|
|
578
|
+
|
|
548
579
|
if (!initial && !queries.length)
|
|
549
580
|
return move(c, open)
|
|
550
581
|
|
|
@@ -583,7 +614,7 @@ function Postgres(a, b) {
|
|
|
583
614
|
function onclose(c, e) {
|
|
584
615
|
move(c, closed)
|
|
585
616
|
c.owner && settle(c.owner, Lease.Closed, e)
|
|
586
|
-
options.onclose
|
|
617
|
+
callback(options.onclose, c.id)
|
|
587
618
|
if (ending)
|
|
588
619
|
return closedWhileEnding(c, e)
|
|
589
620
|
|
|
@@ -638,7 +669,7 @@ function parseOptions(a, b) {
|
|
|
638
669
|
connect_timeout : 30,
|
|
639
670
|
max_lifetime : max_lifetime,
|
|
640
671
|
max_pipeline : 100,
|
|
641
|
-
backoff :
|
|
672
|
+
backoff : defaultBackoff,
|
|
642
673
|
keep_alive : 60,
|
|
643
674
|
prepare : true,
|
|
644
675
|
debug : false,
|
|
@@ -697,10 +728,6 @@ function tsa(o, url, env) {
|
|
|
697
728
|
throw new Error('target_session_attrs ' + x + ' is not supported')
|
|
698
729
|
}
|
|
699
730
|
|
|
700
|
-
function backoff(retries) {
|
|
701
|
-
return (0.5 + Math.random() / 2) * Math.min(3 ** retries / 100, 20)
|
|
702
|
-
}
|
|
703
|
-
|
|
704
731
|
function max_lifetime() {
|
|
705
732
|
return 60 * (30 + Math.random() * 30)
|
|
706
733
|
}
|