@steadybrew/postgresjs 3.4.9 → 4.0.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 +27 -3
- package/cf/polyfills.js +27 -9
- package/cf/src/connection.js +487 -224
- package/cf/src/index.js +137 -57
- package/cf/src/types.js +26 -3
- package/cjs/src/connection.js +487 -224
- package/cjs/src/index.js +137 -57
- package/cjs/src/types.js +26 -3
- package/package.json +11 -8
- package/src/connection.js +487 -224
- package/src/index.js +137 -57
- package/src/types.js +26 -3
package/cjs/src/index.js
CHANGED
|
@@ -3,6 +3,7 @@ const fs = require('fs')
|
|
|
3
3
|
|
|
4
4
|
const {
|
|
5
5
|
mergeUserTypes,
|
|
6
|
+
addDefaultArrayTypes,
|
|
6
7
|
inferType,
|
|
7
8
|
Parameter,
|
|
8
9
|
Identifier,
|
|
@@ -62,7 +63,7 @@ function Postgres(a, b) {
|
|
|
62
63
|
, full = Queue()
|
|
63
64
|
, queues = { connecting, reserved, closed, ended, open, busy, full }
|
|
64
65
|
|
|
65
|
-
const connections = [...Array(options.max)].map(() => Connection(options, queues, { onopen, onend, onclose }))
|
|
66
|
+
const connections = [...Array(options.max)].map(() => Connection(options, queues, { onopen, onend, onclose, ondrain }))
|
|
66
67
|
|
|
67
68
|
const sql = Sql(handler)
|
|
68
69
|
|
|
@@ -200,58 +201,104 @@ function Postgres(a, b) {
|
|
|
200
201
|
return await sql`select pg_notify(${ channel }, ${ '' + payload })`
|
|
201
202
|
}
|
|
202
203
|
|
|
203
|
-
async function
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
204
|
+
async function lease(auto) {
|
|
205
|
+
if (ending)
|
|
206
|
+
throw Errors.connection('CONNECTION_ENDED', options)
|
|
207
|
+
|
|
208
|
+
const l = { connection: null, closed: null, onclose: null, reserved: null, queue: Queue() }
|
|
209
|
+
open.length
|
|
210
|
+
? own(open.shift(), l)
|
|
211
|
+
: auto && !closed.length && busy.length
|
|
212
|
+
? own(busy.shift(), l)
|
|
213
|
+
: await new Promise((resolve, reject) => {
|
|
214
|
+
const query = { reserve: c => resolve(own(c, l)), reject }
|
|
215
|
+
closed.length
|
|
216
|
+
? connect(closed.shift(), query)
|
|
217
|
+
: queries.push(query)
|
|
218
|
+
})
|
|
219
|
+
return l
|
|
220
|
+
}
|
|
212
221
|
|
|
222
|
+
function own(c, l) {
|
|
223
|
+
l.connection = c
|
|
224
|
+
c.lease = l
|
|
213
225
|
move(c, reserved)
|
|
214
|
-
c.reserved = () => queue.length
|
|
215
|
-
? c.execute(queue.shift())
|
|
226
|
+
c.reserved = l.reserved = () => l.queue.length
|
|
227
|
+
? c.execute(l.queue.shift())
|
|
216
228
|
: move(c, reserved)
|
|
217
229
|
c.reserved.release = true
|
|
230
|
+
return c
|
|
231
|
+
}
|
|
218
232
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
onopen(c)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return sql
|
|
233
|
+
function valid(l) {
|
|
234
|
+
return !l.closed && l.connection.lease === l && l.connection.reserved === l.reserved
|
|
235
|
+
}
|
|
226
236
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
237
|
+
function send(l, q) {
|
|
238
|
+
const c = l.connection
|
|
239
|
+
valid(l)
|
|
240
|
+
? c.queue === full
|
|
241
|
+
? l.queue.push(q)
|
|
230
242
|
: c.execute(q) || move(c, full)
|
|
231
|
-
|
|
243
|
+
: q.reject(gone(l))
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function gone(l) {
|
|
247
|
+
return Errors.connection(l.closed && l.closed.code === 'CONNECTION_ENDED' ? 'CONNECTION_ENDED' : 'CONNECTION_CLOSED', options)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function finish(l) {
|
|
251
|
+
const c = l.connection
|
|
252
|
+
if (l.closed || c.lease !== l)
|
|
253
|
+
return false
|
|
254
|
+
|
|
255
|
+
const held = c.reserved === l.reserved
|
|
256
|
+
c.lease = null
|
|
257
|
+
l.closed = Errors.connection('CONNECTION_ENDED', options)
|
|
258
|
+
held && (c.reserved = null)
|
|
259
|
+
while (l.queue.length)
|
|
260
|
+
l.queue.shift().reject(gone(l))
|
|
261
|
+
return held
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function reserve() {
|
|
265
|
+
const l = await lease(false)
|
|
266
|
+
const sql = Sql(q => send(l, q))
|
|
267
|
+
sql.release = () => finish(l) && l.connection.release()
|
|
268
|
+
return sql
|
|
232
269
|
}
|
|
233
270
|
|
|
234
271
|
async function begin(options, fn) {
|
|
235
272
|
!fn && (fn = options, options = '')
|
|
236
|
-
const
|
|
273
|
+
const l = await lease(true)
|
|
237
274
|
let savepoints = 0
|
|
238
|
-
, connection
|
|
239
275
|
, prepare = null
|
|
276
|
+
, settled = false
|
|
240
277
|
|
|
241
278
|
try {
|
|
242
|
-
|
|
243
|
-
return await Promise.race([
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
279
|
+
const closing = new Promise((_, reject) => l.onclose = reject)
|
|
280
|
+
return await Promise.race([transaction(), closing])
|
|
281
|
+
} finally {
|
|
282
|
+
finish(l) && (settled ? l.connection.release() : l.connection.terminate())
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function transaction() {
|
|
286
|
+
await Sql(q => send(l, q)).unsafe('begin ' + options.replace(/[^a-z ]/ig, ''), []).execute().catch(e => {
|
|
287
|
+
e instanceof PostgresError && (settled = true)
|
|
288
|
+
throw e
|
|
289
|
+
})
|
|
290
|
+
return scope(fn)
|
|
249
291
|
}
|
|
250
292
|
|
|
251
|
-
async function scope(
|
|
293
|
+
async function scope(fn, name) {
|
|
252
294
|
const sql = Sql(handler)
|
|
253
295
|
sql.savepoint = savepoint
|
|
254
|
-
sql.prepare = x =>
|
|
296
|
+
sql.prepare = x => {
|
|
297
|
+
if (typeof x !== 'string' || !x || x.includes('\0'))
|
|
298
|
+
throw Errors.generic('INVALID_TRANSACTION_NAME', 'sql.prepare requires a non-empty string without null bytes')
|
|
299
|
+
|
|
300
|
+
prepare = 'E\'' + x.replace(/\\/g, '\\\\').replace(/'/g, '\'\'') + '\''
|
|
301
|
+
}
|
|
255
302
|
let uncaughtError
|
|
256
303
|
, result
|
|
257
304
|
|
|
@@ -265,17 +312,22 @@ function Postgres(a, b) {
|
|
|
265
312
|
if (uncaughtError)
|
|
266
313
|
throw uncaughtError
|
|
267
314
|
} catch (e) {
|
|
268
|
-
await (name
|
|
315
|
+
l.closed || await (name
|
|
269
316
|
? sql`rollback to ${ sql(name) }`
|
|
270
317
|
: sql`rollback`
|
|
271
318
|
)
|
|
319
|
+
name || (settled = true)
|
|
272
320
|
throw e instanceof PostgresError && e.code === '25P02' && uncaughtError || e
|
|
273
321
|
}
|
|
274
322
|
|
|
323
|
+
if (l.closed)
|
|
324
|
+
throw l.closed
|
|
325
|
+
|
|
275
326
|
if (!name) {
|
|
276
327
|
prepare
|
|
277
|
-
? await sql`prepare transaction
|
|
328
|
+
? await sql`prepare transaction ${ sql.unsafe(prepare) }`
|
|
278
329
|
: await sql`commit`
|
|
330
|
+
settled = true
|
|
279
331
|
}
|
|
280
332
|
|
|
281
333
|
return result
|
|
@@ -285,24 +337,14 @@ function Postgres(a, b) {
|
|
|
285
337
|
return savepoint(sql => sql.apply(sql, arguments))
|
|
286
338
|
|
|
287
339
|
arguments.length === 1 && (fn = name, name = null)
|
|
288
|
-
return scope(
|
|
340
|
+
return scope(fn, 's' + savepoints++ + (name ? '_' + name : ''))
|
|
289
341
|
}
|
|
290
342
|
|
|
291
343
|
function handler(q) {
|
|
292
344
|
q.catch(e => uncaughtError || (uncaughtError = e))
|
|
293
|
-
|
|
294
|
-
? queries.push(q)
|
|
295
|
-
: c.execute(q) || move(c, full)
|
|
345
|
+
send(l, q)
|
|
296
346
|
}
|
|
297
347
|
}
|
|
298
|
-
|
|
299
|
-
function onexecute(c) {
|
|
300
|
-
connection = c
|
|
301
|
-
move(c, reserved)
|
|
302
|
-
c.reserved = () => queries.length
|
|
303
|
-
? c.execute(queries.shift())
|
|
304
|
-
: move(c, reserved)
|
|
305
|
-
}
|
|
306
348
|
}
|
|
307
349
|
|
|
308
350
|
function move(c, queue) {
|
|
@@ -368,13 +410,17 @@ function Postgres(a, b) {
|
|
|
368
410
|
|
|
369
411
|
await 1
|
|
370
412
|
let timer
|
|
371
|
-
return ending = Promise.race([
|
|
372
|
-
new Promise(r => timeout !== null && (timer = setTimeout(destroy, timeout * 1000
|
|
413
|
+
return ending = Promise.resolve().then(() => Promise.race([
|
|
414
|
+
new Promise(r => timeout !== null && (timer = setTimeout(() => destroy(r), timeout * 1000))),
|
|
373
415
|
Promise.all(connections.map(c => c.end()).concat(
|
|
374
416
|
listen.sql ? listen.sql.end({ timeout: 0 }) : [],
|
|
375
417
|
subscribe.sql ? subscribe.sql.end({ timeout: 0 }) : []
|
|
376
418
|
))
|
|
377
|
-
]).then(() =>
|
|
419
|
+
])).then(() => {
|
|
420
|
+
clearTimeout(timer)
|
|
421
|
+
while (queries.length)
|
|
422
|
+
queries.shift().reject(Errors.connection('CONNECTION_CLOSED', options))
|
|
423
|
+
})
|
|
378
424
|
}
|
|
379
425
|
|
|
380
426
|
async function close() {
|
|
@@ -382,9 +428,9 @@ function Postgres(a, b) {
|
|
|
382
428
|
}
|
|
383
429
|
|
|
384
430
|
async function destroy(resolve) {
|
|
385
|
-
await Promise.all(connections.map(c => c.terminate()))
|
|
386
431
|
while (queries.length)
|
|
387
432
|
queries.shift().reject(Errors.connection('CONNECTION_DESTROYED', options))
|
|
433
|
+
await Promise.all(connections.map(c => c.terminate()))
|
|
388
434
|
resolve()
|
|
389
435
|
}
|
|
390
436
|
|
|
@@ -398,7 +444,10 @@ function Postgres(a, b) {
|
|
|
398
444
|
move(c, ended)
|
|
399
445
|
}
|
|
400
446
|
|
|
401
|
-
function onopen(c) {
|
|
447
|
+
function onopen(c, initial) {
|
|
448
|
+
if (initial && initial.reserve)
|
|
449
|
+
return initial.reserve(move(c, reserved))
|
|
450
|
+
|
|
402
451
|
if (queries.length === 0)
|
|
403
452
|
return move(c, open)
|
|
404
453
|
|
|
@@ -408,7 +457,7 @@ function Postgres(a, b) {
|
|
|
408
457
|
while (ready && queries.length && max-- > 0) {
|
|
409
458
|
const query = queries.shift()
|
|
410
459
|
if (query.reserve)
|
|
411
|
-
return query.reserve(c)
|
|
460
|
+
return query.reserve(move(c, reserved))
|
|
412
461
|
|
|
413
462
|
ready = c.execute(query)
|
|
414
463
|
}
|
|
@@ -418,12 +467,40 @@ function Postgres(a, b) {
|
|
|
418
467
|
: move(c, full)
|
|
419
468
|
}
|
|
420
469
|
|
|
470
|
+
function ondrain(c) {
|
|
471
|
+
if (!ending)
|
|
472
|
+
return false
|
|
473
|
+
|
|
474
|
+
let drained = false
|
|
475
|
+
let ready = true
|
|
476
|
+
while (ready && queries.length) {
|
|
477
|
+
const query = queries.shift()
|
|
478
|
+
query.reserve
|
|
479
|
+
? query.reject(Errors.connection('CONNECTION_ENDED', options))
|
|
480
|
+
: (drained = true, ready = c.execute(query))
|
|
481
|
+
}
|
|
482
|
+
return drained
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function abandon(l, e) {
|
|
486
|
+
l.connection.lease = null
|
|
487
|
+
l.closed = e || Errors.connection('CONNECTION_CLOSED', options)
|
|
488
|
+
while (l.queue.length)
|
|
489
|
+
l.queue.shift().reject(gone(l))
|
|
490
|
+
l.onclose && l.onclose(e)
|
|
491
|
+
}
|
|
492
|
+
|
|
421
493
|
function onclose(c, e) {
|
|
422
494
|
move(c, closed)
|
|
423
495
|
c.reserved = null
|
|
424
|
-
c.
|
|
496
|
+
c.lease && abandon(c.lease, e)
|
|
425
497
|
options.onclose && options.onclose(c.id)
|
|
426
|
-
|
|
498
|
+
if (ending) {
|
|
499
|
+
while (queries.length)
|
|
500
|
+
queries.shift().reject(e)
|
|
501
|
+
} else if (queries.length && c.queue === closed) {
|
|
502
|
+
connect(c, queries.shift())
|
|
503
|
+
}
|
|
427
504
|
}
|
|
428
505
|
}
|
|
429
506
|
|
|
@@ -462,7 +539,7 @@ function parseOptions(a, b) {
|
|
|
462
539
|
target_session_attrs: null
|
|
463
540
|
}
|
|
464
541
|
|
|
465
|
-
|
|
542
|
+
const options = {
|
|
466
543
|
host : Array.isArray(host) ? host : host.split(',').map(x => x.split(':')[0]),
|
|
467
544
|
port : Array.isArray(port) ? port : host.split(',').map(x => parseInt(x.split(':')[1] || port)),
|
|
468
545
|
path : o.path || host.indexOf('/') > -1 && host + '/.s.PGSQL.' + port,
|
|
@@ -498,6 +575,9 @@ function parseOptions(a, b) {
|
|
|
498
575
|
shared : { retries: 0, typeArrayMap: {} },
|
|
499
576
|
...mergeUserTypes(o.types)
|
|
500
577
|
}
|
|
578
|
+
|
|
579
|
+
!options.fetch_types && addDefaultArrayTypes(options)
|
|
580
|
+
return options
|
|
501
581
|
}
|
|
502
582
|
|
|
503
583
|
function tsa(o, url, env) {
|
package/cjs/src/types.js
CHANGED
|
@@ -190,6 +190,25 @@ function firstIsString(x) {
|
|
|
190
190
|
return typeof x === 'string' ? 1009 : 0
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
const builtInArrays = [[16, 1000], [17, 1001], [18, 1002], [19, 1003], [20, 1016], [21, 1005], [23, 1007], [25, 1009],
|
|
194
|
+
[26, 1028], [114, 199], [700, 1021], [701, 1022], [1042, 1014], [1043, 1015], [1082, 1182],
|
|
195
|
+
[1083, 1183], [1114, 1115], [1184, 1185], [1186, 1187], [1700, 1231], [2950, 2951], [3802, 3807]]
|
|
196
|
+
|
|
197
|
+
module.exports.addDefaultArrayTypes = addDefaultArrayTypes;function addDefaultArrayTypes(options) {
|
|
198
|
+
builtInArrays.forEach(([oid, typarray]) => addArrayType(options, oid, typarray))
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports.addArrayType = addArrayType;function addArrayType(options, oid, typarray) {
|
|
202
|
+
options.shared.typeArrayMap[oid] = typarray
|
|
203
|
+
if (!options.parsers[typarray]) {
|
|
204
|
+
const parser = options.parsers[oid]
|
|
205
|
+
options.parsers[typarray] = xs => arrayParser(xs, parser, typarray)
|
|
206
|
+
options.parsers[typarray].array = true
|
|
207
|
+
}
|
|
208
|
+
if (!options.serializers[typarray])
|
|
209
|
+
options.serializers[typarray] = xs => arraySerializer(xs, options.serializers[oid], options, typarray)
|
|
210
|
+
}
|
|
211
|
+
|
|
193
212
|
const mergeUserTypes = module.exports.mergeUserTypes = function(types) {
|
|
194
213
|
const user = typeHandlers(types || {})
|
|
195
214
|
return {
|
|
@@ -278,6 +297,10 @@ const arrayParser = module.exports.arrayParser = function arrayParser(x, parser,
|
|
|
278
297
|
return arrayParserLoop(arrayParserState, x, parser, typarray)
|
|
279
298
|
}
|
|
280
299
|
|
|
300
|
+
function parseArrayValue(value, parser) {
|
|
301
|
+
return value === 'NULL' ? null : parser ? parser(value) : value
|
|
302
|
+
}
|
|
303
|
+
|
|
281
304
|
function arrayParserLoop(s, x, parser, typarray) {
|
|
282
305
|
const xs = []
|
|
283
306
|
// Only _box (1020) has the ';' delimiter for arrays, all other types use the ',' delimiter
|
|
@@ -302,16 +325,16 @@ function arrayParserLoop(s, x, parser, typarray) {
|
|
|
302
325
|
xs.push(arrayParserLoop(s, x, parser, typarray))
|
|
303
326
|
} else if (s.char === '}') {
|
|
304
327
|
s.quoted = false
|
|
305
|
-
s.last < s.i && xs.push(
|
|
328
|
+
s.last < s.i && xs.push(parseArrayValue(x.slice(s.last, s.i), parser))
|
|
306
329
|
s.last = s.i + 1
|
|
307
330
|
break
|
|
308
331
|
} else if (s.char === delimiter && s.p !== '}' && s.p !== '"') {
|
|
309
|
-
xs.push(
|
|
332
|
+
xs.push(parseArrayValue(x.slice(s.last, s.i), parser))
|
|
310
333
|
s.last = s.i + 1
|
|
311
334
|
}
|
|
312
335
|
s.p = s.char
|
|
313
336
|
}
|
|
314
|
-
s.last < s.i && xs.push(
|
|
337
|
+
s.last < s.i && xs.push(parseArrayValue(x.slice(s.last, s.i + 1), parser))
|
|
315
338
|
return xs
|
|
316
339
|
}
|
|
317
340
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steadybrew/postgresjs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "PostgreSQL client for Node.js and Deno, independently maintained by Steady Brew",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -15,20 +15,23 @@
|
|
|
15
15
|
"types": "types/index.d.ts",
|
|
16
16
|
"typings": "types/index.d.ts",
|
|
17
17
|
"engines": {
|
|
18
|
-
"node": ">=
|
|
18
|
+
"node": ">=24"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "npm run build:cjs && npm run build:deno && npm run build:cf",
|
|
22
22
|
"build:cjs": "node transpile.cjs",
|
|
23
23
|
"build:deno": "node transpile.deno.js",
|
|
24
24
|
"build:cf": "node transpile.cf.js",
|
|
25
|
-
"test": "npm run test:esm && npm run test:cjs && npm run test:deno",
|
|
26
|
-
"test:esm": "node tests/index.js",
|
|
27
|
-
"test:
|
|
28
|
-
"test:
|
|
29
|
-
"
|
|
25
|
+
"test": "npm run test:startup && npm run test:esm && npm run test:cjs && npm run test:deno",
|
|
26
|
+
"test:esm": "node tests-startup/run.js --integration && node tests/index.js",
|
|
27
|
+
"test:startup": "node tests-startup/run.js",
|
|
28
|
+
"test:cjs": "npm run build:cjs && node tests-startup/run.js --integration --cjs && cd cjs/tests && node index.js && cd ../../",
|
|
29
|
+
"test:deno": "npm run test:deno-socket && npm run build:deno && cd deno/tests && deno run --no-lock --allow-all --unsafely-ignore-certificate-errors index.js && cd ../../",
|
|
30
|
+
"lint": "eslint src && eslint tests && eslint tests-startup --ext .js,.mjs",
|
|
30
31
|
"prepare": "npm run build",
|
|
31
|
-
"prepublishOnly": "npm run lint"
|
|
32
|
+
"prepublishOnly": "npm run lint",
|
|
33
|
+
"test:workerd": "npm exec --yes --package=wrangler@4.123.0 -- node tests-startup/workerd-run.mjs",
|
|
34
|
+
"test:deno-socket": "node tests-startup/deno-run.js"
|
|
32
35
|
},
|
|
33
36
|
"files": [
|
|
34
37
|
"/UNLICENSE",
|