@steadybrew/postgresjs 4.3.0 → 4.4.0
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 +58 -19
- package/cf/src/errors.js +8 -0
- package/cf/src/index.js +47 -32
- package/cf/src/subscribe.js +122 -47
- package/cjs/src/connection.js +58 -19
- package/cjs/src/errors.js +8 -0
- package/cjs/src/index.js +47 -32
- package/cjs/src/subscribe.js +122 -47
- package/package.json +1 -1
- package/src/connection.js +58 -19
- package/src/errors.js +8 -0
- package/src/index.js +47 -32
- package/src/subscribe.js +122 -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,8 @@ 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 },
|
|
227
232
|
get acquiring() { return acquisition && !acquisition.owner.cancelled ? 1 : 0 },
|
|
228
233
|
count: 0,
|
|
229
234
|
id
|
|
@@ -268,8 +273,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
268
273
|
return !query && sent.length === 0
|
|
269
274
|
}
|
|
270
275
|
|
|
276
|
+
function accepting() {
|
|
277
|
+
return !query || (!barrier && sent.length < max_pipeline)
|
|
278
|
+
}
|
|
279
|
+
|
|
271
280
|
function backoffMs() {
|
|
272
|
-
return (
|
|
281
|
+
return backoffSeconds(backoff, options.shared.retries) * 1000
|
|
273
282
|
}
|
|
274
283
|
|
|
275
284
|
function standbyPass() {
|
|
@@ -446,7 +455,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
446
455
|
queryError(pending, err)
|
|
447
456
|
pending.cancelled && pending.cancelled.resolve()
|
|
448
457
|
}
|
|
449
|
-
query = results = errorResponse = chunk = nextWriteTimer = null
|
|
458
|
+
query = results = errorResponse = chunk = nextWriteTimer = barrier = null
|
|
450
459
|
result = new Result()
|
|
451
460
|
rows = 0
|
|
452
461
|
nonce = serverSignature = null
|
|
@@ -510,8 +519,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
510
519
|
}
|
|
511
520
|
|
|
512
521
|
function submit(q) {
|
|
513
|
-
if (stream)
|
|
514
|
-
|
|
522
|
+
if (stream) {
|
|
523
|
+
queryError(q, Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy'))
|
|
524
|
+
return true
|
|
525
|
+
}
|
|
515
526
|
|
|
516
527
|
if (q.cancelled)
|
|
517
528
|
return true
|
|
@@ -525,17 +536,21 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
525
536
|
: (query = q, query.active = true)
|
|
526
537
|
|
|
527
538
|
build(q)
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
539
|
+
const written = write(toBuffer(q))
|
|
540
|
+
if (q.describeFirst || q.cursorFn || mayCopy(q))
|
|
541
|
+
barrier = q
|
|
542
|
+
return written && accepting()
|
|
532
543
|
} catch (error) {
|
|
533
544
|
sent.remove(q) || write(Sync)
|
|
534
545
|
queryError(q, error)
|
|
535
|
-
return
|
|
546
|
+
return accepting()
|
|
536
547
|
}
|
|
537
548
|
}
|
|
538
549
|
|
|
550
|
+
function mayCopy(q) {
|
|
551
|
+
return q.options.simple && /\bcopy\b/i.test(q.string)
|
|
552
|
+
}
|
|
553
|
+
|
|
539
554
|
function toBuffer(q) {
|
|
540
555
|
if (q.parameters.length >= 65534)
|
|
541
556
|
throw Errors.generic('MAX_PARAMETERS_EXCEEDED', 'Max number of parameters (65534) exceeded')
|
|
@@ -594,7 +609,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
594
609
|
? statements[q.signature]
|
|
595
610
|
: { string, types, name: q.prepare ? statementId + statementCount++ : '' }
|
|
596
611
|
|
|
597
|
-
typeof options.debug === 'function' && options.debug
|
|
612
|
+
typeof options.debug === 'function' && callback(options.debug, id, string, parameters, types)
|
|
598
613
|
}
|
|
599
614
|
|
|
600
615
|
function write(x, fn) {
|
|
@@ -765,18 +780,21 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
765
780
|
backendParameters[k] = v
|
|
766
781
|
if (options.parameters[k] !== v) {
|
|
767
782
|
options.parameters[k] = v
|
|
768
|
-
onparameter
|
|
783
|
+
callback(onparameter, k, v)
|
|
769
784
|
}
|
|
770
785
|
}
|
|
771
786
|
|
|
772
|
-
function ReadyForQuery() {
|
|
787
|
+
function ReadyForQuery(x) {
|
|
788
|
+
query === barrier && (barrier = null)
|
|
773
789
|
if (query) {
|
|
774
790
|
if (errorResponse) {
|
|
775
791
|
if (query.initialization)
|
|
776
792
|
return dispatch('initFailed', errorResponse)
|
|
793
|
+
query.prepared && retryRoutines.has(errorResponse.routine) && delete statements[query.signature]
|
|
777
794
|
query.retried
|
|
778
795
|
? errored(query.retried)
|
|
779
|
-
: query.prepared && retryRoutines.has(errorResponse.routine) && query.owner === connection.owner
|
|
796
|
+
: query.prepared && retryRoutines.has(errorResponse.routine) && query.owner === connection.owner && !barrier
|
|
797
|
+
&& (x[5] !== 69 || endsAbortedState.test(query.string))
|
|
780
798
|
? retry(query, errorResponse)
|
|
781
799
|
: errored(errorResponse)
|
|
782
800
|
} else {
|
|
@@ -1059,7 +1077,6 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1059
1077
|
}
|
|
1060
1078
|
|
|
1061
1079
|
function retry(q, error) {
|
|
1062
|
-
delete statements[q.signature]
|
|
1063
1080
|
q.retried = error
|
|
1064
1081
|
execute(q)
|
|
1065
1082
|
}
|
|
@@ -1070,7 +1087,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1070
1087
|
|
|
1071
1088
|
let index = 9
|
|
1072
1089
|
while (x[index++] !== 0);
|
|
1073
|
-
|
|
1090
|
+
callback(
|
|
1091
|
+
onnotify,
|
|
1074
1092
|
x.toString('utf8', 9, index - 1),
|
|
1075
1093
|
x.toString('utf8', index, x.length - 1)
|
|
1076
1094
|
)
|
|
@@ -1116,6 +1134,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1116
1134
|
}
|
|
1117
1135
|
})
|
|
1118
1136
|
query.resolve(stream)
|
|
1137
|
+
connection.owner && connection.owner.next()
|
|
1119
1138
|
}
|
|
1120
1139
|
|
|
1121
1140
|
function CopyOutResponse() {
|
|
@@ -1123,6 +1142,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1123
1142
|
read() { socket.resume() }
|
|
1124
1143
|
})
|
|
1125
1144
|
query.resolve(stream)
|
|
1145
|
+
connection.owner && connection.owner.next()
|
|
1126
1146
|
}
|
|
1127
1147
|
|
|
1128
1148
|
/* c8 ignore next 3 */
|
|
@@ -1145,6 +1165,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1145
1165
|
}
|
|
1146
1166
|
})
|
|
1147
1167
|
query.resolve(stream)
|
|
1168
|
+
connection.owner && connection.owner.next()
|
|
1148
1169
|
}
|
|
1149
1170
|
|
|
1150
1171
|
function CopyData(x) {
|
|
@@ -1157,10 +1178,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
1157
1178
|
}
|
|
1158
1179
|
|
|
1159
1180
|
function NoticeResponse(x) {
|
|
1181
|
+
if (onnotice === false)
|
|
1182
|
+
return
|
|
1183
|
+
|
|
1160
1184
|
onnotice
|
|
1161
|
-
? onnotice
|
|
1185
|
+
? callback(onnotice, parseError(x))
|
|
1162
1186
|
: console.log(parseError(x)) // eslint-disable-line
|
|
1163
|
-
|
|
1164
1187
|
}
|
|
1165
1188
|
|
|
1166
1189
|
/* c8 ignore next 3 */
|
|
@@ -1311,3 +1334,19 @@ function timer(fn, seconds) {
|
|
|
1311
1334
|
fn.apply(null, args)
|
|
1312
1335
|
}
|
|
1313
1336
|
}
|
|
1337
|
+
|
|
1338
|
+
export function defaultBackoff(retries) {
|
|
1339
|
+
return (0.5 + Math.random() / 2) * Math.min(3 ** retries / 100, 20)
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
export function backoffSeconds(backoff, retries) {
|
|
1343
|
+
if (typeof backoff !== 'function')
|
|
1344
|
+
return backoff
|
|
1345
|
+
|
|
1346
|
+
try {
|
|
1347
|
+
return backoff(retries)
|
|
1348
|
+
} catch (e) {
|
|
1349
|
+
callback(() => { throw e })
|
|
1350
|
+
return defaultBackoff(retries)
|
|
1351
|
+
}
|
|
1352
|
+
}
|
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() {
|
|
@@ -294,9 +295,9 @@ function Postgres(a, b) {
|
|
|
294
295
|
function send(l, q, expected = Lease.Active) {
|
|
295
296
|
const c = l.connection
|
|
296
297
|
l.state === expected
|
|
297
|
-
? c.queue
|
|
298
|
-
? (q
|
|
299
|
-
:
|
|
298
|
+
? c.copying || (c.queue !== full && c.accepting)
|
|
299
|
+
? c.execute(q) || move(c, full)
|
|
300
|
+
: (move(c, full), q.queue = l.queue, l.queue.push(q))
|
|
300
301
|
: q.reject(leaseError(l.state))
|
|
301
302
|
}
|
|
302
303
|
|
|
@@ -352,14 +353,16 @@ function Postgres(a, b) {
|
|
|
352
353
|
}
|
|
353
354
|
|
|
354
355
|
async function finish(statement) {
|
|
356
|
+
let result
|
|
355
357
|
l.state = Lease.Settling
|
|
356
358
|
try {
|
|
357
|
-
await statement(Sql(q => send(l, q, Lease.Settling)))
|
|
359
|
+
result = await statement(Sql(q => send(l, q, Lease.Settling)))
|
|
358
360
|
} catch (e) {
|
|
359
361
|
settle(l, Lease.Discarded)
|
|
360
362
|
throw e
|
|
361
363
|
}
|
|
362
364
|
settle(l, Lease.Released)
|
|
365
|
+
return result
|
|
363
366
|
}
|
|
364
367
|
|
|
365
368
|
async function scope(fn, name) {
|
|
@@ -374,7 +377,7 @@ function Postgres(a, b) {
|
|
|
374
377
|
let uncaughtError
|
|
375
378
|
, result
|
|
376
379
|
|
|
377
|
-
name && await sql
|
|
380
|
+
name && await sql.unsafe('savepoint ' + escapeIdentifier(name))
|
|
378
381
|
try {
|
|
379
382
|
result = await new Promise((resolve, reject) => {
|
|
380
383
|
const x = fn(sql)
|
|
@@ -385,8 +388,8 @@ function Postgres(a, b) {
|
|
|
385
388
|
throw uncaughtError
|
|
386
389
|
} catch (e) {
|
|
387
390
|
l.state === Lease.Active && await (name
|
|
388
|
-
? sql
|
|
389
|
-
: finish(final => final
|
|
391
|
+
? sql.unsafe('rollback to ' + escapeIdentifier(name))
|
|
392
|
+
: finish(final => final.unsafe('rollback'))
|
|
390
393
|
)
|
|
391
394
|
throw e instanceof PostgresError && e.code === '25P02' && uncaughtError || e
|
|
392
395
|
}
|
|
@@ -394,10 +397,18 @@ function Postgres(a, b) {
|
|
|
394
397
|
if (l.state !== Lease.Active)
|
|
395
398
|
throw l.error || leaseError(l.state)
|
|
396
399
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
400
|
+
if (!name) {
|
|
401
|
+
const done = await finish(final => prepare
|
|
402
|
+
? final.unsafe('prepare transaction ' + prepare)
|
|
403
|
+
: final.unsafe('commit')
|
|
404
|
+
)
|
|
405
|
+
if (done.command === 'ROLLBACK') {
|
|
406
|
+
throw Object.assign(
|
|
407
|
+
Errors.generic('TRANSACTION_ROLLED_BACK', 'The server rolled the transaction back instead of committing it'),
|
|
408
|
+
uncaughtError && { cause: uncaughtError }
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
401
412
|
|
|
402
413
|
return result
|
|
403
414
|
|
|
@@ -426,14 +437,6 @@ function Postgres(a, b) {
|
|
|
426
437
|
return c
|
|
427
438
|
}
|
|
428
439
|
|
|
429
|
-
function callback(fn, ...args) {
|
|
430
|
-
try {
|
|
431
|
-
fn && fn(...args)
|
|
432
|
-
} catch (e) {
|
|
433
|
-
queueMicrotask(() => { throw e })
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
440
|
function json(x) {
|
|
438
441
|
return new Parameter(x, 3802)
|
|
439
442
|
}
|
|
@@ -456,11 +459,24 @@ function Postgres(a, b) {
|
|
|
456
459
|
if (closed.length)
|
|
457
460
|
return connect(closed.shift(), query)
|
|
458
461
|
|
|
459
|
-
|
|
460
|
-
|
|
462
|
+
const c = takeBusy()
|
|
463
|
+
c
|
|
464
|
+
? go(c, query)
|
|
461
465
|
: queries.push(query)
|
|
462
466
|
}
|
|
463
467
|
|
|
468
|
+
function takeBusy() {
|
|
469
|
+
while (busy.length) {
|
|
470
|
+
const c = busy.shift()
|
|
471
|
+
if (c.accepting)
|
|
472
|
+
return c
|
|
473
|
+
|
|
474
|
+
move(c, full)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return null
|
|
478
|
+
}
|
|
479
|
+
|
|
464
480
|
function takeOpen() {
|
|
465
481
|
while (open.length) {
|
|
466
482
|
const c = open.shift()
|
|
@@ -545,6 +561,9 @@ function Postgres(a, b) {
|
|
|
545
561
|
if (initial && initial.reserve)
|
|
546
562
|
return initial.reserve(c)
|
|
547
563
|
|
|
564
|
+
if (!initial && !c.accepting)
|
|
565
|
+
return move(c, full)
|
|
566
|
+
|
|
548
567
|
if (!initial && !queries.length)
|
|
549
568
|
return move(c, open)
|
|
550
569
|
|
|
@@ -583,7 +602,7 @@ function Postgres(a, b) {
|
|
|
583
602
|
function onclose(c, e) {
|
|
584
603
|
move(c, closed)
|
|
585
604
|
c.owner && settle(c.owner, Lease.Closed, e)
|
|
586
|
-
options.onclose
|
|
605
|
+
callback(options.onclose, c.id)
|
|
587
606
|
if (ending)
|
|
588
607
|
return closedWhileEnding(c, e)
|
|
589
608
|
|
|
@@ -638,7 +657,7 @@ function parseOptions(a, b) {
|
|
|
638
657
|
connect_timeout : 30,
|
|
639
658
|
max_lifetime : max_lifetime,
|
|
640
659
|
max_pipeline : 100,
|
|
641
|
-
backoff :
|
|
660
|
+
backoff : defaultBackoff,
|
|
642
661
|
keep_alive : 60,
|
|
643
662
|
prepare : true,
|
|
644
663
|
debug : false,
|
|
@@ -697,10 +716,6 @@ function tsa(o, url, env) {
|
|
|
697
716
|
throw new Error('target_session_attrs ' + x + ' is not supported')
|
|
698
717
|
}
|
|
699
718
|
|
|
700
|
-
function backoff(retries) {
|
|
701
|
-
return (0.5 + Math.random() / 2) * Math.min(3 ** retries / 100, 20)
|
|
702
|
-
}
|
|
703
|
-
|
|
704
719
|
function max_lifetime() {
|
|
705
720
|
return 60 * (30 + Math.random() * 30)
|
|
706
721
|
}
|