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
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../../src/lib/impl/transaction.ts"],"names":[],"mappings":";;;;;;;;;;;AAKA,0CAA0C;AAC1C,MAAsB,mBAAmB;IACxC,YAA6B,UAA+B;QAA/B,eAAU,GAAV,UAAU,CAAqB;IAC5D,CAAC;IAED,mDAAmD;IAC7C,MAAM;;YACX,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;YAE5B,IAAI,CAAC,UAAW,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC7B,CAAC;KAAA;IAED,yEAAyE;IACnE,eAAe;;YACpB,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,OAAO,MAAM,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC7C,CAAC;KAAA;IAED,qDAAqD;IAC/C,QAAQ;;YACb,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAE9B,IAAI,CAAC,UAAW,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC7B,CAAC;KAAA;IAED,2EAA2E;IACrE,iBAAiB;;YACtB,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,OAAO,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QAC/C,CAAC;KAAA;IAEO,KAAK;QACZ,IAAI,CAAC,IAAI,CAAC,UAAU;YACnB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;CAMD;AA/CD,kDA+CC"}
1
+ {"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../../src/lib/impl/transaction.ts"],"names":[],"mappings":";;;;;;;;;;;;AAKA,0CAA0C;AAC1C,MAAsB,mBAAmB;IACxC,YAA6B,UAA+B;QAA/B,eAAU,GAAV,UAAU,CAAqB;IAC5D,CAAC;IAED,mDAAmD;IAC7C,MAAM;;YACX,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;YAE5B,IAAI,CAAC,UAAW,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC7B,CAAC;KAAA;IAED,yEAAyE;IACnE,eAAe;;YACpB,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,OAAO,MAAM,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC7C,CAAC;KAAA;IAED,qDAAqD;IAC/C,QAAQ;;YACb,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAE9B,IAAI,CAAC,UAAW,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC7B,CAAC;KAAA;IAED,2EAA2E;IACrE,iBAAiB;;YACtB,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,OAAO,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QAC/C,CAAC;KAAA;IAED,IAAI,OAAO;QACV,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;IAC1B,CAAC;IAEO,KAAK;QACZ,IAAI,CAAC,IAAI,CAAC,OAAO;YAChB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;CAMD;AAnDD,kDAmDC"}
@@ -7,6 +7,8 @@ export interface Client {
7
7
  connect(uri: string, options?: ConnectOptions): Promise<Attachment>;
8
8
  /** Creates a database. */
9
9
  createDatabase(uri: string, options?: CreateDatabaseOptions): Promise<Attachment>;
10
+ /** True if the client has not been disposed. */
11
+ readonly isValid: boolean;
10
12
  /** Default connect options. */
11
13
  defaultConnectOptions?: ConnectOptions;
12
14
  /** Default create database options. */
@@ -91,11 +93,27 @@ export interface Attachment {
91
93
  executeOptions?: ExecuteOptions;
92
94
  }): Promise<void>;
93
95
  /** Executes a statement that returns a single record as [col1, col2, ..., colN]. */
94
- executeReturning(transaction: Transaction, sqlStmt: string, parameters?: any[], options?: {
96
+ executeSingleton(transaction: Transaction, sqlStmt: string, parameters?: any[], options?: {
95
97
  prepareOptions?: PrepareOptions;
96
98
  executeOptions?: ExecuteOptions;
97
99
  }): Promise<any[]>;
98
100
  /** Executes a statement that returns a single record as an object. */
101
+ executeSingletonAsObject<T extends object>(transaction: Transaction, sqlStmt: string, parameters?: any[], options?: {
102
+ prepareOptions?: PrepareOptions;
103
+ executeOptions?: ExecuteOptions;
104
+ }): Promise<T>;
105
+ /**
106
+ * Executes a statement that returns a single record as [col1, col2, ..., colN].
107
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingleton.
108
+ */
109
+ executeReturning(transaction: Transaction, sqlStmt: string, parameters?: any[], options?: {
110
+ prepareOptions?: PrepareOptions;
111
+ executeOptions?: ExecuteOptions;
112
+ }): Promise<any[]>;
113
+ /**
114
+ * Executes a statement that returns a single record as an object.
115
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingletonAsObject.
116
+ */
99
117
  executeReturningAsObject<T extends object>(transaction: Transaction, sqlStmt: string, parameters?: any[], options?: {
100
118
  prepareOptions?: PrepareOptions;
101
119
  executeOptions?: ExecuteOptions;
@@ -106,6 +124,8 @@ export interface Attachment {
106
124
  executeOptions?: ExecuteQueryOptions;
107
125
  }): Promise<ResultSet>;
108
126
  queueEvents(names: string[], callBack: (counters: [string, number][]) => Promise<void>): Promise<Events>;
127
+ /** True if the attachment is connected. */
128
+ readonly isValid: boolean;
109
129
  /** Default transaction options. */
110
130
  defaultTransactionOptions?: TransactionOptions;
111
131
  /** Default query's prepare options. */
@@ -127,6 +147,8 @@ export interface Transaction {
127
147
  rollback(): Promise<void>;
128
148
  /** Rollbacks and maintains this transaction object for subsequent work. */
129
149
  rollbackRetaining(): Promise<void>;
150
+ /** True if the transaction is active. */
151
+ readonly isValid: boolean;
130
152
  }
131
153
  /** Statement interface. */
132
154
  export interface Statement {
@@ -137,13 +159,34 @@ export interface Statement {
137
159
  /** Executes a prepared statement that has no result set. */
138
160
  execute(transaction: Transaction, parameters?: any[], options?: ExecuteOptions): Promise<void>;
139
161
  /** Executes a statement that returns a single record as [col1, col2, ..., colN]. */
140
- executeReturning(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<any[]>;
162
+ executeSingleton(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<any[]>;
141
163
  /** Executes a statement that returns a single record as an object. */
164
+ executeSingletonAsObject<T extends object>(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<T>;
165
+ /**
166
+ * Executes a statement that returns a single record as [col1, col2, ..., colN].
167
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingleton.
168
+ */
169
+ executeReturning(transaction: Transaction, parameters?: any[], executeOptions?: ExecuteOptions): Promise<any[]>;
170
+ /**
171
+ * Executes a statement that returns a single record as an object.
172
+ * @deprecated since version 2.4.0 and will be removed in next major version. Replaced by executeSingletonAsObject.
173
+ */
142
174
  executeReturningAsObject<T extends object>(transaction: Transaction, parameters?: any[], options?: ExecuteOptions): Promise<T>;
143
175
  /** Executes a prepared statement that has result set. */
144
176
  executeQuery(transaction: Transaction, parameters?: any[], options?: ExecuteQueryOptions): Promise<ResultSet>;
177
+ /**
178
+ * Set cursor name of a SELECT ... FOR UPDATE statement.
179
+ *
180
+ * Use with ResultSet.fetch({ fetchSize: 1 }) and other statement with WHERE CURRENT OF <cursorName>.
181
+ */
182
+ setCursorName(cursorName: string): Promise<void>;
183
+ getExecPathText(): Promise<string | undefined>;
184
+ /** True if the statement has not been disposed. */
185
+ readonly isValid: boolean;
145
186
  /** Gets the query's result columns labels. Returns empty array for queries without result. */
146
187
  readonly columnLabels: Promise<string[]>;
188
+ /** When true, query result must be obtained with method executeQuery. */
189
+ readonly hasResultSet: boolean;
147
190
  /** Default query's execute options. */
148
191
  defaultExecuteOptions?: ExecuteOptions;
149
192
  /** Default query's executeQuery options. */
@@ -172,11 +215,15 @@ export interface ResultSet {
172
215
  * If result set has no more rows, returns an empty array.
173
216
  */
174
217
  fetchAsObject<T extends object>(options?: FetchOptions): Promise<T[]>;
218
+ /** True if the ResultSet is open. */
219
+ readonly isValid: boolean;
175
220
  /** Default result set's fetch options. */
176
221
  defaultFetchOptions?: FetchOptions;
177
222
  }
178
223
  export interface Events {
179
224
  cancel(): Promise<void>;
225
+ /** True if the events' attachment is valid. */
226
+ readonly isValid: boolean;
180
227
  }
181
228
  /** Blob class. */
182
229
  export declare class Blob {
@@ -185,13 +232,15 @@ export declare class Blob {
185
232
  /** Gets the blob's id. */
186
233
  readonly id: Uint8Array;
187
234
  constructor(attachment: Attachment, id: Uint8Array);
235
+ /** True if the blob's attachment is valid. */
236
+ get isValid(): boolean;
188
237
  }
189
238
  /** BlobStream class. */
190
239
  export declare abstract class BlobStream {
191
240
  /** Gets the blob's. */
192
241
  readonly blob: Blob;
193
242
  /** Gets the blob's stream length in bytes. */
194
- readonly length: Promise<number>;
243
+ abstract get length(): Promise<number>;
195
244
  protected constructor(blob: Blob);
196
245
  /** Closes the blob's stream. */
197
246
  abstract close(): Promise<void>;
@@ -204,4 +253,15 @@ export declare abstract class BlobStream {
204
253
  abstract read(buffer: Buffer): Promise<number>;
205
254
  /** Writes data to the blob. */
206
255
  abstract write(buffer: Buffer): Promise<void>;
256
+ /** True if the blob stream is open. */
257
+ abstract get isValid(): boolean;
258
+ }
259
+ /** TIME WITH TIME ZONE and TIMESTAMP WITH TIME ZONE to be sent as parameter */
260
+ export interface ZonedDate {
261
+ date: Date;
262
+ timeZone: string;
263
+ }
264
+ /** TIME WITH TIME ZONE and TIMESTAMP WITH TIME ZONE returned by Firebird */
265
+ export interface ZonedDateEx extends ZonedDate {
266
+ offset: number;
207
267
  }
package/dist/lib/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BlobStream = exports.Blob = exports.TransactionIsolation = void 0;
3
4
  /** TransactionIsolation enum */
4
5
  var TransactionIsolation;
5
6
  (function (TransactionIsolation) {
@@ -15,6 +16,10 @@ class Blob {
15
16
  this.attachment = attachment;
16
17
  this.id.set(id);
17
18
  }
19
+ /** True if the blob's attachment is valid. */
20
+ get isValid() {
21
+ return this.attachment.isValid;
22
+ }
18
23
  }
19
24
  exports.Blob = Blob;
20
25
  /** BlobStream class. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":";;AAmDA,gCAAgC;AAChC,IAAY,oBAIX;AAJD,WAAY,oBAAoB;IAC/B,mDAA2B,CAAA;IAC3B,yDAAiC,CAAA;IACjC,6CAAqB,CAAA;AACtB,CAAC,EAJW,oBAAoB,GAApB,4BAAoB,KAApB,4BAAoB,QAI/B;AA0LD,kBAAkB;AAClB,MAAa,IAAI;IAOhB,YAAY,UAAsB,EAAE,EAAc;QAHlD,0BAA0B;QACjB,OAAE,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QAG/B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;CACD;AAXD,oBAWC;AAED,wBAAwB;AACxB,MAAsB,UAAU;IAO/B,YAAsB,IAAU;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;CAgBD;AAzBD,gCAyBC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":";;;AAsDA,gCAAgC;AAChC,IAAY,oBAIX;AAJD,WAAY,oBAAoB;IAC/B,mDAA2B,CAAA;IAC3B,yDAAiC,CAAA;IACjC,6CAAqB,CAAA;AACtB,CAAC,EAJW,oBAAoB,GAApB,4BAAoB,KAApB,4BAAoB,QAI/B;AAqPD,kBAAkB;AAClB,MAAa,IAAI;IAOhB,YAAY,UAAsB,EAAE,EAAc;QAHlD,0BAA0B;QACjB,OAAE,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QAG/B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,8CAA8C;IAC9C,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;IAChC,CAAC;CACD;AAhBD,oBAgBC;AAED,wBAAwB;AACxB,MAAsB,UAAU;IAO/B,YAAsB,IAAU;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;CAmBD;AA5BD,gCA4BC"}
@@ -9,20 +9,34 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.runCommonTests = void 0;
12
13
  const lib_1 = require("../lib");
13
14
  const fs = require("fs-extra-promise");
14
15
  const tmp = require("temp-fs");
15
16
  require('dotenv').config({ path: '../../.env' });
16
17
  function runCommonTests(client) {
17
18
  function dateToString(d) {
18
- return d && `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
19
+ return d && `${(d.getFullYear() + '').padStart(4, '0')}-${d.getMonth() + 1}-${d.getDate()}`;
19
20
  }
20
21
  function timeToString(d) {
21
22
  return d && `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`;
22
23
  }
24
+ function timeTzToString(zd) {
25
+ if (!zd)
26
+ return null;
27
+ const d = new Date(zd.date.getTime() + (zd.offset * 60 * 1000));
28
+ return `time '${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`;
29
+ }
23
30
  function dateTimeToString(d) {
24
31
  return d && `${dateToString(d)} ${timeToString(d)}`;
25
32
  }
33
+ function dateTimeTzToString(zd) {
34
+ if (!zd)
35
+ return null;
36
+ const d = new Date(zd.date.getTime() + (zd.offset * 60 * 1000));
37
+ return `timestamp '${(d.getUTCFullYear() + '').padStart(4, '0')}-${d.getUTCMonth() + 1}-${d.getUTCDate()} ` +
38
+ `${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`;
39
+ }
26
40
  describe('node-firebird-driver', () => {
27
41
  const testConfig = {
28
42
  username: process.env.ISC_USER,
@@ -39,13 +53,14 @@ function runCommonTests(client) {
39
53
  function getTempFile(name) {
40
54
  var _a;
41
55
  const database = `${testConfig.tmpDir}/${name}`;
42
- return (_a = testConfig.host, (_a !== null && _a !== void 0 ? _a : '')) +
56
+ return ((_a = testConfig.host) !== null && _a !== void 0 ? _a : '') +
43
57
  (testConfig.host && testConfig.port ? `/${testConfig.port}` : '') +
44
58
  (testConfig.host ? ':' : '') +
45
59
  database;
46
60
  }
47
61
  jest.setTimeout(10000);
48
62
  beforeAll(() => {
63
+ expect(client.isValid).toBeTruthy();
49
64
  if (isLocal() && !testConfig.tmpDir) {
50
65
  testConfig.tmpDir = tmp.mkdirSync().path.toString();
51
66
  // Important for MacOS tests with non-embedded server.
@@ -60,6 +75,7 @@ function runCommonTests(client) {
60
75
  });
61
76
  afterAll(() => __awaiter(this, void 0, void 0, function* () {
62
77
  yield client.dispose();
78
+ expect(client.isValid).toBeFalsy();
63
79
  if (isLocal())
64
80
  fs.rmdirSync(testConfig.tmpDir);
65
81
  }));
@@ -72,8 +88,12 @@ function runCommonTests(client) {
72
88
  const filename = getTempFile('Client-connect.fdb');
73
89
  const attachment1 = yield client.createDatabase(filename);
74
90
  const attachment2 = yield client.connect(filename);
91
+ expect(attachment1.isValid).toBeTruthy();
92
+ expect(attachment2.isValid).toBeTruthy();
75
93
  yield attachment2.disconnect();
76
94
  yield attachment1.dropDatabase();
95
+ expect(attachment1.isValid).toBeFalsy();
96
+ expect(attachment2.isValid).toBeFalsy();
77
97
  }));
78
98
  });
79
99
  describe('Attachment', () => {
@@ -81,21 +101,29 @@ function runCommonTests(client) {
81
101
  const attachment = yield client.createDatabase(getTempFile('Attachment-startTransaction.fdb'));
82
102
  const isolationQuery = 'select rdb$get_context(\'SYSTEM\', \'ISOLATION_LEVEL\') from rdb$database';
83
103
  const transaction1 = yield attachment.startTransaction();
84
- expect((yield attachment.executeReturning(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
104
+ expect(transaction1.isValid).toBeTruthy();
105
+ expect((yield attachment.executeSingleton(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
85
106
  yield transaction1.commit();
107
+ expect(transaction1.isValid).toBeFalsy();
86
108
  const transaction2 = yield attachment.startTransaction({ isolation: lib_1.TransactionIsolation.READ_COMMITTED });
87
- expect((yield attachment.executeReturning(transaction2, isolationQuery))[0]).toBe('READ COMMITTED');
109
+ expect(transaction2.isValid).toBeTruthy();
110
+ expect((yield attachment.executeSingleton(transaction2, isolationQuery))[0]).toBe('READ COMMITTED');
88
111
  yield transaction2.commit();
112
+ expect(transaction2.isValid).toBeFalsy();
89
113
  const transaction3 = yield attachment.startTransaction({ isolation: lib_1.TransactionIsolation.CONSISTENCY });
90
- expect((yield attachment.executeReturning(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
114
+ expect(transaction3.isValid).toBeTruthy();
115
+ expect((yield attachment.executeSingleton(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
91
116
  yield transaction3.commit();
117
+ expect(transaction3.isValid).toBeFalsy();
92
118
  yield attachment.dropDatabase();
93
119
  }));
94
120
  test('#prepare()', () => __awaiter(this, void 0, void 0, function* () {
95
121
  const attachment = yield client.createDatabase(getTempFile('Attachment-prepare.fdb'));
96
122
  const transaction = yield attachment.startTransaction();
97
123
  const statement = yield attachment.prepare(transaction, 'create table t1 (n1 integer)');
124
+ expect(statement.isValid).toBeTruthy();
98
125
  yield statement.dispose();
126
+ expect(statement.isValid).toBeFalsy();
99
127
  let error;
100
128
  try {
101
129
  yield attachment.prepare(transaction, 'create select t1 (n1 integer)');
@@ -127,7 +155,30 @@ function runCommonTests(client) {
127
155
  yield attachment.execute(transaction, 'create table t1 (n1 integer)');
128
156
  yield transaction.commitRetaining();
129
157
  const resultSet = yield attachment.executeQuery(transaction, 'select n1 from t1');
158
+ expect(resultSet.isValid).toBeTruthy();
130
159
  yield resultSet.close();
160
+ expect(resultSet.isValid).toBeFalsy();
161
+ yield transaction.commit();
162
+ yield attachment.dropDatabase();
163
+ }));
164
+ test('#executeSingleton()', () => __awaiter(this, void 0, void 0, function* () {
165
+ const attachment = yield client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
166
+ const transaction = yield attachment.startTransaction();
167
+ yield attachment.execute(transaction, 'create table t1 (n1 integer)');
168
+ yield transaction.commitRetaining();
169
+ const result = yield attachment.executeSingleton(transaction, 'insert into t1 values (11) returning n1');
170
+ expect(result.length).toBe(1);
171
+ expect(result[0]).toBe(11);
172
+ yield transaction.commit();
173
+ yield attachment.dropDatabase();
174
+ }));
175
+ test('#executeSingletonAsObject()', () => __awaiter(this, void 0, void 0, function* () {
176
+ const attachment = yield client.createDatabase(getTempFile('Attachment-executeSingletonAsObject.fdb'));
177
+ const transaction = yield attachment.startTransaction();
178
+ yield attachment.execute(transaction, 'create table t1 (n1 integer)');
179
+ yield transaction.commitRetaining();
180
+ const output = yield attachment.executeSingletonAsObject(transaction, 'insert into t1 values (11) returning n1');
181
+ expect(output.N1).toBe(11);
131
182
  yield transaction.commit();
132
183
  yield attachment.dropDatabase();
133
184
  }));
@@ -180,6 +231,7 @@ function runCommonTests(client) {
180
231
  if (Array.from(eventsMap.values()).every(obj => obj.count >= obj.expected)) {
181
232
  if (events) {
182
233
  yield events.cancel();
234
+ expect(events.isValid).toBeFalsy();
183
235
  events = null;
184
236
  }
185
237
  }
@@ -202,10 +254,12 @@ function runCommonTests(client) {
202
254
  // Commit retaining to test internal event rescheduling
203
255
  // after each handler dispatch.
204
256
  yield transaction.commitRetaining();
257
+ expect(transaction.isValid).toBeTruthy();
205
258
  }
206
259
  }
207
260
  finally {
208
261
  yield transaction.commit();
262
+ expect(transaction.isValid).toBeFalsy();
209
263
  }
210
264
  yield Promise.all(eventsObj.map(ev => ev.promise));
211
265
  if (events)
@@ -255,9 +309,18 @@ function runCommonTests(client) {
255
309
  yield statement1.execute(transaction);
256
310
  yield statement1.dispose();
257
311
  yield transaction.commitRetaining();
258
- const statement2 = yield attachment.prepare(transaction, 'insert into t1 (n1) values (1)');
259
- yield statement2.execute(transaction);
312
+ const statement2 = yield attachment.prepare(transaction, 'insert into t1 (n1) values (?)');
313
+ yield statement2.execute(transaction, [1]);
314
+ yield statement2.execute(transaction, [null]);
315
+ yield statement2.execute(transaction, [10]);
316
+ yield statement2.execute(transaction, [100]);
317
+ expect(statement2.isValid).toBeTruthy();
260
318
  yield statement2.dispose();
319
+ expect(statement2.isValid).toBeFalsy();
320
+ const rs = yield attachment.executeQuery(transaction, `select sum(n1) || ', ' || count(n1) || ', ' || count(*) ret from t1`);
321
+ const ret = yield rs.fetchAsObject();
322
+ yield rs.close();
323
+ expect(ret[0].RET).toStrictEqual('111, 3, 4');
261
324
  yield transaction.commit();
262
325
  yield attachment.dropDatabase();
263
326
  }));
@@ -275,6 +338,20 @@ function runCommonTests(client) {
275
338
  yield transaction.commit();
276
339
  yield attachment.dropDatabase();
277
340
  }));
341
+ test('#executeSingleton()', () => __awaiter(this, void 0, void 0, function* () {
342
+ const attachment = yield client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
343
+ const transaction = yield attachment.startTransaction();
344
+ yield attachment.execute(transaction, 'create table t1 (n1 integer)');
345
+ yield transaction.commitRetaining();
346
+ const statement = yield attachment.prepare(transaction, 'insert into t1 values (11) returning n1, n1 * 2');
347
+ const result = yield statement.executeSingleton(transaction);
348
+ expect(result.length).toBe(2);
349
+ expect(result[0]).toBe(11);
350
+ expect(result[1]).toBe(11 * 2);
351
+ yield statement.dispose();
352
+ yield transaction.commit();
353
+ yield attachment.dropDatabase();
354
+ }));
278
355
  test('#executeReturning()', () => __awaiter(this, void 0, void 0, function* () {
279
356
  const attachment = yield client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
280
357
  const transaction = yield attachment.startTransaction();
@@ -303,6 +380,35 @@ function runCommonTests(client) {
303
380
  yield transaction.commit();
304
381
  yield attachment.dropDatabase();
305
382
  }));
383
+ test('#hasResultSet()', () => __awaiter(this, void 0, void 0, function* () {
384
+ const attachment = yield client.createDatabase(getTempFile('Statement-hasResultSet.fdb'));
385
+ const transaction = yield attachment.startTransaction();
386
+ const statement1 = yield attachment.prepare(transaction, 'create table t1 (n1 integer)');
387
+ expect(statement1.hasResultSet).toBe(false);
388
+ yield statement1.execute(transaction);
389
+ yield statement1.dispose();
390
+ yield transaction.commitRetaining();
391
+ const statement2 = yield attachment.prepare(transaction, 'insert into t1 values (1)');
392
+ expect(statement2.hasResultSet).toBe(false);
393
+ yield statement2.dispose();
394
+ const statement3 = yield attachment.prepare(transaction, 'insert into t1 values (1) returning *');
395
+ expect(statement3.hasResultSet).toBe(false);
396
+ yield statement3.dispose();
397
+ const statement4 = yield attachment.prepare(transaction, 'execute block as begin end');
398
+ expect(statement4.hasResultSet).toBe(false);
399
+ yield statement4.dispose();
400
+ const statement5 = yield attachment.prepare(transaction, 'select * from t1');
401
+ expect(statement5.hasResultSet).toBe(true);
402
+ yield statement5.dispose();
403
+ const statement6 = yield attachment.prepare(transaction, 'execute block returns (n integer) as begin suspend; end');
404
+ expect(statement6.hasResultSet).toBe(true);
405
+ yield statement6.dispose();
406
+ const statement7 = yield attachment.prepare(transaction, 'execute block returns (n integer) as begin end');
407
+ expect(statement7.hasResultSet).toBe(true);
408
+ yield statement7.dispose();
409
+ yield transaction.commit();
410
+ yield attachment.dropDatabase();
411
+ }));
306
412
  });
307
413
  describe('ResultSet', () => {
308
414
  test('#fetch()', () => __awaiter(this, void 0, void 0, function* () {
@@ -315,10 +421,38 @@ function runCommonTests(client) {
315
421
  { name: 'x_int_scale', type: 'numeric(5, 2)', valToStr: (v) => v },
316
422
  { name: 'x_bigint', type: 'bigint', valToStr: (v) => v },
317
423
  { name: 'x_bigint_scale', type: 'numeric(15, 2)', valToStr: (v) => v },
424
+ { name: 'x_int128', type: 'int128', valToStr: (v) => v },
425
+ { name: 'x_int128_scale', type: 'numeric(20, 2)', valToStr: (v) => v },
426
+ { name: 'x_dec16', type: 'decfloat(16)', valToStr: (v) => v },
427
+ { name: 'x_dec34', type: 'decfloat(34)', valToStr: (v) => v },
318
428
  { name: 'x_double', type: 'double precision', valToStr: (v) => v },
319
- { name: 'x_date', type: 'date', valToStr: (v) => `date '${dateToString(v)}'` },
429
+ { name: 'x_date1', type: 'date', valToStr: (v) => `date '${dateToString(v)}'` },
430
+ { name: 'x_date2', type: 'date', valToStr: (v) => `date '${dateToString(v)}'` },
431
+ { name: 'x_date3', type: 'date', valToStr: (v) => `date '${dateToString(v)}'` },
320
432
  { name: 'x_time', type: 'time', valToStr: (v) => `time '${timeToString(v)}'` },
321
- { name: 'x_timestamp', type: 'timestamp', valToStr: (v) => `timestamp '${dateTimeToString(v)}'` },
433
+ {
434
+ name: 'x_time_tz1',
435
+ type: 'time with time zone',
436
+ valToStr: (v) => `${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
437
+ },
438
+ {
439
+ name: 'x_time_tz2',
440
+ type: 'time with time zone',
441
+ valToStr: (v) => `${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
442
+ },
443
+ { name: 'x_timestamp1', type: 'timestamp', valToStr: (v) => `timestamp '${dateTimeToString(v)}'` },
444
+ { name: 'x_timestamp2', type: 'timestamp', valToStr: (v) => `timestamp '${dateTimeToString(v)}'` },
445
+ { name: 'x_timestamp3', type: 'timestamp', valToStr: (v) => `timestamp '${dateTimeToString(v)}'` },
446
+ {
447
+ name: 'x_timestamp_tz1',
448
+ type: 'timestamp with time zone',
449
+ valToStr: (v) => `${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
450
+ },
451
+ {
452
+ name: 'x_timestamp_tz2',
453
+ type: 'timestamp with time zone',
454
+ valToStr: (v) => `${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
455
+ },
322
456
  { name: 'x_boolean', type: 'boolean', valToStr: (v) => v },
323
457
  { name: 'x_varchar', type: 'varchar(10) character set utf8', valToStr: (v) => `'${v}'` },
324
458
  { name: 'x_char', type: 'char(10) character set utf8', valToStr: (v) => `'${v}'` },
@@ -330,7 +464,6 @@ function runCommonTests(client) {
330
464
  yield statement1.dispose();
331
465
  yield transaction.commitRetaining();
332
466
  const recordCount = 5;
333
- const now = new Date();
334
467
  let parameters;
335
468
  { // scope
336
469
  const statement2a = yield attachment.prepare(transaction, `insert into t1 (${fields.map(f => f.name).join(', ')}) values (${fields.map(() => '?').join(', ')})`);
@@ -338,18 +471,39 @@ function runCommonTests(client) {
338
471
  yield transaction.commit();
339
472
  transaction = yield attachment.startTransaction();
340
473
  const blob = yield attachment.createBlob(transaction);
474
+ expect(blob.isValid).toBeTruthy();
341
475
  yield blob.write(blobBuffer);
476
+ expect(blob.isValid).toBeTruthy();
342
477
  yield blob.close();
478
+ expect(blob.isValid).toBeFalsy();
343
479
  parameters = [
344
480
  -1,
345
481
  -2,
346
482
  -3.45,
347
483
  -2,
348
484
  -3.45,
485
+ '-45699999999999999999999999999999999876',
486
+ '-45699999999999999999999999999999999.87',
487
+ '-456999999999876',
488
+ '-456999999999999999999999999999.87',
349
489
  -4.567,
350
490
  new Date(2017, 3 - 1, 26),
351
- new Date(now.getFullYear(), now.getMonth(), now.getDate(), 11, 56, 32, 123),
491
+ new Date(new Date(2000, 3 - 1, 26).setFullYear(50)),
492
+ new Date(9999, 3 - 1, 26),
493
+ new Date(2020, 1 - 1, 1, 11, 56, 32, 123),
494
+ {
495
+ date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
496
+ timeZone: 'America/New_York'
497
+ },
498
+ {
499
+ date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
500
+ timeZone: 'America/Sao_Paulo'
501
+ },
352
502
  new Date(2017, 3 - 1, 26, 11, 56, 32, 123),
503
+ new Date(new Date(2000, 3 - 1, 26, 11, 56, 32, 123).setFullYear(50)),
504
+ new Date(9999, 3 - 1, 26, 11, 56, 32, 123),
505
+ { date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)), timeZone: 'America/New_York' },
506
+ { date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)), timeZone: 'America/Sao_Paulo' },
353
507
  true,
354
508
  '123áé4567',
355
509
  '123áé4567',
@@ -373,10 +527,22 @@ function runCommonTests(client) {
373
527
  x_int_scale,
374
528
  x_bigint,
375
529
  x_bigint_scale,
530
+ x_int128,
531
+ x_int128_scale,
532
+ x_dec16,
533
+ x_dec34,
376
534
  x_double,
377
- x_date,
535
+ x_date1,
536
+ x_date2,
537
+ x_date3,
378
538
  x_time,
379
- x_timestamp,
539
+ x_time_tz1,
540
+ x_time_tz2,
541
+ x_timestamp1,
542
+ x_timestamp2,
543
+ x_timestamp3,
544
+ x_timestamp_tz1,
545
+ x_timestamp_tz2,
380
546
  x_boolean,
381
547
  x_varchar,
382
548
  char_length(x_varchar),
@@ -399,10 +565,22 @@ function runCommonTests(client) {
399
565
  expect(columns[n++]).toBe(-3.45);
400
566
  expect(columns[n++]).toBe(-2);
401
567
  expect(columns[n++]).toBe(-3.45);
568
+ expect(columns[n++]).toBe('-45699999999999999999999999999999999876');
569
+ expect(columns[n++]).toBe('-45699999999999999999999999999999999.87');
570
+ expect(columns[n++]).toBe('-456999999999876');
571
+ expect(columns[n++]).toBe('-456999999999999999999999999999.87');
402
572
  expect(columns[n++]).toBe(-4.567);
403
573
  expect(dateTimeToString(columns[n++])).toBe('2017-3-26 0:0:0.0');
574
+ expect(dateTimeToString(columns[n++])).toBe('0050-3-26 0:0:0.0');
575
+ expect(dateTimeToString(columns[n++])).toBe('9999-3-26 0:0:0.0');
404
576
  expect(timeToString(columns[n++])).toBe('11:56:32.123');
577
+ expect(timeTzToString(columns[n++])).toBe(`time '6:56:32.123 America/New_York'`);
578
+ expect(timeTzToString(columns[n++])).toBe(`time '8:56:32.123 America/Sao_Paulo'`);
405
579
  expect(dateTimeToString(columns[n++])).toBe('2017-3-26 11:56:32.123');
580
+ expect(dateTimeToString(columns[n++])).toBe('0050-3-26 11:56:32.123');
581
+ expect(dateTimeToString(columns[n++])).toBe('9999-3-26 11:56:32.123');
582
+ expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 7:56:32.123 America/New_York'`);
583
+ expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 8:56:32.123 America/Sao_Paulo'`);
406
584
  expect(columns[n++]).toBe(true);
407
585
  expect(columns[n++]).toBe('123áé4567');
408
586
  expect(columns[n++]).toBe(9);
@@ -414,6 +592,7 @@ function runCommonTests(client) {
414
592
  expect(columns[n++]).toBeNull();
415
593
  for (const i = n + 2; n < i; ++n) {
416
594
  const blob = columns[n];
595
+ expect(blob.isValid).toBeTruthy();
417
596
  const blobStream = yield attachment.openBlob(transaction, blob);
418
597
  const buffer = Buffer.alloc(yield blobStream.length);
419
598
  expect(yield blobStream.read(buffer)).toBe(buffer.length);