node-firebird-driver 2.3.0 → 3.0.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 (42) hide show
  1. package/dist/lib/impl/attachment.d.ts +14 -3
  2. package/dist/lib/impl/attachment.js +112 -138
  3. package/dist/lib/impl/attachment.js.map +1 -1
  4. package/dist/lib/impl/blob.d.ts +3 -1
  5. package/dist/lib/impl/blob.js +11 -25
  6. package/dist/lib/impl/blob.js.map +1 -1
  7. package/dist/lib/impl/client.d.ts +1 -0
  8. package/dist/lib/impl/client.js +24 -36
  9. package/dist/lib/impl/client.js.map +1 -1
  10. package/dist/lib/impl/events.d.ts +1 -0
  11. package/dist/lib/impl/events.js +9 -18
  12. package/dist/lib/impl/events.js.map +1 -1
  13. package/dist/lib/impl/fb-util.d.ts +34 -5
  14. package/dist/lib/impl/fb-util.js +82 -42
  15. package/dist/lib/impl/fb-util.js.map +1 -1
  16. package/dist/lib/impl/index.js +5 -1
  17. package/dist/lib/impl/index.js.map +1 -1
  18. package/dist/lib/impl/resultset.d.ts +1 -0
  19. package/dist/lib/impl/resultset.js +33 -46
  20. package/dist/lib/impl/resultset.js.map +1 -1
  21. package/dist/lib/impl/statement.d.ts +6 -0
  22. package/dist/lib/impl/statement.js +47 -57
  23. package/dist/lib/impl/statement.js.map +1 -1
  24. package/dist/lib/impl/transaction.d.ts +1 -0
  25. package/dist/lib/impl/transaction.js +20 -34
  26. package/dist/lib/impl/transaction.js.map +1 -1
  27. package/dist/lib/index.d.ts +57 -3
  28. package/dist/lib/index.js +4 -0
  29. package/dist/lib/index.js.map +1 -1
  30. package/dist/test/tests.js +385 -301
  31. package/dist/test/tests.js.map +1 -1
  32. package/package.json +3 -3
  33. package/src/lib/impl/attachment.ts +32 -9
  34. package/src/lib/impl/blob.ts +6 -1
  35. package/src/lib/impl/client.ts +5 -1
  36. package/src/lib/impl/events.ts +5 -1
  37. package/src/lib/impl/fb-util.ts +55 -0
  38. package/src/lib/impl/resultset.ts +5 -1
  39. package/src/lib/impl/statement.ts +21 -4
  40. package/src/lib/impl/transaction.ts +5 -1
  41. package/src/lib/index.ts +77 -3
  42. package/src/test/tests.ts +123 -3
package/src/lib/index.ts CHANGED
@@ -9,6 +9,9 @@ export interface Client {
9
9
  /** Creates a database. */
10
10
  createDatabase(uri: string, options?: CreateDatabaseOptions): Promise<Attachment>;
11
11
 
12
+ /** True if the client has not been disposed. */
13
+ readonly isValid: boolean;
14
+
12
15
  /** Default connect options. */
13
16
  defaultConnectOptions?: ConnectOptions;
14
17
 
@@ -87,6 +90,11 @@ export interface FetchOptions {
87
90
  fetchSize?: number;
88
91
  }
89
92
 
93
+ /** CreateBlobOptions interface. */
94
+ export interface CreateBlobOptions {
95
+ type?: 'SEGMENTED' | 'STREAM';
96
+ }
97
+
90
98
  /** Attachment interface. */
91
99
  export interface Attachment {
92
100
  /** Disconnects this attachment. */
@@ -96,7 +104,7 @@ export interface Attachment {
96
104
  dropDatabase(): Promise<void>;
97
105
 
98
106
  /** Creates a blob and return its stream. */
99
- createBlob(transaction: Transaction): Promise<BlobStream>;
107
+ createBlob(transaction: Transaction, options?: CreateBlobOptions): Promise<BlobStream>;
100
108
 
101
109
  /** Opens a blob's stream. */
102
110
  openBlob(transaction: Transaction, blob: Blob): Promise<BlobStream>;
@@ -121,13 +129,33 @@ export interface Attachment {
121
129
  }): Promise<void>;
122
130
 
123
131
  /** Executes a statement that returns a single record as [col1, col2, ..., colN]. */
124
- executeReturning(transaction: Transaction, sqlStmt: string, parameters?: any[],
132
+ executeSingleton(transaction: Transaction, sqlStmt: string, parameters?: any[],
125
133
  options?: {
126
134
  prepareOptions?: PrepareOptions,
127
135
  executeOptions?: ExecuteOptions
128
136
  }): Promise<any[]>;
129
137
 
130
138
  /** Executes a statement that returns a single record as an object. */
139
+ executeSingletonAsObject<T extends object>(transaction: Transaction, sqlStmt: string, parameters?: any[],
140
+ options?: {
141
+ prepareOptions?: PrepareOptions,
142
+ executeOptions?: ExecuteOptions
143
+ }): Promise<T>;
144
+
145
+ /**
146
+ * Executes a statement that returns a single record as [col1, col2, ..., colN].
147
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingleton.
148
+ */
149
+ executeReturning(transaction: Transaction, sqlStmt: string, parameters?: any[],
150
+ options?: {
151
+ prepareOptions?: PrepareOptions,
152
+ executeOptions?: ExecuteOptions
153
+ }): Promise<any[]>;
154
+
155
+ /**
156
+ * Executes a statement that returns a single record as an object.
157
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingletonAsObject.
158
+ */
131
159
  executeReturningAsObject<T extends object>(transaction: Transaction, sqlStmt: string, parameters?: any[],
132
160
  options?: {
133
161
  prepareOptions?: PrepareOptions,
@@ -143,6 +171,9 @@ export interface Attachment {
143
171
 
144
172
  queueEvents(names: string[], callBack: (counters: [string, number][]) => Promise<void>): Promise<Events>;
145
173
 
174
+ /** True if the attachment is connected. */
175
+ readonly isValid: boolean;
176
+
146
177
  /** Default transaction options. */
147
178
  defaultTransactionOptions?: TransactionOptions;
148
179
 
@@ -172,6 +203,9 @@ export interface Transaction {
172
203
 
173
204
  /** Rollbacks and maintains this transaction object for subsequent work. */
174
205
  rollbackRetaining(): Promise<void>;
206
+
207
+ /** True if the transaction is active. */
208
+ readonly isValid: boolean;
175
209
  }
176
210
 
177
211
  /** Statement interface. */
@@ -186,9 +220,21 @@ export interface Statement {
186
220
  execute(transaction: Transaction, parameters?: any[], options?: ExecuteOptions): Promise<void>;
187
221
 
188
222
  /** Executes a statement that returns a single record as [col1, col2, ..., colN]. */
189
- executeReturning(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<any[]>;
223
+ executeSingleton(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<any[]>;
190
224
 
191
225
  /** Executes a statement that returns a single record as an object. */
226
+ executeSingletonAsObject<T extends object>(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<T>;
227
+
228
+ /**
229
+ * Executes a statement that returns a single record as [col1, col2, ..., colN].
230
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingleton.
231
+ */
232
+ executeReturning(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<any[]>;
233
+
234
+ /**
235
+ * Executes a statement that returns a single record as an object.
236
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingletonAsObject.
237
+ */
192
238
  executeReturningAsObject<T extends object>(transaction: Transaction, parameters?: any[],
193
239
  options?: ExecuteOptions): Promise<T>;
194
240
 
@@ -202,6 +248,11 @@ export interface Statement {
202
248
  */
203
249
  setCursorName(cursorName: string): Promise<void>;
204
250
 
251
+ getExecPathText(): Promise<string | undefined>;
252
+
253
+ /** True if the statement has not been disposed. */
254
+ readonly isValid: boolean;
255
+
205
256
  /** Gets the query's result columns labels. Returns empty array for queries without result. */
206
257
  readonly columnLabels: Promise<string[]>;
207
258
 
@@ -242,12 +293,18 @@ export interface ResultSet {
242
293
  */
243
294
  fetchAsObject<T extends object>(options?: FetchOptions): Promise<T[]>;
244
295
 
296
+ /** True if the ResultSet is open. */
297
+ readonly isValid: boolean;
298
+
245
299
  /** Default result set's fetch options. */
246
300
  defaultFetchOptions?: FetchOptions;
247
301
  }
248
302
 
249
303
  export interface Events {
250
304
  cancel(): Promise<void>;
305
+
306
+ /** True if the events' attachment is valid. */
307
+ readonly isValid: boolean;
251
308
  }
252
309
 
253
310
  /** Blob class. */
@@ -262,6 +319,17 @@ export class Blob {
262
319
  this.attachment = attachment;
263
320
  this.id.set(id);
264
321
  }
322
+
323
+ /** True if the blob's attachment is valid. */
324
+ get isValid(): boolean {
325
+ return this.attachment.isValid;
326
+ }
327
+ }
328
+
329
+ export const enum BlobSeekWhence {
330
+ START = 0,
331
+ CURRENT = 1,
332
+ END = 2
265
333
  }
266
334
 
267
335
  /** BlobStream class. */
@@ -282,6 +350,9 @@ export abstract class BlobStream {
282
350
  /** Cancels the blob's creation. */
283
351
  abstract cancel(): Promise<void>;
284
352
 
353
+ /** Seeks into the blob stream and return the new position. */
354
+ abstract seek(offset: number, whence?: BlobSeekWhence): Promise<number>;
355
+
285
356
  /**
286
357
  * Reads data from the blob and return the number of bytes read or -1 for end-of-stream.
287
358
  * The number of bytes read may be less than the buffer' size while more data to be read exists.
@@ -290,6 +361,9 @@ export abstract class BlobStream {
290
361
 
291
362
  /** Writes data to the blob. */
292
363
  abstract write(buffer: Buffer): Promise<void>;
364
+
365
+ /** True if the blob stream is open. */
366
+ abstract get isValid(): boolean;
293
367
  }
294
368
 
295
369
  /** TIME WITH TIME ZONE and TIMESTAMP WITH TIME ZONE to be sent as parameter */
package/src/test/tests.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  Blob,
3
+ BlobSeekWhence,
3
4
  Client,
4
5
  TransactionIsolation,
5
6
  ZonedDate,
@@ -74,6 +75,8 @@ export function runCommonTests(client: Client) {
74
75
 
75
76
 
76
77
  beforeAll(() => {
78
+ expect(client.isValid).toBeTruthy();
79
+
77
80
  if (isLocal() && !testConfig.tmpDir) {
78
81
  testConfig.tmpDir = tmp.mkdirSync().path.toString();
79
82
 
@@ -99,6 +102,8 @@ export function runCommonTests(client: Client) {
99
102
  afterAll(async () => {
100
103
  await client.dispose();
101
104
 
105
+ expect(client.isValid).toBeFalsy();
106
+
102
107
  if (isLocal())
103
108
  fs.rmdirSync(testConfig.tmpDir!);
104
109
  });
@@ -114,8 +119,14 @@ export function runCommonTests(client: Client) {
114
119
  const attachment1 = await client.createDatabase(filename);
115
120
  const attachment2 = await client.connect(filename);
116
121
 
122
+ expect(attachment1.isValid).toBeTruthy();
123
+ expect(attachment2.isValid).toBeTruthy();
124
+
117
125
  await attachment2.disconnect();
118
126
  await attachment1.dropDatabase();
127
+
128
+ expect(attachment1.isValid).toBeFalsy();
129
+ expect(attachment2.isValid).toBeFalsy();
119
130
  });
120
131
  });
121
132
 
@@ -126,16 +137,22 @@ export function runCommonTests(client: Client) {
126
137
  const isolationQuery = 'select rdb$get_context(\'SYSTEM\', \'ISOLATION_LEVEL\') from rdb$database';
127
138
 
128
139
  const transaction1 = await attachment.startTransaction();
129
- expect((await attachment.executeReturning(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
140
+ expect(transaction1.isValid).toBeTruthy()
141
+ expect((await attachment.executeSingleton(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
130
142
  await transaction1.commit();
143
+ expect(transaction1.isValid).toBeFalsy()
131
144
 
132
145
  const transaction2 = await attachment.startTransaction({ isolation: TransactionIsolation.READ_COMMITTED });
133
- expect((await attachment.executeReturning(transaction2, isolationQuery))[0]).toBe('READ COMMITTED');
146
+ expect(transaction2.isValid).toBeTruthy()
147
+ expect((await attachment.executeSingleton(transaction2, isolationQuery))[0]).toBe('READ COMMITTED');
134
148
  await transaction2.commit();
149
+ expect(transaction2.isValid).toBeFalsy()
135
150
 
136
151
  const transaction3 = await attachment.startTransaction({ isolation: TransactionIsolation.CONSISTENCY });
137
- expect((await attachment.executeReturning(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
152
+ expect(transaction3.isValid).toBeTruthy()
153
+ expect((await attachment.executeSingleton(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
138
154
  await transaction3.commit();
155
+ expect(transaction3.isValid).toBeFalsy()
139
156
 
140
157
  await attachment.dropDatabase();
141
158
  });
@@ -145,7 +162,9 @@ export function runCommonTests(client: Client) {
145
162
  const transaction = await attachment.startTransaction();
146
163
 
147
164
  const statement = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
165
+ expect(statement.isValid).toBeTruthy();
148
166
  await statement.dispose();
167
+ expect(statement.isValid).toBeFalsy();
149
168
 
150
169
  let error: Error | undefined;
151
170
  try {
@@ -189,7 +208,39 @@ export function runCommonTests(client: Client) {
189
208
  await transaction.commitRetaining();
190
209
 
191
210
  const resultSet = await attachment.executeQuery(transaction, 'select n1 from t1');
211
+ expect(resultSet.isValid).toBeTruthy();
192
212
  await resultSet.close();
213
+ expect(resultSet.isValid).toBeFalsy();
214
+
215
+ await transaction.commit();
216
+ await attachment.dropDatabase();
217
+ });
218
+
219
+ test('#executeSingleton()', async () => {
220
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
221
+ const transaction = await attachment.startTransaction();
222
+
223
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
224
+ await transaction.commitRetaining();
225
+
226
+ const result = await attachment.executeSingleton(transaction, 'insert into t1 values (11) returning n1');
227
+ expect(result.length).toBe(1);
228
+ expect(result[0]).toBe(11);
229
+
230
+ await transaction.commit();
231
+ await attachment.dropDatabase();
232
+ });
233
+
234
+ test('#executeSingletonAsObject()', async () => {
235
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeSingletonAsObject.fdb'));
236
+ const transaction = await attachment.startTransaction();
237
+
238
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
239
+ await transaction.commitRetaining();
240
+
241
+ const output = await attachment.executeSingletonAsObject<{ N1: number }>(transaction,
242
+ 'insert into t1 values (11) returning n1');
243
+ expect(output.N1).toBe(11);
193
244
 
194
245
  await transaction.commit();
195
246
  await attachment.dropDatabase();
@@ -260,6 +311,7 @@ export function runCommonTests(client: Client) {
260
311
  if (Array.from(eventsMap.values()).every(obj => obj.count >= obj.expected)) {
261
312
  if (events) {
262
313
  await events.cancel();
314
+ expect(events.isValid).toBeFalsy();
263
315
  events = null!;
264
316
  }
265
317
  }
@@ -285,10 +337,12 @@ export function runCommonTests(client: Client) {
285
337
  // Commit retaining to test internal event rescheduling
286
338
  // after each handler dispatch.
287
339
  await transaction.commitRetaining();
340
+ expect(transaction.isValid).toBeTruthy();
288
341
  }
289
342
  }
290
343
  finally {
291
344
  await transaction.commit();
345
+ expect(transaction.isValid).toBeFalsy();
292
346
  }
293
347
 
294
348
  await Promise.all(eventsObj.map(ev => ev.promise));
@@ -355,7 +409,9 @@ export function runCommonTests(client: Client) {
355
409
  await statement2.execute(transaction, [null]);
356
410
  await statement2.execute(transaction, [10]);
357
411
  await statement2.execute(transaction, [100]);
412
+ expect(statement2.isValid).toBeTruthy();
358
413
  await statement2.dispose();
414
+ expect(statement2.isValid).toBeFalsy();
359
415
 
360
416
  const rs = await attachment.executeQuery(transaction,
361
417
  `select sum(n1) || ', ' || count(n1) || ', ' || count(*) ret from t1`);
@@ -386,6 +442,26 @@ export function runCommonTests(client: Client) {
386
442
  await attachment.dropDatabase();
387
443
  });
388
444
 
445
+ test('#executeSingleton()', async () => {
446
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
447
+ const transaction = await attachment.startTransaction();
448
+
449
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
450
+ await transaction.commitRetaining();
451
+
452
+ const statement = await attachment.prepare(transaction, 'insert into t1 values (11) returning n1, n1 * 2');
453
+
454
+ const result = await statement.executeSingleton(transaction);
455
+ expect(result.length).toBe(2);
456
+ expect(result[0]).toBe(11);
457
+ expect(result[1]).toBe(11 * 2);
458
+
459
+ await statement.dispose();
460
+
461
+ await transaction.commit();
462
+ await attachment.dropDatabase();
463
+ });
464
+
389
465
  test('#executeReturning()', async () => {
390
466
  const attachment = await client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
391
467
  const transaction = await attachment.startTransaction();
@@ -467,6 +543,7 @@ export function runCommonTests(client: Client) {
467
543
  describe('ResultSet', () => {
468
544
  test('#fetch()', async () => {
469
545
  const attachment = await client.createDatabase(getTempFile('ResultSet-fetch.fdb'));
546
+
470
547
  let transaction = await attachment.startTransaction();
471
548
 
472
549
  const blobBuffer = Buffer.alloc(11, '12345678á9');
@@ -538,8 +615,11 @@ export function runCommonTests(client: Client) {
538
615
  transaction = await attachment.startTransaction();
539
616
 
540
617
  const blob = await attachment.createBlob(transaction);
618
+ expect(blob.isValid).toBeTruthy();
541
619
  await blob.write(blobBuffer);
620
+ expect(blob.isValid).toBeTruthy();
542
621
  await blob.close();
622
+ expect(blob.isValid).toBeFalsy();
543
623
 
544
624
  parameters = [
545
625
  -1,
@@ -667,6 +747,7 @@ export function runCommonTests(client: Client) {
667
747
 
668
748
  for (const i = n + 2; n < i; ++n) {
669
749
  const blob = columns[n] as Blob;
750
+ expect(blob.isValid).toBeTruthy();
670
751
  const blobStream = await attachment.openBlob(transaction, blob);
671
752
  const buffer = Buffer.alloc(await blobStream.length);
672
753
  expect(await blobStream.read(buffer)).toBe(buffer.length);
@@ -805,5 +886,44 @@ export function runCommonTests(client: Client) {
805
886
  await attachment.dropDatabase();
806
887
  });
807
888
  });
889
+
890
+ describe('BlobStream', () => {
891
+ test('#seek()', async () => {
892
+ const attachment = await client.createDatabase(getTempFile('BlobStream-seek.fdb'));
893
+ const transaction = await attachment.startTransaction();
894
+
895
+ await attachment.execute(transaction, 'create table t1 (b blob)');
896
+ await transaction.commitRetaining();
897
+
898
+ const blobStream = await attachment.createBlob(transaction, { type: 'STREAM' });
899
+ await blobStream.write(Buffer.alloc(10, '1234567890'));
900
+ await blobStream.close();
901
+ await attachment.execute(transaction, 'insert into t1 (b) values (?)', [blobStream.blob]);
902
+
903
+ const blob = (await attachment.executeSingleton(transaction, 'select b from t1'))[0] as Blob;
904
+ const readBlobStream = await attachment.openBlob(transaction, blob);
905
+
906
+ const buffer = Buffer.alloc(3);
907
+
908
+ expect(await readBlobStream.seek(2)).toBe(2);
909
+ expect(await readBlobStream.read(buffer)).toBe(3);
910
+ expect(buffer.toString()).toBe('345');
911
+
912
+ expect(await readBlobStream.seek(-1, BlobSeekWhence.CURRENT)).toBe(4);
913
+ expect(await readBlobStream.read(buffer)).toBe(3);
914
+ expect(buffer.toString()).toBe('567');
915
+
916
+ expect(await readBlobStream.seek(1, BlobSeekWhence.START)).toBe(1);
917
+ expect(await readBlobStream.read(buffer)).toBe(3);
918
+ expect(buffer.toString()).toBe('234');
919
+
920
+ expect(await readBlobStream.seek(-2, BlobSeekWhence.END)).toBe(8);
921
+ expect(await readBlobStream.read(buffer)).toBe(2);
922
+ expect(buffer.slice(0, 2).toString()).toBe('90');
923
+
924
+ await transaction.commit();
925
+ await attachment.dropDatabase();
926
+ });
927
+ });
808
928
  });
809
929
  }