@m2k-5f/pgtx 2.6.11 → 2.7.1

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 (37) hide show
  1. package/README.md +244 -494
  2. package/dist/batch.d.ts +2 -1
  3. package/dist/batch.d.ts.map +1 -1
  4. package/dist/batch.js +8 -7
  5. package/dist/connection.d.ts +39 -150
  6. package/dist/connection.d.ts.map +1 -1
  7. package/dist/connection.js +199 -284
  8. package/dist/error.d.ts +4 -0
  9. package/dist/error.d.ts.map +1 -1
  10. package/dist/error.js +4 -0
  11. package/dist/pool.d.ts +29 -181
  12. package/dist/pool.d.ts.map +1 -1
  13. package/dist/pool.js +49 -180
  14. package/dist/protocol/connection-request-writer.d.ts +1 -0
  15. package/dist/protocol/connection-request-writer.d.ts.map +1 -1
  16. package/dist/protocol/connection-request-writer.js +6 -0
  17. package/dist/protocol/connection-response-reader.d.ts +1 -0
  18. package/dist/protocol/connection-response-reader.d.ts.map +1 -1
  19. package/dist/protocol/connection-response-reader.js +3 -0
  20. package/dist/protocol/constants.d.ts +2 -0
  21. package/dist/protocol/constants.d.ts.map +1 -1
  22. package/dist/protocol/constants.js +3 -1
  23. package/dist/protocol/socket-authorization.d.ts +5 -4
  24. package/dist/protocol/socket-authorization.d.ts.map +1 -1
  25. package/dist/protocol/socket-authorization.js +167 -74
  26. package/dist/protocol/socket-connector.d.ts +5 -5
  27. package/dist/protocol/socket-connector.d.ts.map +1 -1
  28. package/dist/protocol/socket-connector.js +24 -15
  29. package/dist/query.d.ts +14 -17
  30. package/dist/query.d.ts.map +1 -1
  31. package/dist/query.js +20 -17
  32. package/dist/transaction.d.ts +9 -1
  33. package/dist/transaction.d.ts.map +1 -1
  34. package/dist/transaction.js +11 -0
  35. package/dist/types.d.ts +14 -9
  36. package/dist/types.d.ts.map +1 -1
  37. package/package.json +1 -1
@@ -64,5 +64,6 @@ export declare class ConnectionResponseReader {
64
64
  readBindComplete(): void;
65
65
  readParameterDescription(): void;
66
66
  readNoData(): void;
67
+ skip(count: number): void;
67
68
  }
68
69
  //# sourceMappingURL=connection-response-reader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection-response-reader.d.ts","sourceRoot":"","sources":["../../src/protocol/connection-response-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA6B,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC5G,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAOxC,qBAAa,wBAAwB;IAI7B,OAAO,CAAC,MAAM;IAHlB,OAAO,CAAC,KAAK,CAAI;IAEjB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ,IAAI,MAAM;IAOlB,SAAS,IAAI,MAAM;IAOnB,SAAS,IAAI,MAAM;IAOnB,WAAW,IAAI,MAAM;IAQrB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAOrC,OAAO,IAAI,OAAO;IAKlB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAO3C,cAAc,IAAI,IAAI;IAOtB,mBAAmB,IAAI,IAAI;IAO3B,cAAc,IAAI,MAAM;IAaxB,SAAS,CAAC,SAAS,EAAE,MAAM;IAK3B,aAAa,IAAI,OAAO;IAaxB,iBAAiB;IAIjB,QAAQ;IAMR,YAAY,IAAI,MAAM;IAOtB,SAAS;IAST,WAAW;IAOX,WAAW,IAAI,MAAM;IAMrB,QAAQ;IAWR,SAAS,CAAC,MAAM,EAAE,MAAM;IAQxB,aAAa,CAAC,MAAM,EAAE,MAAM;CAW/B;AAGD,qBAAa,wBAAwB;IAG7B,OAAO,CAAC,MAAM;IADlB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ;cACoC,YAAY;;;IAIxD,kBAAkB,IACoB,kBAAkB;IAIxD,WAAW;IAKX,mBAAmB;;;;IAQnB,kBAAkB;;;;IAQlB,iBAAiB,IAAI,aAAa;IA4ClC,iBAAiB,IACoB,iBAAiB;IAItD,kBAAkB,IAAI,MAAM,EAAE;IAa9B,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAKvC,kBAAkB;IAsBlB,WAAW,CAAC,YAAY,EAAE,iBAAiB,EAAE,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IA0G1F,wBAAwB;;;;IASxB,mBAAmB,IAAI,MAAM;IAK7B,OAAO;IAKP,aAAa;IAKb,iBAAiB;IAKjB,iBAAiB;IAGjB,gBAAgB;IAGhB,wBAAwB;IAOxB,UAAU;CACb"}
1
+ {"version":3,"file":"connection-response-reader.d.ts","sourceRoot":"","sources":["../../src/protocol/connection-response-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA6B,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC5G,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAOxC,qBAAa,wBAAwB;IAI7B,OAAO,CAAC,MAAM;IAHlB,OAAO,CAAC,KAAK,CAAI;IAEjB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ,IAAI,MAAM;IAOlB,SAAS,IAAI,MAAM;IAOnB,SAAS,IAAI,MAAM;IAOnB,WAAW,IAAI,MAAM;IAQrB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAOrC,OAAO,IAAI,OAAO;IAKlB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAO3C,cAAc,IAAI,IAAI;IAOtB,mBAAmB,IAAI,IAAI;IAO3B,cAAc,IAAI,MAAM;IAaxB,SAAS,CAAC,SAAS,EAAE,MAAM;IAK3B,aAAa,IAAI,OAAO;IAaxB,iBAAiB;IAIjB,QAAQ;IAMR,YAAY,IAAI,MAAM;IAOtB,SAAS;IAST,WAAW;IAOX,WAAW,IAAI,MAAM;IAMrB,QAAQ;IAWR,SAAS,CAAC,MAAM,EAAE,MAAM;IAQxB,aAAa,CAAC,MAAM,EAAE,MAAM;CAW/B;AAGD,qBAAa,wBAAwB;IAG7B,OAAO,CAAC,MAAM;IADlB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ;cACoC,YAAY;;;IAIxD,kBAAkB,IACoB,kBAAkB;IAIxD,WAAW;IAKX,mBAAmB;;;;IAQnB,kBAAkB;;;;IAQlB,iBAAiB,IAAI,aAAa;IA4ClC,iBAAiB,IACoB,iBAAiB;IAItD,kBAAkB,IAAI,MAAM,EAAE;IAa9B,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAKvC,kBAAkB;IAsBlB,WAAW,CAAC,YAAY,EAAE,iBAAiB,EAAE,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IA0G1F,wBAAwB;;;;IASxB,mBAAmB,IAAI,MAAM;IAK7B,OAAO;IAKP,aAAa;IAKb,iBAAiB;IAKjB,iBAAiB;IAGjB,gBAAgB;IAGhB,wBAAwB;IAOxB,UAAU;IAEV,IAAI,CAAC,KAAK,EAAE,MAAM;CAGrB"}
@@ -376,4 +376,7 @@ export class ConnectionResponseReader {
376
376
  }
377
377
  }
378
378
  readNoData() { }
379
+ skip(count) {
380
+ this.buffer.skipBytes(count);
381
+ }
379
382
  }
@@ -27,6 +27,8 @@ export declare const ResponseTypes: {
27
27
  readonly NoData: "n";
28
28
  readonly Notice: "N";
29
29
  readonly NotificationResponse: "A";
30
+ readonly SSLOk: "S";
31
+ readonly SSLDenied: "N";
30
32
  };
31
33
  export declare const DataTypeOids: {
32
34
  readonly Bool: 16;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/protocol/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAElC,eAAO,MAAM,YAAY;;;;;;;;;CASf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,YAAY,CAAC,CAAA;AAGtD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;CAiBhB,CAAA;AAGV,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAIzE,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,aAAa,CAAC,CAAA;AAGxD,eAAO,MAAM,mBAAmB;;;;;;;CAOtB,CAAA;AAEV,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAGpE,eAAO,MAAM,mBAAmB;;;;CAItB,CAAA;AAEV,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/protocol/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAElC,eAAO,MAAM,YAAY;;;;;;;;;CASf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,YAAY,CAAC,CAAA;AAGtD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;CAmBhB,CAAA;AAGV,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAIzE,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,aAAa,CAAC,CAAA;AAGxD,eAAO,MAAM,mBAAmB;;;;;;;CAOtB,CAAA;AAEV,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAGpE,eAAO,MAAM,mBAAmB;;;;CAItB,CAAA;AAEV,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA"}
@@ -24,7 +24,9 @@ export const ResponseTypes = {
24
24
  ParameterDescription: "t",
25
25
  NoData: "n",
26
26
  Notice: "N",
27
- NotificationResponse: "A"
27
+ NotificationResponse: "A",
28
+ SSLOk: "S",
29
+ SSLDenied: "N"
28
30
  };
29
31
  export const DataTypeOids = {
30
32
  Bool: 16,
@@ -1,7 +1,8 @@
1
- import { Socket } from "node:net";
2
- import { ConnectionRequestWriter } from "./connection-request-writer";
3
1
  import { PostgresError } from "../error";
4
2
  import { Future } from "fluent-future";
5
- import { AuthorizationParams } from "../types";
6
- export declare const createAuthorizedSocket: (writer: ConnectionRequestWriter, params: AuthorizationParams) => Future<Socket, PostgresError>;
3
+ import { Socket } from "node:net";
4
+ import { ConnectionConfig } from "../types";
5
+ export declare const createSocket: (config: ConnectionConfig) => Future<Socket, PostgresError>;
6
+ export declare const upgradeSocket: (socket: Socket, config: ConnectionConfig) => Future<Socket, PostgresError>;
7
+ export declare const authorizeSocket: (socket: Socket, config: ConnectionConfig) => Future<Socket, PostgresError>;
7
8
  //# sourceMappingURL=socket-authorization.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket-authorization.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-authorization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,MAAM,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AAKrE,OAAO,EAAoE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC1G,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG9C,eAAO,MAAM,sBAAsB,GAAI,QAAQ,uBAAuB,EAAE,QAAQ,mBAAmB,kCAoHlG,CAAA"}
1
+ {"version":3,"file":"socket-authorization.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-authorization.ts"],"names":[],"mappings":"AAKA,OAAO,EAA4J,aAAa,EAAE,MAAM,UAAU,CAAA;AAClM,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAEtC,OAAO,EAAoB,MAAM,EAAE,MAAM,UAAU,CAAA;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAI3C,eAAO,MAAM,YAAY,GAAI,QAAQ,gBAAgB,kCASpD,CAAA;AAGD,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,EAAE,QAAQ,gBAAgB,kCA+ErE,CAAA;AAGD,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,EAAE,QAAQ,gBAAgB,kCAyHvE,CAAA"}
@@ -1,93 +1,186 @@
1
- import { createConnection } from "node:net";
1
+ import { ConnectionRequestWriter } from "./connection-request-writer";
2
2
  import { calculateScramAuth, generateNonce } from "../security/sasl";
3
3
  import { SocketConnector } from "./socket-connector";
4
4
  import { AuthenticationCodes, ResponseTypes } from "./constants";
5
5
  import { encryptMd5 } from "../security/md5";
6
- import { ErrNonceMismatch, ErrPasswordRequired, ErrSocketFailedDuringAuth } from "../error";
6
+ import { ErrCertificateFileNotFound, ErrDatabaseNotFound, ErrNonceMismatch, ErrPasswordRequired, ErrSocketFailedDuringAuth, ErrSSLDenied, ErrUntrustedCertificate } from "../error";
7
7
  import { Future } from "fluent-future";
8
- export const createAuthorizedSocket = (writer, params) => {
8
+ import { connect } from "node:tls";
9
+ import { createConnection } from "node:net";
10
+ import { readFileSync } from "node:fs";
11
+ export const createSocket = (config) => {
12
+ const { future, resolve, reject } = Future.withResolvers();
13
+ const socket = createConnection({ host: config.host, port: config.port });
14
+ socket.once('connect', () => resolve(socket));
15
+ socket.once('error', () => reject(ErrDatabaseNotFound));
16
+ return future;
17
+ };
18
+ export const upgradeSocket = (socket, config) => {
19
+ if (config.ssl === 'disable')
20
+ return Future.resolve(socket);
21
+ const { future, reject, resolve } = Future.withResolvers();
22
+ const writer = ConnectionRequestWriter.new();
23
+ const onError = () => {
24
+ cleanup();
25
+ reject(ErrSocketFailedDuringAuth);
26
+ };
27
+ socket.once('error', onError);
28
+ const cleanup = () => {
29
+ socket.off('error', onError);
30
+ };
31
+ socket.once('data', (data) => {
32
+ cleanup();
33
+ const responseCode = data.toString('utf8', 0, 1);
34
+ if (responseCode === 'S') {
35
+ if (data.length > 1) {
36
+ socket.unshift(data.subarray(1));
37
+ }
38
+ let cert = undefined;
39
+ try {
40
+ cert = config.caPath ? readFileSync(config.caPath) : undefined;
41
+ }
42
+ catch {
43
+ socket.destroy();
44
+ return reject(ErrCertificateFileNotFound);
45
+ }
46
+ const tls = connect({
47
+ socket: socket,
48
+ host: config.host,
49
+ rejectUnauthorized: config.ssl === 'require',
50
+ ca: cert
51
+ });
52
+ const tlsCleanup = () => {
53
+ tls.off('secureConnect', onSecureConnect);
54
+ tls.off('error', onTlsError);
55
+ };
56
+ const onSecureConnect = () => {
57
+ tlsCleanup();
58
+ resolve(tls);
59
+ };
60
+ const onTlsError = () => {
61
+ tlsCleanup();
62
+ tls.destroy();
63
+ reject(ErrUntrustedCertificate);
64
+ };
65
+ tls.once('secureConnect', onSecureConnect);
66
+ tls.once('error', onTlsError);
67
+ }
68
+ else if (responseCode === 'N') {
69
+ if (config.ssl === 'require') {
70
+ socket.destroy();
71
+ reject(ErrSSLDenied);
72
+ return;
73
+ }
74
+ resolve(socket);
75
+ }
76
+ else {
77
+ socket.destroy();
78
+ reject(ErrSocketFailedDuringAuth);
79
+ }
80
+ });
81
+ socket.write(writer.writeSSLRequest().asBuffer());
82
+ writer.clear();
83
+ return future;
84
+ };
85
+ export const authorizeSocket = (socket, config) => {
9
86
  const { future, reject, resolve } = Future.withResolvers();
87
+ const writer = ConnectionRequestWriter.new();
10
88
  const nonce = generateNonce();
11
89
  let clientMessage = '';
12
90
  let serverMessage = '';
13
- const socket = createConnection({ host: params.host, port: params.port });
14
- const connector = new SocketConnector(socket, (type, length, reader) => {
15
- writer.clear();
91
+ const connector = new SocketConnector(socket, handle, () => reject(ErrSocketFailedDuringAuth));
92
+ function handle(type, length, reader) {
16
93
  switch (type) {
17
- case ResponseTypes.Authentication: {
18
- switch (reader.readAuthentication()) {
19
- case AuthenticationCodes.Ok: break;
20
- case AuthenticationCodes.CleartextPassword: {
21
- if (!params.password)
22
- throw ErrPasswordRequired;
23
- connector.write(writer.writePassword(params.password));
24
- break;
25
- }
26
- case AuthenticationCodes.MD5Password: {
27
- const salt = reader.readMD5Salt();
28
- if (!params.password)
29
- throw ErrPasswordRequired;
30
- const password = encryptMd5(params.password, params.user, salt);
31
- connector.write(writer.writePassword(password));
32
- break;
33
- }
34
- case AuthenticationCodes.SASL: {
35
- reader.readSaslMechanisms();
36
- if (!params.password)
37
- throw ErrPasswordRequired;
38
- clientMessage = `n=${params.user},r=${nonce}`;
39
- connector.write(writer.writeSaslInitial('SCRAM-SHA-256', `n,,${clientMessage}`));
40
- break;
41
- }
42
- case AuthenticationCodes.SASLContinue: {
43
- serverMessage = reader.readSaslMessage(length);
44
- if (!params.password)
45
- throw ErrPasswordRequired;
46
- const parts = Object.fromEntries(serverMessage.split(',').map(x => x.split('=')));
47
- const serverNonce = parts.r;
48
- const saltBase64 = parts.s;
49
- const iterations = parseInt(parts.i, 10);
50
- if (!serverNonce.startsWith(nonce)) {
51
- connector.destroy();
52
- return reject(ErrNonceMismatch);
53
- }
54
- const clientFinalMessageWithoutProof = `c=biws,r=${serverNonce}`;
55
- const authMessage = `${clientMessage},${serverMessage},${clientFinalMessageWithoutProof}`;
56
- const { clientProof } = calculateScramAuth(params.password, saltBase64, iterations, authMessage);
57
- const clientFinalMessage = `${clientFinalMessageWithoutProof},p=${clientProof}`;
58
- connector.write(writer.writeSaslResponse(clientFinalMessage));
59
- break;
60
- }
61
- case AuthenticationCodes.SASLFinal: {
62
- reader.readSaslMessage(length);
63
- break;
64
- }
94
+ case ResponseTypes.Authentication:
95
+ {
96
+ Authentication(length, reader);
65
97
  }
66
98
  break;
67
- }
68
- case ResponseTypes.ParamaterStatus: {
69
- reader.readParameterStatus();
99
+ case ResponseTypes.ParamaterStatus:
100
+ {
101
+ reader.readParameterStatus();
102
+ }
70
103
  break;
71
- }
72
- case ResponseTypes.ErrorResponse: {
73
- const error = reader.readErrorResponse();
74
- connector.destroy();
75
- reject(error);
104
+ case ResponseTypes.ErrorResponse:
105
+ {
106
+ const error = reader.readErrorResponse();
107
+ connector.destroy();
108
+ reject(error);
109
+ }
76
110
  return;
77
- }
78
- case ResponseTypes.BackendKeyData: {
79
- reader.readBackendKeyData();
80
- }
81
- case ResponseTypes.ReadyForQuery: {
82
- reader.readReadyForQuery();
83
- resolve(connector.unwrapSocket());
111
+ case ResponseTypes.BackendKeyData:
112
+ {
113
+ reader.readBackendKeyData();
114
+ }
115
+ break;
116
+ case ResponseTypes.ReadyForQuery:
117
+ {
118
+ reader.readReadyForQuery();
119
+ resolve(connector.unwrapSocket());
120
+ }
84
121
  return;
85
- }
86
122
  }
87
- }, error => {
88
- reject(ErrSocketFailedDuringAuth);
89
- });
90
- connector.write(writer.writeStartup(params.user, params.database));
123
+ }
124
+ function Authentication(length, reader) {
125
+ switch (reader.readAuthentication()) {
126
+ case AuthenticationCodes.Ok: break;
127
+ case AuthenticationCodes.CleartextPassword:
128
+ {
129
+ if (!config.password)
130
+ throw ErrPasswordRequired;
131
+ connector.write(writer.writePassword(config.password));
132
+ writer.clear();
133
+ }
134
+ break;
135
+ case AuthenticationCodes.MD5Password:
136
+ {
137
+ const salt = reader.readMD5Salt();
138
+ if (!config.password)
139
+ throw ErrPasswordRequired;
140
+ const password = encryptMd5(config.password, config.user, salt);
141
+ connector.write(writer.writePassword(password));
142
+ writer.clear();
143
+ }
144
+ break;
145
+ case AuthenticationCodes.SASL:
146
+ {
147
+ reader.readSaslMechanisms();
148
+ if (!config.password)
149
+ throw ErrPasswordRequired;
150
+ clientMessage = `n=${config.user},r=${nonce}`;
151
+ connector.write(writer.writeSaslInitial('SCRAM-SHA-256', `n,,${clientMessage}`));
152
+ writer.clear();
153
+ }
154
+ break;
155
+ case AuthenticationCodes.SASLContinue:
156
+ {
157
+ serverMessage = reader.readSaslMessage(length);
158
+ if (!config.password)
159
+ throw ErrPasswordRequired;
160
+ const parts = Object.fromEntries(serverMessage.split(',').map(x => x.split('=')));
161
+ const serverNonce = parts.r;
162
+ const saltBase64 = parts.s;
163
+ const iterations = parseInt(parts.i, 10);
164
+ if (!serverNonce.startsWith(nonce)) {
165
+ connector.destroy();
166
+ return reject(ErrNonceMismatch);
167
+ }
168
+ const clientFinalMessageWithoutProof = `c=biws,r=${serverNonce}`;
169
+ const authMessage = `${clientMessage},${serverMessage},${clientFinalMessageWithoutProof}`;
170
+ const { clientProof } = calculateScramAuth(config.password, saltBase64, iterations, authMessage);
171
+ const clientFinalMessage = `${clientFinalMessageWithoutProof},p=${clientProof}`;
172
+ connector.write(writer.writeSaslResponse(clientFinalMessage));
173
+ writer.clear();
174
+ }
175
+ break;
176
+ case AuthenticationCodes.SASLFinal:
177
+ {
178
+ reader.readSaslMessage(length);
179
+ }
180
+ break;
181
+ }
182
+ }
183
+ connector.write(writer.writeStartup(config.user, config.database));
91
184
  writer.clear();
92
185
  return future;
93
186
  };
@@ -4,14 +4,14 @@ import { ConnectionResponseReader } from '../protocol/connection-response-reader
4
4
  import { ConnectionRequestWriter } from '../protocol/connection-request-writer';
5
5
  export declare class SocketConnector {
6
6
  private _socket;
7
- private _onData;
8
- private _onError;
9
7
  private residualBuffer;
10
- private _isDestroyed;
11
- constructor(_socket: Socket, _onData: (type: ResponseType, length: number, reader: ConnectionResponseReader) => void, _onError: (error: Error) => void);
8
+ private _onError;
9
+ private _onClose;
10
+ private _onData;
11
+ private _destroyed;
12
+ constructor(_socket: Socket, onData: (type: ResponseType, length: number, reader: ConnectionResponseReader) => void, onError: (error: unknown) => void);
12
13
  write(writer: ConnectionRequestWriter): void;
13
14
  unwrapSocket(): Socket;
14
15
  destroy(): void;
15
- get isDestroyed(): boolean;
16
16
  }
17
17
  //# sourceMappingURL=socket-connector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket-connector.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAE/E,qBAAa,eAAe;IAKpB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IANpB,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,YAAY,CAAQ;gBAGhB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,wBAAwB,KAAK,IAAI,EACvF,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;IA8B5C,KAAK,CAAC,MAAM,EAAE,uBAAuB;IAMrC,YAAY;IAQZ,OAAO;IAMP,IAAI,WAAW,YAA6B;CAC/C"}
1
+ {"version":3,"file":"socket-connector.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAE/E,qBAAa,eAAe;IAQpB,OAAO,CAAC,OAAO;IAPnB,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAAQ;gBAGd,OAAO,EAAE,MAAM,EACvB,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,wBAAwB,KAAK,IAAI,EACtF,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI;IA4CrC,KAAK,CAAC,MAAM,EAAE,uBAAuB;IAKrC,YAAY;IASZ,OAAO;CAGV"}
@@ -1,13 +1,24 @@
1
1
  import { ConnectionResponseReader } from '../protocol/connection-response-reader';
2
2
  export class SocketConnector {
3
- constructor(_socket, _onData, _onError) {
3
+ constructor(_socket, onData, onError) {
4
4
  this._socket = _socket;
5
- this._onData = _onData;
6
- this._onError = _onError;
7
5
  this.residualBuffer = null;
8
- this._isDestroyed = false;
9
- _socket.setKeepAlive(true, 10000);
10
- _socket.on('data', buffer => {
6
+ this._destroyed = false;
7
+ this._onError = (err) => {
8
+ if (this._destroyed)
9
+ return;
10
+ this._destroyed = true;
11
+ onError(err);
12
+ this.destroy();
13
+ };
14
+ this._onClose = () => {
15
+ if (this._destroyed)
16
+ return;
17
+ this._destroyed = true;
18
+ onError(new Error("Socket closed"));
19
+ this.destroy();
20
+ };
21
+ this._onData = buffer => {
11
22
  const currentBuffer = this.residualBuffer
12
23
  ? Buffer.concat([this.residualBuffer, buffer])
13
24
  : buffer;
@@ -19,14 +30,13 @@ export class SocketConnector {
19
30
  return;
20
31
  }
21
32
  const { type, length } = reader.readType();
22
- this._onData(type, length, reader);
33
+ onData(type, length, reader);
23
34
  }
24
- });
25
- _socket.on('error', error => {
26
- this._onError(error);
27
- this._socket.destroy();
28
- this._isDestroyed = true;
29
- });
35
+ };
36
+ _socket.setKeepAlive(true, 10000);
37
+ _socket.on('data', this._onData);
38
+ _socket.on('error', this._onError);
39
+ _socket.on('close', this._onClose);
30
40
  }
31
41
  write(writer) {
32
42
  this._socket.write(writer.asBuffer());
@@ -34,11 +44,10 @@ export class SocketConnector {
34
44
  unwrapSocket() {
35
45
  this._socket.off('error', this._onError);
36
46
  this._socket.off("data", this._onData);
47
+ this._socket.off('close', this._onClose);
37
48
  return this._socket;
38
49
  }
39
50
  destroy() {
40
- this._isDestroyed = true;
41
51
  this._socket.destroy();
42
52
  }
43
- get isDestroyed() { return this._isDestroyed; }
44
53
  }
package/dist/query.d.ts CHANGED
@@ -1,44 +1,41 @@
1
1
  import { Future } from "fluent-future";
2
- import { ColumnDescription, QueryMeta, QueryText, StatementName } from "./types";
2
+ import { ColumnDescription, QueryText, Row, StatementName } from "./types";
3
3
  import { PostgresError } from "./error";
4
4
  export declare abstract class Query {
5
5
  statement: StatementName;
6
+ text: QueryText;
7
+ args: (string | null)[];
6
8
  protected _timer?: NodeJS.Timeout;
7
- constructor(statement: StatementName, timeout: number);
9
+ constructor(statement: StatementName, text: QueryText, args: (string | null)[], timeout: number);
8
10
  abstract reject(cause: PostgresError): void;
9
11
  abstract resolve(...args: any[]): void;
10
12
  }
11
- export declare class SimpleQuery<T> extends Query {
12
- text: QueryText;
13
- args: (string | null)[];
14
- columns: ColumnDescription[];
13
+ export declare class CollectQuery<T extends Row> extends Query {
14
+ columns: ColumnDescription[] | null;
15
15
  future: Future<T[], PostgresError>;
16
16
  private _resolve;
17
17
  private _reject;
18
18
  private _rows;
19
- constructor(statement: StatementName, text: QueryText, args: (string | null)[], columns: ColumnDescription[], timeout: number);
19
+ constructor(statement: StatementName, text: QueryText, args: (string | null)[], columns: ColumnDescription[] | null, timeout: number);
20
20
  push(value: T): void;
21
21
  reject(cause: PostgresError): void;
22
22
  resolve(): void;
23
23
  }
24
- export declare class ParseQuery extends Query {
25
- text: QueryText;
26
- future: Future<QueryMeta, PostgresError>;
24
+ export declare class ExecuteQuery extends Query {
25
+ future: Future<void, PostgresError>;
27
26
  private _resolve;
28
27
  private _reject;
29
- constructor(statement: StatementName, text: QueryText, timeout: number);
28
+ constructor(statement: StatementName, text: QueryText, args: (string | null)[], timeout: number);
30
29
  reject(cause: PostgresError): void;
31
- resolve(meta: QueryMeta): void;
30
+ resolve(): void;
32
31
  }
33
32
  export declare class StreamQuery<T> extends Query {
34
- text: QueryText;
35
- args: (string | null)[];
36
33
  controller: ReadableStreamDefaultController<T>;
37
- columns: ColumnDescription[];
38
- constructor(statement: StatementName, text: QueryText, args: (string | null)[], controller: ReadableStreamDefaultController<T>, columns: ColumnDescription[], timeout: number);
34
+ columns: ColumnDescription[] | null;
35
+ constructor(statement: StatementName, text: QueryText, args: (string | null)[], controller: ReadableStreamDefaultController<T>, columns: ColumnDescription[] | null, timeout: number);
39
36
  push(value: T): void;
40
37
  reject(cause: PostgresError): void;
41
38
  resolve(): void;
42
39
  }
43
- export type PostgresQuery = SimpleQuery<any> | ParseQuery | StreamQuery<any>;
40
+ export type PostgresQuery = CollectQuery<any> | StreamQuery<any> | ExecuteQuery;
44
41
  //# sourceMappingURL=query.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAmB,aAAa,EAAE,MAAM,SAAS,CAAC;AAGzD,8BAAsB,KAAK;IAIZ,SAAS,EAAE,aAAa;IAHnC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,CAAA;gBAGtB,SAAS,EAAE,aAAa,EAC/B,OAAO,EAAE,MAAM;IAQnB,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAE3C,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;CACzC;AAGD,qBAAa,WAAW,CAAC,CAAC,CAAE,SAAQ,KAAK;IAQ1B,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IACvB,OAAO,EAAE,iBAAiB,EAAE;IAThC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,aAAa,CAAC,CAAA;IACzC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,KAAK,CAAU;gBAGnB,SAAS,EAAE,aAAa,EACjB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EACvB,OAAO,EAAE,iBAAiB,EAAE,EACnC,OAAO,EAAE,MAAM;IAWnB,IAAI,CAAC,KAAK,EAAE,CAAC;IAKb,MAAM,CAAC,KAAK,EAAE,aAAa;IAM3B,OAAO;CAIV;AAGD,qBAAa,UAAW,SAAQ,KAAK;IAOtB,IAAI,EAAE,SAAS;IANnB,MAAM,EAAE,MAAM,CAAC,SAAS,EAAG,aAAa,CAAC,CAAA;IAChD,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,OAAO,CAAiC;gBAG5C,SAAS,EAAE,aAAa,EACjB,IAAI,EAAE,SAAS,EACtB,OAAO,EAAE,MAAM;IAWnB,MAAM,CAAC,KAAK,EAAE,aAAa;IAM3B,OAAO,CAAC,IAAI,EAAE,SAAS;CAI1B;AAGD,qBAAa,WAAW,CAAC,CAAC,CAAE,SAAQ,KAAK;IAG1B,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IACvB,UAAU,EAAE,+BAA+B,CAAC,CAAC,CAAC;IAC9C,OAAO,EAAE,iBAAiB,EAAE;gBAJnC,SAAS,EAAE,aAAa,EACjB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EACvB,UAAU,EAAE,+BAA+B,CAAC,CAAC,CAAC,EAC9C,OAAO,EAAE,iBAAiB,EAAE,EACnC,OAAO,EAAE,MAAM;IAMnB,IAAI,CAAC,KAAK,EAAE,CAAC;IAKb,MAAM,CAAC,KAAK,EAAE,aAAa;IAM3B,OAAO;CAIV;AAED,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAa,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtF,OAAO,EAAmB,aAAa,EAAE,MAAM,SAAS,CAAC;AAGzD,8BAAsB,KAAK;IAIZ,SAAS,EAAE,aAAa;IACxB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IALlC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,CAAA;gBAGtB,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAC9B,OAAO,EAAE,MAAM;IAQnB,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAE3C,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;CACzC;AAGD,qBAAa,YAAY,CAAC,CAAC,SAAS,GAAG,CAAE,SAAQ,KAAK;IAUvC,OAAO,EAAE,iBAAiB,EAAE,GAAG,IAAI;IATvC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,aAAa,CAAC,CAAA;IACzC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,KAAK,CAAU;gBAGnB,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAChB,OAAO,EAAE,iBAAiB,EAAE,GAAG,IAAI,EAC1C,OAAO,EAAE,MAAM;IAWnB,IAAI,CAAC,KAAK,EAAE,CAAC;IAKb,MAAM,CAAC,KAAK,EAAE,aAAa;IAM3B,OAAO;CAIV;AAGD,qBAAa,YAAa,SAAQ,KAAK;IAC5B,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IAC1C,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,OAAO,CAAiC;gBAE5C,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EACvB,OAAO,EAAE,MAAM;IASnB,MAAM,CAAC,KAAK,EAAE,aAAa;IAM3B,OAAO;CAIV;AAGD,qBAAa,WAAW,CAAC,CAAC,CAAE,SAAQ,KAAK;IAK1B,UAAU,EAAE,+BAA+B,CAAC,CAAC,CAAC;IAC9C,OAAO,EAAE,iBAAiB,EAAE,GAAG,IAAI;gBAJ1C,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAChB,UAAU,EAAE,+BAA+B,CAAC,CAAC,CAAC,EAC9C,OAAO,EAAE,iBAAiB,EAAE,GAAG,IAAI,EAC1C,OAAO,EAAE,MAAM;IAMnB,IAAI,CAAC,KAAK,EAAE,CAAC;IAOb,MAAM,CAAC,KAAK,EAAE,aAAa;IAM3B,OAAO;CAMV;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,YAAY,CAAA"}
package/dist/query.js CHANGED
@@ -1,18 +1,18 @@
1
1
  import { Future } from "fluent-future";
2
2
  import { ErrQueryTimeout } from "./error";
3
3
  export class Query {
4
- constructor(statement, timeout) {
4
+ constructor(statement, text, args, timeout) {
5
5
  this.statement = statement;
6
+ this.text = text;
7
+ this.args = args;
6
8
  this._timer = setTimeout(() => {
7
9
  this.reject(ErrQueryTimeout);
8
10
  }, timeout);
9
11
  }
10
12
  }
11
- export class SimpleQuery extends Query {
13
+ export class CollectQuery extends Query {
12
14
  constructor(statement, text, args, columns, timeout) {
13
- super(statement, timeout);
14
- this.text = text;
15
- this.args = args;
15
+ super(statement, text, args, timeout);
16
16
  this.columns = columns;
17
17
  this._rows = [];
18
18
  const { future, reject, resolve } = Future.withResolvers();
@@ -32,34 +32,34 @@ export class SimpleQuery extends Query {
32
32
  this._resolve(this._rows);
33
33
  }
34
34
  }
35
- export class ParseQuery extends Query {
36
- constructor(statement, text, timeout) {
37
- super(statement, timeout);
38
- this.text = text;
35
+ export class ExecuteQuery extends Query {
36
+ constructor(statement, text, args, timeout) {
37
+ super(statement, text, args, timeout);
39
38
  const { future, reject, resolve } = Future.withResolvers();
40
39
  this.future = future;
41
- this._resolve = resolve;
42
40
  this._reject = reject;
41
+ this._resolve = resolve;
43
42
  }
44
43
  reject(cause) {
45
44
  clearTimeout(this._timer);
46
45
  this._reject(cause);
47
46
  }
48
- resolve(meta) {
47
+ resolve() {
49
48
  clearTimeout(this._timer);
50
- this._resolve(meta);
49
+ this._resolve();
51
50
  }
52
51
  }
53
52
  export class StreamQuery extends Query {
54
53
  constructor(statement, text, args, controller, columns, timeout) {
55
- super(statement, timeout);
56
- this.text = text;
57
- this.args = args;
54
+ super(statement, text, args, timeout);
58
55
  this.controller = controller;
59
56
  this.columns = columns;
60
57
  }
61
58
  push(value) {
62
- this.controller.enqueue(value);
59
+ try {
60
+ this.controller.enqueue(value);
61
+ }
62
+ catch { }
63
63
  }
64
64
  reject(cause) {
65
65
  clearTimeout(this._timer);
@@ -67,6 +67,9 @@ export class StreamQuery extends Query {
67
67
  }
68
68
  resolve() {
69
69
  clearTimeout(this._timer);
70
- this.controller.close();
70
+ try {
71
+ this.controller.close();
72
+ }
73
+ catch { }
71
74
  }
72
75
  }
@@ -1,6 +1,7 @@
1
1
  import { Future } from "fluent-future";
2
2
  import { Connection } from "./connection";
3
3
  import { PostgresError } from "./error";
4
+ import { Row } from "./types";
4
5
  /**
5
6
  * Represents an active SQL transaction.
6
7
  * All queries are executed on a single dedicated connection.
@@ -24,7 +25,14 @@ export declare class Transaction {
24
25
  /**
25
26
  * Executes a query within the current transaction.
26
27
  */
27
- query<T extends Record<string, any>>(strings: TemplateStringsArray, ...values: any[]): Future<T[], PostgresError>;
28
+ query<T extends Row>(strings: TemplateStringsArray, ...values: any[]): Future<T[], PostgresError>;
29
+ /**
30
+ * Like {@link query}, but for statements that don't return rows (INSERT/UPDATE/DDL/etc).
31
+ *
32
+ * @example
33
+ * await tx.execute`UPDATE users SET name = ${name} WHERE id = ${id}`
34
+ */
35
+ execute(strings: TemplateStringsArray, ...params: any[]): Future<void, PostgresError>;
28
36
  /**
29
37
  * Creates a sub-transaction using PostgreSQL SAVEPOINT.
30
38
  * If the callback throws, only the actions within this savepoint are rolled back.
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,eAAe,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAwB,aAAa,EAAE,MAAM,SAAS,CAAA;AAE7D;;;GAGG;AACH,qBAAa,WAAW;IAIhB,QAAQ,CAAC,IAAI,EAAE,UAAU;IAH7B,OAAO,CAAC,UAAU,CAAiB;gBAGtB,IAAI,EAAE,UAAU;IAG7B;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED;;OAEG;IACI,MAAM;IAQb;;OAEG;IACI,QAAQ;IAQf;;OAEG;IACI,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAM3F;;;;;;;;;OASG;IACI,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;CAW9E"}
1
+ {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,eAAe,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAwB,aAAa,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAE7B;;;GAGG;AACH,qBAAa,WAAW;IAIhB,QAAQ,CAAC,IAAI,EAAE,UAAU;IAH7B,OAAO,CAAC,UAAU,CAAiB;gBAGtB,IAAI,EAAE,UAAU;IAG7B;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED;;OAEG;IACI,MAAM;IAQb;;OAEG;IACI,QAAQ;IAQf;;OAEG;IACI,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAM3E;;;;;OAKG;IACI,OAAO,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAM9D;;;;;;;;;OASG;IACI,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;CAW9E"}
@@ -44,6 +44,17 @@ export class Transaction {
44
44
  return Future.reject(ErrTransactionClosed);
45
45
  return this.conn.query(strings, ...values);
46
46
  }
47
+ /**
48
+ * Like {@link query}, but for statements that don't return rows (INSERT/UPDATE/DDL/etc).
49
+ *
50
+ * @example
51
+ * await tx.execute`UPDATE users SET name = ${name} WHERE id = ${id}`
52
+ */
53
+ execute(strings, ...params) {
54
+ if (this.isFinished)
55
+ return Future.reject(ErrTransactionClosed);
56
+ return this.conn.execute(strings, ...params);
57
+ }
47
58
  /**
48
59
  * Creates a sub-transaction using PostgreSQL SAVEPOINT.
49
60
  * If the callback throws, only the actions within this savepoint are rolled back.