node-firebird 2.9.0 → 2.10.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 (49) hide show
  1. package/README.md +166 -6
  2. package/lib/index.d.ts +5 -0
  3. package/lib/index.js +32 -1
  4. package/lib/pool.js +1 -1
  5. package/lib/srp.d.ts +3 -3
  6. package/lib/types.d.ts +143 -5
  7. package/lib/uri.js +2 -2
  8. package/lib/wire/connection.d.ts +92 -59
  9. package/lib/wire/connection.js +267 -53
  10. package/lib/wire/const.d.ts +9 -1
  11. package/lib/wire/const.js +21 -9
  12. package/lib/wire/database.d.ts +51 -26
  13. package/lib/wire/database.js +26 -8
  14. package/lib/wire/eventConnection.js +5 -3
  15. package/lib/wire/query-stream.d.ts +18 -0
  16. package/lib/wire/query-stream.js +73 -0
  17. package/lib/wire/serialize.d.ts +18 -2
  18. package/lib/wire/serialize.js +7 -0
  19. package/lib/wire/service.d.ts +42 -0
  20. package/lib/wire/service.js +145 -0
  21. package/lib/wire/socket.d.ts +3 -1
  22. package/lib/wire/socket.js +5 -2
  23. package/lib/wire/statement.d.ts +31 -19
  24. package/lib/wire/statement.js +1 -5
  25. package/lib/wire/transaction.d.ts +30 -18
  26. package/lib/wire/transaction.js +23 -4
  27. package/lib/wire/wire-types.d.ts +116 -0
  28. package/lib/wire/wire-types.js +10 -0
  29. package/lib/wire/xsqlvar.d.ts +18 -18
  30. package/package.json +1 -1
  31. package/src/index.ts +36 -4
  32. package/src/messages.ts +1 -1
  33. package/src/pool.ts +1 -1
  34. package/src/srp.ts +6 -6
  35. package/src/types.ts +140 -5
  36. package/src/unix-crypt.ts +9 -9
  37. package/src/uri.ts +2 -2
  38. package/src/wire/connection.ts +464 -232
  39. package/src/wire/const.ts +21 -9
  40. package/src/wire/database.ts +75 -43
  41. package/src/wire/eventConnection.ts +8 -5
  42. package/src/wire/query-stream.ts +80 -0
  43. package/src/wire/serialize.ts +29 -0
  44. package/src/wire/service.ts +188 -6
  45. package/src/wire/socket.ts +17 -8
  46. package/src/wire/statement.ts +37 -29
  47. package/src/wire/transaction.ts +57 -32
  48. package/src/wire/wire-types.ts +127 -0
  49. package/src/wire/xsqlvar.ts +9 -7
@@ -2,7 +2,7 @@ import Events from 'events';
2
2
  import stream from 'stream';
3
3
  import Const from './const';
4
4
  import { BlrReader } from './serialize';
5
- import { doError } from '../callback';
5
+ import { doError, fromCallback } from '../callback';
6
6
 
7
7
  /***************************************
8
8
  *
@@ -994,7 +994,7 @@ class ServiceManager extends Events.EventEmitter {
994
994
  var buffersize = options.buffersize || 2048;
995
995
  var timeout = options.timeout || 60;
996
996
  var self = this;
997
- this.connection.svcquery([Const.isc_info_svc_line], buffersize, timeout, function (err, data) {
997
+ this.connection.svcquery([Const.isc_info_svc_line], buffersize, timeout, function (err: any, data: any) {
998
998
  if (err || !data.buffer) {
999
999
  doError(new Error(err||'Bad query return'), callback);
1000
1000
  return;
@@ -1007,7 +1007,7 @@ class ServiceManager extends Events.EventEmitter {
1007
1007
  var buffersize = options.buffersize || (8 * 1024);
1008
1008
  var timeout = options.timeout || 60;
1009
1009
  var self = this;
1010
- this.connection.svcquery([Const.isc_info_svc_to_eof], buffersize, timeout, function (err, data) {
1010
+ this.connection.svcquery([Const.isc_info_svc_to_eof], buffersize, timeout, function (err: any, data: any) {
1011
1011
  if (err || !data.buffer) {
1012
1012
  doError(new Error(err||'Bad query return'), callback);
1013
1013
  return;
@@ -1020,7 +1020,7 @@ class ServiceManager extends Events.EventEmitter {
1020
1020
  var buffersize = options.buffersize || 2048;
1021
1021
  var timeout = options.timeout || 60;
1022
1022
  var self = this;
1023
- this.connection.svcquery([Const.isc_info_svc_running], buffersize, timeout, function (err, data) {
1023
+ this.connection.svcquery([Const.isc_info_svc_running], buffersize, timeout, function (err: any, data: any) {
1024
1024
  if (err || !data.buffer) {
1025
1025
  doError(new Error(err||'Bad query return'), callback);
1026
1026
  return;
@@ -1033,7 +1033,7 @@ class ServiceManager extends Events.EventEmitter {
1033
1033
  var buffersize = options.buffersize || 2048;
1034
1034
  var timeout = options.timeout || 60;
1035
1035
  var self = this;
1036
- this.connection.svcquery([Const.isc_info_svc_get_users], buffersize, timeout, function (err, data) {
1036
+ this.connection.svcquery([Const.isc_info_svc_get_users], buffersize, timeout, function (err: any, data: any) {
1037
1037
  if (err || !data.buffer) {
1038
1038
  doError(new Error(err||'Bad query return'), callback);
1039
1039
  return;
@@ -1046,7 +1046,7 @@ class ServiceManager extends Events.EventEmitter {
1046
1046
  var buffersize = options.buffersize || 2048;
1047
1047
  var timeout = options.timeout || 60;
1048
1048
  var self = this;
1049
- this.connection.svcquery([Const.isc_info_svc_limbo_trans], buffersize, timeout, function (err, data) {
1049
+ this.connection.svcquery([Const.isc_info_svc_limbo_trans], buffersize, timeout, function (err: any, data: any) {
1050
1050
  if (err || !data.buffer) {
1051
1051
  doError(new Error(err||'Bad query return'), callback);
1052
1052
  return;
@@ -1055,6 +1055,188 @@ class ServiceManager extends Events.EventEmitter {
1055
1055
  });
1056
1056
  }
1057
1057
 
1058
+ /* Promise / async-await API — wrappers over the callback methods above. */
1059
+
1060
+ detachAsync(force?: boolean): Promise<void> {
1061
+ var self = this;
1062
+ return fromCallback(function(cb) { self.detach(cb, force); });
1063
+ }
1064
+
1065
+ backupAsync(options: any): Promise<stream.Readable> {
1066
+ var self = this;
1067
+ return fromCallback(function(cb) { self.backup(options, cb); });
1068
+ }
1069
+
1070
+ nbackupAsync(options: any): Promise<stream.Readable> {
1071
+ var self = this;
1072
+ return fromCallback(function(cb) { self.nbackup(options, cb); });
1073
+ }
1074
+
1075
+ restoreAsync(options: any): Promise<stream.Readable> {
1076
+ var self = this;
1077
+ return fromCallback(function(cb) { self.restore(options, cb); });
1078
+ }
1079
+
1080
+ nrestoreAsync(options: any): Promise<stream.Readable> {
1081
+ var self = this;
1082
+ return fromCallback(function(cb) { self.nrestore(options, cb); });
1083
+ }
1084
+
1085
+ setDialectAsync(db: string, dialect: number): Promise<any> {
1086
+ var self = this;
1087
+ return fromCallback(function(cb) { self.setDialect(db, dialect, cb); });
1088
+ }
1089
+
1090
+ setSweepintervalAsync(db: string, sweepinterval: number): Promise<any> {
1091
+ var self = this;
1092
+ return fromCallback(function(cb) { self.setSweepinterval(db, sweepinterval, cb); });
1093
+ }
1094
+
1095
+ setCachebufferAsync(db: string, nbpages: number): Promise<any> {
1096
+ var self = this;
1097
+ return fromCallback(function(cb) { self.setCachebuffer(db, nbpages, cb); });
1098
+ }
1099
+
1100
+ BringOnlineAsync(db: string): Promise<any> {
1101
+ var self = this;
1102
+ return fromCallback(function(cb) { self.BringOnline(db, cb); });
1103
+ }
1104
+
1105
+ ShutdownAsync(db: string, kind: number, delay: number, mode?: any): Promise<any> {
1106
+ var self = this;
1107
+ return fromCallback(function(cb) { self.Shutdown(db, kind, delay, mode, cb); });
1108
+ }
1109
+
1110
+ setShadowAsync(db: string, val: boolean): Promise<any> {
1111
+ var self = this;
1112
+ return fromCallback(function(cb) { self.setShadow(db, val, cb); });
1113
+ }
1114
+
1115
+ setForcewriteAsync(db: string, val: boolean): Promise<any> {
1116
+ var self = this;
1117
+ return fromCallback(function(cb) { self.setForcewrite(db, val, cb); });
1118
+ }
1119
+
1120
+ setReservespaceAsync(db: string, val: boolean): Promise<any> {
1121
+ var self = this;
1122
+ return fromCallback(function(cb) { self.setReservespace(db, val, cb); });
1123
+ }
1124
+
1125
+ setReadonlyModeAsync(db: string): Promise<any> {
1126
+ var self = this;
1127
+ return fromCallback(function(cb) { self.setReadonlyMode(db, cb); });
1128
+ }
1129
+
1130
+ setReadwriteModeAsync(db: string): Promise<any> {
1131
+ var self = this;
1132
+ return fromCallback(function(cb) { self.setReadwriteMode(db, cb); });
1133
+ }
1134
+
1135
+ validateAsync(options: any): Promise<stream.Readable> {
1136
+ var self = this;
1137
+ return fromCallback(function(cb) { self.validate(options, cb); });
1138
+ }
1139
+
1140
+ commitAsync(db: string, transactid: number): Promise<any> {
1141
+ var self = this;
1142
+ return fromCallback(function(cb) { self.commit(db, transactid, cb); });
1143
+ }
1144
+
1145
+ rollbackAsync(db: string, transactid: number): Promise<any> {
1146
+ var self = this;
1147
+ return fromCallback(function(cb) { self.rollback(db, transactid, cb); });
1148
+ }
1149
+
1150
+ recoverAsync(db: string, transactid: number): Promise<any> {
1151
+ var self = this;
1152
+ return fromCallback(function(cb) { self.recover(db, transactid, cb); });
1153
+ }
1154
+
1155
+ getStatsAsync(options: any): Promise<stream.Readable> {
1156
+ var self = this;
1157
+ return fromCallback(function(cb) { self.getStats(options, cb); });
1158
+ }
1159
+
1160
+ getLogAsync(options: any): Promise<stream.Readable> {
1161
+ var self = this;
1162
+ return fromCallback(function(cb) { self.getLog(options, cb); });
1163
+ }
1164
+
1165
+ getUsersAsync(username?: string | null): Promise<any> {
1166
+ var self = this;
1167
+ return fromCallback(function(cb) { self.getUsers(username === undefined ? null : username, cb); });
1168
+ }
1169
+
1170
+ addUserAsync(username: string, password: string, options?: any): Promise<any> {
1171
+ var self = this;
1172
+ return fromCallback(function(cb) { self.addUser(username, password, options, cb); });
1173
+ }
1174
+
1175
+ editUserAsync(username: string, options: any): Promise<any> {
1176
+ var self = this;
1177
+ return fromCallback(function(cb) { self.editUser(username, options, cb); });
1178
+ }
1179
+
1180
+ removeUserAsync(username: string, rolename?: string | null): Promise<any> {
1181
+ var self = this;
1182
+ return fromCallback(function(cb) { self.removeUser(username, rolename === undefined ? null : rolename, cb); });
1183
+ }
1184
+
1185
+ getFbserverInfosAsync(infos?: any, options?: any): Promise<any> {
1186
+ var self = this;
1187
+ return fromCallback(function(cb) { self.getFbserverInfos(infos || {}, options || {}, cb); });
1188
+ }
1189
+
1190
+ startTraceAsync(options: any): Promise<stream.Readable> {
1191
+ var self = this;
1192
+ return fromCallback(function(cb) { self.startTrace(options, cb); });
1193
+ }
1194
+
1195
+ suspendTraceAsync(options: any): Promise<stream.Readable> {
1196
+ var self = this;
1197
+ return fromCallback(function(cb) { self.suspendTrace(options, cb); });
1198
+ }
1199
+
1200
+ resumeTraceAsync(options: any): Promise<stream.Readable> {
1201
+ var self = this;
1202
+ return fromCallback(function(cb) { self.resumeTrace(options, cb); });
1203
+ }
1204
+
1205
+ stopTraceAsync(options: any): Promise<stream.Readable> {
1206
+ var self = this;
1207
+ return fromCallback(function(cb) { self.stopTrace(options, cb); });
1208
+ }
1209
+
1210
+ getTraceListAsync(options?: any): Promise<stream.Readable> {
1211
+ var self = this;
1212
+ return fromCallback(function(cb) { self.getTraceList(options || {}, cb); });
1213
+ }
1214
+
1215
+ readlineAsync(options?: any): Promise<{ result: number, line: string }> {
1216
+ var self = this;
1217
+ return fromCallback(function(cb) { self.readline(options || {}, cb); });
1218
+ }
1219
+
1220
+ readeofAsync(options?: any): Promise<{ result: number, line: string }> {
1221
+ var self = this;
1222
+ return fromCallback(function(cb) { self.readeof(options || {}, cb); });
1223
+ }
1224
+
1225
+ hasRunningActionAsync(options?: any): Promise<any> {
1226
+ var self = this;
1227
+ return fromCallback(function(cb) { self.hasRunningAction(options || {}, cb); });
1228
+ }
1229
+
1230
+ readusersAsync(options?: any): Promise<any> {
1231
+ var self = this;
1232
+ return fromCallback(function(cb) { self.readusers(options || {}, cb); });
1233
+ }
1234
+
1235
+ readlimboAsync(options?: any): Promise<any> {
1236
+ var self = this;
1237
+ return fromCallback(function(cb) { self.readlimbo(options || {}, cb); });
1238
+ }
1239
+
1058
1240
  }
1059
1241
 
1060
1242
  export = ServiceManager;
@@ -91,8 +91,15 @@ class ChaChaCipher {
91
91
  class Socket {
92
92
  static Arc4 = Arc4;
93
93
 
94
+ // The constructor returns a Proxy whose get trap falls through to the
95
+ // underlying net.Socket, so callers can use net.Socket members not
96
+ // reimplemented here. Declare the ones the driver relies on (type-only,
97
+ // nothing is emitted).
98
+ declare end: net.Socket['end'];
99
+ declare removeAllListeners: net.Socket['removeAllListeners'];
100
+
94
101
  _socket: net.Socket;
95
- compress: boolean;
102
+ compress: boolean = false;
96
103
  compressor: zlib.Deflate | null;
97
104
  compressorBuffer: Buffer[];
98
105
  decompressor: zlib.Inflate | null;
@@ -102,10 +109,12 @@ class Socket {
102
109
  encryptCipher: any;
103
110
  decryptCipher: any;
104
111
 
105
- constructor(port: number, host: string) {
112
+ constructor(port: number, host: string, enableKeepAlive = true, keepAliveInitialDelay = 60000) {
106
113
  this._socket = net.createConnection(port, host);
107
114
  this._socket.setNoDelay(true);
108
- this._socket.setKeepAlive(true, 60000); // 1 minute delay to detect dead/stale connections
115
+ // TCP keepalive probing detects dead/stale connections; the delay is
116
+ // how long the socket must be idle before the first probe.
117
+ this._socket.setKeepAlive(enableKeepAlive, keepAliveInitialDelay);
109
118
  this.compressor = null;
110
119
  this.compressorBuffer = [];
111
120
  this.decompressor = null;
@@ -137,7 +146,7 @@ class Socket {
137
146
  }
138
147
 
139
148
  if (this.compress) {
140
- this.decompressor.write(data, () => {
149
+ this.decompressor!.write(data, () => {
141
150
  mainCb(Buffer.concat(this.decompressorBuffer));
142
151
  this.decompressorBuffer = []; // Reset buffer
143
152
  });
@@ -176,7 +185,7 @@ class Socket {
176
185
  }
177
186
 
178
187
  if (this.compress) {
179
- this.compressor.write(data, () => {
188
+ this.compressor!.write(data, () => {
180
189
  var compressedData = Buffer.concat(this.compressorBuffer);
181
190
  this.compressorBuffer = []; // Reset buffer
182
191
 
@@ -236,8 +245,8 @@ class Socket {
236
245
  const stretchedKey = crypto.createHash('sha256').update(sessionKey).digest();
237
246
  const ivlen = pluginName === 'ChaCha64' ? 8 : (iv ? iv.length : 16);
238
247
 
239
- this.encryptCipher = new ChaChaCipher(stretchedKey, iv, ivlen, true);
240
- this.decryptCipher = new ChaChaCipher(stretchedKey, iv, ivlen, false);
248
+ this.encryptCipher = new ChaChaCipher(stretchedKey, iv!, ivlen, true);
249
+ this.decryptCipher = new ChaChaCipher(stretchedKey, iv!, ivlen, false);
241
250
  } else {
242
251
  throw new Error('Unsupported encryption plugin: ' + pluginName);
243
252
  }
@@ -248,7 +257,7 @@ class Socket {
248
257
  */
249
258
  get(target: any, field: string | symbol): any {
250
259
  if (field in this) {
251
- return this[field].bind(this);
260
+ return (this as any)[field].bind(this);
252
261
  }
253
262
 
254
263
  if (typeof target[field] === 'function') {
@@ -4,47 +4,55 @@
4
4
  *
5
5
  ***************************************/
6
6
 
7
- import { doError, fromCallback } from '../callback';
7
+ import { doError, fromCallback, type Callback, type SimpleCallback } from '../callback';
8
8
  import { bindNamedParams, isNamedParamsObject } from '../named-params';
9
+ import type Connection from './connection';
10
+ import type Transaction from './transaction';
11
+ import type { SQLVarBase } from './xsqlvar';
12
+ import type { QueryOptions, QueryParams } from '../types';
9
13
 
10
14
  class Statement {
11
- connection: any;
12
- query: string;
13
- type: number;
14
- output: any[];
15
- input: any[];
16
- options: any;
17
- handle: number;
18
- plan: string;
15
+ connection: Connection;
16
+ // populated externally from the op_allocate_statement /
17
+ // op_prepare_statement responses (see describe() in connection.ts),
18
+ // hence the definite assignment assertions
19
+ query!: string;
20
+ type!: number;
21
+ output!: SQLVarBase[];
22
+ input!: SQLVarBase[];
23
+ /** per-execute query options (asObject/asStream/timeout/...) */
24
+ options: QueryOptions & { [key: string]: any } | undefined;
25
+ handle!: number;
26
+ plan!: string;
19
27
  /**
20
28
  * Placeholder names in positional order when this statement was
21
29
  * prepared from SQL with named placeholders (namedPlaceholders on),
22
30
  * null/undefined otherwise. Set by Transaction.newStatement.
23
31
  */
24
32
  namedParams?: string[] | null;
25
- [key: string]: any;
33
+ /** set when an execute/fetch on this statement errored — the statement
34
+ * is dropped on release instead of going back into the cache */
35
+ _failed?: boolean;
36
+ /** rows fetched so far by the current cursor (decodeResponse) */
37
+ nbrowsfetched?: number;
26
38
 
27
- constructor(connection: any) {
39
+ constructor(connection: Connection) {
28
40
  this.connection = connection;
29
41
  }
30
42
 
31
- close(callback?: (err?: any) => void): void {
43
+ close(callback?: SimpleCallback): void {
32
44
  this.connection.closeStatement(this, callback);
33
45
  }
34
46
 
35
- drop(callback?: (err?: any) => void): void {
47
+ drop(callback?: SimpleCallback): void {
36
48
  this.connection.dropStatement(this, callback);
37
49
  }
38
50
 
39
- release(callback?: (err?: any) => void): void {
40
- var cache_query = this.connection.getCachedQuery(this.query);
41
- if (cache_query)
42
- this.connection.closeStatement(this, callback);
43
- else
44
- this.connection.dropStatement(this, callback);
51
+ release(callback?: SimpleCallback): void {
52
+ this.connection.releaseStatement(this, callback);
45
53
  }
46
54
 
47
- execute(transaction: any, params?: any, callback?: any, options?: any): void {
55
+ execute(transaction: Transaction, params?: any, callback?: any, options?: any): void {
48
56
  if (params instanceof Function) {
49
57
  options = callback;
50
58
  callback = params;
@@ -64,11 +72,11 @@ class Statement {
64
72
  this.connection.executeStatement(transaction, this, params, callback, options);
65
73
  }
66
74
 
67
- fetch(transaction: any, count: number | string, callback: (err: any, result?: any) => void): void {
75
+ fetch(transaction: Transaction, count: number | string, callback: Callback): void {
68
76
  this.connection.fetch(this, transaction, count, callback);
69
77
  }
70
78
 
71
- fetchScroll(transaction: any, direction: string | number, offset?: any, count?: any, callback?: any): void {
79
+ fetchScroll(transaction: Transaction, direction: string | number, offset?: any, count?: any, callback?: any): void {
72
80
  if (typeof count === 'function') {
73
81
  callback = count;
74
82
  count = undefined;
@@ -81,7 +89,7 @@ class Statement {
81
89
  this.connection.fetchScroll(this, transaction, direction, offset, count, callback);
82
90
  }
83
91
 
84
- fetchAll(transaction: any, callback: (err: any, result?: any) => void): void {
92
+ fetchAll(transaction: Transaction, callback: Callback): void {
85
93
  this.connection.fetchAll(this, transaction, callback);
86
94
  }
87
95
 
@@ -91,7 +99,7 @@ class Statement {
91
99
  * statement was prepared with named placeholders, of values-by-name
92
100
  * objects (the two forms can be mixed).
93
101
  */
94
- executeBatch(transaction: any, rows: any[][], callback?: any, options?: any): void {
102
+ executeBatch(transaction: Transaction, rows: QueryParams[], callback?: any, options?: any): void {
95
103
  var names = this.namedParams;
96
104
  if (names && Array.isArray(rows)) {
97
105
  try {
@@ -108,27 +116,27 @@ class Statement {
108
116
 
109
117
  /* Promise / async-await API — wrappers over the callback methods above. */
110
118
 
111
- executeAsync(transaction: any, params?: any, options?: any): Promise<any> {
119
+ executeAsync(transaction: Transaction, params?: any, options?: any): Promise<any> {
112
120
  var self = this;
113
121
  return fromCallback(function(cb) { self.execute(transaction, params, cb, options); });
114
122
  }
115
123
 
116
- executeBatchAsync(transaction: any, rows: any[][], options?: any): Promise<any> {
124
+ executeBatchAsync(transaction: Transaction, rows: QueryParams[], options?: any): Promise<any> {
117
125
  var self = this;
118
126
  return fromCallback(function(cb) { self.executeBatch(transaction, rows, cb, options); });
119
127
  }
120
128
 
121
- fetchAsync(transaction: any, count: number | string): Promise<any> {
129
+ fetchAsync(transaction: Transaction, count: number | string): Promise<any> {
122
130
  var self = this;
123
131
  return fromCallback(function(cb) { self.fetch(transaction, count, cb); });
124
132
  }
125
133
 
126
- fetchScrollAsync(transaction: any, direction: string | number, offset?: any, count?: any): Promise<any> {
134
+ fetchScrollAsync(transaction: Transaction, direction: string | number, offset?: any, count?: any): Promise<any> {
127
135
  var self = this;
128
136
  return fromCallback(function(cb) { self.fetchScroll(transaction, direction, offset, count, cb); });
129
137
  }
130
138
 
131
- fetchAllAsync(transaction: any): Promise<any> {
139
+ fetchAllAsync(transaction: Transaction): Promise<any> {
132
140
  var self = this;
133
141
  return fromCallback(function(cb) { self.fetchAll(transaction, cb); });
134
142
  }
@@ -1,7 +1,13 @@
1
- import { doCallback, doError, fromCallback } from '../callback';
1
+ import { doCallback, doError, fromCallback, type Callback, type SimpleCallback } from '../callback';
2
2
  import { parseNamedPlaceholders } from '../named-params';
3
3
  import { noop } from '../utils';
4
4
  import Const from './const';
5
+ import makeQueryStream from './query-stream';
6
+ import type Connection from './connection';
7
+ import type Database from './database';
8
+ import type Statement from './statement';
9
+ import type { BatchCb, StatementCb, InternalQueryOptions } from './wire-types';
10
+ import type { BatchOptions, BatchResult, QueryOptions, QueryParams, QueryStreamOptions, SequentialCallback } from '../types';
5
11
 
6
12
  /***************************************
7
13
  *
@@ -26,7 +32,7 @@ function abortError(signal: any): Error {
26
32
  * GDSCode.CANCELLED). Returns the wrapped callback that detaches the
27
33
  * listener once the operation settles.
28
34
  */
29
- function hookAbortSignal(connection: any, signal: any, callback: any): any {
35
+ function hookAbortSignal(connection: Connection, signal: AbortSignal, callback: any): any {
30
36
  var settled = false;
31
37
  var onAbort = function() {
32
38
  if (!settled)
@@ -42,26 +48,29 @@ function hookAbortSignal(connection: any, signal: any, callback: any): any {
42
48
  }
43
49
 
44
50
  class Transaction {
45
- connection: any;
46
- db: any;
47
- handle: number;
48
- [key: string]: any;
51
+ connection: Connection;
52
+ db: Database;
53
+ // populated externally from the op_transaction response
54
+ handle!: number;
49
55
 
50
- constructor(connection: any) {
56
+ constructor(connection: Connection) {
51
57
  this.connection = connection;
52
58
  this.db = connection.db;
53
59
  }
54
60
 
55
61
  /** Per-call options.namedPlaceholders overrides the connection option. */
56
- private namedPlaceholdersEnabled(options?: any): boolean {
62
+ private namedPlaceholdersEnabled(options?: InternalQueryOptions): boolean {
57
63
  if (options && options.namedPlaceholders !== undefined)
58
64
  return !!options.namedPlaceholders;
59
65
  return !!(this.connection.options && this.connection.options.namedPlaceholders);
60
66
  }
61
67
 
62
- newStatement(query: string, callback: (err: any, statement?: any) => void, options?: any): void {
68
+ newStatement(query: string, callback: StatementCb, options?: InternalQueryOptions): void {
63
69
  var cnx = this.connection;
64
70
  var self = this;
71
+ // the public strict callback shape and the internal optional-args
72
+ // shape only differ in optionality; treat it as the internal one
73
+ var cb = callback as Callback<Statement>;
65
74
 
66
75
  // With namedPlaceholders on, prepare the positional rewrite and
67
76
  // remember the name order on the statement so statement.execute can
@@ -75,13 +84,13 @@ class Transaction {
75
84
  }
76
85
  }
77
86
 
78
- var deliver = function(err: any, statement?: any) {
87
+ var deliver = function(err: any, statement?: Statement) {
79
88
  if (statement)
80
89
  statement.namedParams = names;
81
- callback(err, statement);
90
+ cb(err, statement);
82
91
  };
83
92
 
84
- var query_cache = cnx.getCachedQuery(query);
93
+ var query_cache = cnx.takeCachedStatement(query);
85
94
 
86
95
  if (query_cache) {
87
96
  deliver(null, query_cache);
@@ -90,7 +99,7 @@ class Transaction {
90
99
  }
91
100
  }
92
101
 
93
- execute(query: string, params?: any, callback?: any, options?: any): void {
102
+ execute(query: string, params?: QueryParams | Callback, callback?: any, options?: InternalQueryOptions): void {
94
103
  if (params instanceof Function) {
95
104
  options = callback;
96
105
  callback = params;
@@ -107,15 +116,19 @@ class Transaction {
107
116
  }
108
117
 
109
118
  var self = this;
110
- this.newStatement(query, function(err: any, statement: any) {
119
+ this.newStatement(query, function(err: any, statement?: Statement) {
111
120
 
112
- if (err) {
121
+ if (err || !statement) {
113
122
  doError(err, callback);
114
123
  return;
115
124
  }
116
125
 
117
126
  function dropError(err: any) {
118
- statement.release();
127
+ // do not put a statement that just failed back into the cache
128
+ // (statement is guaranteed by the guard above; hoisting keeps
129
+ // the narrowing from reaching this function declaration)
130
+ statement!._failed = true;
131
+ statement!.release();
119
132
  doCallback(err, callback);
120
133
  }
121
134
 
@@ -178,7 +191,7 @@ class Transaction {
178
191
  }, options);
179
192
  }
180
193
 
181
- sequentially(query: string, params?: any, on?: any, callback?: any, options: any = {}): this {
194
+ sequentially(query: string, params?: any, on?: any, callback?: any, options: InternalQueryOptions | boolean = {}): this {
182
195
  if (params instanceof Function) {
183
196
  options = callback;
184
197
  callback = on;
@@ -196,7 +209,7 @@ class Transaction {
196
209
  }
197
210
 
198
211
  var self = this;
199
- var _on = function(row: any, i: number, meta: any, next: (err?: any) => void) {
212
+ var _on = function(row: any, i: number, meta: any[], next: (err?: any) => void) {
200
213
  var done = false;
201
214
  var finish = function(err?: any) {
202
215
  if (done) {
@@ -242,7 +255,17 @@ class Transaction {
242
255
  return self;
243
256
  }
244
257
 
245
- query(query: string, params?: any, callback?: any, options: any = {}): void {
258
+ /**
259
+ * Run `query` inside this transaction and return an object-mode
260
+ * Readable emitting one row per chunk, with real backpressure (see
261
+ * Database.queryStream). The transaction is NOT committed when the
262
+ * stream ends — commit or roll back yourself.
263
+ */
264
+ queryStream(query: string, params?: QueryParams, options?: QueryStreamOptions) {
265
+ return makeQueryStream(this, query, params, options);
266
+ }
267
+
268
+ query(query: string, params?: QueryParams | Callback, callback?: any, options: InternalQueryOptions = {}): void {
246
269
  if (params instanceof Function) {
247
270
  callback = params;
248
271
  params = undefined;
@@ -269,15 +292,17 @@ class Transaction {
269
292
  * commit or roll back yourself (or use db.executeBatch for
270
293
  * all-or-nothing semantics).
271
294
  */
272
- executeBatch(query: string, rows: any[][], callback?: any, options?: any): void {
295
+ executeBatch(query: string, rows: QueryParams[], callback?: BatchCb, options?: BatchOptions & QueryOptions): void {
273
296
  var self = this;
274
- this.newStatement(query, function(err: any, statement: any) {
275
- if (err) {
297
+ this.newStatement(query, function(err: any, statement?: Statement) {
298
+ if (err || !statement) {
276
299
  doError(err, callback);
277
300
  return;
278
301
  }
279
302
 
280
- statement.executeBatch(self, rows, function(err: any, result: any) {
303
+ statement.executeBatch(self, rows, function(err: any, result: BatchResult) {
304
+ if (err)
305
+ statement._failed = true;
281
306
  statement.release();
282
307
  if (callback)
283
308
  callback(err, result);
@@ -285,40 +310,40 @@ class Transaction {
285
310
  }, options);
286
311
  }
287
312
 
288
- executeBatchAsync(query: string, rows: any[][], options?: any): Promise<any> {
313
+ executeBatchAsync(query: string, rows: QueryParams[], options?: BatchOptions & QueryOptions): Promise<BatchResult> {
289
314
  var self = this;
290
315
  return fromCallback(function(cb) { self.executeBatch(query, rows, cb, options); });
291
316
  }
292
317
 
293
- commit(callback?: (err?: any) => void): void {
318
+ commit(callback?: SimpleCallback): void {
294
319
  this.connection.commit(this, callback);
295
320
  }
296
321
 
297
- rollback(callback?: (err?: any) => void): void {
322
+ rollback(callback?: SimpleCallback): void {
298
323
  this.connection.rollback(this, callback);
299
324
  }
300
325
 
301
- commitRetaining(callback?: (err?: any) => void): void {
326
+ commitRetaining(callback?: SimpleCallback): void {
302
327
  this.connection.commitRetaining(this, callback);
303
328
  }
304
329
 
305
- rollbackRetaining(callback?: (err?: any) => void): void {
330
+ rollbackRetaining(callback?: SimpleCallback): void {
306
331
  this.connection.rollbackRetaining(this, callback);
307
332
  }
308
333
 
309
334
  /* Promise / async-await API — wrappers over the callback methods above. */
310
335
 
311
- queryAsync(query: string, params?: any, options?: any): Promise<any[]> {
336
+ queryAsync(query: string, params?: QueryParams, options?: InternalQueryOptions): Promise<any[]> {
312
337
  var self = this;
313
338
  return fromCallback(function(cb) { self.query(query, params, cb, options); });
314
339
  }
315
340
 
316
- executeAsync(query: string, params?: any, options?: any): Promise<any[]> {
341
+ executeAsync(query: string, params?: QueryParams, options?: InternalQueryOptions): Promise<any[]> {
317
342
  var self = this;
318
343
  return fromCallback(function(cb) { self.execute(query, params, cb, options); });
319
344
  }
320
345
 
321
- sequentiallyAsync(query: string, params?: any, on?: any, options?: any): Promise<void> {
346
+ sequentiallyAsync(query: string, params?: any, on?: SequentialCallback, options?: InternalQueryOptions | boolean): Promise<void> {
322
347
  if (params instanceof Function) {
323
348
  options = on;
324
349
  on = params;
@@ -328,7 +353,7 @@ class Transaction {
328
353
  return fromCallback(function(cb) { self.sequentially(query, params, on, cb, options); });
329
354
  }
330
355
 
331
- newStatementAsync(query: string): Promise<any> {
356
+ newStatementAsync(query: string): Promise<Statement> {
332
357
  var self = this;
333
358
  return fromCallback(function(cb) { self.newStatement(query, cb); });
334
359
  }