node-firebird-driver 2.1.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.
Files changed (49) hide show
  1. package/dist/lib/impl/attachment.d.ts +11 -0
  2. package/dist/lib/impl/attachment.js +21 -5
  3. package/dist/lib/impl/attachment.js.map +1 -1
  4. package/dist/lib/impl/blob.js +1 -0
  5. package/dist/lib/impl/blob.js.map +1 -1
  6. package/dist/lib/impl/client.d.ts +1 -0
  7. package/dist/lib/impl/client.js +5 -1
  8. package/dist/lib/impl/client.js.map +1 -1
  9. package/dist/lib/impl/date-time.js +1 -0
  10. package/dist/lib/impl/date-time.js.map +1 -1
  11. package/dist/lib/impl/events.d.ts +1 -0
  12. package/dist/lib/impl/events.js +5 -1
  13. package/dist/lib/impl/events.js.map +1 -1
  14. package/dist/lib/impl/fb-util.d.ts +23 -0
  15. package/dist/lib/impl/fb-util.js +98 -10
  16. package/dist/lib/impl/fb-util.js.map +1 -1
  17. package/dist/lib/impl/index.d.ts +1 -0
  18. package/dist/lib/impl/index.js +20 -12
  19. package/dist/lib/impl/index.js.map +1 -1
  20. package/dist/lib/impl/resultset.d.ts +1 -0
  21. package/dist/lib/impl/resultset.js +5 -1
  22. package/dist/lib/impl/resultset.js.map +1 -1
  23. package/dist/lib/impl/statement.d.ts +10 -1
  24. package/dist/lib/impl/statement.js +21 -6
  25. package/dist/lib/impl/statement.js.map +1 -1
  26. package/dist/lib/impl/time-zones.d.ts +2 -0
  27. package/dist/lib/impl/time-zones.js +655 -0
  28. package/dist/lib/impl/time-zones.js.map +1 -0
  29. package/dist/lib/impl/transaction.d.ts +1 -0
  30. package/dist/lib/impl/transaction.js +5 -1
  31. package/dist/lib/impl/transaction.js.map +1 -1
  32. package/dist/lib/index.d.ts +63 -3
  33. package/dist/lib/index.js +5 -0
  34. package/dist/lib/index.js.map +1 -1
  35. package/dist/test/tests.js +192 -13
  36. package/dist/test/tests.js.map +1 -1
  37. package/package.json +3 -3
  38. package/src/lib/impl/attachment.ts +34 -12
  39. package/src/lib/impl/blob.ts +5 -5
  40. package/src/lib/impl/client.ts +8 -4
  41. package/src/lib/impl/events.ts +6 -2
  42. package/src/lib/impl/fb-util.ts +115 -4
  43. package/src/lib/impl/index.ts +1 -0
  44. package/src/lib/impl/resultset.ts +7 -3
  45. package/src/lib/impl/statement.ts +31 -9
  46. package/src/lib/impl/time-zones.ts +655 -0
  47. package/src/lib/impl/transaction.ts +9 -5
  48. package/src/lib/index.ts +84 -3
  49. package/src/test/tests.ts +240 -13
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,18 +215,45 @@ 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
 
195
236
  /** Executes a prepared statement that has result set. */
196
237
  executeQuery(transaction: Transaction, parameters?: any[], options?: ExecuteQueryOptions): Promise<ResultSet>;
197
238
 
239
+ /**
240
+ * Set cursor name of a SELECT ... FOR UPDATE statement.
241
+ *
242
+ * Use with ResultSet.fetch({ fetchSize: 1 }) and other statement with WHERE CURRENT OF <cursorName>.
243
+ */
244
+ setCursorName(cursorName: string): Promise<void>;
245
+
246
+ getExecPathText(): Promise<string | undefined>;
247
+
248
+ /** True if the statement has not been disposed. */
249
+ readonly isValid: boolean;
250
+
198
251
  /** Gets the query's result columns labels. Returns empty array for queries without result. */
199
252
  readonly columnLabels: Promise<string[]>;
200
253
 
254
+ /** When true, query result must be obtained with method executeQuery. */
255
+ readonly hasResultSet: boolean;
256
+
201
257
  /** Default query's execute options. */
202
258
  defaultExecuteOptions?: ExecuteOptions;
203
259
 
@@ -232,12 +288,18 @@ export interface ResultSet {
232
288
  */
233
289
  fetchAsObject<T extends object>(options?: FetchOptions): Promise<T[]>;
234
290
 
291
+ /** True if the ResultSet is open. */
292
+ readonly isValid: boolean;
293
+
235
294
  /** Default result set's fetch options. */
236
295
  defaultFetchOptions?: FetchOptions;
237
296
  }
238
297
 
239
298
  export interface Events {
240
299
  cancel(): Promise<void>;
300
+
301
+ /** True if the events' attachment is valid. */
302
+ readonly isValid: boolean;
241
303
  }
242
304
 
243
305
  /** Blob class. */
@@ -252,6 +314,11 @@ export class Blob {
252
314
  this.attachment = attachment;
253
315
  this.id.set(id);
254
316
  }
317
+
318
+ /** True if the blob's attachment is valid. */
319
+ get isValid(): boolean {
320
+ return this.attachment.isValid;
321
+ }
255
322
  }
256
323
 
257
324
  /** BlobStream class. */
@@ -260,7 +327,7 @@ export abstract class BlobStream {
260
327
  readonly blob: Blob;
261
328
 
262
329
  /** Gets the blob's stream length in bytes. */
263
- readonly length: Promise<number>;
330
+ abstract get length(): Promise<number>;
264
331
 
265
332
  protected constructor(blob: Blob) {
266
333
  this.blob = blob;
@@ -280,4 +347,18 @@ export abstract class BlobStream {
280
347
 
281
348
  /** Writes data to the blob. */
282
349
  abstract write(buffer: Buffer): Promise<void>;
350
+
351
+ /** True if the blob stream is open. */
352
+ abstract get isValid(): boolean;
353
+ }
354
+
355
+ /** TIME WITH TIME ZONE and TIMESTAMP WITH TIME ZONE to be sent as parameter */
356
+ export interface ZonedDate {
357
+ date: Date;
358
+ timeZone: string;
359
+ }
360
+
361
+ /** TIME WITH TIME ZONE and TIMESTAMP WITH TIME ZONE returned by Firebird */
362
+ export interface ZonedDateEx extends ZonedDate {
363
+ offset: number;
283
364
  }
package/src/test/tests.ts CHANGED
@@ -1,4 +1,10 @@
1
- import { Blob, Client, TransactionIsolation } from '../lib';
1
+ import {
2
+ Blob,
3
+ Client,
4
+ TransactionIsolation,
5
+ ZonedDate,
6
+ ZonedDateEx
7
+ } from '../lib';
2
8
 
3
9
  import * as fs from 'fs-extra-promise';
4
10
  import * as tmp from 'temp-fs';
@@ -9,17 +15,36 @@ require('dotenv').config({ path: '../../.env' });
9
15
 
10
16
  export function runCommonTests(client: Client) {
11
17
  function dateToString(d: Date) {
12
- return d && `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
18
+ return d && `${(d.getFullYear() + '').padStart(4, '0')}-${d.getMonth() + 1}-${d.getDate()}`;
13
19
  }
14
20
 
15
21
  function timeToString(d: Date) {
16
22
  return d && `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`;
17
23
  }
18
24
 
25
+ function timeTzToString(zd: ZonedDateEx) {
26
+ if (!zd)
27
+ return null;
28
+
29
+ const d = new Date(zd.date.getTime() + (zd.offset * 60 * 1000));
30
+
31
+ return `time '${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`;
32
+ }
33
+
19
34
  function dateTimeToString(d: Date) {
20
35
  return d && `${dateToString(d)} ${timeToString(d)}`;
21
36
  }
22
37
 
38
+ function dateTimeTzToString(zd: ZonedDateEx) {
39
+ if (!zd)
40
+ return null;
41
+
42
+ const d = new Date(zd.date.getTime() + (zd.offset * 60 * 1000));
43
+
44
+ return `timestamp '${(d.getUTCFullYear() + '').padStart(4, '0')}-${d.getUTCMonth() + 1}-${d.getUTCDate()} ` +
45
+ `${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`;
46
+ }
47
+
23
48
 
24
49
  describe('node-firebird-driver', () => {
25
50
  const testConfig = {
@@ -49,6 +74,8 @@ export function runCommonTests(client: Client) {
49
74
 
50
75
 
51
76
  beforeAll(() => {
77
+ expect(client.isValid).toBeTruthy();
78
+
52
79
  if (isLocal() && !testConfig.tmpDir) {
53
80
  testConfig.tmpDir = tmp.mkdirSync().path.toString();
54
81
 
@@ -74,6 +101,8 @@ export function runCommonTests(client: Client) {
74
101
  afterAll(async () => {
75
102
  await client.dispose();
76
103
 
104
+ expect(client.isValid).toBeFalsy();
105
+
77
106
  if (isLocal())
78
107
  fs.rmdirSync(testConfig.tmpDir!);
79
108
  });
@@ -89,8 +118,14 @@ export function runCommonTests(client: Client) {
89
118
  const attachment1 = await client.createDatabase(filename);
90
119
  const attachment2 = await client.connect(filename);
91
120
 
121
+ expect(attachment1.isValid).toBeTruthy();
122
+ expect(attachment2.isValid).toBeTruthy();
123
+
92
124
  await attachment2.disconnect();
93
125
  await attachment1.dropDatabase();
126
+
127
+ expect(attachment1.isValid).toBeFalsy();
128
+ expect(attachment2.isValid).toBeFalsy();
94
129
  });
95
130
  });
96
131
 
@@ -101,16 +136,22 @@ export function runCommonTests(client: Client) {
101
136
  const isolationQuery = 'select rdb$get_context(\'SYSTEM\', \'ISOLATION_LEVEL\') from rdb$database';
102
137
 
103
138
  const transaction1 = await attachment.startTransaction();
104
- expect((await attachment.executeReturning(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
139
+ expect(transaction1.isValid).toBeTruthy()
140
+ expect((await attachment.executeSingleton(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
105
141
  await transaction1.commit();
142
+ expect(transaction1.isValid).toBeFalsy()
106
143
 
107
144
  const transaction2 = await attachment.startTransaction({ isolation: TransactionIsolation.READ_COMMITTED });
108
- 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');
109
147
  await transaction2.commit();
148
+ expect(transaction2.isValid).toBeFalsy()
110
149
 
111
150
  const transaction3 = await attachment.startTransaction({ isolation: TransactionIsolation.CONSISTENCY });
112
- expect((await attachment.executeReturning(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
151
+ expect(transaction3.isValid).toBeTruthy()
152
+ expect((await attachment.executeSingleton(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
113
153
  await transaction3.commit();
154
+ expect(transaction3.isValid).toBeFalsy()
114
155
 
115
156
  await attachment.dropDatabase();
116
157
  });
@@ -120,7 +161,9 @@ export function runCommonTests(client: Client) {
120
161
  const transaction = await attachment.startTransaction();
121
162
 
122
163
  const statement = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
164
+ expect(statement.isValid).toBeTruthy();
123
165
  await statement.dispose();
166
+ expect(statement.isValid).toBeFalsy();
124
167
 
125
168
  let error: Error | undefined;
126
169
  try {
@@ -164,7 +207,39 @@ export function runCommonTests(client: Client) {
164
207
  await transaction.commitRetaining();
165
208
 
166
209
  const resultSet = await attachment.executeQuery(transaction, 'select n1 from t1');
210
+ expect(resultSet.isValid).toBeTruthy();
167
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);
168
243
 
169
244
  await transaction.commit();
170
245
  await attachment.dropDatabase();
@@ -235,6 +310,7 @@ export function runCommonTests(client: Client) {
235
310
  if (Array.from(eventsMap.values()).every(obj => obj.count >= obj.expected)) {
236
311
  if (events) {
237
312
  await events.cancel();
313
+ expect(events.isValid).toBeFalsy();
238
314
  events = null!;
239
315
  }
240
316
  }
@@ -260,10 +336,12 @@ export function runCommonTests(client: Client) {
260
336
  // Commit retaining to test internal event rescheduling
261
337
  // after each handler dispatch.
262
338
  await transaction.commitRetaining();
339
+ expect(transaction.isValid).toBeTruthy();
263
340
  }
264
341
  }
265
342
  finally {
266
343
  await transaction.commit();
344
+ expect(transaction.isValid).toBeFalsy();
267
345
  }
268
346
 
269
347
  await Promise.all(eventsObj.map(ev => ev.promise));
@@ -325,9 +403,21 @@ export function runCommonTests(client: Client) {
325
403
  await statement1.dispose();
326
404
  await transaction.commitRetaining();
327
405
 
328
- const statement2 = await attachment.prepare(transaction, 'insert into t1 (n1) values (1)');
329
- await statement2.execute(transaction);
406
+ const statement2 = await attachment.prepare(transaction, 'insert into t1 (n1) values (?)');
407
+ await statement2.execute(transaction, [1]);
408
+ await statement2.execute(transaction, [null]);
409
+ await statement2.execute(transaction, [10]);
410
+ await statement2.execute(transaction, [100]);
411
+ expect(statement2.isValid).toBeTruthy();
330
412
  await statement2.dispose();
413
+ expect(statement2.isValid).toBeFalsy();
414
+
415
+ const rs = await attachment.executeQuery(transaction,
416
+ `select sum(n1) || ', ' || count(n1) || ', ' || count(*) ret from t1`);
417
+ const ret = await rs.fetchAsObject<{ RET: string }>();
418
+ await rs.close();
419
+
420
+ expect(ret[0].RET).toStrictEqual('111, 3, 4');
331
421
 
332
422
  await transaction.commit();
333
423
  await attachment.dropDatabase();
@@ -351,6 +441,26 @@ export function runCommonTests(client: Client) {
351
441
  await attachment.dropDatabase();
352
442
  });
353
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
+
354
464
  test('#executeReturning()', async () => {
355
465
  const attachment = await client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
356
466
  const transaction = await attachment.startTransaction();
@@ -388,11 +498,51 @@ export function runCommonTests(client: Client) {
388
498
  await transaction.commit();
389
499
  await attachment.dropDatabase();
390
500
  });
501
+
502
+ test('#hasResultSet()', async () => {
503
+ const attachment = await client.createDatabase(getTempFile('Statement-hasResultSet.fdb'));
504
+ const transaction = await attachment.startTransaction();
505
+
506
+ const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
507
+ expect(statement1.hasResultSet).toBe(false);
508
+ await statement1.execute(transaction);
509
+ await statement1.dispose();
510
+
511
+ await transaction.commitRetaining();
512
+
513
+ const statement2 = await attachment.prepare(transaction, 'insert into t1 values (1)');
514
+ expect(statement2.hasResultSet).toBe(false);
515
+ await statement2.dispose();
516
+
517
+ const statement3 = await attachment.prepare(transaction, 'insert into t1 values (1) returning *');
518
+ expect(statement3.hasResultSet).toBe(false);
519
+ await statement3.dispose();
520
+
521
+ const statement4 = await attachment.prepare(transaction, 'execute block as begin end');
522
+ expect(statement4.hasResultSet).toBe(false);
523
+ await statement4.dispose();
524
+
525
+ const statement5 = await attachment.prepare(transaction, 'select * from t1');
526
+ expect(statement5.hasResultSet).toBe(true);
527
+ await statement5.dispose();
528
+
529
+ const statement6 = await attachment.prepare(transaction, 'execute block returns (n integer) as begin suspend; end');
530
+ expect(statement6.hasResultSet).toBe(true);
531
+ await statement6.dispose();
532
+
533
+ const statement7 = await attachment.prepare(transaction, 'execute block returns (n integer) as begin end');
534
+ expect(statement7.hasResultSet).toBe(true);
535
+ await statement7.dispose();
536
+
537
+ await transaction.commit();
538
+ await attachment.dropDatabase();
539
+ });
391
540
  });
392
541
 
393
542
  describe('ResultSet', () => {
394
543
  test('#fetch()', async () => {
395
544
  const attachment = await client.createDatabase(getTempFile('ResultSet-fetch.fdb'));
545
+
396
546
  let transaction = await attachment.startTransaction();
397
547
 
398
548
  const blobBuffer = Buffer.alloc(11, '12345678á9');
@@ -403,10 +553,42 @@ export function runCommonTests(client: Client) {
403
553
  { name: 'x_int_scale', type: 'numeric(5, 2)', valToStr: (v: any) => v },
404
554
  { name: 'x_bigint', type: 'bigint', valToStr: (v: any) => v },
405
555
  { name: 'x_bigint_scale', type: 'numeric(15, 2)', valToStr: (v: any) => v },
556
+ { name: 'x_int128', type: 'int128', valToStr: (v: any) => v },
557
+ { name: 'x_int128_scale', type: 'numeric(20, 2)', valToStr: (v: any) => v },
558
+ { name: 'x_dec16', type: 'decfloat(16)', valToStr: (v: any) => v },
559
+ { name: 'x_dec34', type: 'decfloat(34)', valToStr: (v: any) => v },
406
560
  { name: 'x_double', type: 'double precision', valToStr: (v: any) => v },
407
- { name: 'x_date', type: 'date', valToStr: (v: any) => `date '${dateToString(v)}'` },
561
+ { name: 'x_date1', type: 'date', valToStr: (v: any) => `date '${dateToString(v)}'` },
562
+ { name: 'x_date2', type: 'date', valToStr: (v: any) => `date '${dateToString(v)}'` },
563
+ { name: 'x_date3', type: 'date', valToStr: (v: any) => `date '${dateToString(v)}'` },
408
564
  { name: 'x_time', type: 'time', valToStr: (v: any) => `time '${timeToString(v)}'` },
409
- { name: 'x_timestamp', type: 'timestamp', valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'` },
565
+ {
566
+ name: 'x_time_tz1',
567
+ type: 'time with time zone',
568
+ valToStr: (v: ZonedDate) =>
569
+ `${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
570
+ },
571
+ {
572
+ name: 'x_time_tz2',
573
+ type: 'time with time zone',
574
+ valToStr: (v: ZonedDate) =>
575
+ `${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
576
+ },
577
+ { name: 'x_timestamp1', type: 'timestamp', valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'` },
578
+ { name: 'x_timestamp2', type: 'timestamp', valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'` },
579
+ { name: 'x_timestamp3', type: 'timestamp', valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'` },
580
+ {
581
+ name: 'x_timestamp_tz1',
582
+ type: 'timestamp with time zone',
583
+ valToStr: (v: ZonedDate) =>
584
+ `${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
585
+ },
586
+ {
587
+ name: 'x_timestamp_tz2',
588
+ type: 'timestamp with time zone',
589
+ valToStr: (v: ZonedDate) =>
590
+ `${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
591
+ },
410
592
  { name: 'x_boolean', type: 'boolean', valToStr: (v: any) => v },
411
593
  { name: 'x_varchar', type: 'varchar(10) character set utf8', valToStr: (v: any) => `'${v}'` },
412
594
  { name: 'x_char', type: 'char(10) character set utf8', valToStr: (v: any) => `'${v}'` },
@@ -421,7 +603,6 @@ export function runCommonTests(client: Client) {
421
603
  await transaction.commitRetaining();
422
604
 
423
605
  const recordCount = 5;
424
- const now = new Date();
425
606
  let parameters: any[];
426
607
 
427
608
  { // scope
@@ -433,8 +614,11 @@ export function runCommonTests(client: Client) {
433
614
  transaction = await attachment.startTransaction();
434
615
 
435
616
  const blob = await attachment.createBlob(transaction);
617
+ expect(blob.isValid).toBeTruthy();
436
618
  await blob.write(blobBuffer);
619
+ expect(blob.isValid).toBeTruthy();
437
620
  await blob.close();
621
+ expect(blob.isValid).toBeFalsy();
438
622
 
439
623
  parameters = [
440
624
  -1,
@@ -442,10 +626,28 @@ export function runCommonTests(client: Client) {
442
626
  -3.45,
443
627
  -2,
444
628
  -3.45,
629
+ '-45699999999999999999999999999999999876',
630
+ '-45699999999999999999999999999999999.87',
631
+ '-456999999999876',
632
+ '-456999999999999999999999999999.87',
445
633
  -4.567,
446
634
  new Date(2017, 3 - 1, 26),
447
- new Date(now.getFullYear(), now.getMonth(), now.getDate(), 11, 56, 32, 123),
635
+ new Date(new Date(2000, 3 - 1, 26).setFullYear(50)),
636
+ new Date(9999, 3 - 1, 26),
637
+ new Date(2020, 1 - 1, 1, 11, 56, 32, 123),
638
+ {
639
+ date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
640
+ timeZone: 'America/New_York'
641
+ } as ZonedDate,
642
+ {
643
+ date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
644
+ timeZone: 'America/Sao_Paulo'
645
+ } as ZonedDate,
448
646
  new Date(2017, 3 - 1, 26, 11, 56, 32, 123),
647
+ new Date(new Date(2000, 3 - 1, 26, 11, 56, 32, 123).setFullYear(50)),
648
+ new Date(9999, 3 - 1, 26, 11, 56, 32, 123),
649
+ { date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)), timeZone: 'America/New_York' } as ZonedDate,
650
+ { date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)), timeZone: 'America/Sao_Paulo' } as ZonedDate,
449
651
  true,
450
652
  '123áé4567',
451
653
  '123áé4567',
@@ -476,10 +678,22 @@ export function runCommonTests(client: Client) {
476
678
  x_int_scale,
477
679
  x_bigint,
478
680
  x_bigint_scale,
681
+ x_int128,
682
+ x_int128_scale,
683
+ x_dec16,
684
+ x_dec34,
479
685
  x_double,
480
- x_date,
686
+ x_date1,
687
+ x_date2,
688
+ x_date3,
481
689
  x_time,
482
- x_timestamp,
690
+ x_time_tz1,
691
+ x_time_tz2,
692
+ x_timestamp1,
693
+ x_timestamp2,
694
+ x_timestamp3,
695
+ x_timestamp_tz1,
696
+ x_timestamp_tz2,
483
697
  x_boolean,
484
698
  x_varchar,
485
699
  char_length(x_varchar),
@@ -504,10 +718,22 @@ export function runCommonTests(client: Client) {
504
718
  expect(columns[n++]).toBe(-3.45);
505
719
  expect(columns[n++]).toBe(-2);
506
720
  expect(columns[n++]).toBe(-3.45);
721
+ expect(columns[n++]).toBe('-45699999999999999999999999999999999876');
722
+ expect(columns[n++]).toBe('-45699999999999999999999999999999999.87');
723
+ expect(columns[n++]).toBe('-456999999999876');
724
+ expect(columns[n++]).toBe('-456999999999999999999999999999.87');
507
725
  expect(columns[n++]).toBe(-4.567);
508
726
  expect(dateTimeToString(columns[n++])).toBe('2017-3-26 0:0:0.0');
727
+ expect(dateTimeToString(columns[n++])).toBe('0050-3-26 0:0:0.0');
728
+ expect(dateTimeToString(columns[n++])).toBe('9999-3-26 0:0:0.0');
509
729
  expect(timeToString(columns[n++])).toBe('11:56:32.123');
730
+ expect(timeTzToString(columns[n++])).toBe(`time '6:56:32.123 America/New_York'`);
731
+ expect(timeTzToString(columns[n++])).toBe(`time '8:56:32.123 America/Sao_Paulo'`);
510
732
  expect(dateTimeToString(columns[n++])).toBe('2017-3-26 11:56:32.123');
733
+ expect(dateTimeToString(columns[n++])).toBe('0050-3-26 11:56:32.123');
734
+ expect(dateTimeToString(columns[n++])).toBe('9999-3-26 11:56:32.123');
735
+ expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 7:56:32.123 America/New_York'`);
736
+ expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 8:56:32.123 America/Sao_Paulo'`);
511
737
  expect(columns[n++]).toBe(true);
512
738
  expect(columns[n++]).toBe('123áé4567');
513
739
  expect(columns[n++]).toBe(9);
@@ -520,6 +746,7 @@ export function runCommonTests(client: Client) {
520
746
 
521
747
  for (const i = n + 2; n < i; ++n) {
522
748
  const blob = columns[n] as Blob;
749
+ expect(blob.isValid).toBeTruthy();
523
750
  const blobStream = await attachment.openBlob(transaction, blob);
524
751
  const buffer = Buffer.alloc(await blobStream.length);
525
752
  expect(await blobStream.read(buffer)).toBe(buffer.length);