node-firebird 2.4.2 → 2.5.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/README.md +52 -0
- package/lib/callback.d.ts +13 -0
- package/lib/callback.js +31 -0
- package/lib/index.d.ts +6 -1
- package/lib/index.js +16 -0
- package/lib/pool.d.ts +7 -0
- package/lib/pool.js +25 -0
- package/lib/types.d.ts +32 -0
- package/lib/wire/connection.js +19 -14
- package/lib/wire/database.d.ts +15 -0
- package/lib/wire/database.js +66 -0
- package/lib/wire/statement.d.ts +7 -0
- package/lib/wire/statement.js +30 -0
- package/lib/wire/transaction.d.ts +8 -0
- package/lib/wire/transaction.js +38 -0
- package/package.json +1 -1
- package/src/callback.ts +36 -0
- package/src/index.ts +28 -1
- package/src/pool.ts +28 -0
- package/src/types.ts +41 -0
- package/src/wire/connection.ts +19 -14
- package/src/wire/database.ts +76 -1
- package/src/wire/statement.ts +39 -0
- package/src/wire/transaction.ts +48 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
- [Installation](#installation)
|
|
12
12
|
- [Usage](#usage) — including [developing the driver](#developing-the-driver)
|
|
13
|
+
- [Promises and async/await](#promises-and-asyncawait) — the `*Async` API plus `withConnection` / `withTransaction` helpers
|
|
13
14
|
- [Connection types](#connection-types) — connection options, classic connections, pooling
|
|
14
15
|
- [Database object (db)](#database-object-db) — database, transaction and statement methods/options
|
|
15
16
|
- [Examples](#examples) — parametrized queries, BLOBs, streaming big data, transactions, driver events, database events (POST_EVENT), service manager, charsets/encoding, Firebird 3.0–6.0 features
|
|
@@ -98,6 +99,55 @@ npm test # build + run the vitest suite (unit + integration)
|
|
|
98
99
|
- `Firebird.create(options, function(err, db))` create a database
|
|
99
100
|
- `Firebird.attachOrCreate(options, function(err, db))` attach or create database
|
|
100
101
|
- `Firebird.pool(max, options) -> return {Object}` create a connection pooling
|
|
102
|
+
- `Firebird.attachAsync(options) -> Promise<Database>`, `createAsync`, `attachOrCreateAsync`, `dropAsync` — promise counterparts, see [Promises and async/await](#promises-and-asyncawait)
|
|
103
|
+
|
|
104
|
+
## Promises and async/await
|
|
105
|
+
|
|
106
|
+
Every callback API has a promise-returning counterpart with an `Async`
|
|
107
|
+
suffix, plus two higher-level helpers: `pool.withConnection()` and
|
|
108
|
+
`db.withTransaction()`. The callback API is unchanged and the two styles can
|
|
109
|
+
be mixed freely, though sticking to one per project keeps code readable.
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
const Firebird = require('node-firebird');
|
|
113
|
+
|
|
114
|
+
const pool = Firebird.pool(5, options);
|
|
115
|
+
|
|
116
|
+
// acquire → work → always release, even when `work` throws
|
|
117
|
+
const users = await pool.withConnection((db) =>
|
|
118
|
+
db.queryAsync('SELECT id, name FROM users WHERE plan = ?', ['pro'])
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// commit on success, rollback on error
|
|
122
|
+
await pool.withConnection((db) =>
|
|
123
|
+
db.withTransaction(async (transaction) => {
|
|
124
|
+
await transaction.executeAsync('INSERT INTO audit (msg) VALUES (?)', ['signup']);
|
|
125
|
+
await transaction.executeAsync('UPDATE stats SET signups = signups + 1');
|
|
126
|
+
})
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
await pool.destroyAsync();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Available wrappers:
|
|
133
|
+
|
|
134
|
+
- **module** — `Firebird.attachAsync(options)`, `createAsync`, `attachOrCreateAsync`, `dropAsync`; resolve with a `Database` (or a `ServiceManager` when `options.manager` is `true`)
|
|
135
|
+
- **pool** — `pool.getAsync()`, `pool.destroyAsync()`, `pool.withConnection(work)`
|
|
136
|
+
- **database** — `db.queryAsync(sql, params?, options?)`, `executeAsync`, `sequentiallyAsync(sql, params?, onRow, options?)`, `transactionAsync(options?)`, `newStatementAsync(sql)`, `attachEventAsync()`, `detachAsync()`, `dropAsync()`, `db.withTransaction(work, options?)`
|
|
137
|
+
- **transaction** — `queryAsync`, `executeAsync`, `sequentiallyAsync`, `newStatementAsync`, `commitAsync`, `rollbackAsync`, `commitRetainingAsync`, `rollbackRetainingAsync`
|
|
138
|
+
- **statement** — `executeAsync(transaction, params?, options?)`, `fetchAsync`, `fetchScrollAsync`, `fetchAllAsync`, `closeAsync`, `dropAsync`, `releaseAsync`
|
|
139
|
+
|
|
140
|
+
Notes:
|
|
141
|
+
|
|
142
|
+
- Rejections are always `Error` instances carrying the usual Firebird
|
|
143
|
+
properties (`err.gdscode`, `err.gdsparams`) — see [Using GDS codes](#using-gds-codes).
|
|
144
|
+
- `queryAsync` / `executeAsync` resolve with the rows only; column metadata
|
|
145
|
+
is currently available through the callback API only.
|
|
146
|
+
- An un-`await`ed rejected promise becomes an unhandled rejection instead of
|
|
147
|
+
a callback error — prefer the `withConnection` / `withTransaction` helpers,
|
|
148
|
+
which guarantee cleanup on every path.
|
|
149
|
+
- TypeScript: the async methods accept a row-shape generic, e.g.
|
|
150
|
+
`db.queryAsync<User>(sql, params)` returns `Promise<User[]>`.
|
|
101
151
|
|
|
102
152
|
## Connection types
|
|
103
153
|
|
|
@@ -1230,6 +1280,8 @@ process.on('SIGTERM', function() {
|
|
|
1230
1280
|
|
|
1231
1281
|
node-firebird works well with Express, but because the driver is connection/pool based rather than an ORM with automatic connection management, a few request-lifecycle patterns keep connections from leaking under load. This section documents the recommended architecture, referenced from the [roadmap](ROADMAP.md#2-expressjs-support-first-class-integration).
|
|
1232
1282
|
|
|
1283
|
+
> The driver now ships native `pool.withConnection()` and `db.withTransaction()` helpers (see [Promises and async/await](#promises-and-asyncawait)) that supersede the hand-rolled `withConnection` / `transactional` helpers shown in the examples below. The examples remain valid and show what the helpers do under the hood.
|
|
1284
|
+
|
|
1233
1285
|
### Recommended architecture: one pool per app, created at startup
|
|
1234
1286
|
|
|
1235
1287
|
Create a single `Firebird.pool(...)` when the app boots and reuse it for the lifetime of the process. Do **not** call `Firebird.pool()` or `Firebird.attach()` inside a request handler — that opens a new socket (or an entire new pool) on every request and will exhaust server and database resources under load.
|
package/lib/callback.d.ts
CHANGED
|
@@ -16,5 +16,18 @@ export interface FbError extends Error {
|
|
|
16
16
|
}
|
|
17
17
|
export type SimpleCallback = (err?: any) => void;
|
|
18
18
|
export type Callback<T = any> = (err?: any, result?: T) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Normalize the values the driver passes as the callback error argument.
|
|
21
|
+
* Most code paths already deliver Error instances, but a few older ones
|
|
22
|
+
* pass plain objects (status vectors, `{error, message}` wrappers). A
|
|
23
|
+
* Promise must reject with an Error, so wrap those while preserving all
|
|
24
|
+
* their properties (gdscode, gdsparams, status, sqlcode, ...).
|
|
25
|
+
*/
|
|
26
|
+
export declare function toError(err: any): Error;
|
|
27
|
+
/**
|
|
28
|
+
* Run a callback-style operation and return a Promise for its result.
|
|
29
|
+
* Usage: fromCallback<Database>(cb => attach(options, cb))
|
|
30
|
+
*/
|
|
31
|
+
export declare function fromCallback<T = any>(executor: (cb: Callback<T>) => void): Promise<T>;
|
|
19
32
|
export declare function doError(obj: any, callback?: (...args: any[]) => void): void;
|
|
20
33
|
export declare function doCallback<T>(obj: T, callback?: Callback<T>): void;
|
package/lib/callback.js
CHANGED
|
@@ -1,7 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toError = toError;
|
|
4
|
+
exports.fromCallback = fromCallback;
|
|
3
5
|
exports.doError = doError;
|
|
4
6
|
exports.doCallback = doCallback;
|
|
7
|
+
/**
|
|
8
|
+
* Normalize the values the driver passes as the callback error argument.
|
|
9
|
+
* Most code paths already deliver Error instances, but a few older ones
|
|
10
|
+
* pass plain objects (status vectors, `{error, message}` wrappers). A
|
|
11
|
+
* Promise must reject with an Error, so wrap those while preserving all
|
|
12
|
+
* their properties (gdscode, gdsparams, status, sqlcode, ...).
|
|
13
|
+
*/
|
|
14
|
+
function toError(err) {
|
|
15
|
+
if (err instanceof Error)
|
|
16
|
+
return err;
|
|
17
|
+
var error = new Error(err != null && typeof err === 'object' && err.message ? err.message : String(err));
|
|
18
|
+
if (err != null && typeof err === 'object')
|
|
19
|
+
Object.assign(error, err);
|
|
20
|
+
return error;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Run a callback-style operation and return a Promise for its result.
|
|
24
|
+
* Usage: fromCallback<Database>(cb => attach(options, cb))
|
|
25
|
+
*/
|
|
26
|
+
function fromCallback(executor) {
|
|
27
|
+
return new Promise(function (resolve, reject) {
|
|
28
|
+
executor(function (err, result) {
|
|
29
|
+
if (err)
|
|
30
|
+
reject(toError(err));
|
|
31
|
+
else
|
|
32
|
+
resolve(result);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
5
36
|
function doError(obj, callback) {
|
|
6
37
|
if (callback)
|
|
7
38
|
callback(obj);
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Connection from './wire/connection';
|
|
2
2
|
import { escape as escapeValue } from './utils';
|
|
3
|
-
import type { Options, SvcMgrOptions, DatabaseCallback, ServiceManagerCallback, SimpleCallback, ConnectionPool } from './types';
|
|
3
|
+
import type { Options, SvcMgrOptions, DatabaseCallback, ServiceManagerCallback, SimpleCallback, ConnectionPool, Database, ServiceManager } from './types';
|
|
4
4
|
export * from './types';
|
|
5
5
|
export { GDSCode } from './gdscodes';
|
|
6
6
|
export declare const AUTH_PLUGIN_LEGACY: string;
|
|
@@ -35,3 +35,8 @@ export declare function drop(options: Options, callback: SimpleCallback): void;
|
|
|
35
35
|
export declare function create(options: Options, callback: DatabaseCallback): void;
|
|
36
36
|
export declare function attachOrCreate(options: Options, callback: DatabaseCallback): void;
|
|
37
37
|
export declare function pool(max: number, options: Options): ConnectionPool;
|
|
38
|
+
export declare function attachAsync(options: SvcMgrOptions): Promise<ServiceManager>;
|
|
39
|
+
export declare function attachAsync(options: Options): Promise<Database>;
|
|
40
|
+
export declare function createAsync(options: Options): Promise<Database>;
|
|
41
|
+
export declare function attachOrCreateAsync(options: Options): Promise<Database>;
|
|
42
|
+
export declare function dropAsync(options: Options): Promise<void>;
|
package/lib/index.js
CHANGED
|
@@ -23,6 +23,10 @@ exports.drop = drop;
|
|
|
23
23
|
exports.create = create;
|
|
24
24
|
exports.attachOrCreate = attachOrCreate;
|
|
25
25
|
exports.pool = pool;
|
|
26
|
+
exports.attachAsync = attachAsync;
|
|
27
|
+
exports.createAsync = createAsync;
|
|
28
|
+
exports.attachOrCreateAsync = attachOrCreateAsync;
|
|
29
|
+
exports.dropAsync = dropAsync;
|
|
26
30
|
const const_1 = __importDefault(require("./wire/const"));
|
|
27
31
|
const callback_1 = require("./callback");
|
|
28
32
|
const connection_1 = __importDefault(require("./wire/connection"));
|
|
@@ -137,3 +141,15 @@ function attachOrCreate(options, callback) {
|
|
|
137
141
|
function pool(max, options) {
|
|
138
142
|
return new pool_1.default(attach, max, Object.assign({}, options, { isPool: true }));
|
|
139
143
|
}
|
|
144
|
+
function attachAsync(options) {
|
|
145
|
+
return (0, callback_1.fromCallback)(function (cb) { attach(options, cb); });
|
|
146
|
+
}
|
|
147
|
+
function createAsync(options) {
|
|
148
|
+
return (0, callback_1.fromCallback)(function (cb) { create(options, cb); });
|
|
149
|
+
}
|
|
150
|
+
function attachOrCreateAsync(options) {
|
|
151
|
+
return (0, callback_1.fromCallback)(function (cb) { attachOrCreate(options, cb); });
|
|
152
|
+
}
|
|
153
|
+
function dropAsync(options) {
|
|
154
|
+
return (0, callback_1.fromCallback)(function (cb) { drop(options, cb); });
|
|
155
|
+
}
|
package/lib/pool.d.ts
CHANGED
|
@@ -19,5 +19,12 @@ declare class Pool {
|
|
|
19
19
|
get(callback: Callback): this;
|
|
20
20
|
check(): this;
|
|
21
21
|
destroy(callback?: (err?: any) => void): void;
|
|
22
|
+
getAsync(): Promise<any>;
|
|
23
|
+
destroyAsync(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Run `work` with a connection from the pool, returning it to the pool
|
|
26
|
+
* (detach) when the returned promise settles — success or failure.
|
|
27
|
+
*/
|
|
28
|
+
withConnection<T>(work: (db: any) => Promise<T> | T): Promise<T>;
|
|
22
29
|
}
|
|
23
30
|
export = Pool;
|
package/lib/pool.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Simple Pooling
|
|
5
5
|
*
|
|
6
6
|
***************************************/
|
|
7
|
+
const callback_1 = require("./callback");
|
|
7
8
|
class Pool {
|
|
8
9
|
constructor(attach, max, options) {
|
|
9
10
|
this.attach = attach;
|
|
@@ -178,5 +179,29 @@ class Pool {
|
|
|
178
179
|
}
|
|
179
180
|
});
|
|
180
181
|
}
|
|
182
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
183
|
+
getAsync() {
|
|
184
|
+
var self = this;
|
|
185
|
+
return (0, callback_1.fromCallback)(function (cb) { self.get(cb); });
|
|
186
|
+
}
|
|
187
|
+
destroyAsync() {
|
|
188
|
+
var self = this;
|
|
189
|
+
return (0, callback_1.fromCallback)(function (cb) { self.destroy(cb); });
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Run `work` with a connection from the pool, returning it to the pool
|
|
193
|
+
* (detach) when the returned promise settles — success or failure.
|
|
194
|
+
*/
|
|
195
|
+
async withConnection(work) {
|
|
196
|
+
const db = await this.getAsync();
|
|
197
|
+
try {
|
|
198
|
+
return await work(db);
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
// A pooled detach only returns the connection to the pool; do not
|
|
202
|
+
// let a detach hiccup mask the outcome of `work`.
|
|
203
|
+
await new Promise(function (resolve) { db.detach(function () { resolve(); }); });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
181
206
|
}
|
|
182
207
|
module.exports = Pool;
|
package/lib/types.d.ts
CHANGED
|
@@ -82,6 +82,18 @@ export interface Database {
|
|
|
82
82
|
alterTablespace(name: string, filePath: string, callback?: QueryCallback): Database;
|
|
83
83
|
dropTablespace(name: string, callback?: QueryCallback): Database;
|
|
84
84
|
createSchema(schemaName: string, tablespaceName?: string | QueryCallback, callback?: QueryCallback): Database;
|
|
85
|
+
queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
86
|
+
executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
87
|
+
sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
88
|
+
sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
89
|
+
transactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction>;
|
|
90
|
+
startTransactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction>;
|
|
91
|
+
newStatementAsync(query: string): Promise<Statement>;
|
|
92
|
+
detachAsync(force?: boolean): Promise<void>;
|
|
93
|
+
dropAsync(): Promise<void>;
|
|
94
|
+
attachEventAsync(): Promise<any>;
|
|
95
|
+
/** Starts a transaction, commits when `work` resolves, rolls back when it rejects. */
|
|
96
|
+
withTransaction<T>(work: (transaction: Transaction) => Promise<T> | T, options?: TransactionOptions | Isolation): Promise<T>;
|
|
85
97
|
}
|
|
86
98
|
export interface Transaction {
|
|
87
99
|
newStatement(query: string, callback: (err: Error | null, statement: Statement) => void): void;
|
|
@@ -92,6 +104,15 @@ export interface Transaction {
|
|
|
92
104
|
commitRetaining(callback?: SimpleCallback): void;
|
|
93
105
|
rollback(callback?: SimpleCallback): void;
|
|
94
106
|
rollbackRetaining(callback?: SimpleCallback): void;
|
|
107
|
+
queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
108
|
+
executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
109
|
+
sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
110
|
+
sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
111
|
+
newStatementAsync(query: string): Promise<Statement>;
|
|
112
|
+
commitAsync(): Promise<void>;
|
|
113
|
+
commitRetainingAsync(): Promise<void>;
|
|
114
|
+
rollbackAsync(): Promise<void>;
|
|
115
|
+
rollbackRetainingAsync(): Promise<void>;
|
|
95
116
|
}
|
|
96
117
|
export interface Statement {
|
|
97
118
|
close(callback?: SimpleCallback): void;
|
|
@@ -101,6 +122,13 @@ export interface Statement {
|
|
|
101
122
|
fetch(transaction: Transaction, count: number, callback: QueryCallback): void;
|
|
102
123
|
fetchScroll(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset: number, count: number, callback: QueryCallback): void;
|
|
103
124
|
fetchAll(transaction: Transaction, callback: QueryCallback): void;
|
|
125
|
+
executeAsync(transaction: Transaction, params?: any[], options?: QueryOptions): Promise<any>;
|
|
126
|
+
fetchAsync(transaction: Transaction, count: number | 'all'): Promise<any>;
|
|
127
|
+
fetchScrollAsync(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset?: number, count?: number): Promise<any>;
|
|
128
|
+
fetchAllAsync(transaction: Transaction): Promise<any>;
|
|
129
|
+
closeAsync(): Promise<void>;
|
|
130
|
+
dropAsync(): Promise<void>;
|
|
131
|
+
releaseAsync(): Promise<void>;
|
|
104
132
|
}
|
|
105
133
|
export type SupportedCharacterSet = 'NONE' | 'CP943C' | 'DOS737' | 'DOS775' | 'DOS858' | 'DOS862' | 'DOS864' | 'DOS866' | 'DOS869' | 'GB18030' | 'GBK' | 'ISO8859_1' | 'ISO8859_2' | 'ISO8859_3' | 'ISO8859_4' | 'ISO8859_5' | 'ISO8859_6' | 'ISO8859_7' | 'ISO8859_8' | 'ISO8859_9' | 'ISO8859_13' | 'KOI8R' | 'KOI8U' | 'TIS620' | 'UTF8' | 'WIN1251' | 'WIN1252' | 'WIN1253' | 'WIN1254' | 'WIN1255' | 'WIN1256' | 'WIN1257' | 'WIN1258' | 'WIN_1258';
|
|
106
134
|
export interface Options {
|
|
@@ -188,6 +216,10 @@ export interface SvcMgrOptions extends Options {
|
|
|
188
216
|
export interface ConnectionPool {
|
|
189
217
|
get(callback: DatabaseCallback): void;
|
|
190
218
|
destroy(callback?: SimpleCallback): void;
|
|
219
|
+
getAsync(): Promise<Database>;
|
|
220
|
+
destroyAsync(): Promise<void>;
|
|
221
|
+
/** Acquire a connection, run `work`, always return the connection to the pool. */
|
|
222
|
+
withConnection<T>(work: (db: Database) => Promise<T> | T): Promise<T>;
|
|
191
223
|
}
|
|
192
224
|
export interface ReadableOptions {
|
|
193
225
|
optread?: 'byline' | 'buffer';
|
package/lib/wire/connection.js
CHANGED
|
@@ -1823,16 +1823,20 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
1823
1823
|
public: BigInt('0x' + d.buffer.slice(keyStart, d.buffer.length).toString('utf8')),
|
|
1824
1824
|
pluginName: accept.pluginName
|
|
1825
1825
|
};
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1826
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
1827
|
+
console.log('--- DEBUG SRP Handshake ---');
|
|
1828
|
+
console.log('salt:', cnx.serverKeys.salt);
|
|
1829
|
+
console.log('server public key:', cnx.serverKeys.public.toString(16));
|
|
1830
|
+
console.log('client public key:', cnx.clientKeys.public.toString(16));
|
|
1831
|
+
console.log('hashAlgo:', accept.srpAlgo);
|
|
1832
|
+
}
|
|
1832
1833
|
const _t1 = Date.now();
|
|
1833
1834
|
var proof = srp.clientProof(cnx.options.user.toUpperCase(), cnx.options.password, cnx.serverKeys.salt, cnx.clientKeys.public, cnx.serverKeys.public, cnx.clientKeys.private, accept.srpAlgo);
|
|
1834
|
-
|
|
1835
|
-
|
|
1835
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
1836
|
+
// Never log the private key or the session key: the
|
|
1837
|
+
// session key is the wire-encryption key material.
|
|
1838
|
+
console.log('client proof M1:', proof.authData.toString(16));
|
|
1839
|
+
}
|
|
1836
1840
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1837
1841
|
console.log('[fb-debug] srp.clientProof(%s): %dms', accept.srpAlgo, Date.now() - _t1);
|
|
1838
1842
|
}
|
|
@@ -1917,12 +1921,13 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
1917
1921
|
Srp512: 'sha512'
|
|
1918
1922
|
};
|
|
1919
1923
|
var srpAlgo = crypto[pluginName];
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1924
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
1925
|
+
console.log('--- DEBUG SRP Handshake ---');
|
|
1926
|
+
console.log('salt:', cnx.serverKeys.salt);
|
|
1927
|
+
console.log('server public key:', cnx.serverKeys.public.toString(16));
|
|
1928
|
+
console.log('client public key:', cnx.clientKeys.public.toString(16));
|
|
1929
|
+
console.log('hashAlgo:', srpAlgo);
|
|
1930
|
+
}
|
|
1926
1931
|
const _t1 = Date.now();
|
|
1927
1932
|
var proof = srp.clientProof(cnx.options.user.toUpperCase(), cnx.options.password, cnx.serverKeys.salt, cnx.clientKeys.public, cnx.serverKeys.public, cnx.clientKeys.private, srpAlgo);
|
|
1928
1933
|
if (process.env.FIREBIRD_DEBUG) {
|
package/lib/wire/database.d.ts
CHANGED
|
@@ -53,5 +53,20 @@ declare class Database extends Events.EventEmitter {
|
|
|
53
53
|
* @returns {Database}
|
|
54
54
|
*/
|
|
55
55
|
createSchema(schemaName: string, tablespaceName?: string | ((err?: any) => void), callback?: any): this;
|
|
56
|
+
queryAsync(query: string, params?: any, options?: any): Promise<any[]>;
|
|
57
|
+
executeAsync(query: string, params?: any, options?: any): Promise<any[]>;
|
|
58
|
+
sequentiallyAsync(query: string, params?: any, on?: any, options?: any): Promise<void>;
|
|
59
|
+
transactionAsync(options?: any): Promise<any>;
|
|
60
|
+
startTransactionAsync(options?: any): Promise<any>;
|
|
61
|
+
newStatementAsync(query: string): Promise<any>;
|
|
62
|
+
detachAsync(force?: boolean): Promise<void>;
|
|
63
|
+
dropAsync(): Promise<void>;
|
|
64
|
+
attachEventAsync(): Promise<any>;
|
|
65
|
+
/**
|
|
66
|
+
* Run `work` inside a transaction: commits when the returned promise
|
|
67
|
+
* resolves, rolls back when it rejects (the original error is rethrown,
|
|
68
|
+
* even if the rollback itself fails).
|
|
69
|
+
*/
|
|
70
|
+
withTransaction<T>(work: (transaction: any) => Promise<T> | T, options?: any): Promise<T>;
|
|
56
71
|
}
|
|
57
72
|
export = Database;
|
package/lib/wire/database.js
CHANGED
|
@@ -377,5 +377,71 @@ class Database extends events_1.default.EventEmitter {
|
|
|
377
377
|
}
|
|
378
378
|
return this.execute(sql, [], callback);
|
|
379
379
|
}
|
|
380
|
+
/*
|
|
381
|
+
* Promise / async-await API.
|
|
382
|
+
* Each *Async method wraps its callback counterpart; the callback API
|
|
383
|
+
* stays untouched. Result metadata is only available through the
|
|
384
|
+
* callback API — the promises resolve with the rows alone.
|
|
385
|
+
*/
|
|
386
|
+
queryAsync(query, params, options) {
|
|
387
|
+
var self = this;
|
|
388
|
+
return (0, callback_1.fromCallback)(function (cb) { self.query(query, params, cb, options); });
|
|
389
|
+
}
|
|
390
|
+
executeAsync(query, params, options) {
|
|
391
|
+
var self = this;
|
|
392
|
+
return (0, callback_1.fromCallback)(function (cb) { self.execute(query, params, cb, options); });
|
|
393
|
+
}
|
|
394
|
+
sequentiallyAsync(query, params, on, options) {
|
|
395
|
+
if (params instanceof Function) {
|
|
396
|
+
options = on;
|
|
397
|
+
on = params;
|
|
398
|
+
params = undefined;
|
|
399
|
+
}
|
|
400
|
+
var self = this;
|
|
401
|
+
return (0, callback_1.fromCallback)(function (cb) { self.sequentially(query, params, on, cb, options); });
|
|
402
|
+
}
|
|
403
|
+
transactionAsync(options) {
|
|
404
|
+
var self = this;
|
|
405
|
+
return (0, callback_1.fromCallback)(function (cb) { self.startTransaction(options, cb); });
|
|
406
|
+
}
|
|
407
|
+
startTransactionAsync(options) {
|
|
408
|
+
return this.transactionAsync(options);
|
|
409
|
+
}
|
|
410
|
+
newStatementAsync(query) {
|
|
411
|
+
var self = this;
|
|
412
|
+
return (0, callback_1.fromCallback)(function (cb) { self.newStatement(query, cb); });
|
|
413
|
+
}
|
|
414
|
+
detachAsync(force) {
|
|
415
|
+
var self = this;
|
|
416
|
+
return (0, callback_1.fromCallback)(function (cb) { self.detach(cb, force); });
|
|
417
|
+
}
|
|
418
|
+
dropAsync() {
|
|
419
|
+
var self = this;
|
|
420
|
+
return (0, callback_1.fromCallback)(function (cb) { self.drop(cb); });
|
|
421
|
+
}
|
|
422
|
+
attachEventAsync() {
|
|
423
|
+
var self = this;
|
|
424
|
+
return (0, callback_1.fromCallback)(function (cb) { self.attachEvent(cb); });
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Run `work` inside a transaction: commits when the returned promise
|
|
428
|
+
* resolves, rolls back when it rejects (the original error is rethrown,
|
|
429
|
+
* even if the rollback itself fails).
|
|
430
|
+
*/
|
|
431
|
+
async withTransaction(work, options) {
|
|
432
|
+
const transaction = await this.transactionAsync(options);
|
|
433
|
+
try {
|
|
434
|
+
const result = await work(transaction);
|
|
435
|
+
await (0, callback_1.fromCallback)(function (cb) { transaction.commit(cb); });
|
|
436
|
+
return result;
|
|
437
|
+
}
|
|
438
|
+
catch (err) {
|
|
439
|
+
try {
|
|
440
|
+
await (0, callback_1.fromCallback)(function (cb) { transaction.rollback(cb); });
|
|
441
|
+
}
|
|
442
|
+
catch { /* surface the original error, not the rollback failure */ }
|
|
443
|
+
throw err;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
380
446
|
}
|
|
381
447
|
module.exports = Database;
|
package/lib/wire/statement.d.ts
CHANGED
|
@@ -21,5 +21,12 @@ declare class Statement {
|
|
|
21
21
|
fetch(transaction: any, count: number | string, callback: (err: any, result?: any) => void): void;
|
|
22
22
|
fetchScroll(transaction: any, direction: string | number, offset?: any, count?: any, callback?: any): void;
|
|
23
23
|
fetchAll(transaction: any, callback: (err: any, result?: any) => void): void;
|
|
24
|
+
executeAsync(transaction: any, params?: any, options?: any): Promise<any>;
|
|
25
|
+
fetchAsync(transaction: any, count: number | string): Promise<any>;
|
|
26
|
+
fetchScrollAsync(transaction: any, direction: string | number, offset?: any, count?: any): Promise<any>;
|
|
27
|
+
fetchAllAsync(transaction: any): Promise<any>;
|
|
28
|
+
closeAsync(): Promise<void>;
|
|
29
|
+
dropAsync(): Promise<void>;
|
|
30
|
+
releaseAsync(): Promise<void>;
|
|
24
31
|
}
|
|
25
32
|
export = Statement;
|
package/lib/wire/statement.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Statement
|
|
5
5
|
*
|
|
6
6
|
***************************************/
|
|
7
|
+
const callback_1 = require("../callback");
|
|
7
8
|
class Statement {
|
|
8
9
|
constructor(connection) {
|
|
9
10
|
this.connection = connection;
|
|
@@ -48,5 +49,34 @@ class Statement {
|
|
|
48
49
|
fetchAll(transaction, callback) {
|
|
49
50
|
this.connection.fetchAll(this, transaction, callback);
|
|
50
51
|
}
|
|
52
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
53
|
+
executeAsync(transaction, params, options) {
|
|
54
|
+
var self = this;
|
|
55
|
+
return (0, callback_1.fromCallback)(function (cb) { self.execute(transaction, params, cb, options); });
|
|
56
|
+
}
|
|
57
|
+
fetchAsync(transaction, count) {
|
|
58
|
+
var self = this;
|
|
59
|
+
return (0, callback_1.fromCallback)(function (cb) { self.fetch(transaction, count, cb); });
|
|
60
|
+
}
|
|
61
|
+
fetchScrollAsync(transaction, direction, offset, count) {
|
|
62
|
+
var self = this;
|
|
63
|
+
return (0, callback_1.fromCallback)(function (cb) { self.fetchScroll(transaction, direction, offset, count, cb); });
|
|
64
|
+
}
|
|
65
|
+
fetchAllAsync(transaction) {
|
|
66
|
+
var self = this;
|
|
67
|
+
return (0, callback_1.fromCallback)(function (cb) { self.fetchAll(transaction, cb); });
|
|
68
|
+
}
|
|
69
|
+
closeAsync() {
|
|
70
|
+
var self = this;
|
|
71
|
+
return (0, callback_1.fromCallback)(function (cb) { self.close(cb); });
|
|
72
|
+
}
|
|
73
|
+
dropAsync() {
|
|
74
|
+
var self = this;
|
|
75
|
+
return (0, callback_1.fromCallback)(function (cb) { self.drop(cb); });
|
|
76
|
+
}
|
|
77
|
+
releaseAsync() {
|
|
78
|
+
var self = this;
|
|
79
|
+
return (0, callback_1.fromCallback)(function (cb) { self.release(cb); });
|
|
80
|
+
}
|
|
51
81
|
}
|
|
52
82
|
module.exports = Statement;
|
|
@@ -17,5 +17,13 @@ declare class Transaction {
|
|
|
17
17
|
rollback(callback?: (err?: any) => void): void;
|
|
18
18
|
commitRetaining(callback?: (err?: any) => void): void;
|
|
19
19
|
rollbackRetaining(callback?: (err?: any) => void): void;
|
|
20
|
+
queryAsync(query: string, params?: any, options?: any): Promise<any[]>;
|
|
21
|
+
executeAsync(query: string, params?: any, options?: any): Promise<any[]>;
|
|
22
|
+
sequentiallyAsync(query: string, params?: any, on?: any, options?: any): Promise<void>;
|
|
23
|
+
newStatementAsync(query: string): Promise<any>;
|
|
24
|
+
commitAsync(): Promise<void>;
|
|
25
|
+
rollbackAsync(): Promise<void>;
|
|
26
|
+
commitRetainingAsync(): Promise<void>;
|
|
27
|
+
rollbackRetainingAsync(): Promise<void>;
|
|
20
28
|
}
|
|
21
29
|
export = Transaction;
|
package/lib/wire/transaction.js
CHANGED
|
@@ -174,5 +174,43 @@ class Transaction {
|
|
|
174
174
|
rollbackRetaining(callback) {
|
|
175
175
|
this.connection.rollbackRetaining(this, callback);
|
|
176
176
|
}
|
|
177
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
178
|
+
queryAsync(query, params, options) {
|
|
179
|
+
var self = this;
|
|
180
|
+
return (0, callback_1.fromCallback)(function (cb) { self.query(query, params, cb, options); });
|
|
181
|
+
}
|
|
182
|
+
executeAsync(query, params, options) {
|
|
183
|
+
var self = this;
|
|
184
|
+
return (0, callback_1.fromCallback)(function (cb) { self.execute(query, params, cb, options); });
|
|
185
|
+
}
|
|
186
|
+
sequentiallyAsync(query, params, on, options) {
|
|
187
|
+
if (params instanceof Function) {
|
|
188
|
+
options = on;
|
|
189
|
+
on = params;
|
|
190
|
+
params = undefined;
|
|
191
|
+
}
|
|
192
|
+
var self = this;
|
|
193
|
+
return (0, callback_1.fromCallback)(function (cb) { self.sequentially(query, params, on, cb, options); });
|
|
194
|
+
}
|
|
195
|
+
newStatementAsync(query) {
|
|
196
|
+
var self = this;
|
|
197
|
+
return (0, callback_1.fromCallback)(function (cb) { self.newStatement(query, cb); });
|
|
198
|
+
}
|
|
199
|
+
commitAsync() {
|
|
200
|
+
var self = this;
|
|
201
|
+
return (0, callback_1.fromCallback)(function (cb) { self.commit(cb); });
|
|
202
|
+
}
|
|
203
|
+
rollbackAsync() {
|
|
204
|
+
var self = this;
|
|
205
|
+
return (0, callback_1.fromCallback)(function (cb) { self.rollback(cb); });
|
|
206
|
+
}
|
|
207
|
+
commitRetainingAsync() {
|
|
208
|
+
var self = this;
|
|
209
|
+
return (0, callback_1.fromCallback)(function (cb) { self.commitRetaining(cb); });
|
|
210
|
+
}
|
|
211
|
+
rollbackRetainingAsync() {
|
|
212
|
+
var self = this;
|
|
213
|
+
return (0, callback_1.fromCallback)(function (cb) { self.rollbackRetaining(cb); });
|
|
214
|
+
}
|
|
177
215
|
}
|
|
178
216
|
module.exports = Transaction;
|
package/package.json
CHANGED
package/src/callback.ts
CHANGED
|
@@ -20,6 +20,42 @@ export interface FbError extends Error {
|
|
|
20
20
|
export type SimpleCallback = (err?: any) => void;
|
|
21
21
|
export type Callback<T = any> = (err?: any, result?: T) => void;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Normalize the values the driver passes as the callback error argument.
|
|
25
|
+
* Most code paths already deliver Error instances, but a few older ones
|
|
26
|
+
* pass plain objects (status vectors, `{error, message}` wrappers). A
|
|
27
|
+
* Promise must reject with an Error, so wrap those while preserving all
|
|
28
|
+
* their properties (gdscode, gdsparams, status, sqlcode, ...).
|
|
29
|
+
*/
|
|
30
|
+
export function toError(err: any): Error {
|
|
31
|
+
if (err instanceof Error)
|
|
32
|
+
return err;
|
|
33
|
+
|
|
34
|
+
var error: FbError = new Error(
|
|
35
|
+
err != null && typeof err === 'object' && err.message ? err.message : String(err)
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (err != null && typeof err === 'object')
|
|
39
|
+
Object.assign(error, err);
|
|
40
|
+
|
|
41
|
+
return error;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Run a callback-style operation and return a Promise for its result.
|
|
46
|
+
* Usage: fromCallback<Database>(cb => attach(options, cb))
|
|
47
|
+
*/
|
|
48
|
+
export function fromCallback<T = any>(executor: (cb: Callback<T>) => void): Promise<T> {
|
|
49
|
+
return new Promise<T>(function(resolve, reject) {
|
|
50
|
+
executor(function(err?: any, result?: T) {
|
|
51
|
+
if (err)
|
|
52
|
+
reject(toError(err));
|
|
53
|
+
else
|
|
54
|
+
resolve(result as T);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
23
59
|
export function doError(obj: any, callback?: (...args: any[]) => void): void {
|
|
24
60
|
if (callback)
|
|
25
61
|
callback(obj)
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Const from './wire/const';
|
|
2
|
-
import { doError, doCallback } from './callback';
|
|
2
|
+
import { doError, doCallback, fromCallback } from './callback';
|
|
3
3
|
import Connection from './wire/connection';
|
|
4
4
|
import Pool from './pool';
|
|
5
5
|
import { escape as escapeValue } from './utils';
|
|
@@ -10,6 +10,8 @@ import type {
|
|
|
10
10
|
ServiceManagerCallback,
|
|
11
11
|
SimpleCallback,
|
|
12
12
|
ConnectionPool,
|
|
13
|
+
Database,
|
|
14
|
+
ServiceManager,
|
|
13
15
|
} from './types';
|
|
14
16
|
|
|
15
17
|
export * from './types';
|
|
@@ -155,3 +157,28 @@ export function attachOrCreate(options: Options, callback: DatabaseCallback): vo
|
|
|
155
157
|
export function pool(max: number, options: Options): ConnectionPool {
|
|
156
158
|
return new Pool(attach, max, Object.assign({}, options, { isPool: true }));
|
|
157
159
|
}
|
|
160
|
+
|
|
161
|
+
/*
|
|
162
|
+
* Promise / async-await API.
|
|
163
|
+
* Wrappers over the callback functions above; the callback API stays
|
|
164
|
+
* untouched. Rejections are always Error instances carrying the usual
|
|
165
|
+
* Firebird properties (gdscode, gdsparams, ...).
|
|
166
|
+
*/
|
|
167
|
+
|
|
168
|
+
export function attachAsync(options: SvcMgrOptions): Promise<ServiceManager>;
|
|
169
|
+
export function attachAsync(options: Options): Promise<Database>;
|
|
170
|
+
export function attachAsync(options: any): Promise<any> {
|
|
171
|
+
return fromCallback(function(cb) { attach(options, cb); });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function createAsync(options: Options): Promise<Database> {
|
|
175
|
+
return fromCallback(function(cb) { create(options, cb); });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function attachOrCreateAsync(options: Options): Promise<Database> {
|
|
179
|
+
return fromCallback(function(cb) { attachOrCreate(options, cb); });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function dropAsync(options: Options): Promise<void> {
|
|
183
|
+
return fromCallback(function(cb) { drop(options, cb); });
|
|
184
|
+
}
|
package/src/pool.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
***************************************/
|
|
6
6
|
|
|
7
|
+
import { fromCallback } from './callback';
|
|
7
8
|
import type { Callback } from './callback';
|
|
8
9
|
|
|
9
10
|
type AttachFn = (options: any, callback: Callback) => void;
|
|
@@ -204,6 +205,33 @@ class Pool {
|
|
|
204
205
|
}
|
|
205
206
|
});
|
|
206
207
|
}
|
|
208
|
+
|
|
209
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
210
|
+
|
|
211
|
+
getAsync(): Promise<any> {
|
|
212
|
+
var self = this;
|
|
213
|
+
return fromCallback(function(cb) { self.get(cb); });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
destroyAsync(): Promise<void> {
|
|
217
|
+
var self = this;
|
|
218
|
+
return fromCallback(function(cb) { self.destroy(cb); });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Run `work` with a connection from the pool, returning it to the pool
|
|
223
|
+
* (detach) when the returned promise settles — success or failure.
|
|
224
|
+
*/
|
|
225
|
+
async withConnection<T>(work: (db: any) => Promise<T> | T): Promise<T> {
|
|
226
|
+
const db = await this.getAsync();
|
|
227
|
+
try {
|
|
228
|
+
return await work(db);
|
|
229
|
+
} finally {
|
|
230
|
+
// A pooled detach only returns the connection to the pool; do not
|
|
231
|
+
// let a detach hiccup mask the outcome of `work`.
|
|
232
|
+
await new Promise<void>(function(resolve) { db.detach(function() { resolve(); }); });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
207
235
|
}
|
|
208
236
|
|
|
209
237
|
export = Pool;
|
package/src/types.ts
CHANGED
|
@@ -94,6 +94,21 @@ export interface Database {
|
|
|
94
94
|
alterTablespace(name: string, filePath: string, callback?: QueryCallback): Database;
|
|
95
95
|
dropTablespace(name: string, callback?: QueryCallback): Database;
|
|
96
96
|
createSchema(schemaName: string, tablespaceName?: string | QueryCallback, callback?: QueryCallback): Database;
|
|
97
|
+
|
|
98
|
+
// Promise / async-await API (see README § Promises / async–await).
|
|
99
|
+
// Result metadata is only available through the callback API.
|
|
100
|
+
queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
101
|
+
executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
102
|
+
sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
103
|
+
sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
104
|
+
transactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction>;
|
|
105
|
+
startTransactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction>;
|
|
106
|
+
newStatementAsync(query: string): Promise<Statement>;
|
|
107
|
+
detachAsync(force?: boolean): Promise<void>;
|
|
108
|
+
dropAsync(): Promise<void>;
|
|
109
|
+
attachEventAsync(): Promise<any>;
|
|
110
|
+
/** Starts a transaction, commits when `work` resolves, rolls back when it rejects. */
|
|
111
|
+
withTransaction<T>(work: (transaction: Transaction) => Promise<T> | T, options?: TransactionOptions | Isolation): Promise<T>;
|
|
97
112
|
}
|
|
98
113
|
|
|
99
114
|
export interface Transaction {
|
|
@@ -105,6 +120,17 @@ export interface Transaction {
|
|
|
105
120
|
commitRetaining(callback?: SimpleCallback): void;
|
|
106
121
|
rollback(callback?: SimpleCallback): void;
|
|
107
122
|
rollbackRetaining(callback?: SimpleCallback): void;
|
|
123
|
+
|
|
124
|
+
// Promise / async-await API
|
|
125
|
+
queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
126
|
+
executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
|
|
127
|
+
sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
128
|
+
sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
|
|
129
|
+
newStatementAsync(query: string): Promise<Statement>;
|
|
130
|
+
commitAsync(): Promise<void>;
|
|
131
|
+
commitRetainingAsync(): Promise<void>;
|
|
132
|
+
rollbackAsync(): Promise<void>;
|
|
133
|
+
rollbackRetainingAsync(): Promise<void>;
|
|
108
134
|
}
|
|
109
135
|
|
|
110
136
|
export interface Statement {
|
|
@@ -115,6 +141,15 @@ export interface Statement {
|
|
|
115
141
|
fetch(transaction: Transaction, count: number, callback: QueryCallback): void;
|
|
116
142
|
fetchScroll(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset: number, count: number, callback: QueryCallback): void;
|
|
117
143
|
fetchAll(transaction: Transaction, callback: QueryCallback): void;
|
|
144
|
+
|
|
145
|
+
// Promise / async-await API
|
|
146
|
+
executeAsync(transaction: Transaction, params?: any[], options?: QueryOptions): Promise<any>;
|
|
147
|
+
fetchAsync(transaction: Transaction, count: number | 'all'): Promise<any>;
|
|
148
|
+
fetchScrollAsync(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset?: number, count?: number): Promise<any>;
|
|
149
|
+
fetchAllAsync(transaction: Transaction): Promise<any>;
|
|
150
|
+
closeAsync(): Promise<void>;
|
|
151
|
+
dropAsync(): Promise<void>;
|
|
152
|
+
releaseAsync(): Promise<void>;
|
|
118
153
|
}
|
|
119
154
|
|
|
120
155
|
export type SupportedCharacterSet = |
|
|
@@ -240,6 +275,12 @@ export interface SvcMgrOptions extends Options {
|
|
|
240
275
|
export interface ConnectionPool {
|
|
241
276
|
get(callback: DatabaseCallback): void;
|
|
242
277
|
destroy(callback?: SimpleCallback): void;
|
|
278
|
+
|
|
279
|
+
// Promise / async-await API
|
|
280
|
+
getAsync(): Promise<Database>;
|
|
281
|
+
destroyAsync(): Promise<void>;
|
|
282
|
+
/** Acquire a connection, run `work`, always return the connection to the pool. */
|
|
283
|
+
withConnection<T>(work: (db: Database) => Promise<T> | T): Promise<T>;
|
|
243
284
|
}
|
|
244
285
|
|
|
245
286
|
export interface ReadableOptions {
|
package/src/wire/connection.ts
CHANGED
|
@@ -2185,12 +2185,13 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2185
2185
|
pluginName: accept.pluginName
|
|
2186
2186
|
};
|
|
2187
2187
|
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2188
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
2189
|
+
console.log('--- DEBUG SRP Handshake ---');
|
|
2190
|
+
console.log('salt:', cnx.serverKeys.salt);
|
|
2191
|
+
console.log('server public key:', cnx.serverKeys.public.toString(16));
|
|
2192
|
+
console.log('client public key:', cnx.clientKeys.public.toString(16));
|
|
2193
|
+
console.log('hashAlgo:', accept.srpAlgo);
|
|
2194
|
+
}
|
|
2194
2195
|
|
|
2195
2196
|
const _t1 = Date.now();
|
|
2196
2197
|
var proof = srp.clientProof(
|
|
@@ -2203,8 +2204,11 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2203
2204
|
accept.srpAlgo
|
|
2204
2205
|
);
|
|
2205
2206
|
|
|
2206
|
-
|
|
2207
|
-
|
|
2207
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
2208
|
+
// Never log the private key or the session key: the
|
|
2209
|
+
// session key is the wire-encryption key material.
|
|
2210
|
+
console.log('client proof M1:', proof.authData.toString(16));
|
|
2211
|
+
}
|
|
2208
2212
|
|
|
2209
2213
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2210
2214
|
console.log('[fb-debug] srp.clientProof(%s): %dms', accept.srpAlgo, Date.now() - _t1);
|
|
@@ -2309,12 +2313,13 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2309
2313
|
};
|
|
2310
2314
|
var srpAlgo = crypto[pluginName];
|
|
2311
2315
|
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2316
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
2317
|
+
console.log('--- DEBUG SRP Handshake ---');
|
|
2318
|
+
console.log('salt:', cnx.serverKeys.salt);
|
|
2319
|
+
console.log('server public key:', cnx.serverKeys.public.toString(16));
|
|
2320
|
+
console.log('client public key:', cnx.clientKeys.public.toString(16));
|
|
2321
|
+
console.log('hashAlgo:', srpAlgo);
|
|
2322
|
+
}
|
|
2318
2323
|
|
|
2319
2324
|
const _t1 = Date.now();
|
|
2320
2325
|
var proof = srp.clientProof(
|
package/src/wire/database.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Events from 'events';
|
|
2
|
-
import { doError } from '../callback';
|
|
2
|
+
import { doError, fromCallback } from '../callback';
|
|
3
3
|
import { escape } from '../utils';
|
|
4
4
|
import Const from './const';
|
|
5
5
|
import EventConnection from './eventConnection';
|
|
@@ -439,6 +439,81 @@ class Database extends Events.EventEmitter {
|
|
|
439
439
|
}
|
|
440
440
|
return this.execute(sql, [], callback);
|
|
441
441
|
}
|
|
442
|
+
|
|
443
|
+
/*
|
|
444
|
+
* Promise / async-await API.
|
|
445
|
+
* Each *Async method wraps its callback counterpart; the callback API
|
|
446
|
+
* stays untouched. Result metadata is only available through the
|
|
447
|
+
* callback API — the promises resolve with the rows alone.
|
|
448
|
+
*/
|
|
449
|
+
|
|
450
|
+
queryAsync(query: string, params?: any, options?: any): Promise<any[]> {
|
|
451
|
+
var self = this;
|
|
452
|
+
return fromCallback(function(cb) { self.query(query, params, cb, options); });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
executeAsync(query: string, params?: any, options?: any): Promise<any[]> {
|
|
456
|
+
var self = this;
|
|
457
|
+
return fromCallback(function(cb) { self.execute(query, params, cb, options); });
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
sequentiallyAsync(query: string, params?: any, on?: any, options?: any): Promise<void> {
|
|
461
|
+
if (params instanceof Function) {
|
|
462
|
+
options = on;
|
|
463
|
+
on = params;
|
|
464
|
+
params = undefined;
|
|
465
|
+
}
|
|
466
|
+
var self = this;
|
|
467
|
+
return fromCallback(function(cb) { self.sequentially(query, params, on, cb, options); });
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
transactionAsync(options?: any): Promise<any> {
|
|
471
|
+
var self = this;
|
|
472
|
+
return fromCallback(function(cb) { self.startTransaction(options, cb); });
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
startTransactionAsync(options?: any): Promise<any> {
|
|
476
|
+
return this.transactionAsync(options);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
newStatementAsync(query: string): Promise<any> {
|
|
480
|
+
var self = this;
|
|
481
|
+
return fromCallback(function(cb) { self.newStatement(query, cb); });
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
detachAsync(force?: boolean): Promise<void> {
|
|
485
|
+
var self = this;
|
|
486
|
+
return fromCallback(function(cb) { self.detach(cb, force); });
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
dropAsync(): Promise<void> {
|
|
490
|
+
var self = this;
|
|
491
|
+
return fromCallback(function(cb) { self.drop(cb); });
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
attachEventAsync(): Promise<any> {
|
|
495
|
+
var self = this;
|
|
496
|
+
return fromCallback(function(cb) { self.attachEvent(cb); });
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Run `work` inside a transaction: commits when the returned promise
|
|
501
|
+
* resolves, rolls back when it rejects (the original error is rethrown,
|
|
502
|
+
* even if the rollback itself fails).
|
|
503
|
+
*/
|
|
504
|
+
async withTransaction<T>(work: (transaction: any) => Promise<T> | T, options?: any): Promise<T> {
|
|
505
|
+
const transaction = await this.transactionAsync(options);
|
|
506
|
+
try {
|
|
507
|
+
const result = await work(transaction);
|
|
508
|
+
await fromCallback(function(cb) { transaction.commit(cb); });
|
|
509
|
+
return result;
|
|
510
|
+
} catch (err) {
|
|
511
|
+
try {
|
|
512
|
+
await fromCallback(function(cb) { transaction.rollback(cb); });
|
|
513
|
+
} catch { /* surface the original error, not the rollback failure */ }
|
|
514
|
+
throw err;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
442
517
|
}
|
|
443
518
|
|
|
444
519
|
export = Database;
|
package/src/wire/statement.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
***************************************/
|
|
6
6
|
|
|
7
|
+
import { fromCallback } from '../callback';
|
|
8
|
+
|
|
7
9
|
class Statement {
|
|
8
10
|
connection: any;
|
|
9
11
|
query: string;
|
|
@@ -66,6 +68,43 @@ class Statement {
|
|
|
66
68
|
fetchAll(transaction: any, callback: (err: any, result?: any) => void): void {
|
|
67
69
|
this.connection.fetchAll(this, transaction, callback);
|
|
68
70
|
}
|
|
71
|
+
|
|
72
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
73
|
+
|
|
74
|
+
executeAsync(transaction: any, params?: any, options?: any): Promise<any> {
|
|
75
|
+
var self = this;
|
|
76
|
+
return fromCallback(function(cb) { self.execute(transaction, params, cb, options); });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fetchAsync(transaction: any, count: number | string): Promise<any> {
|
|
80
|
+
var self = this;
|
|
81
|
+
return fromCallback(function(cb) { self.fetch(transaction, count, cb); });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
fetchScrollAsync(transaction: any, direction: string | number, offset?: any, count?: any): Promise<any> {
|
|
85
|
+
var self = this;
|
|
86
|
+
return fromCallback(function(cb) { self.fetchScroll(transaction, direction, offset, count, cb); });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fetchAllAsync(transaction: any): Promise<any> {
|
|
90
|
+
var self = this;
|
|
91
|
+
return fromCallback(function(cb) { self.fetchAll(transaction, cb); });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
closeAsync(): Promise<void> {
|
|
95
|
+
var self = this;
|
|
96
|
+
return fromCallback(function(cb) { self.close(cb); });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
dropAsync(): Promise<void> {
|
|
100
|
+
var self = this;
|
|
101
|
+
return fromCallback(function(cb) { self.drop(cb); });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
releaseAsync(): Promise<void> {
|
|
105
|
+
var self = this;
|
|
106
|
+
return fromCallback(function(cb) { self.release(cb); });
|
|
107
|
+
}
|
|
69
108
|
}
|
|
70
109
|
|
|
71
110
|
export = Statement;
|
package/src/wire/transaction.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { doCallback, doError } from '../callback';
|
|
1
|
+
import { doCallback, doError, fromCallback } from '../callback';
|
|
2
2
|
import { noop } from '../utils';
|
|
3
3
|
import Const from './const';
|
|
4
4
|
|
|
@@ -207,6 +207,53 @@ class Transaction {
|
|
|
207
207
|
rollbackRetaining(callback?: (err?: any) => void): void {
|
|
208
208
|
this.connection.rollbackRetaining(this, callback);
|
|
209
209
|
}
|
|
210
|
+
|
|
211
|
+
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
212
|
+
|
|
213
|
+
queryAsync(query: string, params?: any, options?: any): Promise<any[]> {
|
|
214
|
+
var self = this;
|
|
215
|
+
return fromCallback(function(cb) { self.query(query, params, cb, options); });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
executeAsync(query: string, params?: any, options?: any): Promise<any[]> {
|
|
219
|
+
var self = this;
|
|
220
|
+
return fromCallback(function(cb) { self.execute(query, params, cb, options); });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
sequentiallyAsync(query: string, params?: any, on?: any, options?: any): Promise<void> {
|
|
224
|
+
if (params instanceof Function) {
|
|
225
|
+
options = on;
|
|
226
|
+
on = params;
|
|
227
|
+
params = undefined;
|
|
228
|
+
}
|
|
229
|
+
var self = this;
|
|
230
|
+
return fromCallback(function(cb) { self.sequentially(query, params, on, cb, options); });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
newStatementAsync(query: string): Promise<any> {
|
|
234
|
+
var self = this;
|
|
235
|
+
return fromCallback(function(cb) { self.newStatement(query, cb); });
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
commitAsync(): Promise<void> {
|
|
239
|
+
var self = this;
|
|
240
|
+
return fromCallback(function(cb) { self.commit(cb); });
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
rollbackAsync(): Promise<void> {
|
|
244
|
+
var self = this;
|
|
245
|
+
return fromCallback(function(cb) { self.rollback(cb); });
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
commitRetainingAsync(): Promise<void> {
|
|
249
|
+
var self = this;
|
|
250
|
+
return fromCallback(function(cb) { self.commitRetaining(cb); });
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
rollbackRetainingAsync(): Promise<void> {
|
|
254
|
+
var self = this;
|
|
255
|
+
return fromCallback(function(cb) { self.rollbackRetaining(cb); });
|
|
256
|
+
}
|
|
210
257
|
}
|
|
211
258
|
|
|
212
259
|
export = Transaction;
|