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