node-firebird-driver 3.2.2 → 3.3.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 (41) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/impl/attachment.d.ts +4 -4
  3. package/dist/lib/impl/attachment.js +8 -6
  4. package/dist/lib/impl/attachment.js.map +1 -1
  5. package/dist/lib/impl/blob.js.map +1 -1
  6. package/dist/lib/impl/client.js +3 -2
  7. package/dist/lib/impl/client.js.map +1 -1
  8. package/dist/lib/impl/date-time.js +2 -1
  9. package/dist/lib/impl/date-time.js.map +1 -1
  10. package/dist/lib/impl/events.js +2 -1
  11. package/dist/lib/impl/events.js.map +1 -1
  12. package/dist/lib/impl/fb-util.d.ts +2 -1
  13. package/dist/lib/impl/fb-util.js +100 -81
  14. package/dist/lib/impl/fb-util.js.map +1 -1
  15. package/dist/lib/impl/resultset.js +11 -5
  16. package/dist/lib/impl/resultset.js.map +1 -1
  17. package/dist/lib/impl/statement.js +4 -2
  18. package/dist/lib/impl/statement.js.map +1 -1
  19. package/dist/lib/impl/time-zones.js +5 -3
  20. package/dist/lib/impl/time-zones.js.map +1 -1
  21. package/dist/lib/impl/transaction.js +2 -1
  22. package/dist/lib/impl/transaction.js.map +1 -1
  23. package/dist/lib/index.d.ts +8 -1
  24. package/dist/lib/index.js +7 -1
  25. package/dist/lib/index.js.map +1 -1
  26. package/dist/test/tests.js +176 -68
  27. package/dist/test/tests.js.map +1 -1
  28. package/package.json +6 -5
  29. package/src/lib/impl/attachment.ts +290 -253
  30. package/src/lib/impl/blob.ts +37 -35
  31. package/src/lib/impl/client.ts +60 -61
  32. package/src/lib/impl/date-time.ts +33 -33
  33. package/src/lib/impl/events.ts +17 -18
  34. package/src/lib/impl/fb-util.ts +552 -448
  35. package/src/lib/impl/resultset.ts +94 -86
  36. package/src/lib/impl/statement.ts +154 -127
  37. package/src/lib/impl/time-zones.ts +643 -641
  38. package/src/lib/impl/transaction.ts +37 -38
  39. package/src/lib/index.ts +325 -285
  40. package/src/test/tests.ts +996 -860
  41. package/tsconfig.json +7 -13
package/src/test/tests.ts CHANGED
@@ -1,330 +1,369 @@
1
1
  import {
2
- Blob,
3
- BlobSeekWhence,
4
- Client,
5
- TransactionIsolation,
6
- ZonedDate,
7
- ZonedDateEx
2
+ Blob,
3
+ BlobSeekWhence,
4
+ Client,
5
+ DatabaseReadWriteMode,
6
+ TransactionIsolation,
7
+ ZonedDate,
8
+ ZonedDateEx,
8
9
  } from '../lib';
9
10
 
10
11
  import * as fs from 'fs-extra-promise';
11
12
  import * as tmp from 'temp-fs';
12
13
 
13
-
14
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
14
15
  require('dotenv').config({ path: '../../.env' });
15
16
 
16
-
17
17
  export function runCommonTests(client: Client) {
18
- function dateToString(d: Date) {
19
- return d && `${(d.getFullYear() + '').padStart(4, '0')}-${d.getMonth() + 1}-${d.getDate()}`;
20
- }
21
-
22
- function timeToString(d: Date) {
23
- return d && `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`;
24
- }
25
-
26
- function timeTzToString(zd: ZonedDateEx) {
27
- if (!zd)
28
- return null;
29
-
30
- const d = new Date(zd.date.getTime() + (zd.offset * 60 * 1000));
31
-
32
- return `time '${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`;
33
- }
34
-
35
- function dateTimeToString(d: Date) {
36
- return d && `${dateToString(d)} ${timeToString(d)}`;
37
- }
38
-
39
- function dateTimeTzToString(zd: ZonedDateEx) {
40
- if (!zd)
41
- return null;
42
-
43
- const d = new Date(zd.date.getTime() + (zd.offset * 60 * 1000));
44
-
45
- return `timestamp '${(d.getUTCFullYear() + '').padStart(4, '0')}-${d.getUTCMonth() + 1}-${d.getUTCDate()} ` +
46
- `${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`;
47
- }
48
-
49
-
50
- describe('node-firebird-driver', () => {
51
- const testConfig = {
52
- username: process.env.ISC_USER,
53
- password: process.env.ISC_PASSWORD,
54
- host: process.env.NODE_FB_TEST_HOST,
55
- port: process.env.NODE_FB_TEST_PORT,
56
- tmpDir: process.env.NODE_FB_TEST_TMP_DIR
57
- };
58
-
59
- function isLocal(): boolean {
60
- return testConfig.host == undefined ||
61
- testConfig.host == 'localhost' ||
62
- testConfig.host == '127.0.0.1';
63
- }
64
-
65
- function getTempFile(name: string): string {
66
- const database = `${testConfig.tmpDir}/${name}`;
67
- return (testConfig.host ?? '') +
68
- (testConfig.host && testConfig.port ? `/${testConfig.port}` : '') +
69
- (testConfig.host ? ':' : '') +
70
- database;
71
- }
72
-
73
-
74
- jest.setTimeout(10000);
75
-
76
-
77
- beforeAll(() => {
78
- expect(client.isValid).toBeTruthy();
79
-
80
- if (isLocal() && !testConfig.tmpDir) {
81
- testConfig.tmpDir = tmp.mkdirSync().path.toString();
82
-
83
- // Important for MacOS tests with non-embedded server.
84
- fs.chmodSync(testConfig.tmpDir, 0o777);
85
- }
86
-
87
- const defaultOptions = {
88
- password: testConfig.password,
89
- username: testConfig.username
90
- };
91
-
92
- client.defaultCreateDatabaseOptions = {
93
- forcedWrite: false,
94
- ...defaultOptions
95
- };
96
-
97
- client.defaultConnectOptions = {
98
- ...defaultOptions
99
- };
100
- });
101
-
102
- afterAll(async () => {
103
- await client.dispose();
104
-
105
- expect(client.isValid).toBeFalsy();
106
-
107
- if (isLocal())
108
- fs.rmdirSync(testConfig.tmpDir!);
109
- });
110
-
111
- describe('Client', () => {
112
- test('#createDatabase()', async () => {
113
- const attachment = await client.createDatabase(getTempFile('Client-createDatabase.fdb'));
114
- await attachment.dropDatabase();
115
- });
116
-
117
- test('#connect()', async () => {
118
- const filename = getTempFile('Client-connect.fdb');
119
- const attachment1 = await client.createDatabase(filename);
120
- const attachment2 = await client.connect(filename);
121
-
122
- expect(attachment1.isValid).toBeTruthy();
123
- expect(attachment2.isValid).toBeTruthy();
124
-
125
- await attachment2.disconnect();
126
- await attachment1.dropDatabase();
127
-
128
- expect(attachment1.isValid).toBeFalsy();
129
- expect(attachment2.isValid).toBeFalsy();
130
- });
131
- });
132
-
133
- describe('Attachment', () => {
134
- test('#startTransaction()', async () => {
135
- const attachment = await client.createDatabase(getTempFile('Attachment-startTransaction.fdb'));
136
-
137
- const isolationQuery = 'select rdb$get_context(\'SYSTEM\', \'ISOLATION_LEVEL\') from rdb$database';
138
-
139
- const transaction1 = await attachment.startTransaction();
140
- expect(transaction1.isValid).toBeTruthy()
141
- expect((await attachment.executeSingleton(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
142
- await transaction1.commit();
143
- expect(transaction1.isValid).toBeFalsy()
144
-
145
- const transaction2 = await attachment.startTransaction({ isolation: TransactionIsolation.READ_COMMITTED });
146
- expect(transaction2.isValid).toBeTruthy()
147
- expect((await attachment.executeSingleton(transaction2, isolationQuery))[0]).toBe('READ COMMITTED');
148
- await transaction2.commit();
149
- expect(transaction2.isValid).toBeFalsy()
150
-
151
- const transaction3 = await attachment.startTransaction({ isolation: TransactionIsolation.CONSISTENCY });
152
- expect(transaction3.isValid).toBeTruthy()
153
- expect((await attachment.executeSingleton(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
154
- await transaction3.commit();
155
- expect(transaction3.isValid).toBeFalsy()
156
-
157
- await attachment.dropDatabase();
158
- });
159
-
160
- test('#prepare()', async () => {
161
- const attachment = await client.createDatabase(getTempFile('Attachment-prepare.fdb'));
162
- const transaction = await attachment.startTransaction();
163
-
164
- const statement = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
165
- expect(statement.isValid).toBeTruthy();
166
- await statement.dispose();
167
- expect(statement.isValid).toBeFalsy();
168
-
169
- let error: Error | undefined;
170
- try {
171
- await attachment.prepare(transaction, 'create select t1 (n1 integer)');
172
- }
173
- catch (e) {
174
- error = e as Error;
175
- expect(error.message).toBe(
176
- 'Dynamic SQL Error\n' +
177
- '-SQL error code = -104\n' +
178
- '-Token unknown - line 1, column 8\n' +
179
- '-select');
180
- }
181
-
182
- expect(error).toBeTruthy();
183
-
184
- await transaction.commit();
185
- await attachment.dropDatabase();
186
- });
187
-
188
- //// TODO: #executeTransaction
189
-
190
- test('#execute()', async () => {
191
- const attachment = await client.createDatabase(getTempFile('Attachment-execute.fdb'));
192
- const transaction = await attachment.startTransaction();
193
-
194
- await attachment.execute(transaction, 'create table t1 (n1 integer)');
195
- await transaction.commitRetaining();
196
-
197
- await attachment.execute(transaction, 'insert into t1 (n1) values (1)');
198
-
199
- await transaction.commit();
200
- await attachment.dropDatabase();
201
- });
202
-
203
- test('#executeQuery()', async () => {
204
- const attachment = await client.createDatabase(getTempFile('Attachment-executeQuery.fdb'));
205
- const transaction = await attachment.startTransaction();
206
-
207
- await attachment.execute(transaction, 'create table t1 (n1 integer)');
208
- await transaction.commitRetaining();
209
-
210
- const resultSet = await attachment.executeQuery(transaction, 'select n1 from t1');
211
- expect(resultSet.isValid).toBeTruthy();
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);
244
-
245
- await transaction.commit();
246
- await attachment.dropDatabase();
247
- });
248
-
249
- test('#executeReturning()', async () => {
250
- const attachment = await client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
251
- const transaction = await attachment.startTransaction();
252
-
253
- await attachment.execute(transaction, 'create table t1 (n1 integer)');
254
- await transaction.commitRetaining();
255
-
256
- const result = await attachment.executeReturning(transaction, 'insert into t1 values (11) returning n1');
257
- expect(result.length).toBe(1);
258
- expect(result[0]).toBe(11);
259
-
260
- await transaction.commit();
261
- await attachment.dropDatabase();
262
- });
263
-
264
- test('#executeReturningAsObject()', async () => {
265
- const attachment = await client.createDatabase(getTempFile('Attachment-executeReturningAsObject.fdb'));
266
- const transaction = await attachment.startTransaction();
267
-
268
- await attachment.execute(transaction, 'create table t1 (n1 integer)');
269
- await transaction.commitRetaining();
270
-
271
- const output = await attachment.executeReturningAsObject<{ N1: number }>(transaction,
272
- 'insert into t1 values (11) returning n1');
273
- expect(output.N1).toBe(11);
274
-
275
- await transaction.commit();
276
- await attachment.dropDatabase();
277
- });
278
-
279
- test('#queueEvents()', async () => {
280
- const attachment = await client.createDatabase(getTempFile('Attachment-queueEvents.fdb'));
281
-
282
- const eventNames: [string, number][] = [
283
- ['EVENT1', 16],
284
- ['EVENT2', 8]
285
- ];
286
-
287
- const eventsObj = eventNames.map(([name, expected]) => {
288
- let resolver: () => void = undefined!;
289
-
290
- const obj = {
291
- name,
292
- expected,
293
- count: 0,
294
- promise: new Promise<void>(resolve => resolver = resolve)
295
- };
296
-
297
- return { ...obj, resolver };
298
- });
299
- const eventsMap = new Map(eventsObj.map(ev => [ev.name, ev]));
300
-
301
- const eventHandler = async (counters: [string, number][]) => {
302
- counters.forEach(([name, count]) => {
303
- const obj = eventsMap.get(name)!;
304
- const newCount = obj.count + count;
305
- obj.count = newCount;
306
-
307
- if (newCount >= obj.expected)
308
- obj.resolver();
309
- });
310
-
311
- if (Array.from(eventsMap.values()).every(obj => obj.count >= obj.expected)) {
312
- if (events) {
313
- await events.cancel();
314
- expect(events.isValid).toBeFalsy();
315
- events = null!;
316
- }
317
- }
318
- };
319
-
320
- let events = await attachment.queueEvents(Array.from(eventsMap.keys()), eventHandler);
321
-
322
- const transaction = await attachment.startTransaction();
323
- try {
324
- // Iterate more times than the neccessary so that
325
- // eventHandler may have a chance to cancel the events.
326
- for (let i = 0; i < 20; ++i) {
327
- await attachment.execute(transaction, `
18
+ function dateToString(d: Date) {
19
+ return d && `${(d.getFullYear() + '').padStart(4, '0')}-${d.getMonth() + 1}-${d.getDate()}`;
20
+ }
21
+
22
+ function timeToString(d: Date) {
23
+ return d && `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`;
24
+ }
25
+
26
+ function timeTzToString(zd: ZonedDateEx) {
27
+ if (!zd) {
28
+ return null;
29
+ }
30
+
31
+ const d = new Date(zd.date.getTime() + zd.offset * 60 * 1000);
32
+
33
+ return `time '${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`;
34
+ }
35
+
36
+ function dateTimeToString(d: Date) {
37
+ return d && `${dateToString(d)} ${timeToString(d)}`;
38
+ }
39
+
40
+ function dateTimeTzToString(zd: ZonedDateEx) {
41
+ if (!zd) {
42
+ return null;
43
+ }
44
+
45
+ const d = new Date(zd.date.getTime() + zd.offset * 60 * 1000);
46
+
47
+ return (
48
+ `timestamp '${(d.getUTCFullYear() + '').padStart(4, '0')}-${d.getUTCMonth() + 1}-${d.getUTCDate()} ` +
49
+ `${d.getUTCHours()}:${d.getUTCMinutes()}:${d.getUTCSeconds()}.${d.getUTCMilliseconds()} ${zd.timeZone}'`
50
+ );
51
+ }
52
+
53
+ describe('node-firebird-driver', () => {
54
+ const testConfig = {
55
+ username: process.env.ISC_USER,
56
+ password: process.env.ISC_PASSWORD,
57
+ host: process.env.NODE_FB_TEST_HOST,
58
+ port: process.env.NODE_FB_TEST_PORT,
59
+ tmpDir: process.env.NODE_FB_TEST_TMP_DIR,
60
+ };
61
+
62
+ function isLocal(): boolean {
63
+ return testConfig.host == undefined || testConfig.host == 'localhost' || testConfig.host == '127.0.0.1';
64
+ }
65
+
66
+ function getTempFile(name: string): string {
67
+ const database = `${testConfig.tmpDir}/${name}`;
68
+ return (
69
+ (testConfig.host ?? '') +
70
+ (testConfig.host && testConfig.port ? `/${testConfig.port}` : '') +
71
+ (testConfig.host ? ':' : '') +
72
+ database
73
+ );
74
+ }
75
+
76
+ jest.setTimeout(10000);
77
+
78
+ beforeAll(() => {
79
+ expect(client.isValid).toBeTruthy();
80
+
81
+ if (isLocal() && !testConfig.tmpDir) {
82
+ testConfig.tmpDir = tmp.mkdirSync().path.toString();
83
+
84
+ // Important for MacOS tests with non-embedded server.
85
+ fs.chmodSync(testConfig.tmpDir, 0o777);
86
+ }
87
+
88
+ const defaultOptions = {
89
+ password: testConfig.password,
90
+ username: testConfig.username,
91
+ };
92
+
93
+ client.defaultCreateDatabaseOptions = {
94
+ forcedWrite: false,
95
+ ...defaultOptions,
96
+ };
97
+
98
+ client.defaultConnectOptions = {
99
+ ...defaultOptions,
100
+ };
101
+ });
102
+
103
+ afterAll(async () => {
104
+ await client.dispose();
105
+
106
+ expect(client.isValid).toBeFalsy();
107
+
108
+ if (isLocal()) {
109
+ fs.rmdirSync(testConfig.tmpDir!);
110
+ }
111
+ });
112
+
113
+ describe('Client', () => {
114
+ test('#createDatabase()', async () => {
115
+ const attachment = await client.createDatabase(getTempFile('Client-createDatabase.fdb'));
116
+ await attachment.dropDatabase();
117
+ });
118
+
119
+ test('#connect()', async () => {
120
+ const filename = getTempFile('Client-connect.fdb');
121
+ const attachment1 = await client.createDatabase(filename);
122
+ const attachment2 = await client.connect(filename);
123
+
124
+ expect(attachment1.isValid).toBeTruthy();
125
+ expect(attachment2.isValid).toBeTruthy();
126
+
127
+ await attachment2.disconnect();
128
+ await attachment1.dropDatabase();
129
+
130
+ expect(attachment1.isValid).toBeFalsy();
131
+ expect(attachment2.isValid).toBeFalsy();
132
+ });
133
+
134
+ test('setDatabaseReadWriteMode', async () => {
135
+ const filename = getTempFile('setDatabaseReadWriteMode.fdb');
136
+ const attachment1 = await client.createDatabase(filename);
137
+ await attachment1.disconnect();
138
+
139
+ const attachment2 = await client.connect(filename, {
140
+ setDatabaseReadWriteMode: DatabaseReadWriteMode.READ_ONLY,
141
+ });
142
+ try {
143
+ const transaction = await attachment2.startTransaction();
144
+ await expect(attachment2.execute(transaction, 'create table t1 (id integer)')).rejects.toThrow();
145
+ await transaction.rollback();
146
+ } finally {
147
+ await attachment2.disconnect();
148
+ }
149
+
150
+ const attachment3 = await client.connect(filename, {
151
+ setDatabaseReadWriteMode: DatabaseReadWriteMode.READ_WRITE,
152
+ });
153
+ try {
154
+ const transaction = await attachment3.startTransaction();
155
+ await attachment3.execute(transaction, 'create table t1 (id integer)');
156
+ await transaction.commit();
157
+ } finally {
158
+ await attachment3.disconnect();
159
+ }
160
+
161
+ const attachment4 = await client.connect(filename);
162
+ await attachment4.dropDatabase();
163
+ });
164
+ });
165
+
166
+ describe('Attachment', () => {
167
+ test('#startTransaction()', async () => {
168
+ const attachment = await client.createDatabase(getTempFile('Attachment-startTransaction.fdb'));
169
+
170
+ const isolationQuery = "select rdb$get_context('SYSTEM', 'ISOLATION_LEVEL') from rdb$database";
171
+
172
+ const transaction1 = await attachment.startTransaction();
173
+ expect(transaction1.isValid).toBeTruthy();
174
+ expect((await attachment.executeSingleton(transaction1, isolationQuery))[0]).toBe('SNAPSHOT');
175
+ await transaction1.commit();
176
+ expect(transaction1.isValid).toBeFalsy();
177
+
178
+ const transaction2 = await attachment.startTransaction({
179
+ isolation: TransactionIsolation.READ_COMMITTED,
180
+ });
181
+ expect(transaction2.isValid).toBeTruthy();
182
+ expect((await attachment.executeSingleton(transaction2, isolationQuery))[0]).toBe('READ COMMITTED');
183
+ await transaction2.commit();
184
+ expect(transaction2.isValid).toBeFalsy();
185
+
186
+ const transaction3 = await attachment.startTransaction({
187
+ isolation: TransactionIsolation.CONSISTENCY,
188
+ });
189
+ expect(transaction3.isValid).toBeTruthy();
190
+ expect((await attachment.executeSingleton(transaction3, isolationQuery))[0]).toBe('CONSISTENCY');
191
+ await transaction3.commit();
192
+ expect(transaction3.isValid).toBeFalsy();
193
+
194
+ await attachment.dropDatabase();
195
+ });
196
+
197
+ test('#prepare()', async () => {
198
+ const attachment = await client.createDatabase(getTempFile('Attachment-prepare.fdb'));
199
+ const transaction = await attachment.startTransaction();
200
+
201
+ const statement = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
202
+ expect(statement.isValid).toBeTruthy();
203
+ await statement.dispose();
204
+ expect(statement.isValid).toBeFalsy();
205
+
206
+ let error: Error | undefined;
207
+ try {
208
+ await attachment.prepare(transaction, 'create select t1 (n1 integer)');
209
+ } catch (e) {
210
+ error = e as Error;
211
+ expect(error.message).toBe(
212
+ 'Dynamic SQL Error\n' + '-SQL error code = -104\n' + '-Token unknown - line 1, column 8\n' + '-select',
213
+ );
214
+ }
215
+
216
+ expect(error).toBeTruthy();
217
+
218
+ await transaction.commit();
219
+ await attachment.dropDatabase();
220
+ });
221
+
222
+ //// TODO: #executeTransaction
223
+
224
+ test('#execute()', async () => {
225
+ const attachment = await client.createDatabase(getTempFile('Attachment-execute.fdb'));
226
+ const transaction = await attachment.startTransaction();
227
+
228
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
229
+ await transaction.commitRetaining();
230
+
231
+ await attachment.execute(transaction, 'insert into t1 (n1) values (1)');
232
+
233
+ await transaction.commit();
234
+ await attachment.dropDatabase();
235
+ });
236
+
237
+ test('#executeQuery()', async () => {
238
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeQuery.fdb'));
239
+ const transaction = await attachment.startTransaction();
240
+
241
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
242
+ await transaction.commitRetaining();
243
+
244
+ const resultSet = await attachment.executeQuery(transaction, 'select n1 from t1');
245
+ expect(resultSet.isValid).toBeTruthy();
246
+ await resultSet.close();
247
+ expect(resultSet.isValid).toBeFalsy();
248
+
249
+ await transaction.commit();
250
+ await attachment.dropDatabase();
251
+ });
252
+
253
+ test('#executeSingleton()', async () => {
254
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
255
+ const transaction = await attachment.startTransaction();
256
+
257
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
258
+ await transaction.commitRetaining();
259
+
260
+ const result = await attachment.executeSingleton(transaction, 'insert into t1 values (11) returning n1');
261
+ expect(result.length).toBe(1);
262
+ expect(result[0]).toBe(11);
263
+
264
+ await transaction.commit();
265
+ await attachment.dropDatabase();
266
+ });
267
+
268
+ test('#executeSingletonAsObject()', async () => {
269
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeSingletonAsObject.fdb'));
270
+ const transaction = await attachment.startTransaction();
271
+
272
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
273
+ await transaction.commitRetaining();
274
+
275
+ const output = await attachment.executeSingletonAsObject<{
276
+ N1: number;
277
+ }>(transaction, 'insert into t1 values (11) returning n1');
278
+ expect(output.N1).toBe(11);
279
+
280
+ await transaction.commit();
281
+ await attachment.dropDatabase();
282
+ });
283
+
284
+ test('#executeReturning()', async () => {
285
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
286
+ const transaction = await attachment.startTransaction();
287
+
288
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
289
+ await transaction.commitRetaining();
290
+
291
+ const result = await attachment.executeReturning(transaction, 'insert into t1 values (11) returning n1');
292
+ expect(result.length).toBe(1);
293
+ expect(result[0]).toBe(11);
294
+
295
+ await transaction.commit();
296
+ await attachment.dropDatabase();
297
+ });
298
+
299
+ test('#executeReturningAsObject()', async () => {
300
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeReturningAsObject.fdb'));
301
+ const transaction = await attachment.startTransaction();
302
+
303
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
304
+ await transaction.commitRetaining();
305
+
306
+ const output = await attachment.executeReturningAsObject<{
307
+ N1: number;
308
+ }>(transaction, 'insert into t1 values (11) returning n1');
309
+ expect(output.N1).toBe(11);
310
+
311
+ await transaction.commit();
312
+ await attachment.dropDatabase();
313
+ });
314
+
315
+ test('#queueEvents()', async () => {
316
+ const attachment = await client.createDatabase(getTempFile('Attachment-queueEvents.fdb'));
317
+
318
+ const eventNames: [string, number][] = [
319
+ ['EVENT1', 16],
320
+ ['EVENT2', 8],
321
+ ];
322
+
323
+ const eventsObj = eventNames.map(([name, expected]) => {
324
+ let resolver: () => void = undefined!;
325
+
326
+ const obj = {
327
+ name,
328
+ expected,
329
+ count: 0,
330
+ promise: new Promise<void>((resolve) => (resolver = resolve)),
331
+ };
332
+
333
+ return { ...obj, resolver };
334
+ });
335
+ const eventsMap = new Map(eventsObj.map((ev) => [ev.name, ev]));
336
+
337
+ const eventHandler = async (counters: [string, number][]) => {
338
+ counters.forEach(([name, count]) => {
339
+ const obj = eventsMap.get(name)!;
340
+ const newCount = obj.count + count;
341
+ obj.count = newCount;
342
+
343
+ if (newCount >= obj.expected) {
344
+ obj.resolver();
345
+ }
346
+ });
347
+
348
+ if (Array.from(eventsMap.values()).every((obj) => obj.count >= obj.expected)) {
349
+ if (events) {
350
+ await events.cancel();
351
+ expect(events.isValid).toBeFalsy();
352
+ events = null!;
353
+ }
354
+ }
355
+ };
356
+
357
+ let events = await attachment.queueEvents(Array.from(eventsMap.keys()), eventHandler);
358
+
359
+ const transaction = await attachment.startTransaction();
360
+ try {
361
+ // Iterate more times than the neccessary so that
362
+ // eventHandler may have a chance to cancel the events.
363
+ for (let i = 0; i < 20; ++i) {
364
+ await attachment.execute(
365
+ transaction,
366
+ `
328
367
  execute block as
329
368
  begin
330
369
  post_event 'EVENT1';
@@ -332,379 +371,463 @@ export function runCommonTests(client: Client) {
332
371
  post_event 'EVENT2';
333
372
  post_event 'EVENT3';
334
373
  end
335
- `);
336
-
337
- // Commit retaining to test internal event rescheduling
338
- // after each handler dispatch.
339
- await transaction.commitRetaining();
340
- expect(transaction.isValid).toBeTruthy();
341
- }
342
- }
343
- finally {
344
- await transaction.commit();
345
- expect(transaction.isValid).toBeFalsy();
346
- }
347
-
348
- await Promise.all(eventsObj.map(ev => ev.promise));
349
-
350
- if (events)
351
- await events.cancel();
352
-
353
- eventsObj.forEach(ev => expect(ev.count).toBeGreaterThanOrEqual(ev.expected));
354
-
355
- await attachment.dropDatabase();
356
- });
357
-
358
- test('#cancelOperation()', async () => {
359
- const attachment = await client.createDatabase(getTempFile('Attachment-cancelOperation.fdb'));
360
- const transaction1 = await attachment.startTransaction();
361
-
362
- await attachment.execute(transaction1, 'create table t1(n1 integer)');
363
- await transaction1.commitRetaining();
364
-
365
- await attachment.execute(transaction1, 'insert into t1 values (1)');
366
- await transaction1.commitRetaining();
367
-
368
- await attachment.execute(transaction1, 'update t1 set n1 = n1 + 1');
369
-
370
- await attachment.enableCancellation(true);
371
-
372
- const transaction2 = await attachment.startTransaction();
373
-
374
- const promise = attachment.execute(transaction2, 'update t1 set n1 = n1 - 1')
375
- .catch(e => `Error: ${e.message}`);
376
-
377
- await new Promise(resolve => setTimeout(resolve, 1000));
378
-
379
- await attachment.cancelOperation();
380
-
381
- await expect(promise).resolves.toEqual('Error: operation was cancelled');
382
-
383
- await transaction2.commit();
384
- await transaction1.commit();
385
- await attachment.dropDatabase();
386
- });
387
- });
388
-
389
- describe('Transaction', () => {
390
- test('#commit()', async () => {
391
- const attachment = await client.createDatabase(getTempFile('Transaction-commit.fdb'));
392
- const transaction = await attachment.startTransaction();
393
- await transaction.commit();
394
- await attachment.dropDatabase();
395
- });
396
-
397
- test('#commitRetaining()', async () => {
398
- const attachment = await client.createDatabase(getTempFile('Transaction-commitRetaining.fdb'));
399
- const transaction = await attachment.startTransaction();
400
- await transaction.commitRetaining();
401
- await transaction.commit();
402
- await attachment.dropDatabase();
403
- });
404
-
405
- test('#rollback()', async () => {
406
- const attachment = await client.createDatabase(getTempFile('Transaction-rollback.fdb'));
407
- const transaction = await attachment.startTransaction();
408
- await transaction.rollback();
409
- await attachment.dropDatabase();
410
- });
411
-
412
- test('#rollbackRetaining()', async () => {
413
- const attachment = await client.createDatabase(getTempFile('Transaction-rollbackRetaining.fdb'));
414
- const transaction = await attachment.startTransaction();
415
- await transaction.rollbackRetaining();
416
- await transaction.rollback();
417
- await attachment.dropDatabase();
418
- });
419
-
420
- test('transaction left opened', async () => {
421
- const attachment = await client.createDatabase(getTempFile('Transaction-left-opened.fdb'));
422
- await attachment.startTransaction();
423
- await attachment.dropDatabase();
424
- });
425
- });
426
-
427
- describe('Statement', () => {
428
- test('#execute()', async () => {
429
- const attachment = await client.createDatabase(getTempFile('Statement-execute.fdb'));
430
- const transaction = await attachment.startTransaction();
431
-
432
- const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
433
- await statement1.execute(transaction);
434
- await statement1.dispose();
435
- await transaction.commitRetaining();
436
-
437
- const statement2 = await attachment.prepare(transaction, 'insert into t1 (n1) values (?)');
438
- await statement2.execute(transaction, [1]);
439
- await statement2.execute(transaction, [null]);
440
- await statement2.execute(transaction, [10]);
441
- await statement2.execute(transaction, [100]);
442
- expect(statement2.isValid).toBeTruthy();
443
- await statement2.dispose();
444
- expect(statement2.isValid).toBeFalsy();
445
-
446
- const rs = await attachment.executeQuery(transaction,
447
- `select sum(n1) || ', ' || count(n1) || ', ' || count(*) ret from t1`);
448
- const ret = await rs.fetchAsObject<{ RET: string }>();
449
- await rs.close();
450
-
451
- expect(ret[0].RET).toStrictEqual('111, 3, 4');
374
+ `,
375
+ );
376
+
377
+ // Commit retaining to test internal event rescheduling
378
+ // after each handler dispatch.
379
+ await transaction.commitRetaining();
380
+ expect(transaction.isValid).toBeTruthy();
381
+ }
382
+ } finally {
383
+ await transaction.commit();
384
+ expect(transaction.isValid).toBeFalsy();
385
+ }
386
+
387
+ await Promise.all(eventsObj.map((ev) => ev.promise));
388
+
389
+ if (events) {
390
+ await events.cancel();
391
+ }
392
+
393
+ eventsObj.forEach((ev) => expect(ev.count).toBeGreaterThanOrEqual(ev.expected));
394
+
395
+ await attachment.dropDatabase();
396
+ });
397
+
398
+ test('#cancelOperation()', async () => {
399
+ const attachment = await client.createDatabase(getTempFile('Attachment-cancelOperation.fdb'));
400
+ const transaction1 = await attachment.startTransaction();
401
+
402
+ await attachment.execute(transaction1, 'create table t1(n1 integer)');
403
+ await transaction1.commitRetaining();
404
+
405
+ await attachment.execute(transaction1, 'insert into t1 values (1)');
406
+ await transaction1.commitRetaining();
407
+
408
+ await attachment.execute(transaction1, 'update t1 set n1 = n1 + 1');
409
+
410
+ await attachment.enableCancellation(true);
411
+
412
+ const transaction2 = await attachment.startTransaction();
413
+
414
+ const promise = attachment
415
+ .execute(transaction2, 'update t1 set n1 = n1 - 1')
416
+ .catch((e) => `Error: ${e.message}`);
417
+
418
+ await new Promise((resolve) => setTimeout(resolve, 1000));
419
+
420
+ await attachment.cancelOperation();
421
+
422
+ await expect(promise).resolves.toEqual('Error: operation was cancelled');
423
+
424
+ await transaction2.commit();
425
+ await transaction1.commit();
426
+ await attachment.dropDatabase();
427
+ });
428
+ });
429
+
430
+ describe('Transaction', () => {
431
+ test('#commit()', async () => {
432
+ const attachment = await client.createDatabase(getTempFile('Transaction-commit.fdb'));
433
+ const transaction = await attachment.startTransaction();
434
+ await transaction.commit();
435
+ await attachment.dropDatabase();
436
+ });
437
+
438
+ test('#commitRetaining()', async () => {
439
+ const attachment = await client.createDatabase(getTempFile('Transaction-commitRetaining.fdb'));
440
+ const transaction = await attachment.startTransaction();
441
+ await transaction.commitRetaining();
442
+ await transaction.commit();
443
+ await attachment.dropDatabase();
444
+ });
445
+
446
+ test('#rollback()', async () => {
447
+ const attachment = await client.createDatabase(getTempFile('Transaction-rollback.fdb'));
448
+ const transaction = await attachment.startTransaction();
449
+ await transaction.rollback();
450
+ await attachment.dropDatabase();
451
+ });
452
+
453
+ test('#rollbackRetaining()', async () => {
454
+ const attachment = await client.createDatabase(getTempFile('Transaction-rollbackRetaining.fdb'));
455
+ const transaction = await attachment.startTransaction();
456
+ await transaction.rollbackRetaining();
457
+ await transaction.rollback();
458
+ await attachment.dropDatabase();
459
+ });
460
+
461
+ test('transaction left opened', async () => {
462
+ const attachment = await client.createDatabase(getTempFile('Transaction-left-opened.fdb'));
463
+ await attachment.startTransaction();
464
+ await attachment.dropDatabase();
465
+ });
466
+ });
467
+
468
+ describe('Statement', () => {
469
+ test('#execute()', async () => {
470
+ const attachment = await client.createDatabase(getTempFile('Statement-execute.fdb'));
471
+ const transaction = await attachment.startTransaction();
472
+
473
+ const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
474
+ await statement1.execute(transaction);
475
+ await statement1.dispose();
476
+ await transaction.commitRetaining();
477
+
478
+ const statement2 = await attachment.prepare(transaction, 'insert into t1 (n1) values (?)');
479
+ await statement2.execute(transaction, [1]);
480
+ await statement2.execute(transaction, [null]);
481
+ await statement2.execute(transaction, [10]);
482
+ await statement2.execute(transaction, [100]);
483
+ expect(statement2.isValid).toBeTruthy();
484
+ await statement2.dispose();
485
+ expect(statement2.isValid).toBeFalsy();
452
486
 
453
- await transaction.commit();
454
- await attachment.dropDatabase();
455
- });
456
-
457
- test('#executeQuery()', async () => {
458
- const attachment = await client.createDatabase(getTempFile('Statement-executeQuery.fdb'));
459
- const transaction = await attachment.startTransaction();
460
-
461
- const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
462
- await statement1.execute(transaction);
463
- await statement1.dispose();
464
- await transaction.commitRetaining();
465
-
466
- const statement2 = await attachment.prepare(transaction, 'select n1 from t1');
467
- const resultSet2 = await statement2.executeQuery(transaction);
468
- await resultSet2.close();
469
- await statement2.dispose();
470
-
471
- await transaction.commit();
472
- await attachment.dropDatabase();
473
- });
474
-
475
- test('#executeSingleton()', async () => {
476
- const attachment = await client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
477
- const transaction = await attachment.startTransaction();
478
-
479
- await attachment.execute(transaction, 'create table t1 (n1 integer)');
480
- await transaction.commitRetaining();
481
-
482
- const statement = await attachment.prepare(transaction, 'insert into t1 values (11) returning n1, n1 * 2');
483
-
484
- const result = await statement.executeSingleton(transaction);
485
- expect(result.length).toBe(2);
486
- expect(result[0]).toBe(11);
487
- expect(result[1]).toBe(11 * 2);
488
-
489
- await statement.dispose();
490
-
491
- await transaction.commit();
492
- await attachment.dropDatabase();
493
- });
494
-
495
- test('#executeReturning()', async () => {
496
- const attachment = await client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
497
- const transaction = await attachment.startTransaction();
498
-
499
- await attachment.execute(transaction, 'create table t1 (n1 integer)');
500
- await transaction.commitRetaining();
501
-
502
- const statement = await attachment.prepare(transaction, 'insert into t1 values (11) returning n1, n1 * 2');
503
-
504
- const result = await statement.executeReturning(transaction);
505
- expect(result.length).toBe(2);
506
- expect(result[0]).toBe(11);
507
- expect(result[1]).toBe(11 * 2);
508
-
509
- await statement.dispose();
510
-
511
- await transaction.commit();
512
- await attachment.dropDatabase();
513
- });
514
-
515
- test('#columnLabels()', async () => {
516
- const attachment = await client.createDatabase(getTempFile('Statement-columnLabels.fdb'));
517
- const transaction = await attachment.startTransaction();
518
-
519
- const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
520
- expect(await statement1.columnLabels).toStrictEqual([]);
521
- await statement1.execute(transaction);
522
- await statement1.dispose();
523
- await transaction.commitRetaining();
524
-
525
- const statement2 = await attachment.prepare(transaction, 'select n1, n1 x from t1');
526
- expect(await statement2.columnLabels).toStrictEqual(['N1', 'X']);
527
- await statement2.dispose();
528
-
529
- await transaction.commit();
530
- await attachment.dropDatabase();
531
- });
532
-
533
- test('#hasResultSet()', async () => {
534
- const attachment = await client.createDatabase(getTempFile('Statement-hasResultSet.fdb'));
535
- const transaction = await attachment.startTransaction();
536
-
537
- const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
538
- expect(statement1.hasResultSet).toBe(false);
539
- await statement1.execute(transaction);
540
- await statement1.dispose();
541
-
542
- await transaction.commitRetaining();
543
-
544
- const statement2 = await attachment.prepare(transaction, 'insert into t1 values (1)');
545
- expect(statement2.hasResultSet).toBe(false);
546
- await statement2.dispose();
547
-
548
- const statement3 = await attachment.prepare(transaction, 'insert into t1 values (1) returning *');
549
- expect(statement3.hasResultSet).toBe(false);
550
- await statement3.dispose();
551
-
552
- const statement4 = await attachment.prepare(transaction, 'execute block as begin end');
553
- expect(statement4.hasResultSet).toBe(false);
554
- await statement4.dispose();
555
-
556
- const statement5 = await attachment.prepare(transaction, 'select * from t1');
557
- expect(statement5.hasResultSet).toBe(true);
558
- await statement5.dispose();
559
-
560
- const statement6 = await attachment.prepare(transaction, 'execute block returns (n integer) as begin suspend; end');
561
- expect(statement6.hasResultSet).toBe(true);
562
- await statement6.dispose();
563
-
564
- const statement7 = await attachment.prepare(transaction, 'execute block returns (n integer) as begin end');
565
- expect(statement7.hasResultSet).toBe(true);
566
- await statement7.dispose();
567
-
568
- await transaction.commit();
569
- await attachment.dropDatabase();
570
- });
571
- });
572
-
573
- describe('ResultSet', () => {
574
- test('#fetch()', async () => {
575
- const attachment = await client.createDatabase(getTempFile('ResultSet-fetch.fdb'));
576
-
577
- let transaction = await attachment.startTransaction();
578
-
579
- const blobBuffer = Buffer.alloc(11, '12345678á9');
580
-
581
- const fields = [
582
- { name: 'x_short', type: 'numeric(2)', valToStr: (v: any) => v },
583
- { name: 'x_int', type: 'integer', valToStr: (v: any) => v },
584
- { name: 'x_int_scale', type: 'numeric(5, 2)', valToStr: (v: any) => v },
585
- { name: 'x_bigint', type: 'bigint', valToStr: (v: any) => v },
586
- { name: 'x_bigint_scale', type: 'numeric(15, 2)', valToStr: (v: any) => v },
587
- { name: 'x_int128', type: 'int128', valToStr: (v: any) => v },
588
- { name: 'x_int128_scale', type: 'numeric(20, 2)', valToStr: (v: any) => v },
589
- { name: 'x_dec16', type: 'decfloat(16)', valToStr: (v: any) => v },
590
- { name: 'x_dec34', type: 'decfloat(34)', valToStr: (v: any) => v },
591
- { name: 'x_double', type: 'double precision', valToStr: (v: any) => v },
592
- { name: 'x_date1', type: 'date', valToStr: (v: any) => `date '${dateToString(v)}'` },
593
- { name: 'x_date2', type: 'date', valToStr: (v: any) => `date '${dateToString(v)}'` },
594
- { name: 'x_date3', type: 'date', valToStr: (v: any) => `date '${dateToString(v)}'` },
595
- { name: 'x_time', type: 'time', valToStr: (v: any) => `time '${timeToString(v)}'` },
596
- {
597
- name: 'x_time_tz1',
598
- type: 'time with time zone',
599
- valToStr: (v: ZonedDate) =>
600
- `${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
601
- },
602
- {
603
- name: 'x_time_tz2',
604
- type: 'time with time zone',
605
- valToStr: (v: ZonedDate) =>
606
- `${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
607
- },
608
- { name: 'x_timestamp1', type: 'timestamp', valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'` },
609
- { name: 'x_timestamp2', type: 'timestamp', valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'` },
610
- { name: 'x_timestamp3', type: 'timestamp', valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'` },
611
- {
612
- name: 'x_timestamp_tz1',
613
- type: 'timestamp with time zone',
614
- valToStr: (v: ZonedDate) =>
615
- `${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
616
- },
617
- {
618
- name: 'x_timestamp_tz2',
619
- type: 'timestamp with time zone',
620
- valToStr: (v: ZonedDate) =>
621
- `${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`
622
- },
623
- { name: 'x_boolean', type: 'boolean', valToStr: (v: any) => v },
624
- { name: 'x_varchar', type: 'varchar(10) character set utf8', valToStr: (v: any) => `'${v}'` },
625
- { name: 'x_char', type: 'char(10) character set utf8', valToStr: (v: any) => `'${v}'` },
626
- { name: 'x_blob1', type: 'blob', valToStr: (v: Buffer) => `'${v.toString()}'` },
627
- { name: 'x_blob2', type: 'blob', valToStr: () => `'${blobBuffer.toString()}'` }
628
- ];
629
-
630
- const statement1 = await attachment.prepare(transaction,
631
- `create table t1 (${fields.map(f => `${f.name} ${f.type}`).join(', ')})`);
632
- await statement1.execute(transaction);
633
- await statement1.dispose();
634
- await transaction.commitRetaining();
635
-
636
- const recordCount = 5;
637
- let parameters: any[];
638
-
639
- { // scope
640
- const statement2a = await attachment.prepare(transaction,
641
- `insert into t1 (${fields.map(f => f.name).join(', ')}) values (${fields.map(() => '?').join(', ')})`);
642
-
643
- // Test execution in a new transaction, after the one used in prepare was committed.
644
- await transaction.commit();
645
- transaction = await attachment.startTransaction();
646
-
647
- const blob = await attachment.createBlob(transaction);
648
- expect(blob.isValid).toBeTruthy();
649
- await blob.write(blobBuffer);
650
- expect(blob.isValid).toBeTruthy();
651
- await blob.close();
652
- expect(blob.isValid).toBeFalsy();
653
-
654
- parameters = [
655
- -1,
656
- -2,
657
- -3.45,
658
- -2,
659
- -3.45,
660
- '-45699999999999999999999999999999999876',
661
- '-45699999999999999999999999999999999.87',
662
- '-456999999999876',
663
- '-456999999999999999999999999999.87',
664
- -4.567,
665
- new Date(2017, 3 - 1, 26),
666
- new Date(new Date(2000, 3 - 1, 26).setFullYear(50)),
667
- new Date(9999, 3 - 1, 26),
668
- new Date(2020, 1 - 1, 1, 11, 56, 32, 123),
669
- {
670
- date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
671
- timeZone: 'America/New_York'
672
- } as ZonedDate,
673
- {
674
- date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
675
- timeZone: 'America/Sao_Paulo'
676
- } as ZonedDate,
677
- new Date(2017, 3 - 1, 26, 11, 56, 32, 123),
678
- new Date(new Date(2000, 3 - 1, 26, 11, 56, 32, 123).setFullYear(50)),
679
- new Date(9999, 3 - 1, 26, 11, 56, 32, 123),
680
- { date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)), timeZone: 'America/New_York' } as ZonedDate,
681
- { date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)), timeZone: 'America/Sao_Paulo' } as ZonedDate,
682
- true,
683
- '123áé4567',
684
- '123áé4567',
685
- blobBuffer,
686
- blob
687
- ];
688
-
689
- for (let i = 0; i < recordCount; ++i)
690
- await statement2a.execute(transaction, parameters);
691
- await statement2a.dispose();
692
- }
693
-
694
- { // scope
695
- const statement2b = await attachment.prepare(transaction,
696
- `insert into t1 (${fields.map(f => f.name).join(', ')}) ` +
697
- `values (${parameters.map((val, index) => fields[index].valToStr(val)).join(', ')})`);
698
-
699
- for (let i = 0; i < recordCount; ++i)
700
- await statement2b.execute(transaction);
701
- await statement2b.dispose();
702
- }
703
-
704
- await transaction.commitRetaining();
705
-
706
- const statement3 = await attachment.prepare(transaction,
707
- `select x_short,
487
+ const rs = await attachment.executeQuery(
488
+ transaction,
489
+ `select sum(n1) || ', ' || count(n1) || ', ' || count(*) ret from t1`,
490
+ );
491
+ const ret = await rs.fetchAsObject<{ RET: string }>();
492
+ await rs.close();
493
+
494
+ expect(ret[0].RET).toStrictEqual('111, 3, 4');
495
+
496
+ await transaction.commit();
497
+ await attachment.dropDatabase();
498
+ });
499
+
500
+ test('#executeQuery()', async () => {
501
+ const attachment = await client.createDatabase(getTempFile('Statement-executeQuery.fdb'));
502
+ const transaction = await attachment.startTransaction();
503
+
504
+ const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
505
+ await statement1.execute(transaction);
506
+ await statement1.dispose();
507
+ await transaction.commitRetaining();
508
+
509
+ const statement2 = await attachment.prepare(transaction, 'select n1 from t1');
510
+ const resultSet2 = await statement2.executeQuery(transaction);
511
+ await resultSet2.close();
512
+ await statement2.dispose();
513
+
514
+ await transaction.commit();
515
+ await attachment.dropDatabase();
516
+ });
517
+
518
+ test('#executeSingleton()', async () => {
519
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeSingleton.fdb'));
520
+ const transaction = await attachment.startTransaction();
521
+
522
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
523
+ await transaction.commitRetaining();
524
+
525
+ const statement = await attachment.prepare(transaction, 'insert into t1 values (11) returning n1, n1 * 2');
526
+
527
+ const result = await statement.executeSingleton(transaction);
528
+ expect(result.length).toBe(2);
529
+ expect(result[0]).toBe(11);
530
+ expect(result[1]).toBe(11 * 2);
531
+
532
+ await statement.dispose();
533
+
534
+ await transaction.commit();
535
+ await attachment.dropDatabase();
536
+ });
537
+
538
+ test('#executeReturning()', async () => {
539
+ const attachment = await client.createDatabase(getTempFile('Attachment-executeReturning.fdb'));
540
+ const transaction = await attachment.startTransaction();
541
+
542
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
543
+ await transaction.commitRetaining();
544
+
545
+ const statement = await attachment.prepare(transaction, 'insert into t1 values (11) returning n1, n1 * 2');
546
+
547
+ const result = await statement.executeReturning(transaction);
548
+ expect(result.length).toBe(2);
549
+ expect(result[0]).toBe(11);
550
+ expect(result[1]).toBe(11 * 2);
551
+
552
+ await statement.dispose();
553
+
554
+ await transaction.commit();
555
+ await attachment.dropDatabase();
556
+ });
557
+
558
+ test('#columnLabels()', async () => {
559
+ const attachment = await client.createDatabase(getTempFile('Statement-columnLabels.fdb'));
560
+ const transaction = await attachment.startTransaction();
561
+
562
+ const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
563
+ expect(await statement1.columnLabels).toStrictEqual([]);
564
+ await statement1.execute(transaction);
565
+ await statement1.dispose();
566
+ await transaction.commitRetaining();
567
+
568
+ const statement2 = await attachment.prepare(transaction, 'select n1, n1 x from t1');
569
+ expect(await statement2.columnLabels).toStrictEqual(['N1', 'X']);
570
+ await statement2.dispose();
571
+
572
+ await transaction.commit();
573
+ await attachment.dropDatabase();
574
+ });
575
+
576
+ test('#hasResultSet()', async () => {
577
+ const attachment = await client.createDatabase(getTempFile('Statement-hasResultSet.fdb'));
578
+ const transaction = await attachment.startTransaction();
579
+
580
+ const statement1 = await attachment.prepare(transaction, 'create table t1 (n1 integer)');
581
+ expect(statement1.hasResultSet).toBe(false);
582
+ await statement1.execute(transaction);
583
+ await statement1.dispose();
584
+
585
+ await transaction.commitRetaining();
586
+
587
+ const statement2 = await attachment.prepare(transaction, 'insert into t1 values (1)');
588
+ expect(statement2.hasResultSet).toBe(false);
589
+ await statement2.dispose();
590
+
591
+ const statement3 = await attachment.prepare(transaction, 'insert into t1 values (1) returning *');
592
+ expect(statement3.hasResultSet).toBe(false);
593
+ await statement3.dispose();
594
+
595
+ const statement4 = await attachment.prepare(transaction, 'execute block as begin end');
596
+ expect(statement4.hasResultSet).toBe(false);
597
+ await statement4.dispose();
598
+
599
+ const statement5 = await attachment.prepare(transaction, 'select * from t1');
600
+ expect(statement5.hasResultSet).toBe(true);
601
+ await statement5.dispose();
602
+
603
+ const statement6 = await attachment.prepare(
604
+ transaction,
605
+ 'execute block returns (n integer) as begin suspend; end',
606
+ );
607
+ expect(statement6.hasResultSet).toBe(true);
608
+ await statement6.dispose();
609
+
610
+ const statement7 = await attachment.prepare(transaction, 'execute block returns (n integer) as begin end');
611
+ expect(statement7.hasResultSet).toBe(true);
612
+ await statement7.dispose();
613
+
614
+ await transaction.commit();
615
+ await attachment.dropDatabase();
616
+ });
617
+ });
618
+
619
+ describe('ResultSet', () => {
620
+ test('#fetch()', async () => {
621
+ const attachment = await client.createDatabase(getTempFile('ResultSet-fetch.fdb'));
622
+
623
+ let transaction = await attachment.startTransaction();
624
+
625
+ const blobBuffer = Buffer.alloc(11, '12345678á9');
626
+
627
+ const fields = [
628
+ { name: 'x_short', type: 'numeric(2)', valToStr: (v: any) => v },
629
+ { name: 'x_int', type: 'integer', valToStr: (v: any) => v },
630
+ {
631
+ name: 'x_int_scale',
632
+ type: 'numeric(5, 2)',
633
+ valToStr: (v: any) => v,
634
+ },
635
+ { name: 'x_bigint', type: 'bigint', valToStr: (v: any) => v },
636
+ {
637
+ name: 'x_bigint_scale',
638
+ type: 'numeric(15, 2)',
639
+ valToStr: (v: any) => v,
640
+ },
641
+ { name: 'x_int128', type: 'int128', valToStr: (v: any) => v },
642
+ {
643
+ name: 'x_int128_scale',
644
+ type: 'numeric(20, 2)',
645
+ valToStr: (v: any) => v,
646
+ },
647
+ { name: 'x_dec16', type: 'decfloat(16)', valToStr: (v: any) => v },
648
+ { name: 'x_dec34', type: 'decfloat(34)', valToStr: (v: any) => v },
649
+ {
650
+ name: 'x_double',
651
+ type: 'double precision',
652
+ valToStr: (v: any) => v,
653
+ },
654
+ {
655
+ name: 'x_date1',
656
+ type: 'date',
657
+ valToStr: (v: any) => `date '${dateToString(v)}'`,
658
+ },
659
+ {
660
+ name: 'x_date2',
661
+ type: 'date',
662
+ valToStr: (v: any) => `date '${dateToString(v)}'`,
663
+ },
664
+ {
665
+ name: 'x_date3',
666
+ type: 'date',
667
+ valToStr: (v: any) => `date '${dateToString(v)}'`,
668
+ },
669
+ {
670
+ name: 'x_time',
671
+ type: 'time',
672
+ valToStr: (v: any) => `time '${timeToString(v)}'`,
673
+ },
674
+ {
675
+ name: 'x_time_tz1',
676
+ type: 'time with time zone',
677
+ valToStr: (v: ZonedDate) =>
678
+ `${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`,
679
+ },
680
+ {
681
+ name: 'x_time_tz2',
682
+ type: 'time with time zone',
683
+ valToStr: (v: ZonedDate) =>
684
+ `${timeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`,
685
+ },
686
+ {
687
+ name: 'x_timestamp1',
688
+ type: 'timestamp',
689
+ valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'`,
690
+ },
691
+ {
692
+ name: 'x_timestamp2',
693
+ type: 'timestamp',
694
+ valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'`,
695
+ },
696
+ {
697
+ name: 'x_timestamp3',
698
+ type: 'timestamp',
699
+ valToStr: (v: any) => `timestamp '${dateTimeToString(v)}'`,
700
+ },
701
+ {
702
+ name: 'x_timestamp_tz1',
703
+ type: 'timestamp with time zone',
704
+ valToStr: (v: ZonedDate) =>
705
+ `${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`,
706
+ },
707
+ {
708
+ name: 'x_timestamp_tz2',
709
+ type: 'timestamp with time zone',
710
+ valToStr: (v: ZonedDate) =>
711
+ `${dateTimeTzToString({ date: v.date, timeZone: 'GMT', offset: 0 })} at time zone '${v.timeZone}'`,
712
+ },
713
+ { name: 'x_boolean', type: 'boolean', valToStr: (v: any) => v },
714
+ {
715
+ name: 'x_varchar',
716
+ type: 'varchar(10) character set utf8',
717
+ valToStr: (v: any) => `'${v}'`,
718
+ },
719
+ {
720
+ name: 'x_char',
721
+ type: 'char(10) character set utf8',
722
+ valToStr: (v: any) => `'${v}'`,
723
+ },
724
+ {
725
+ name: 'x_blob1',
726
+ type: 'blob',
727
+ valToStr: (v: Buffer) => `'${v.toString()}'`,
728
+ },
729
+ {
730
+ name: 'x_blob2',
731
+ type: 'blob',
732
+ valToStr: () => `'${blobBuffer.toString()}'`,
733
+ },
734
+ ];
735
+
736
+ const statement1 = await attachment.prepare(
737
+ transaction,
738
+ `create table t1 (${fields.map((f) => `${f.name} ${f.type}`).join(', ')})`,
739
+ );
740
+ await statement1.execute(transaction);
741
+ await statement1.dispose();
742
+ await transaction.commitRetaining();
743
+
744
+ const recordCount = 5;
745
+ let parameters: any[];
746
+
747
+ {
748
+ // scope
749
+ const statement2a = await attachment.prepare(
750
+ transaction,
751
+ `insert into t1 (${fields.map((f) => f.name).join(', ')}) values (${fields.map(() => '?').join(', ')})`,
752
+ );
753
+
754
+ // Test execution in a new transaction, after the one used in prepare was committed.
755
+ await transaction.commit();
756
+ transaction = await attachment.startTransaction();
757
+
758
+ const blob = await attachment.createBlob(transaction);
759
+ expect(blob.isValid).toBeTruthy();
760
+ await blob.write(blobBuffer);
761
+ expect(blob.isValid).toBeTruthy();
762
+ await blob.close();
763
+ expect(blob.isValid).toBeFalsy();
764
+
765
+ parameters = [
766
+ -1,
767
+ -2,
768
+ -3.45,
769
+ -2,
770
+ -3.45,
771
+ '-45699999999999999999999999999999999876',
772
+ '-45699999999999999999999999999999999.87',
773
+ '-456999999999876',
774
+ '-456999999999999999999999999999.87',
775
+ -4.567,
776
+ new Date(2017, 3 - 1, 26),
777
+ new Date(new Date(2000, 3 - 1, 26).setFullYear(50)),
778
+ new Date(9999, 3 - 1, 26),
779
+ new Date(2020, 1 - 1, 1, 11, 56, 32, 123),
780
+ {
781
+ date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
782
+ timeZone: 'America/New_York',
783
+ } as ZonedDate,
784
+ {
785
+ date: new Date(Date.UTC(2020, 1 - 1, 1, 11, 56, 32, 123)),
786
+ timeZone: 'America/Sao_Paulo',
787
+ } as ZonedDate,
788
+ new Date(2017, 3 - 1, 26, 11, 56, 32, 123),
789
+ new Date(new Date(2000, 3 - 1, 26, 11, 56, 32, 123).setFullYear(50)),
790
+ new Date(9999, 3 - 1, 26, 11, 56, 32, 123),
791
+ {
792
+ date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)),
793
+ timeZone: 'America/New_York',
794
+ } as ZonedDate,
795
+ {
796
+ date: new Date(Date.UTC(2021, 6 - 1, 7, 11, 56, 32, 123)),
797
+ timeZone: 'America/Sao_Paulo',
798
+ } as ZonedDate,
799
+ true,
800
+ '123áé4567',
801
+ '123áé4567',
802
+ blobBuffer,
803
+ blob,
804
+ ];
805
+
806
+ for (let i = 0; i < recordCount; ++i) {
807
+ await statement2a.execute(transaction, parameters);
808
+ }
809
+ await statement2a.dispose();
810
+ }
811
+
812
+ {
813
+ // scope
814
+ const statement2b = await attachment.prepare(
815
+ transaction,
816
+ `insert into t1 (${fields.map((f) => f.name).join(', ')}) ` +
817
+ `values (${parameters.map((val, index) => fields[index].valToStr(val)).join(', ')})`,
818
+ );
819
+
820
+ for (let i = 0; i < recordCount; ++i) {
821
+ await statement2b.execute(transaction);
822
+ }
823
+ await statement2b.dispose();
824
+ }
825
+
826
+ await transaction.commitRetaining();
827
+
828
+ const statement3 = await attachment.prepare(
829
+ transaction,
830
+ `select x_short,
708
831
  x_int,
709
832
  x_int_scale,
710
833
  x_bigint,
@@ -736,92 +859,98 @@ export function runCommonTests(client: Client) {
736
859
  x_char || null,
737
860
  x_blob1,
738
861
  x_blob2
739
- from t1`);
740
- const resultSet3 = await statement3.executeQuery(transaction);
741
-
742
- const data = await resultSet3.fetch();
743
- expect(data.length).toBe(recordCount * 2);
744
-
745
- for (const columns of data) {
746
- let n = 0;
747
- expect(columns[n++]).toBe(-1);
748
- expect(columns[n++]).toBe(-2);
749
- expect(columns[n++]).toBe(-3.45);
750
- expect(columns[n++]).toBe(-2);
751
- expect(columns[n++]).toBe(-3.45);
752
- expect(columns[n++]).toBe('-45699999999999999999999999999999999876');
753
- expect(columns[n++]).toBe('-45699999999999999999999999999999999.87');
754
- expect(columns[n++]).toBe('-456999999999876');
755
- expect(columns[n++]).toBe('-456999999999999999999999999999.87');
756
- expect(columns[n++]).toBe(-4.567);
757
- expect(dateTimeToString(columns[n++])).toBe('2017-3-26 0:0:0.0');
758
- expect(dateTimeToString(columns[n++])).toBe('0050-3-26 0:0:0.0');
759
- expect(dateTimeToString(columns[n++])).toBe('9999-3-26 0:0:0.0');
760
- expect(timeToString(columns[n++])).toBe('11:56:32.123');
761
- expect(timeTzToString(columns[n++])).toBe(`time '6:56:32.123 America/New_York'`);
762
- expect(timeTzToString(columns[n++])).toBe(`time '8:56:32.123 America/Sao_Paulo'`);
763
- expect(dateTimeToString(columns[n++])).toBe('2017-3-26 11:56:32.123');
764
- expect(dateTimeToString(columns[n++])).toBe('0050-3-26 11:56:32.123');
765
- expect(dateTimeToString(columns[n++])).toBe('9999-3-26 11:56:32.123');
766
- expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 7:56:32.123 America/New_York'`);
767
- expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 8:56:32.123 America/Sao_Paulo'`);
768
- expect(columns[n++]).toBe(true);
769
- expect(columns[n++]).toBe('123áé4567');
770
- expect(columns[n++]).toBe(9);
771
- expect(columns[n++]).toBe(11);
772
- expect(columns[n++]).toBe('123áé4567 ');
773
- expect(columns[n++]).toBe(10);
774
- expect(columns[n++]).toBe(12);
775
- expect(columns[n++]).toBeNull();
776
- expect(columns[n++]).toBeNull();
777
-
778
- for (const i = n + 2; n < i; ++n) {
779
- const blob = columns[n] as Blob;
780
- expect(blob.isValid).toBeTruthy();
781
- const blobStream = await attachment.openBlob(transaction, blob);
782
- const buffer = Buffer.alloc(await blobStream.length);
783
- expect(await blobStream.read(buffer)).toBe(buffer.length);
784
- expect(await blobStream.read(buffer)).toBe(-1);
785
-
786
- await blobStream.close();
787
-
788
- expect(buffer.toString()).toBe('12345678á9');
789
- }
790
-
791
- expect(columns.length).toBe(n);
792
- }
793
-
794
- expect((await resultSet3.fetch()).length).toBe(0);
795
- expect((await resultSet3.fetch()).length).toBe(0);
796
-
797
- await resultSet3.close();
798
- await statement3.dispose();
799
-
800
- await transaction.commit();
801
- await attachment.dropDatabase();
802
- });
803
-
804
- test('#fetchAsObject()', async () => {
805
- const attachment = await client.createDatabase(getTempFile('ResultSet-fetchAsObject.fdb'));
806
- const transaction = await attachment.startTransaction();
807
- const resultSet = await attachment.executeQuery(transaction, 'select 1 as a, 2 as b from rdb$database');
808
- const output = await resultSet.fetchAsObject<{ A: number; B: number }>();
809
- expect(output[0].A).toBe(1);
810
- expect(output[0].B).toBe(2);
811
- await resultSet.close();
812
-
813
- await transaction.commit();
814
- await attachment.dropDatabase();
815
- });
816
-
817
- test('#fetch() with fetchSize', async () => {
818
- const attachment = await client.createDatabase(getTempFile('ResultSet-fetch-with-fetchSize.fdb'));
819
- const transaction = await attachment.startTransaction();
820
-
821
- await attachment.execute(transaction, 'create table t1 (n1 integer)');
822
- await transaction.commitRetaining();
823
-
824
- await attachment.execute(transaction, `
862
+ from t1`,
863
+ );
864
+ const resultSet3 = await statement3.executeQuery(transaction);
865
+
866
+ const data = await resultSet3.fetch();
867
+ expect(data.length).toBe(recordCount * 2);
868
+
869
+ for (const columns of data) {
870
+ let n = 0;
871
+ expect(columns[n++]).toBe(-1);
872
+ expect(columns[n++]).toBe(-2);
873
+ expect(columns[n++]).toBe(-3.45);
874
+ expect(columns[n++]).toBe(-2);
875
+ expect(columns[n++]).toBe(-3.45);
876
+ expect(columns[n++]).toBe('-45699999999999999999999999999999999876');
877
+ expect(columns[n++]).toBe('-45699999999999999999999999999999999.87');
878
+ expect(columns[n++]).toBe('-456999999999876');
879
+ expect(columns[n++]).toBe('-456999999999999999999999999999.87');
880
+ expect(columns[n++]).toBe(-4.567);
881
+ expect(dateTimeToString(columns[n++])).toBe('2017-3-26 0:0:0.0');
882
+ expect(dateTimeToString(columns[n++])).toBe('0050-3-26 0:0:0.0');
883
+ expect(dateTimeToString(columns[n++])).toBe('9999-3-26 0:0:0.0');
884
+ expect(timeToString(columns[n++])).toBe('11:56:32.123');
885
+ expect(timeTzToString(columns[n++])).toBe(`time '6:56:32.123 America/New_York'`);
886
+ expect(timeTzToString(columns[n++])).toBe(`time '8:56:32.123 America/Sao_Paulo'`);
887
+ expect(dateTimeToString(columns[n++])).toBe('2017-3-26 11:56:32.123');
888
+ expect(dateTimeToString(columns[n++])).toBe('0050-3-26 11:56:32.123');
889
+ expect(dateTimeToString(columns[n++])).toBe('9999-3-26 11:56:32.123');
890
+ expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 7:56:32.123 America/New_York'`);
891
+ expect(dateTimeTzToString(columns[n++])).toBe(`timestamp '2021-6-7 8:56:32.123 America/Sao_Paulo'`);
892
+ expect(columns[n++]).toBe(true);
893
+ expect(columns[n++]).toBe('123áé4567');
894
+ expect(columns[n++]).toBe(9);
895
+ expect(columns[n++]).toBe(11);
896
+ expect(columns[n++]).toBe('123áé4567 ');
897
+ expect(columns[n++]).toBe(10);
898
+ expect(columns[n++]).toBe(12);
899
+ expect(columns[n++]).toBeNull();
900
+ expect(columns[n++]).toBeNull();
901
+
902
+ for (const i = n + 2; n < i; ++n) {
903
+ const blob = columns[n] as Blob;
904
+ expect(blob.isValid).toBeTruthy();
905
+ const blobStream = await attachment.openBlob(transaction, blob);
906
+ const buffer = Buffer.alloc(await blobStream.length);
907
+ expect(await blobStream.read(buffer)).toBe(buffer.length);
908
+ expect(await blobStream.read(buffer)).toBe(-1);
909
+
910
+ await blobStream.close();
911
+
912
+ expect(buffer.toString()).toBe('12345678á9');
913
+ }
914
+
915
+ expect(columns.length).toBe(n);
916
+ }
917
+
918
+ expect((await resultSet3.fetch()).length).toBe(0);
919
+ expect((await resultSet3.fetch()).length).toBe(0);
920
+
921
+ await resultSet3.close();
922
+ await statement3.dispose();
923
+
924
+ await transaction.commit();
925
+ await attachment.dropDatabase();
926
+ });
927
+
928
+ test('#fetchAsObject()', async () => {
929
+ const attachment = await client.createDatabase(getTempFile('ResultSet-fetchAsObject.fdb'));
930
+ const transaction = await attachment.startTransaction();
931
+ const resultSet = await attachment.executeQuery(transaction, 'select 1 as a, 2 as b from rdb$database');
932
+ const output = await resultSet.fetchAsObject<{
933
+ A: number;
934
+ B: number;
935
+ }>();
936
+ expect(output[0].A).toBe(1);
937
+ expect(output[0].B).toBe(2);
938
+ await resultSet.close();
939
+
940
+ await transaction.commit();
941
+ await attachment.dropDatabase();
942
+ });
943
+
944
+ test('#fetch() with fetchSize', async () => {
945
+ const attachment = await client.createDatabase(getTempFile('ResultSet-fetch-with-fetchSize.fdb'));
946
+ const transaction = await attachment.startTransaction();
947
+
948
+ await attachment.execute(transaction, 'create table t1 (n1 integer)');
949
+ await transaction.commitRetaining();
950
+
951
+ await attachment.execute(
952
+ transaction,
953
+ `
825
954
  execute block
826
955
  as
827
956
  declare n integer = 0;
@@ -832,32 +961,35 @@ export function runCommonTests(client: Client) {
832
961
  n = n + 1;
833
962
  end
834
963
  end
835
- `);
964
+ `,
965
+ );
836
966
 
837
- const rs = await attachment.executeQuery(transaction, 'select n1 from t1 order by n1');
838
- rs.defaultFetchOptions = { fetchSize: 5 };
967
+ const rs = await attachment.executeQuery(transaction, 'select n1 from t1 order by n1');
968
+ rs.defaultFetchOptions = { fetchSize: 5 };
839
969
 
840
- expect((await rs.fetch()).length).toBe(5);
841
- expect((await rs.fetch({ fetchSize: 2 })).length).toBe(2);
842
- expect((await rs.fetch()).length).toBe(5);
843
- expect((await rs.fetch({ fetchSize: 36 })).length).toBe(36);
844
- expect((await rs.fetch()).length).toBe(2);
845
- expect((await rs.fetch()).length).toBe(0);
970
+ expect((await rs.fetch()).length).toBe(5);
971
+ expect((await rs.fetch({ fetchSize: 2 })).length).toBe(2);
972
+ expect((await rs.fetch()).length).toBe(5);
973
+ expect((await rs.fetch({ fetchSize: 36 })).length).toBe(36);
974
+ expect((await rs.fetch()).length).toBe(2);
975
+ expect((await rs.fetch()).length).toBe(0);
846
976
 
847
- await rs.close();
977
+ await rs.close();
848
978
 
849
- await transaction.commit();
850
- await attachment.dropDatabase();
851
- });
979
+ await transaction.commit();
980
+ await attachment.dropDatabase();
981
+ });
852
982
 
853
- test('#fetch() with fetchSize and exception', async () => {
854
- const attachment = await client.createDatabase(getTempFile('ResultSet-fetch-with-fetchSize.fdb'));
855
- const transaction = await attachment.startTransaction();
983
+ test('#fetch() with fetchSize and exception', async () => {
984
+ const attachment = await client.createDatabase(getTempFile('ResultSet-fetch-with-fetchSize.fdb'));
985
+ const transaction = await attachment.startTransaction();
856
986
 
857
- await attachment.execute(transaction, 'create exception e1 \'e1\'');
858
- await transaction.commitRetaining();
987
+ await attachment.execute(transaction, "create exception e1 'e1'");
988
+ await transaction.commitRetaining();
859
989
 
860
- const rs = await attachment.executeQuery(transaction, `
990
+ const rs = await attachment.executeQuery(
991
+ transaction,
992
+ `
861
993
  execute block returns (n integer)
862
994
  as
863
995
  begin
@@ -869,91 +1001,95 @@ export function runCommonTests(client: Client) {
869
1001
  n = 3;
870
1002
  suspend;
871
1003
  end
872
- `);
873
- rs.defaultFetchOptions = { fetchSize: 5 };
1004
+ `,
1005
+ );
1006
+ rs.defaultFetchOptions = { fetchSize: 5 };
874
1007
 
875
- expect((await rs.fetch()).length).toBe(2);
876
- expect(rs.fetch()).rejects.toBeTruthy();
1008
+ expect((await rs.fetch()).length).toBe(2);
1009
+ expect(rs.fetch()).rejects.toBeTruthy();
877
1010
 
878
- await rs.close();
1011
+ await rs.close();
879
1012
 
880
- await transaction.commit();
881
- await attachment.dropDatabase();
882
- });
1013
+ await transaction.commit();
1014
+ await attachment.dropDatabase();
1015
+ });
883
1016
 
884
- test('#fetch() with large blob', async () => {
885
- const attachment = await client.createDatabase(getTempFile('ResultSet-fetch-with-large-blob.fdb'));
886
- let transaction = await attachment.startTransaction();
887
- await attachment.execute(transaction, `create table t1 (x_blob blob)`);
1017
+ test('#fetch() with large blob', async () => {
1018
+ const attachment = await client.createDatabase(getTempFile('ResultSet-fetch-with-large-blob.fdb'));
1019
+ let transaction = await attachment.startTransaction();
1020
+ await attachment.execute(transaction, `create table t1 (x_blob blob)`);
888
1021
 
889
- await transaction.commit();
890
- transaction = await attachment.startTransaction();
891
- const buffer = Buffer.from('123'.repeat(60000));
1022
+ await transaction.commit();
1023
+ transaction = await attachment.startTransaction();
1024
+ const buffer = Buffer.from('123'.repeat(60000));
892
1025
 
893
- await attachment.execute(transaction, `insert into t1 (x_blob) values (?)`, [buffer]);
1026
+ await attachment.execute(transaction, `insert into t1 (x_blob) values (?)`, [buffer]);
894
1027
 
895
- await transaction.commit();
896
- transaction = await attachment.startTransaction();
1028
+ await transaction.commit();
1029
+ transaction = await attachment.startTransaction();
897
1030
 
898
- const resultSet = await attachment.executeQuery(transaction, `select x_blob from t1`);
899
- const result = await resultSet.fetch();
900
- const readStream = await attachment.openBlob(transaction, result[0][0]);
1031
+ const resultSet = await attachment.executeQuery(transaction, `select x_blob from t1`);
1032
+ const result = await resultSet.fetch();
1033
+ const readStream = await attachment.openBlob(transaction, result[0][0]);
901
1034
 
902
- const blobLength = await readStream.length;
903
- const resultBuffer = Buffer.alloc(blobLength);
1035
+ const blobLength = await readStream.length;
1036
+ const resultBuffer = Buffer.alloc(blobLength);
904
1037
 
905
- let size = 0;
906
- let n: number;
907
- while (size < blobLength && (n = await readStream.read(resultBuffer.slice(size))) > 0)
908
- size += n;
1038
+ let size = 0;
1039
+ let n: number;
1040
+ while (size < blobLength && (n = await readStream.read(resultBuffer.slice(size))) > 0) {
1041
+ size += n;
1042
+ }
909
1043
 
910
- await readStream.close();
911
- expect(resultBuffer.toString().length).toEqual(buffer.toString().length);
912
- expect(resultBuffer.toString()).toEqual(buffer.toString());
1044
+ await readStream.close();
1045
+ expect(resultBuffer.toString().length).toEqual(buffer.toString().length);
1046
+ expect(resultBuffer.toString()).toEqual(buffer.toString());
913
1047
 
914
- await resultSet.close();
915
- await transaction.commit();
916
- await attachment.dropDatabase();
917
- });
918
- });
1048
+ await resultSet.close();
1049
+ await transaction.commit();
1050
+ await attachment.dropDatabase();
1051
+ });
1052
+ });
919
1053
 
920
- describe('BlobStream', () => {
921
- test('#seek()', async () => {
922
- const attachment = await client.createDatabase(getTempFile('BlobStream-seek.fdb'));
923
- const transaction = await attachment.startTransaction();
1054
+ describe('BlobStream', () => {
1055
+ test('#seek()', async () => {
1056
+ const attachment = await client.createDatabase(getTempFile('BlobStream-seek.fdb'));
1057
+ const transaction = await attachment.startTransaction();
924
1058
 
925
- await attachment.execute(transaction, 'create table t1 (b blob)');
926
- await transaction.commitRetaining();
1059
+ await attachment.execute(transaction, 'create table t1 (b blob)');
1060
+ await transaction.commitRetaining();
927
1061
 
928
- const blobStream = await attachment.createBlob(transaction, { type: 'STREAM' });
929
- await blobStream.write(Buffer.alloc(10, '1234567890'));
930
- await blobStream.close();
931
- await attachment.execute(transaction, 'insert into t1 (b) values (?)', [blobStream.blob]);
1062
+ const blobStream = await attachment.createBlob(transaction, {
1063
+ type: 'STREAM',
1064
+ });
1065
+ await blobStream.write(Buffer.alloc(10, '1234567890'));
1066
+ await blobStream.close();
1067
+ await attachment.execute(transaction, 'insert into t1 (b) values (?)', [blobStream.blob]);
932
1068
 
933
- const blob = (await attachment.executeSingleton(transaction, 'select b from t1'))[0] as Blob;
934
- const readBlobStream = await attachment.openBlob(transaction, blob);
1069
+ const blob = (await attachment.executeSingleton(transaction, 'select b from t1'))[0] as Blob;
1070
+ const readBlobStream = await attachment.openBlob(transaction, blob);
935
1071
 
936
- const buffer = Buffer.alloc(3);
1072
+ const buffer = Buffer.alloc(3);
937
1073
 
938
- expect(await readBlobStream.seek(2)).toBe(2);
939
- expect(await readBlobStream.read(buffer)).toBe(3);
940
- expect(buffer.toString()).toBe('345');
1074
+ expect(await readBlobStream.seek(2)).toBe(2);
1075
+ expect(await readBlobStream.read(buffer)).toBe(3);
1076
+ expect(buffer.toString()).toBe('345');
941
1077
 
942
- expect(await readBlobStream.seek(-1, BlobSeekWhence.CURRENT)).toBe(4);
943
- expect(await readBlobStream.read(buffer)).toBe(3);
944
- expect(buffer.toString()).toBe('567');
1078
+ expect(await readBlobStream.seek(-1, BlobSeekWhence.CURRENT)).toBe(4);
1079
+ expect(await readBlobStream.read(buffer)).toBe(3);
1080
+ expect(buffer.toString()).toBe('567');
945
1081
 
946
- expect(await readBlobStream.seek(1, BlobSeekWhence.START)).toBe(1);
947
- expect(await readBlobStream.read(buffer)).toBe(3);
948
- expect(buffer.toString()).toBe('234');
1082
+ expect(await readBlobStream.seek(1, BlobSeekWhence.START)).toBe(1);
1083
+ expect(await readBlobStream.read(buffer)).toBe(3);
1084
+ expect(buffer.toString()).toBe('234');
949
1085
 
950
- expect(await readBlobStream.seek(-2, BlobSeekWhence.END)).toBe(8);
951
- expect(await readBlobStream.read(buffer)).toBe(2);
952
- expect(buffer.slice(0, 2).toString()).toBe('90');
1086
+ expect(await readBlobStream.seek(-2, BlobSeekWhence.END)).toBe(8);
1087
+ expect(await readBlobStream.read(buffer)).toBe(2);
1088
+ expect(buffer.slice(0, 2).toString()).toBe('90');
953
1089
 
954
- await transaction.commit();
955
- await attachment.dropDatabase();
956
- });
957
- });
958
- });
1090
+ await transaction.commit();
1091
+ await attachment.dropDatabase();
1092
+ });
1093
+ });
1094
+ });
959
1095
  }