@steadybrew/postgresjs 4.4.1 → 4.5.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/cf/src/index.js CHANGED
@@ -87,7 +87,8 @@ function Postgres(a, b) {
87
87
  listen,
88
88
  begin,
89
89
  close,
90
- end
90
+ end,
91
+ ...Symbol.asyncDispose && { [Symbol.asyncDispose]: () => end() }
91
92
  })
92
93
 
93
94
  return sql
@@ -328,10 +329,17 @@ function Postgres(a, b) {
328
329
 
329
330
  async function reserve() {
330
331
  const l = await lease(false)
331
- const sql = Sql(q => send(l, q))
332
+ const sql = Sql(handler)
332
333
  sql.release = () => settle(l, Lease.Released)
334
+ Symbol.dispose && (sql[Symbol.dispose] = () => sql.release())
335
+ Symbol.asyncDispose && (sql[Symbol.asyncDispose] = async() => sql.release())
333
336
  sql.stats = stats
334
337
  return sql
338
+
339
+ // dd-trace starts query spans only inside function declarations named handler
340
+ function handler(q) {
341
+ send(l, q)
342
+ }
335
343
  }
336
344
 
337
345
  async function begin(options, fn) {
@@ -348,7 +356,7 @@ function Postgres(a, b) {
348
356
  }
349
357
 
350
358
  async function transaction() {
351
- await Sql(q => send(l, q)).unsafe('begin ' + options.replace(/[^a-z ]/ig, ''), []).execute().catch(e => {
359
+ await Sql(handler).unsafe('begin ' + options.replace(/[^a-z ]/ig, ''), []).execute().catch(e => {
352
360
  e instanceof PostgresError && settle(l, Lease.Released)
353
361
  throw e
354
362
  })
@@ -359,7 +367,7 @@ function Postgres(a, b) {
359
367
  let result
360
368
  l.state = Lease.Settling
361
369
  try {
362
- result = await statement(Sql(q => send(l, q, Lease.Settling)))
370
+ result = await statement(Sql(q => handler(q, Lease.Settling)))
363
371
  } catch (e) {
364
372
  settle(l, Lease.Discarded)
365
373
  throw e
@@ -369,7 +377,7 @@ function Postgres(a, b) {
369
377
  }
370
378
 
371
379
  async function scope(fn, name) {
372
- const sql = Sql(handler)
380
+ const sql = Sql(track)
373
381
  sql.savepoint = savepoint
374
382
  sql.prepare = x => {
375
383
  if (typeof x !== 'string' || !x || x.includes('\0'))
@@ -423,11 +431,16 @@ function Postgres(a, b) {
423
431
  return scope(fn, 's' + savepoints++ + (name ? '_' + name : ''))
424
432
  }
425
433
 
426
- function handler(q) {
434
+ function track(q) {
427
435
  q.catch(e => uncaughtError || (uncaughtError = e))
428
- send(l, q)
436
+ handler(q)
429
437
  }
430
438
  }
439
+
440
+ // dd-trace starts query spans only inside function declarations named handler
441
+ function handler(q, expected) {
442
+ send(l, q, expected)
443
+ }
431
444
  }
432
445
 
433
446
  function move(c, queue) {
@@ -675,6 +688,7 @@ function parseOptions(a, b) {
675
688
  prepare : true,
676
689
  debug : false,
677
690
  fetch_types : true,
691
+ parameter_types : 'server',
678
692
  publications : 'alltables',
679
693
  target_session_attrs: null
680
694
  }
@@ -689,8 +703,8 @@ function parseOptions(a, b) {
689
703
  ...Object.entries(defaults).reduce(
690
704
  (acc, [k, d]) => {
691
705
  const value = k in o ? o[k] : k in query
692
- ? (query[k] === 'disable' || query[k] === 'false' ? false : query[k])
693
- : env['PG' + k.toUpperCase()] || d
706
+ ? off(query[k])
707
+ : env['PG' + k.toUpperCase()] ? off(env['PG' + k.toUpperCase()]) : d
694
708
  acc[k] = typeof value === 'string' && ints.includes(k)
695
709
  ? +value
696
710
  : value
@@ -705,11 +719,13 @@ function parseOptions(a, b) {
705
719
  },
706
720
  types : o.types || {},
707
721
  target_session_attrs: tsa(o, url, env),
722
+ parameter_types : parameterTypes(o, url, env),
708
723
  onnotice : o.onnotice,
709
724
  onnotify : o.onnotify,
710
725
  onclose : o.onclose,
711
726
  onidle : o.onidle,
712
727
  onparameter : o.onparameter,
728
+ ontypemismatch : o.ontypemismatch,
713
729
  socket : o.socket,
714
730
  transform : parseTransform(o.transform || { undefined: undefined }),
715
731
  parameters : {},
@@ -721,6 +737,10 @@ function parseOptions(a, b) {
721
737
  return options
722
738
  }
723
739
 
740
+ function off(x) {
741
+ return x === 'disable' || x === 'false' ? false : x
742
+ }
743
+
724
744
  function tsa(o, url, env) {
725
745
  const x = o.target_session_attrs || url.searchParams.get('target_session_attrs') || env.PGTARGETSESSIONATTRS
726
746
  if (!x || ['read-write', 'read-only', 'primary', 'standby', 'prefer-standby'].includes(x))
@@ -729,6 +749,14 @@ function tsa(o, url, env) {
729
749
  throw new Error('target_session_attrs ' + x + ' is not supported')
730
750
  }
731
751
 
752
+ function parameterTypes(o, url, env) {
753
+ const x = o.parameter_types || url.searchParams.get('parameter_types') || env.PGPARAMETER_TYPES || 'server'
754
+ if (['server', 'client', 'warn'].includes(x))
755
+ return x
756
+
757
+ throw new Error('parameter_types ' + x + ' is not supported')
758
+ }
759
+
732
760
  function max_lifetime() {
733
761
  return 60 * (30 + Math.random() * 30)
734
762
  }
package/cf/src/query.js CHANGED
@@ -23,16 +23,9 @@ export class Query extends Promise {
23
23
  this.state = null
24
24
  this.statement = null
25
25
 
26
- this.resolve = x => {
27
- this.active = false
28
- this.settled = true
29
- resolve(x)
30
- }
31
- this.reject = x => {
32
- this.active = false
33
- this.settled = true
34
- reject(x)
35
- }
26
+ // dd-trace's load-time rewrite only accepts single-expression arrows here
27
+ this.resolve = x => (this.active = false, this.settled = true, resolve(x))
28
+ this.reject = x => (this.active = false, this.settled = true, reject(x))
36
29
 
37
30
  this.active = false
38
31
  this.settled = false
@@ -62,6 +55,7 @@ export class Query extends Promise {
62
55
  if (!this.canceller || this.settled)
63
56
  return Promise.resolve()
64
57
 
58
+ Promise.prototype.then.call(this, undefined, () => undefined)
65
59
  const cancelled = this.canceller(this)
66
60
  this.canceller = null
67
61
  cancelled.catch(() => undefined)
package/cf/src/types.js CHANGED
@@ -249,6 +249,11 @@ export const inferType = function inferType(x) {
249
249
  )
250
250
  }
251
251
 
252
+ export function clientSerialize(x) {
253
+ const proto = typeof x === 'object' && Object.getPrototypeOf(x)
254
+ return proto === Object.prototype || proto === null ? JSON.stringify(x) : '' + x
255
+ }
256
+
252
257
  const escapeBackslash = /\\/g
253
258
  const escapeQuote = /"/g
254
259
 
@@ -342,14 +347,14 @@ function arrayParserLoop(s, x, parser, typarray) {
342
347
  export const toCamel = x => {
343
348
  let str = x[0]
344
349
  for (let i = 1; i < x.length; i++)
345
- str += x[i] === '_' ? x[++i].toUpperCase() : x[i]
350
+ str += x[i] === '_' && i + 1 < x.length ? x[++i].toUpperCase() : x[i]
346
351
  return str
347
352
  }
348
353
 
349
354
  export const toPascal = x => {
350
355
  let str = x[0].toUpperCase()
351
356
  for (let i = 1; i < x.length; i++)
352
- str += x[i] === '_' ? x[++i].toUpperCase() : x[i]
357
+ str += x[i] === '_' && i + 1 < x.length ? x[++i].toUpperCase() : x[i]
353
358
  return str
354
359
  }
355
360
 
@@ -4,7 +4,7 @@ const crypto = require('crypto')
4
4
  const Stream = require('stream')
5
5
  const { performance } = require('perf_hooks')
6
6
 
7
- const { stringify, handleValue, addArrayType } = require('./types.js')
7
+ const { stringify, handleValue, addArrayType, clientSerialize } = require('./types.js')
8
8
  const { Errors, callback } = require('./errors.js')
9
9
  const Result = require('./result.js')
10
10
  const Queue = require('./queue.js')
@@ -104,6 +104,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
104
104
  , hostIndex = 0
105
105
  , length = 0
106
106
  , rows = 0
107
+ , copyPaused = false
107
108
  , serverSignature = null
108
109
  , nextWriteTimer = null
109
110
  , incomings = null
@@ -214,7 +215,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
214
215
  const connection = {
215
216
  queue: queues.closed,
216
217
  idleTimer,
217
- connect: request => dispatch('acquire', request),
218
+ // Sentry's hook wraps connect and reads the connection from this, so it must stay a method
219
+ connect(request) {
220
+ dispatch('acquire', request)
221
+ },
218
222
  terminate: () => dispatch('terminate'),
219
223
  execute,
220
224
  release: () => dispatch('release'),
@@ -459,6 +463,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
459
463
  query = results = errorResponse = chunk = nextWriteTimer = barrier = null
460
464
  result = new Result()
461
465
  rows = 0
466
+ copyPaused = false
462
467
  nonce = serverSignature = null
463
468
  }
464
469
 
@@ -538,7 +543,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
538
543
 
539
544
  build(q)
540
545
  const written = write(toBuffer(q))
541
- if (q.describeFirst || q.cursorFn || mayCopy(q))
546
+ if (q.describeFirst || q.cursorFn || mayCopy(q) || (q.prepare && !q.prepared && !q.options.simple && q.parameters.length))
542
547
  barrier = q
543
548
  return written && accepting()
544
549
  } catch (error) {
@@ -576,7 +581,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
576
581
 
577
582
  function prepared(q) {
578
583
  return Buffer.concat([
579
- Bind(q.parameters, q.statement.types, q.statement.name, q.cursorName),
584
+ Bind(q),
580
585
  q.cursorFn
581
586
  ? Execute('', q.cursorRows)
582
587
  : ExecuteUnnamed
@@ -604,8 +609,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
604
609
  q.signature = q.prepare && types + string
605
610
  q.onlyDescribe && (delete statements[q.signature])
606
611
  q.parameters = q.parameters || parameters
612
+ q.inferred = options.parameter_types === 'server' ? null : types.slice()
607
613
  q.prepared = q.prepare && q.signature in statements
608
- q.describeFirst = q.onlyDescribe || (parameters.length && !q.prepared)
614
+ q.describeFirst = q.onlyDescribe || (!q.prepared && types.some((x, i) =>
615
+ !x && (options.parameter_types !== 'client' || Array.isArray(q.parameters[i]))
616
+ ))
609
617
  q.statement = q.prepared
610
618
  ? statements[q.signature]
611
619
  : { string, types, name: q.prepare ? statementId + statementCount++ : '' }
@@ -678,6 +686,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
678
686
 
679
687
  function errored(err) {
680
688
  stream && (stream.destroy(err), stream = null)
689
+ resumeCopy()
681
690
  query && queryError(query, err)
682
691
  }
683
692
 
@@ -689,7 +698,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
689
698
  err = new Error(err)
690
699
 
691
700
  'query' in err || 'parameters' in err || Object.defineProperties(err, {
692
- stack: { value: err.stack + query.origin.replace(/.*\n/, '\n'), enumerable: options.debug },
701
+ stack: { value: err.stack + query.origin.replace(/.*\n/, '\n'), enumerable: options.debug, writable: true, configurable: true },
693
702
  query: { value: query.string, enumerable: options.debug },
694
703
  parameters: { value: query.parameters, enumerable: options.debug },
695
704
  args: { value: query.args, enumerable: options.debug },
@@ -794,7 +803,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
794
803
  query.prepared && retryRoutines.has(errorResponse.routine) && delete statements[query.signature]
795
804
  query.retried
796
805
  ? errored(query.retried)
797
- : query.prepared && retryRoutines.has(errorResponse.routine) && query.owner === connection.owner && !barrier
806
+ : query.prepared && retryRoutines.has(errorResponse.routine) && query.owner === connection.owner && !barrier && !query.cancelled
798
807
  && (x[5] !== 69 || endsAbortedState.test(query.string))
799
808
  ? retry(query, errorResponse)
800
809
  : errored(errorResponse)
@@ -808,6 +817,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
808
817
 
809
818
  query = results = errorResponse = null
810
819
  result = new Result()
820
+ rows = 0
811
821
 
812
822
  dispatch('ready')
813
823
  }
@@ -1040,8 +1050,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
1040
1050
 
1041
1051
  function mismatchReason(x, xs) {
1042
1052
  return (
1053
+ (x === 'read-write' && xs.in_hot_standby === 'on' && 'is a standby') ||
1043
1054
  (x === 'read-write' && xs.default_transaction_read_only === 'on' && 'is read-only') ||
1044
- (x === 'read-only' && xs.default_transaction_read_only === 'off' && 'is read-write') ||
1055
+ (x === 'read-only' && xs.in_hot_standby === 'off' && xs.default_transaction_read_only === 'off' && 'is read-write') ||
1045
1056
  (x === 'primary' && xs.in_hot_standby === 'on' && 'is a standby') ||
1046
1057
  (x === 'standby' && xs.in_hot_standby === 'off' && 'is a primary') ||
1047
1058
  (x === 'prefer-standby' && xs.in_hot_standby === 'off' && standbyPass() && 'is a primary') ||
@@ -1140,7 +1151,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
1140
1151
 
1141
1152
  function CopyOutResponse() {
1142
1153
  stream = new Stream.Readable({
1143
- read() { socket.resume() }
1154
+ read() { copyPaused = false; socket.resume() }
1144
1155
  })
1145
1156
  query.resolve(stream)
1146
1157
  connection.owner && connection.owner.next()
@@ -1150,7 +1161,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
1150
1161
  function CopyBothResponse() {
1151
1162
  stream = new Stream.Duplex({
1152
1163
  autoDestroy: true,
1153
- read() { socket.resume() },
1164
+ read() { copyPaused = false; socket.resume() },
1154
1165
  /* c8 ignore next 11 */
1155
1166
  write(chunk, encoding, callback) {
1156
1167
  socket.write(b().d().raw(chunk).end(), callback)
@@ -1170,12 +1181,23 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
1170
1181
  }
1171
1182
 
1172
1183
  function CopyData(x) {
1173
- stream && (stream.push(x.subarray(5)) || socket.pause())
1184
+ if (stream && !stream.push(x.subarray(5))) {
1185
+ copyPaused = true
1186
+ socket.pause()
1187
+ }
1174
1188
  }
1175
1189
 
1176
1190
  function CopyDone() {
1177
1191
  stream && stream.push(null)
1178
1192
  stream = null
1193
+ resumeCopy()
1194
+ }
1195
+
1196
+ function resumeCopy() {
1197
+ if (copyPaused) {
1198
+ copyPaused = false
1199
+ socket.resume()
1200
+ }
1179
1201
  }
1180
1202
 
1181
1203
  function NoticeResponse(x) {
@@ -1213,20 +1235,21 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
1213
1235
  }
1214
1236
 
1215
1237
  /* Messages */
1216
- function Bind(parameters, types, statement = '', portal = '') {
1238
+ function Bind(q) {
1239
+ const differences = []
1217
1240
  let prev
1218
1241
  , type
1219
1242
 
1220
- b().B().str(portal + b.N).str(statement + b.N).i16(0).i16(parameters.length)
1243
+ b().B().str((q.cursorName || '') + b.N).str(q.statement.name + b.N).i16(0).i16(q.parameters.length)
1221
1244
 
1222
- parameters.forEach((x, i) => {
1245
+ q.parameters.forEach((x, i) => {
1223
1246
  if (x === null)
1224
1247
  return b.i32(0xFFFFFFFF)
1225
1248
 
1226
- type = types[i]
1227
- x = type in options.serializers
1228
- ? options.serializers[type](x)
1229
- : '' + x
1249
+ type = q.statement.types[i]
1250
+ x = !q.inferred || q.inferred[i] || Array.isArray(x)
1251
+ ? serialize(x, type)
1252
+ : options.parameter_types === 'client' ? clientSerialize(x) : compare(x, type, i, differences)
1230
1253
 
1231
1254
  prev = b.i
1232
1255
  b.inc(4).str(x).i32(b.i - prev - 4, prev)
@@ -1234,7 +1257,27 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
1234
1257
 
1235
1258
  b.i16(0)
1236
1259
 
1237
- return b.end()
1260
+ const message = b.end()
1261
+ differences.length && callback(options.ontypemismatch || console.warn, { query: q.string, parameters: differences }) // eslint-disable-line
1262
+ return message
1263
+ }
1264
+
1265
+ function serialize(x, type) {
1266
+ return type in options.serializers
1267
+ ? options.serializers[type](x)
1268
+ : '' + x
1269
+ }
1270
+
1271
+ function compare(x, type, i, differences) {
1272
+ const serverText = serialize(x, type)
1273
+ let clientText
1274
+ try {
1275
+ clientText = clientSerialize(x)
1276
+ } catch (error) {
1277
+ clientText = error
1278
+ }
1279
+ serverText === clientText || differences.push({ position: i + 1, oid: type, typeof: typeof x, ...options.debug && { serverText, clientText } })
1280
+ return serverText
1238
1281
  }
1239
1282
 
1240
1283
  function Parse(str, parameters, types, name = '') {
package/cjs/src/errors.js CHANGED
@@ -1,8 +1,8 @@
1
1
  const PostgresError = module.exports.PostgresError = class PostgresError extends Error {
2
2
  constructor(x) {
3
- super(x.message)
3
+ super(typeof x === 'string' ? x : x.message)
4
4
  this.name = this.constructor.name
5
- Object.assign(this, x)
5
+ typeof x === 'string' || Object.assign(this, x)
6
6
  }
7
7
  }
8
8
 
package/cjs/src/index.js CHANGED
@@ -86,7 +86,8 @@ function Postgres(a, b) {
86
86
  listen,
87
87
  begin,
88
88
  close,
89
- end
89
+ end,
90
+ ...Symbol.asyncDispose && { [Symbol.asyncDispose]: () => end() }
90
91
  })
91
92
 
92
93
  return sql
@@ -327,10 +328,17 @@ function Postgres(a, b) {
327
328
 
328
329
  async function reserve() {
329
330
  const l = await lease(false)
330
- const sql = Sql(q => send(l, q))
331
+ const sql = Sql(handler)
331
332
  sql.release = () => settle(l, Lease.Released)
333
+ Symbol.dispose && (sql[Symbol.dispose] = () => sql.release())
334
+ Symbol.asyncDispose && (sql[Symbol.asyncDispose] = async() => sql.release())
332
335
  sql.stats = stats
333
336
  return sql
337
+
338
+ // dd-trace starts query spans only inside function declarations named handler
339
+ function handler(q) {
340
+ send(l, q)
341
+ }
334
342
  }
335
343
 
336
344
  async function begin(options, fn) {
@@ -347,7 +355,7 @@ function Postgres(a, b) {
347
355
  }
348
356
 
349
357
  async function transaction() {
350
- await Sql(q => send(l, q)).unsafe('begin ' + options.replace(/[^a-z ]/ig, ''), []).execute().catch(e => {
358
+ await Sql(handler).unsafe('begin ' + options.replace(/[^a-z ]/ig, ''), []).execute().catch(e => {
351
359
  e instanceof PostgresError && settle(l, Lease.Released)
352
360
  throw e
353
361
  })
@@ -358,7 +366,7 @@ function Postgres(a, b) {
358
366
  let result
359
367
  l.state = Lease.Settling
360
368
  try {
361
- result = await statement(Sql(q => send(l, q, Lease.Settling)))
369
+ result = await statement(Sql(q => handler(q, Lease.Settling)))
362
370
  } catch (e) {
363
371
  settle(l, Lease.Discarded)
364
372
  throw e
@@ -368,7 +376,7 @@ function Postgres(a, b) {
368
376
  }
369
377
 
370
378
  async function scope(fn, name) {
371
- const sql = Sql(handler)
379
+ const sql = Sql(track)
372
380
  sql.savepoint = savepoint
373
381
  sql.prepare = x => {
374
382
  if (typeof x !== 'string' || !x || x.includes('\0'))
@@ -422,11 +430,16 @@ function Postgres(a, b) {
422
430
  return scope(fn, 's' + savepoints++ + (name ? '_' + name : ''))
423
431
  }
424
432
 
425
- function handler(q) {
433
+ function track(q) {
426
434
  q.catch(e => uncaughtError || (uncaughtError = e))
427
- send(l, q)
435
+ handler(q)
428
436
  }
429
437
  }
438
+
439
+ // dd-trace starts query spans only inside function declarations named handler
440
+ function handler(q, expected) {
441
+ send(l, q, expected)
442
+ }
430
443
  }
431
444
 
432
445
  function move(c, queue) {
@@ -674,6 +687,7 @@ function parseOptions(a, b) {
674
687
  prepare : true,
675
688
  debug : false,
676
689
  fetch_types : true,
690
+ parameter_types : 'server',
677
691
  publications : 'alltables',
678
692
  target_session_attrs: null
679
693
  }
@@ -688,8 +702,8 @@ function parseOptions(a, b) {
688
702
  ...Object.entries(defaults).reduce(
689
703
  (acc, [k, d]) => {
690
704
  const value = k in o ? o[k] : k in query
691
- ? (query[k] === 'disable' || query[k] === 'false' ? false : query[k])
692
- : env['PG' + k.toUpperCase()] || d
705
+ ? off(query[k])
706
+ : env['PG' + k.toUpperCase()] ? off(env['PG' + k.toUpperCase()]) : d
693
707
  acc[k] = typeof value === 'string' && ints.includes(k)
694
708
  ? +value
695
709
  : value
@@ -704,11 +718,13 @@ function parseOptions(a, b) {
704
718
  },
705
719
  types : o.types || {},
706
720
  target_session_attrs: tsa(o, url, env),
721
+ parameter_types : parameterTypes(o, url, env),
707
722
  onnotice : o.onnotice,
708
723
  onnotify : o.onnotify,
709
724
  onclose : o.onclose,
710
725
  onidle : o.onidle,
711
726
  onparameter : o.onparameter,
727
+ ontypemismatch : o.ontypemismatch,
712
728
  socket : o.socket,
713
729
  transform : parseTransform(o.transform || { undefined: undefined }),
714
730
  parameters : {},
@@ -720,6 +736,10 @@ function parseOptions(a, b) {
720
736
  return options
721
737
  }
722
738
 
739
+ function off(x) {
740
+ return x === 'disable' || x === 'false' ? false : x
741
+ }
742
+
723
743
  function tsa(o, url, env) {
724
744
  const x = o.target_session_attrs || url.searchParams.get('target_session_attrs') || env.PGTARGETSESSIONATTRS
725
745
  if (!x || ['read-write', 'read-only', 'primary', 'standby', 'prefer-standby'].includes(x))
@@ -728,6 +748,14 @@ function tsa(o, url, env) {
728
748
  throw new Error('target_session_attrs ' + x + ' is not supported')
729
749
  }
730
750
 
751
+ function parameterTypes(o, url, env) {
752
+ const x = o.parameter_types || url.searchParams.get('parameter_types') || env.PGPARAMETER_TYPES || 'server'
753
+ if (['server', 'client', 'warn'].includes(x))
754
+ return x
755
+
756
+ throw new Error('parameter_types ' + x + ' is not supported')
757
+ }
758
+
731
759
  function max_lifetime() {
732
760
  return 60 * (30 + Math.random() * 30)
733
761
  }
package/cjs/src/query.js CHANGED
@@ -23,16 +23,9 @@ const Query = module.exports.Query = class Query extends Promise {
23
23
  this.state = null
24
24
  this.statement = null
25
25
 
26
- this.resolve = x => {
27
- this.active = false
28
- this.settled = true
29
- resolve(x)
30
- }
31
- this.reject = x => {
32
- this.active = false
33
- this.settled = true
34
- reject(x)
35
- }
26
+ // dd-trace's load-time rewrite only accepts single-expression arrows here
27
+ this.resolve = x => (this.active = false, this.settled = true, resolve(x))
28
+ this.reject = x => (this.active = false, this.settled = true, reject(x))
36
29
 
37
30
  this.active = false
38
31
  this.settled = false
@@ -62,6 +55,7 @@ const Query = module.exports.Query = class Query extends Promise {
62
55
  if (!this.canceller || this.settled)
63
56
  return Promise.resolve()
64
57
 
58
+ Promise.prototype.then.call(this, undefined, () => undefined)
65
59
  const cancelled = this.canceller(this)
66
60
  this.canceller = null
67
61
  cancelled.catch(() => undefined)
package/cjs/src/types.js CHANGED
@@ -248,6 +248,11 @@ const inferType = module.exports.inferType = function inferType(x) {
248
248
  )
249
249
  }
250
250
 
251
+ module.exports.clientSerialize = clientSerialize;function clientSerialize(x) {
252
+ const proto = typeof x === 'object' && Object.getPrototypeOf(x)
253
+ return proto === Object.prototype || proto === null ? JSON.stringify(x) : '' + x
254
+ }
255
+
251
256
  const escapeBackslash = /\\/g
252
257
  const escapeQuote = /"/g
253
258
 
@@ -341,14 +346,14 @@ function arrayParserLoop(s, x, parser, typarray) {
341
346
  const toCamel = module.exports.toCamel = x => {
342
347
  let str = x[0]
343
348
  for (let i = 1; i < x.length; i++)
344
- str += x[i] === '_' ? x[++i].toUpperCase() : x[i]
349
+ str += x[i] === '_' && i + 1 < x.length ? x[++i].toUpperCase() : x[i]
345
350
  return str
346
351
  }
347
352
 
348
353
  const toPascal = module.exports.toPascal = x => {
349
354
  let str = x[0].toUpperCase()
350
355
  for (let i = 1; i < x.length; i++)
351
- str += x[i] === '_' ? x[++i].toUpperCase() : x[i]
356
+ str += x[i] === '_' && i + 1 < x.length ? x[++i].toUpperCase() : x[i]
352
357
  return str
353
358
  }
354
359
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steadybrew/postgresjs",
3
- "version": "4.4.1",
3
+ "version": "4.5.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",
@@ -24,7 +24,7 @@
24
24
  "types": "types/index.d.ts",
25
25
  "typings": "types/index.d.ts",
26
26
  "engines": {
27
- "node": ">=24"
27
+ "node": ">=22"
28
28
  },
29
29
  "scripts": {
30
30
  "build": "npm run build:cjs && npm run build:deno && npm run build:cf",
@@ -32,9 +32,10 @@
32
32
  "build:deno": "node transpile.deno.js",
33
33
  "build:cf": "node transpile.cf.js",
34
34
  "test": "npm run test:startup && npm run test:esm && npm run test:cjs && npm run test:deno",
35
- "test:esm": "node tests-startup/run.js --integration && node tests/index.js",
35
+ "test:esm": "node tests-startup/run.js --integration && node tests/index.js && node tests-startup/run.js --reports",
36
36
  "test:startup": "node tests-startup/run.js",
37
- "test:cjs": "npm run build:cjs && node tests-startup/run.js --integration --cjs && cd cjs/tests && node index.js && cd ../../",
37
+ "test:tracing": "node tests-tracing/run.js",
38
+ "test:cjs": "npm run build:cjs && node tests-startup/run.js --integration --cjs && cd cjs/tests && node index.js && cd ../../ && node tests-startup/run.js --reports --cjs",
38
39
  "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 ../../",
39
40
  "lint": "eslint src && eslint tests && eslint tests-startup --ext .js,.mjs",
40
41
  "prepare": "npm run build",