node-firebird-driver 2.3.0 → 2.4.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.
@@ -14,6 +14,8 @@ import {
14
14
  export abstract class AbstractStatement implements Statement {
15
15
  resultSet?: AbstractResultSet;
16
16
 
17
+ abstract getExecPathText(): Promise<string | undefined>;
18
+
17
19
  /** Gets the query's result columns labels. Returns empty array for queries without result. */
18
20
  abstract get columnLabels(): Promise<string[]>
19
21
 
@@ -63,7 +65,7 @@ export abstract class AbstractStatement implements Statement {
63
65
  }
64
66
 
65
67
  /** Executes a statement that returns a single record as [col1, col2, ..., colN]. */
66
- async executeReturning(transaction: AbstractTransaction, parameters?: any[], options?: ExecuteOptions): Promise<any[]> {
68
+ async executeSingleton(transaction: AbstractTransaction, parameters?: any[], options?: ExecuteOptions): Promise<any[]> {
67
69
  this.check();
68
70
 
69
71
  //// TODO: check opened resultSet.
@@ -72,11 +74,11 @@ export abstract class AbstractStatement implements Statement {
72
74
  }
73
75
 
74
76
  /** Executes a statement that returns a single record as an object. */
75
- async executeReturningAsObject<T extends object>(transaction: AbstractTransaction, parameters?: any[],
77
+ async executeSingletonAsObject<T extends object>(transaction: AbstractTransaction, parameters?: any[],
76
78
  options?: ExecuteOptions): Promise<T> {
77
79
  this.check();
78
80
 
79
- const row = await this.executeReturning(transaction, parameters, options);
81
+ const row = await this.executeSingleton(transaction, parameters, options);
80
82
  const cols = (await this?.columnLabels) || [];
81
83
 
82
84
  const obj = {} as T;
@@ -90,6 +92,17 @@ export abstract class AbstractStatement implements Statement {
90
92
  return obj;
91
93
  }
92
94
 
95
+ /** Executes a statement that returns a single record as [col1, col2, ..., colN]. */
96
+ async executeReturning(transaction: AbstractTransaction, parameters?: any[], options?: ExecuteOptions): Promise<any[]> {
97
+ return await this.executeSingleton(transaction, parameters, options);
98
+ }
99
+
100
+ /** Executes a statement that returns a single record as an object. */
101
+ async executeReturningAsObject<T extends object>(transaction: AbstractTransaction, parameters?: any[],
102
+ options?: ExecuteOptions): Promise<T> {
103
+ return await this.executeSingletonAsObject<T>(transaction, parameters, options);
104
+ }
105
+
93
106
  /** Executes a prepared statement that has result set. */
94
107
  async executeQuery(transaction: AbstractTransaction, parameters?: any[], options?: ExecuteQueryOptions):
95
108
  Promise<AbstractResultSet> {
@@ -102,8 +115,12 @@ export abstract class AbstractStatement implements Statement {
102
115
  return resultSet;
103
116
  }
104
117
 
118
+ get isValid(): boolean {
119
+ return !!this.attachment;
120
+ }
121
+
105
122
  private check() {
106
- if (!this.attachment)
123
+ if (!this.isValid)
107
124
  throw new Error('Statement is already disposed.');
108
125
  }
109
126
 
@@ -42,8 +42,12 @@ export abstract class AbstractTransaction implements Transaction {
42
42
  return await this.internalRollbackRetaining();
43
43
  }
44
44
 
45
+ get isValid(): boolean {
46
+ return !!this.attachment;
47
+ }
48
+
45
49
  private check() {
46
- if (!this.attachment)
50
+ if (!this.isValid)
47
51
  throw new Error('Transaction is already committed or rolled back.');
48
52
  }
49
53
 
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
 
@@ -121,13 +124,33 @@ export interface Attachment {
121
124
  }): Promise<void>;
122
125
 
123
126
  /** Executes a statement that returns a single record as [col1, col2, ..., colN]. */
124
- executeReturning(transaction: Transaction, sqlStmt: string, parameters?: any[],
127
+ executeSingleton(transaction: Transaction, sqlStmt: string, parameters?: any[],
125
128
  options?: {
126
129
  prepareOptions?: PrepareOptions,
127
130
  executeOptions?: ExecuteOptions
128
131
  }): Promise<any[]>;
129
132
 
130
133
  /** Executes a statement that returns a single record as an object. */
134
+ executeSingletonAsObject<T extends object>(transaction: Transaction, sqlStmt: string, parameters?: any[],
135
+ options?: {
136
+ prepareOptions?: PrepareOptions,
137
+ executeOptions?: ExecuteOptions
138
+ }): Promise<T>;
139
+
140
+ /**
141
+ * Executes a statement that returns a single record as [col1, col2, ..., colN].
142
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingleton.
143
+ */
144
+ executeReturning(transaction: Transaction, sqlStmt: string, parameters?: any[],
145
+ options?: {
146
+ prepareOptions?: PrepareOptions,
147
+ executeOptions?: ExecuteOptions
148
+ }): Promise<any[]>;
149
+
150
+ /**
151
+ * Executes a statement that returns a single record as an object.
152
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingletonAsObject.
153
+ */
131
154
  executeReturningAsObject<T extends object>(transaction: Transaction, sqlStmt: string, parameters?: any[],
132
155
  options?: {
133
156
  prepareOptions?: PrepareOptions,
@@ -143,6 +166,9 @@ export interface Attachment {
143
166
 
144
167
  queueEvents(names: string[], callBack: (counters: [string, number][]) => Promise<void>): Promise<Events>;
145
168
 
169
+ /** True if the attachment is connected. */
170
+ readonly isValid: boolean;
171
+
146
172
  /** Default transaction options. */
147
173
  defaultTransactionOptions?: TransactionOptions;
148
174
 
@@ -172,6 +198,9 @@ export interface Transaction {
172
198
 
173
199
  /** Rollbacks and maintains this transaction object for subsequent work. */
174
200
  rollbackRetaining(): Promise<void>;
201
+
202
+ /** True if the transaction is active. */
203
+ readonly isValid: boolean;
175
204
  }
176
205
 
177
206
  /** Statement interface. */
@@ -186,9 +215,21 @@ export interface Statement {
186
215
  execute(transaction: Transaction, parameters?: any[], options?: ExecuteOptions): Promise<void>;
187
216
 
188
217
  /** Executes a statement that returns a single record as [col1, col2, ..., colN]. */
189
- executeReturning(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<any[]>;
218
+ executeSingleton(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<any[]>;
190
219
 
191
220
  /** Executes a statement that returns a single record as an object. */
221
+ executeSingletonAsObject<T extends object>(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<T>;
222
+
223
+ /**
224
+ * Executes a statement that returns a single record as [col1, col2, ..., colN].
225
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingleton.
226
+ */
227
+ executeReturning(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<any[]>;
228
+
229
+ /**
230
+ * Executes a statement that returns a single record as an object.
231
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingletonAsObject.
232
+ */
192
233
  executeReturningAsObject<T extends object>(transaction: Transaction, parameters?: any[],
193
234
  options?: ExecuteOptions): Promise<T>;
194
235
 
@@ -202,6 +243,11 @@ export interface Statement {
202
243
  */
203
244
  setCursorName(cursorName: string): Promise<void>;
204
245
 
246
+ getExecPathText(): Promise<string | undefined>;
247
+
248
+ /** True if the statement has not been disposed. */
249
+ readonly isValid: boolean;
250
+
205
251
  /** Gets the query's result columns labels. Returns empty array for queries without result. */
206
252
  readonly columnLabels: Promise<string[]>;
207
253
 
@@ -242,12 +288,18 @@ export interface ResultSet {
242
288
  */
243
289
  fetchAsObject<T extends object>(options?: FetchOptions): Promise<T[]>;
244
290
 
291
+ /** True if the ResultSet is open. */
292
+ readonly isValid: boolean;
293
+
245
294
  /** Default result set's fetch options. */
246
295
  defaultFetchOptions?: FetchOptions;
247
296
  }
248
297
 
249
298
  export interface Events {
250
299
  cancel(): Promise<void>;
300
+
301
+ /** True if the events' attachment is valid. */
302
+ readonly isValid: boolean;
251
303
  }
252
304
 
253
305
  /** Blob class. */
@@ -262,6 +314,11 @@ export class Blob {
262
314
  this.attachment = attachment;
263
315
  this.id.set(id);
264
316
  }
317
+
318
+ /** True if the blob's attachment is valid. */
319
+ get isValid(): boolean {
320
+ return this.attachment.isValid;
321
+ }
265
322
  }
266
323
 
267
324
  /** BlobStream class. */
@@ -290,6 +347,9 @@ export abstract class BlobStream {
290
347
 
291
348
  /** Writes data to the blob. */
292
349
  abstract write(buffer: Buffer): Promise<void>;
350
+
351
+ /** True if the blob stream is open. */
352
+ abstract get isValid(): boolean;
293
353
  }
294
354
 
295
355
  /** TIME WITH TIME ZONE and TIMESTAMP WITH TIME ZONE to be sent as parameter */
package/src/test/tests.ts CHANGED
@@ -74,6 +74,8 @@ export function runCommonTests(client: Client) {
74
74
 
75
75
 
76
76
  beforeAll(() => {
77
+ expect(client.isValid).toBeTruthy();
78
+
77
79
  if (isLocal() && !testConfig.tmpDir) {
78
80
  testConfig.tmpDir = tmp.mkdirSync().path.toString();
79
81
 
@@ -99,6 +101,8 @@ export function runCommonTests(client: Client) {
99
101
  afterAll(async () => {
100
102
  await client.dispose();
101
103
 
104
+ expect(client.isValid).toBeFalsy();
105
+
102
106
  if (isLocal())
103
107
  fs.rmdirSync(testConfig.tmpDir!);
104
108
  });
@@ -114,8 +118,14 @@ export function runCommonTests(client: Client) {
114
118
  const attachment1 = await client.createDatabase(filename);
115
119
  const attachment2 = await client.connect(filename);
116
120
 
121
+ expect(attachment1.isValid).toBeTruthy();
122
+ expect(attachment2.isValid).toBeTruthy();
123
+
117
124
  await attachment2.disconnect();
118
125
  await attachment1.dropDatabase();
126
+
127
+ expect(attachment1.isValid).toBeFalsy();
128
+ expect(attachment2.isValid).toBeFalsy();
119
129
  });
120
130
  });
121
131
 
@@ -126,16 +136,22 @@ export function runCommonTests(client: Client) {
126
136
  const isolationQuery = 'select rdb$get_context(\'SYSTEM\', \'ISOLATION_LEVEL\') from rdb$database';
127
137
 
128
138
  const transaction1 = await attachment.startTransaction();
129
- expect((await attachment.executeReturning(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
139
+ expect(transaction1.isValid).toBeTruthy()
140
+ expect((await attachment.executeSingleton(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
130
141
  await transaction1.commit();
142
+ expect(transaction1.isValid).toBeFalsy()
131
143
 
132
144
  const transaction2 = await attachment.startTransaction({ isolation: TransactionIsolation.READ_COMMITTED });
133
- expect((await attachment.executeReturning(transaction2, isolationQuery))[0]).toBe('READ COMMITTED');
145
+ expect(transaction2.isValid).toBeTruthy()
146
+ expect((await attachment.executeSingleton(transaction2, isolationQuery))[0]).toBe('READ COMMITTED');
134
147
  await transaction2.commit();
148
+ expect(transaction2.isValid).toBeFalsy()
135
149
 
136
150
  const transaction3 = await attachment.startTransaction({ isolation: TransactionIsolation.CONSISTENCY });
137
- expect((await attachment.executeReturning(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
151
+ expect(transaction3.isValid).toBeTruthy()
152
+ expect((await attachment.executeSingleton(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
138
153
  await transaction3.commit();
154
+ expect(transaction3.isValid).toBeFalsy()
139
155
 
140
156
  await attachment.dropDatabase();
141
157
  });
@@ -145,7 +161,9 @@ export function runCommonTests(client: Client) {
145
161
  const transaction = await attachment.startTransaction();
146
162
 
147
163
  const statement = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
164
+ expect(statement.isValid).toBeTruthy();
148
165
  await statement.dispose();
166
+ expect(statement.isValid).toBeFalsy();
149
167
 
150
168
  let error: Error | undefined;
151
169
  try {
@@ -189,7 +207,39 @@ export function runCommonTests(client: Client) {
189
207
  await transaction.commitRetaining();
190
208
 
191
209
  const resultSet = await attachment.executeQuery(transaction, 'select n1 from t1');
210
+ expect(resultSet.isValid).toBeTruthy();
192
211
  await resultSet.close();
212
+ expect(resultSet.isValid).toBeFalsy();
213
+
214
+ await transaction.commit();
215
+ await attachment.dropDatabase();
216
+ });
217
+
218
+ test('#executeSingleton()', async () => {
219
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
220
+ const transaction = await attachment.startTransaction();
221
+
222
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
223
+ await transaction.commitRetaining();
224
+
225
+ const result = await attachment.executeSingleton(transaction, 'insert into t1 values (11) returning n1');
226
+ expect(result.length).toBe(1);
227
+ expect(result[0]).toBe(11);
228
+
229
+ await transaction.commit();
230
+ await attachment.dropDatabase();
231
+ });
232
+
233
+ test('#executeSingletonAsObject()', async () => {
234
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeSingletonAsObject.fdb'));
235
+ const transaction = await attachment.startTransaction();
236
+
237
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
238
+ await transaction.commitRetaining();
239
+
240
+ const output = await attachment.executeSingletonAsObject<{ N1: number }>(transaction,
241
+ 'insert into t1 values (11) returning n1');
242
+ expect(output.N1).toBe(11);
193
243
 
194
244
  await transaction.commit();
195
245
  await attachment.dropDatabase();
@@ -260,6 +310,7 @@ export function runCommonTests(client: Client) {
260
310
  if (Array.from(eventsMap.values()).every(obj => obj.count >= obj.expected)) {
261
311
  if (events) {
262
312
  await events.cancel();
313
+ expect(events.isValid).toBeFalsy();
263
314
  events = null!;
264
315
  }
265
316
  }
@@ -285,10 +336,12 @@ export function runCommonTests(client: Client) {
285
336
  // Commit retaining to test internal event rescheduling
286
337
  // after each handler dispatch.
287
338
  await transaction.commitRetaining();
339
+ expect(transaction.isValid).toBeTruthy();
288
340
  }
289
341
  }
290
342
  finally {
291
343
  await transaction.commit();
344
+ expect(transaction.isValid).toBeFalsy();
292
345
  }
293
346
 
294
347
  await Promise.all(eventsObj.map(ev => ev.promise));
@@ -355,7 +408,9 @@ export function runCommonTests(client: Client) {
355
408
  await statement2.execute(transaction, [null]);
356
409
  await statement2.execute(transaction, [10]);
357
410
  await statement2.execute(transaction, [100]);
411
+ expect(statement2.isValid).toBeTruthy();
358
412
  await statement2.dispose();
413
+ expect(statement2.isValid).toBeFalsy();
359
414
 
360
415
  const rs = await attachment.executeQuery(transaction,
361
416
  `select sum(n1) || ', ' || count(n1) || ', ' || count(*) ret from t1`);
@@ -386,6 +441,26 @@ export function runCommonTests(client: Client) {
386
441
  await attachment.dropDatabase();
387
442
  });
388
443
 
444
+ test('#executeSingleton()', async () => {
445
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
446
+ const transaction = await attachment.startTransaction();
447
+
448
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
449
+ await transaction.commitRetaining();
450
+
451
+ const statement = await attachment.prepare(transaction, 'insert into t1 values (11) returning n1, n1 * 2');
452
+
453
+ const result = await statement.executeSingleton(transaction);
454
+ expect(result.length).toBe(2);
455
+ expect(result[0]).toBe(11);
456
+ expect(result[1]).toBe(11 * 2);
457
+
458
+ await statement.dispose();
459
+
460
+ await transaction.commit();
461
+ await attachment.dropDatabase();
462
+ });
463
+
389
464
  test('#executeReturning()', async () => {
390
465
  const attachment = await client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
391
466
  const transaction = await attachment.startTransaction();
@@ -467,6 +542,7 @@ export function runCommonTests(client: Client) {
467
542
  describe('ResultSet', () => {
468
543
  test('#fetch()', async () => {
469
544
  const attachment = await client.createDatabase(getTempFile('ResultSet-fetch.fdb'));
545
+
470
546
  let transaction = await attachment.startTransaction();
471
547
 
472
548
  const blobBuffer = Buffer.alloc(11, '12345678á9');
@@ -538,8 +614,11 @@ export function runCommonTests(client: Client) {
538
614
  transaction = await attachment.startTransaction();
539
615
 
540
616
  const blob = await attachment.createBlob(transaction);
617
+ expect(blob.isValid).toBeTruthy();
541
618
  await blob.write(blobBuffer);
619
+ expect(blob.isValid).toBeTruthy();
542
620
  await blob.close();
621
+ expect(blob.isValid).toBeFalsy();
543
622
 
544
623
  parameters = [
545
624
  -1,
@@ -667,6 +746,7 @@ export function runCommonTests(client: Client) {
667
746
 
668
747
  for (const i = n + 2; n < i; ++n) {
669
748
  const blob = columns[n] as Blob;
749
+ expect(blob.isValid).toBeTruthy();
670
750
  const blobStream = await attachment.openBlob(transaction, blob);
671
751
  const buffer = Buffer.alloc(await blobStream.length);
672
752
  expect(await blobStream.read(buffer)).toBe(buffer.length);