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
package/src/types.ts CHANGED
@@ -5,6 +5,8 @@
5
5
  // They now live in the TypeScript source tree and are compiled into the
6
6
  // published declaration files.
7
7
 
8
+ import type { Readable } from 'stream';
9
+
8
10
  export type DatabaseCallback = (err: any, db: Database) => void;
9
11
  export type TransactionCallback = (err: any, transaction: Transaction) => void;
10
12
  export type QueryCallback = (err: any, result: any[]) => void;
@@ -127,6 +129,16 @@ export type QueryOptions = {
127
129
  signal?: AbortSignal;
128
130
  }
129
131
 
132
+ export type QueryStreamOptions = QueryOptions & {
133
+ /**
134
+ * Rows buffered internally before fetching pauses (object-mode
135
+ * Readable highWaterMark, default 16).
136
+ */
137
+ highWaterMark?: number;
138
+ /** Emit array rows instead of objects (like db.execute). */
139
+ asObject?: boolean;
140
+ }
141
+
130
142
  export interface Database {
131
143
  detach(callback?: SimpleCallback): Database;
132
144
  transaction(options: TransactionOptions|Isolation|TransactionCallback, callback?: TransactionCallback): Database;
@@ -136,6 +148,13 @@ export interface Database {
136
148
  /** Bulk-execute in its own transaction, all-or-nothing (Firebird 4.0+). */
137
149
  executeBatch(query: string, rows: QueryParams[], callback?: (err: any, result: BatchResult) => void, options?: BatchOptions): Database;
138
150
  sequentially(query: string, params: QueryParams, rowCallback: SequentialCallback, callback: SimpleCallback, options?: QueryOptions | boolean): Database;
151
+ /**
152
+ * Run `query` and return an object-mode Readable emitting one row per
153
+ * chunk, with backpressure (fetching pauses while the buffer is full).
154
+ * Runs in its own transaction. Destroying the stream early aborts the
155
+ * fetch and releases the statement.
156
+ */
157
+ queryStream(query: string, params?: QueryParams, options?: QueryStreamOptions): Readable;
139
158
  drop(callback: SimpleCallback): void;
140
159
  escape(value: any): string;
141
160
  attachEvent(callback: any): this;
@@ -176,6 +195,12 @@ export interface Transaction {
176
195
  /** Bulk-execute within this transaction; per-record failures do not roll back (Firebird 4.0+). */
177
196
  executeBatch(query: string, rows: QueryParams[], callback?: (err: any, result: BatchResult) => void, options?: BatchOptions): void;
178
197
  sequentially(query: string, params: QueryParams, rowCallback: SequentialCallback, callback: SimpleCallback, options?: QueryOptions | boolean): Database;
198
+ /**
199
+ * Run `query` inside this transaction and return an object-mode
200
+ * Readable emitting one row per chunk, with backpressure. The
201
+ * transaction is NOT committed when the stream ends.
202
+ */
203
+ queryStream(query: string, params?: QueryParams, options?: QueryStreamOptions): Readable;
179
204
  commit(callback?: SimpleCallback): void;
180
205
  commitRetaining(callback?: SimpleCallback): void;
181
206
  rollback(callback?: SimpleCallback): void;
@@ -289,6 +314,16 @@ export interface Options {
289
314
  * per-query `namedPlaceholders: false` override.
290
315
  */
291
316
  namedPlaceholders?: boolean;
317
+ /**
318
+ * TCP keepalive probing to detect dead/stale connections (same option
319
+ * names as mysql2). On by default; set false to disable.
320
+ */
321
+ enableKeepAlive?: boolean;
322
+ /**
323
+ * Milliseconds a socket must be idle before the first TCP keepalive
324
+ * probe is sent (default 60000). Ignored when enableKeepAlive is false.
325
+ */
326
+ keepAliveInitialDelay?: number;
292
327
  pluginName?: string;
293
328
  parallelWorkers?: number;
294
329
  maxInlineBlobSize?: number;
@@ -320,11 +355,11 @@ export interface Options {
320
355
  /**
321
356
  * **Firebird 6.0+ only (Protocol 20+)**
322
357
  *
323
- * Sets the session's current schema at connection time. Equivalent to
324
- * executing `SET SCHEMA <name>` immediately after connecting.
325
- *
326
- * Unqualified object references (tables, procedures, etc.) that do not
327
- * match any schema in the `searchPath` fall back to `PUBLIC`.
358
+ * Sets the session's current schema at connection time. `CURRENT_SCHEMA`
359
+ * in Firebird is the first existing schema of the search path, so this
360
+ * option is implemented by putting the schema at the front of the
361
+ * `searchPath` sent to the server (with `PUBLIC` kept as a fallback when
362
+ * no explicit `searchPath` is given).
328
363
  *
329
364
  * Example: `defaultSchema: 'myapp'`
330
365
  */
@@ -346,6 +381,18 @@ export interface Options {
346
381
  * (typically `PUBLIC` then `SYSTEM`).
347
382
  */
348
383
  searchPath?: string | string[];
384
+ /**
385
+ * **Firebird 6.0+ only**
386
+ *
387
+ * Owner of a newly created database (`isc_dpb_owner`), allowing a
388
+ * superuser to create a database owned by another user
389
+ * ([firebird#7718](https://github.com/FirebirdSQL/firebird/issues/7718)).
390
+ * Only honored by `create`/`attachOrCreate` when the database is
391
+ * created; ignored on plain attach and by older servers.
392
+ *
393
+ * Example: `owner: 'APP_OWNER'`
394
+ */
395
+ owner?: string;
349
396
  /**
350
397
  * **Firebird 6.0+ only (Protocol 20+)**
351
398
  *
@@ -354,8 +401,58 @@ export interface Options {
354
401
  * text/BLOB columns back into JavaScript objects/arrays.
355
402
  */
356
403
  jsonAsObject?: boolean;
404
+ /**
405
+ * Custom type parser (mysql2-style). Called for every column value of
406
+ * every result row (including NULLs); whatever it returns becomes the
407
+ * value in the row. Call `next()` to get the value the driver would
408
+ * produce by default (after `blobAsText`/`jsonAsObject` are applied).
409
+ *
410
+ * ```js
411
+ * typeCast: (column, next) =>
412
+ * column.typeName === 'INT64' ? Number(next()) : next()
413
+ * ```
414
+ *
415
+ * Non-text BLOB columns reach the hook as the usual fetch function;
416
+ * text BLOBs with `blobAsText` reach it as the resolved string. The
417
+ * hook must be a pure function: a row can be decoded more than once
418
+ * when a response spans TCP packets.
419
+ */
420
+ typeCast?: TypeCastFunction;
421
+ /**
422
+ * Per-connection LRU cache of prepared statements (like mysql2's
423
+ * statement cache). `db.query`/`tx.query` and friends transparently
424
+ * reuse the prepared handle for a repeated SQL string, skipping the
425
+ * prepare round-trip on hot paths. The number is the maximum of idle
426
+ * cached statements; least-recently-used ones are dropped over the
427
+ * limit. 0 / unset = disabled. Statements that failed and DDL are
428
+ * never cached; concurrent runs of the same SQL never share a
429
+ * statement (extra preparations are simply not cached).
430
+ */
431
+ statementCacheSize?: number;
432
+ }
433
+
434
+ /** Column metadata passed to the {@link Options.typeCast} hook. */
435
+ export interface TypeCastColumn {
436
+ /** Firebird SQL type code (see the exported `SQL_TYPES` map). */
437
+ type: number;
438
+ /** Friendly name of the type code: 'VARYING', 'INT64', 'BLOB', ... */
439
+ typeName: string;
440
+ /** Column subtype (e.g. 1 = text for BLOBs; charset id for strings). */
441
+ subType?: number;
442
+ /** Negative decimal scale for NUMERIC/DECIMAL columns (e.g. -2). */
443
+ scale?: number;
444
+ /** Declared length in bytes. */
445
+ length?: number;
446
+ /** Column name in the table. */
447
+ field?: string;
448
+ /** Table (relation) name. */
449
+ relation?: string;
450
+ /** Alias used in the SELECT list (the row key for object rows). */
451
+ alias?: string;
357
452
  }
358
453
 
454
+ export type TypeCastFunction = (column: TypeCastColumn, next: () => any) => any;
455
+
359
456
  export interface SvcMgrOptions extends Options {
360
457
  manager: true; // Attach to ServiceManager
361
458
  }
@@ -565,4 +662,42 @@ export interface ServiceManager {
565
662
  hasRunningAction(options: ReadableOptions, callback: ReadableCallback): void;
566
663
  readusers(options: ReadableOptions, callback: ReadableCallback): void;
567
664
  readlimbo(options: ReadableOptions, callback: ReadableCallback): void;
665
+
666
+ // Promise / async-await API (see README § Promises / async–await).
667
+ detachAsync(force?: boolean): Promise<void>;
668
+ backupAsync(options: BackupOptions): Promise<NodeJS.ReadableStream>;
669
+ nbackupAsync(options: BackupOptions): Promise<NodeJS.ReadableStream>;
670
+ restoreAsync(options: RestoreOptions): Promise<NodeJS.ReadableStream>;
671
+ nrestoreAsync(options: NRestoreOptions): Promise<NodeJS.ReadableStream>;
672
+ setDialectAsync(db: string, dialect: 1 | 3): Promise<NodeJS.ReadableStream>;
673
+ setSweepintervalAsync(db: string, interval: number): Promise<any>;
674
+ setCachebufferAsync(db: string, nbpages: any): Promise<NodeJS.ReadableStream>;
675
+ BringOnlineAsync(db: string): Promise<NodeJS.ReadableStream>;
676
+ ShutdownAsync(db: string, kind: ShutdownKind, delay: number, mode?: ShutdownMode): Promise<NodeJS.ReadableStream>;
677
+ setShadowAsync(db: string, val: boolean): Promise<NodeJS.ReadableStream>;
678
+ setForcewriteAsync(db: string, val: boolean): Promise<NodeJS.ReadableStream>;
679
+ setReservespaceAsync(db: string, val: boolean): Promise<NodeJS.ReadableStream>;
680
+ setReadonlyModeAsync(db: string): Promise<NodeJS.ReadableStream>;
681
+ setReadwriteModeAsync(db: string): Promise<NodeJS.ReadableStream>;
682
+ validateAsync(options: ValidateOptions): Promise<NodeJS.ReadableStream>;
683
+ commitAsync(db: string, transactid: number): Promise<NodeJS.ReadableStream>;
684
+ rollbackAsync(db: string, transactid: number): Promise<NodeJS.ReadableStream>;
685
+ recoverAsync(db: string, transactid: number): Promise<NodeJS.ReadableStream>;
686
+ getStatsAsync(options: StatsOptions): Promise<NodeJS.ReadableStream>;
687
+ getLogAsync(options: ReadableOptions): Promise<NodeJS.ReadableStream>;
688
+ getUsersAsync(username?: string | null): Promise<ServerInfo>;
689
+ addUserAsync(username: string, password: string, info?: UserInfo): Promise<NodeJS.ReadableStream>;
690
+ editUserAsync(username: string, info: UserInfo): Promise<NodeJS.ReadableStream>;
691
+ removeUserAsync(username: string, rolename?: string | null): Promise<NodeJS.ReadableStream>;
692
+ getFbserverInfosAsync(infos?: ServerInfoReq, options?: { buffersize?: number, timeout?: number }): Promise<ServerInfo>;
693
+ startTraceAsync(options: TraceOptions): Promise<NodeJS.ReadableStream>;
694
+ suspendTraceAsync(options: TraceOptions): Promise<NodeJS.ReadableStream>;
695
+ resumeTraceAsync(options: TraceOptions): Promise<NodeJS.ReadableStream>;
696
+ stopTraceAsync(options: TraceOptions): Promise<NodeJS.ReadableStream>;
697
+ getTraceListAsync(options?: ReadableOptions): Promise<NodeJS.ReadableStream>;
698
+ readlineAsync(options?: ReadableOptions): Promise<{ result: number, line: string }>;
699
+ readeofAsync(options?: ReadableOptions): Promise<{ result: number, line: string }>;
700
+ hasRunningActionAsync(options?: ReadableOptions): Promise<any>;
701
+ readusersAsync(options?: ReadableOptions): Promise<any>;
702
+ readlimboAsync(options?: ReadableOptions): Promise<any>;
568
703
  }
package/src/unix-crypt.ts CHANGED
@@ -152,25 +152,25 @@ var SPTRANS=
152
152
  0x8200020, 32768, 0x208020 ]
153
153
  ];
154
154
 
155
- function hPermOp(a, n, m) {
155
+ function hPermOp(a: number, n: number, m: number) {
156
156
  var t = (a << 16 - n ^ a) & m;
157
157
  a = a ^ t ^ t >>> 16 - n;
158
158
  return a;
159
159
  }
160
160
 
161
- function intToFourBytes(iValue, b, offset) {
161
+ function intToFourBytes(iValue: number, b: Buffer, offset: number) {
162
162
  b[offset++] = iValue & 0xff;
163
163
  b[offset++] = iValue >>> 8 & 0xff;
164
164
  b[offset++] = iValue >>> 16 & 0xff;
165
165
  b[offset++] = iValue >>> 24 & 0xff;
166
166
  }
167
167
 
168
- function byteToUnsigned(b) {
168
+ function byteToUnsigned(b: number) {
169
169
  var value = b;
170
170
  return value < 0 ? value + 256 : value;
171
171
  }
172
172
 
173
- function fourBytesToInt(b, offset) {
173
+ function fourBytesToInt(b: Buffer, offset: number) {
174
174
  var value = byteToUnsigned(b[offset++]);
175
175
  value |= byteToUnsigned(b[offset++]) << 8;
176
176
  value |= byteToUnsigned(b[offset++]) << 16;
@@ -178,7 +178,7 @@ function fourBytesToInt(b, offset) {
178
178
  return value;
179
179
  }
180
180
 
181
- function permOp(a, b, n, m, results) {
181
+ function permOp(a: number, b: number, n: number, m: number, results: number[]) {
182
182
  var t = (a >>> n ^ b) & m;
183
183
  a ^= t << n;
184
184
  b ^= t;
@@ -186,8 +186,8 @@ function permOp(a, b, n, m, results) {
186
186
  results[1] = b;
187
187
  }
188
188
 
189
- function desSetKey(key) {
190
- var schedule = [];
189
+ function desSetKey(key: Buffer) {
190
+ var schedule: number[] = [];
191
191
  var c = fourBytesToInt(key, 0);
192
192
  var d = fourBytesToInt(key, 4);
193
193
  var results = [0, 0];
@@ -232,7 +232,7 @@ function desSetKey(key) {
232
232
  return schedule;
233
233
  }
234
234
 
235
- function dEncrypt(el, r, s, e0, e1, sArr) {
235
+ function dEncrypt(el: number, r: number, s: number, e0: number, e1: number, sArr: number[]) {
236
236
  var v = r ^ r >>> 16;
237
237
  var u = v & e0;
238
238
  v &= e1;
@@ -245,7 +245,7 @@ function dEncrypt(el, r, s, e0, e1, sArr) {
245
245
  return el;
246
246
  }
247
247
 
248
- function body(schedule, eSwap0, eSwap1) {
248
+ function body(schedule: number[], eSwap0: number, eSwap1: number) {
249
249
  var left = 0;
250
250
  var right = 0;
251
251
  var t = 0;
package/src/uri.ts CHANGED
@@ -12,7 +12,7 @@ import type { Options } from './types';
12
12
  */
13
13
  const BOOLEAN_KEYS = new Set([
14
14
  'lowercase_keys', 'blobAsText', 'wireCompression', 'manager',
15
- 'namedPlaceholders',
15
+ 'namedPlaceholders', 'enableKeepAlive',
16
16
  ]);
17
17
 
18
18
  /** Option keys coerced to number when they arrive as URI query parameters. */
@@ -20,7 +20,7 @@ const NUMBER_KEYS = new Set([
20
20
  'port', 'pageSize', 'timeout', 'retryConnectionInterval',
21
21
  'blobChunkSize', 'blobReadChunkSize', 'wireCrypt', 'parallelWorkers',
22
22
  'maxInlineBlobSize', 'maxNegotiatedProtocols', 'connectTimeout',
23
- 'min', 'idleTimeoutMillis',
23
+ 'min', 'idleTimeoutMillis', 'keepAliveInitialDelay',
24
24
  ]);
25
25
 
26
26
  function coerce(key: string, value: string): any {