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