postgrejs 3.6.0 → 3.7.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.
Files changed (66) hide show
  1. package/CHANGELOG.md +64 -6
  2. package/README.md +9 -79
  3. package/connection/intl-connection.d.ts +5 -3
  4. package/connection/intl-connection.js +47 -17
  5. package/connection/pool.d.ts +22 -0
  6. package/connection/pool.js +45 -3
  7. package/connection/prepared-statement.js +2 -2
  8. package/constants.d.ts +60 -0
  9. package/constants.js +119 -1
  10. package/data-type-map.js +82 -0
  11. package/data-types/bit-type.d.ts +5 -0
  12. package/data-types/bit-type.js +91 -0
  13. package/data-types/box-type.js +9 -19
  14. package/data-types/circle-type.js +6 -16
  15. package/data-types/classes/geometric.d.ts +105 -0
  16. package/data-types/classes/geometric.js +197 -0
  17. package/data-types/classes/interval.d.ts +73 -0
  18. package/data-types/classes/interval.js +181 -0
  19. package/data-types/classes/numeric.d.ts +37 -0
  20. package/data-types/classes/numeric.js +47 -0
  21. package/data-types/classes/range.d.ts +74 -0
  22. package/data-types/classes/range.js +111 -0
  23. package/data-types/classes/type-oid.d.ts +34 -0
  24. package/data-types/classes/type-oid.js +45 -0
  25. package/data-types/inet-type.d.ts +5 -0
  26. package/data-types/inet-type.js +286 -0
  27. package/data-types/interval-type.d.ts +5 -0
  28. package/data-types/interval-type.js +79 -0
  29. package/data-types/jsonpath-type.d.ts +3 -0
  30. package/data-types/jsonpath-type.js +53 -0
  31. package/data-types/line-type.d.ts +3 -0
  32. package/data-types/line-type.js +41 -0
  33. package/data-types/lseg-type.js +9 -19
  34. package/data-types/macaddr-type.d.ts +5 -0
  35. package/data-types/macaddr-type.js +86 -0
  36. package/data-types/numeric-type.js +98 -69
  37. package/data-types/path-type.d.ts +5 -0
  38. package/data-types/path-type.js +139 -0
  39. package/data-types/pg-lsn-type.d.ts +3 -0
  40. package/data-types/pg-lsn-type.js +58 -0
  41. package/data-types/point-type.js +8 -13
  42. package/data-types/range-type.d.ts +23 -0
  43. package/data-types/range-type.js +342 -0
  44. package/data-types/snapshot-type.d.ts +5 -0
  45. package/data-types/snapshot-type.js +96 -0
  46. package/data-types/tid-type.d.ts +3 -0
  47. package/data-types/tid-type.js +50 -0
  48. package/data-types/timetz-type.d.ts +3 -0
  49. package/data-types/timetz-type.js +184 -0
  50. package/data-types/tsvector-type.d.ts +5 -0
  51. package/data-types/tsvector-type.js +216 -0
  52. package/data-types/xid-type.d.ts +7 -0
  53. package/data-types/xid-type.js +110 -0
  54. package/index.d.ts +5 -0
  55. package/index.js +5 -0
  56. package/interfaces/data-mapping-options.d.ts +26 -0
  57. package/interfaces/data-type.d.ts +8 -9
  58. package/package.json +1 -1
  59. package/protocol/connection-lost-error.d.ts +42 -0
  60. package/protocol/connection-lost-error.js +56 -0
  61. package/protocol/pg-socket.d.ts +7 -0
  62. package/protocol/pg-socket.js +41 -3
  63. package/util/parse-array.js +17 -2
  64. package/util/resolve-column-formats.d.ts +2 -1
  65. package/util/resolve-column-formats.js +35 -8
  66. package/util/stringify-for-sql.js +37 -1
@@ -1,3 +1,4 @@
1
+ import type { DataTypeMap } from '../data-type-map.js';
1
2
  import type { DataMappingOptions } from '../interfaces/data-mapping-options.js';
2
3
  import { Protocol } from '../protocol/protocol.js';
3
4
  import type { Maybe, OID } from '../types.js';
@@ -23,7 +24,7 @@ export interface ColumnFormatOptions extends DataMappingOptions {
23
24
  * Returns `columnFormat` untouched when there is nothing to do, so the
24
25
  * common case allocates nothing and keeps sending a single format code.
25
26
  */
26
- export declare function resolveColumnFormats(fields: Maybe<Protocol.RowDescription[]>, options: ColumnFormatOptions): Protocol.DataFormat | Protocol.DataFormat[];
27
+ export declare function resolveColumnFormats(fields: Maybe<Protocol.RowDescription[]>, options: ColumnFormatOptions, typeMap?: DataTypeMap): Protocol.DataFormat | Protocol.DataFormat[];
27
28
  /**
28
29
  * Whether two `fetchAsString` lists select the same columns. Used to tell
29
30
  * a cached set of parsers apart from one built for a different list, which
@@ -1,6 +1,18 @@
1
1
  import { DEFAULT_COLUMN_FORMAT } from '../constants.js';
2
2
  import { Protocol } from '../protocol/protocol.js';
3
3
  const DataFormat = Protocol.DataFormat;
4
+ /**
5
+ * Whether this client could read the column if it arrived in `format`.
6
+ * Only ever answers no for binary: a column with no registered type at
7
+ * all still decodes as text, into the string the server printed, which is
8
+ * the whole point of asking for it that way.
9
+ */
10
+ function canDecode(typeMap, oid, format) {
11
+ if (format !== DataFormat.binary)
12
+ return true;
13
+ const reg = typeMap.get(oid);
14
+ return !!reg && typeof reg.decodeBinary === 'function';
15
+ }
4
16
  /**
5
17
  * Turns `fetchAsString`'s OID list into the positional result format codes
6
18
  * a Bind message actually carries.
@@ -20,28 +32,43 @@ const DataFormat = Protocol.DataFormat;
20
32
  * Returns `columnFormat` untouched when there is nothing to do, so the
21
33
  * common case allocates nothing and keeps sending a single format code.
22
34
  */
23
- export function resolveColumnFormats(fields, options) {
35
+ export function resolveColumnFormats(fields, options, typeMap) {
24
36
  const base = options.columnFormat != null ? options.columnFormat : DEFAULT_COLUMN_FORMAT;
25
37
  const asString = options.fetchAsString;
26
- if (!fields || !asString || !asString.length)
38
+ // unknownTypesAsString needs the type map to answer "could this be
39
+ // decoded", so it is inert without one - the call sites that have no
40
+ // map in hand are the ones that have no fields either.
41
+ const unknownAsString = !!options.unknownTypesAsString && !!typeMap;
42
+ const named = !!asString && asString.length > 0;
43
+ if (!fields || (!named && !unknownAsString))
27
44
  return base;
28
45
  const l = fields.length;
29
46
  const baseIsArray = Array.isArray(base);
30
47
  const out = new Array(l);
31
48
  let hit = false;
32
49
  let i;
50
+ let oid;
51
+ let format;
33
52
  for (i = 0; i < l; i++) {
34
- if (asString.includes(fields[i].dataTypeId)) {
53
+ oid = fields[i].dataTypeId;
54
+ format = baseIsArray
55
+ ? (base[i] ?? DEFAULT_COLUMN_FORMAT)
56
+ : base;
57
+ if (named && asString.includes(oid)) {
35
58
  // fetchAsString names the value the caller wants verbatim, so it
36
59
  // overrides an explicit columnFormat for its own columns - the two
37
60
  // cannot both be honored and the OID list is the more specific ask.
38
- out[i] = DataFormat.text;
61
+ format = DataFormat.text;
62
+ hit = true;
63
+ }
64
+ else if (unknownAsString && !canDecode(typeMap, oid, format)) {
65
+ // Nothing here could read the binary, so the bytes would reach the
66
+ // caller as a Buffer. Text at least arrives as what the server
67
+ // printed.
68
+ format = DataFormat.text;
39
69
  hit = true;
40
70
  }
41
- else
42
- out[i] = baseIsArray
43
- ? (base[i] ?? DEFAULT_COLUMN_FORMAT)
44
- : base;
71
+ out[i] = format;
45
72
  }
46
73
  return hit ? out : base;
47
74
  }
@@ -1,9 +1,41 @@
1
+ import { DataTypeOIDs } from '../constants.js';
2
+ import { GlobalTypeMap } from '../data-type-map.js';
1
3
  import { UuidType } from '../data-types/uuid-type.js';
2
4
  import { escapeLiteral } from './escape-literal.js';
3
5
  export function stringifyArrayForSQL(v, options, encode) {
4
6
  const arr = v.map(x => stringifyValueForSQL(x, options, encode));
5
7
  return 'ARRAY[' + arr.join(',') + ']';
6
8
  }
9
+ /**
10
+ * Which type an object is is asked rather than assumed.
11
+ *
12
+ * Every geometric class, Interval, Range, Date and Buffer has a
13
+ * registered `encodeText()` that writes exactly the literal PostgreSQL
14
+ * reads back, and `determine()` already knows which type each one is -
15
+ * it is what the same value is sent as when it is bound as a parameter.
16
+ * Without asking, all of them became `::json`, and since these classes
17
+ * have a `toJSON()` returning their own literal the result was not even
18
+ * a JSON object but a JSON string holding one, which casts to nothing:
19
+ * `'"(1,2)"'::json` where `'(1,2)'::point` was meant. A Date became its
20
+ * ISO string and a Buffer leaked its bytes as `{"type":"Buffer",...}`.
21
+ */
22
+ function stringifyObjectForSQL(v, options) {
23
+ // determine() throws for a class that must carry a type OID and does
24
+ // not - a Range built without one - and that throw is deliberate: the
25
+ // alternative is writing a literal for a type nobody chose.
26
+ const oid = GlobalTypeMap.determine(v);
27
+ const dataType = GlobalTypeMap.get(oid);
28
+ // json and jsonb are the fallback below; reaching them through their
29
+ // own encodeText would only add a cast the literal does not need.
30
+ // Anything with no registered text encoder lands there too.
31
+ if (dataType?.encodeText &&
32
+ oid !== DataTypeOIDs.json &&
33
+ oid !== DataTypeOIDs.jsonb)
34
+ return (escapeLiteral(dataType.encodeText(v, options || {})) +
35
+ '::' +
36
+ dataType.name);
37
+ return escapeLiteral(JSON.stringify(v)) + '::json';
38
+ }
7
39
  export function stringifyValueForSQL(v, options, encode) {
8
40
  if (v == null)
9
41
  return 'null';
@@ -20,6 +52,10 @@ export function stringifyValueForSQL(v, options, encode) {
20
52
  if (typeof v === 'string' && UuidType.isType(v))
21
53
  return escapeLiteral('' + v) + '::uuid';
22
54
  if (typeof v === 'object')
23
- return escapeLiteral(JSON.stringify(v)) + '::json';
55
+ return stringifyObjectForSQL(v, options);
56
+ // A string is deliberately written bare. determine() would answer
57
+ // varchar, but an unadorned literal is `unknown` and takes the type of
58
+ // wherever it lands - `insert into t(n) values('5')` works and
59
+ // `'5'::varchar` would not.
24
60
  return escapeLiteral('' + v);
25
61
  }