node-firebird
node-firebird copied to clipboard
Please, consider async/await interface
Please, consider async/await interface for the library. Some frameworks require Promises (async) to get data from instead of callback(err, data). As a starting point you can use this code fragment I've created working on an grphql apollo application:
import * as Firebird from "node-firebird";
import { ConnectionPool, Database } from "node-firebird";
const
fbOptions: Firebird.Options = {
host: "127.0.0.1",
port: 3050,
database: "database.fdb",
user: "SYSDBA",
password: "masterkey",
lowercase_keys: false, // set to true to lowercase keys
role: null, // default
pageSize: 4096, // default when creating database
cacheQuery: true,
}
const
dbPool = Firebird.pool(5, fbOptions, () => {});
const
LOG_SQL = true;
export class FirebirdPromise {
static attachPool(): Promise<Database> {
return new Promise<Database>(
(resolve, reject) => {
dbPool.get((err, db) => {
if (err) return reject(err);
resolve(db);
});
});
}
static async aquery(querysql: string, params?: any[]): Promise<any> {
const db = await FirebirdPromise.attachPool();
if (db) {
return new Promise(
(resolve, reject) => {
if (LOG_SQL) {console.log(querysql)};
db.query(querysql, params, (err, data) => {
if (err) {
db.detach();
return reject(err);
}
db.detach();
resolve(data);
});
});
} else {
throw "Not enough connections: Cannot get db from the pool!";
}
}
}
And in code requiring promises it can be used like
let dataPromise: Promise<any[]>
dataPromise = FirebirdPromise.aquery(your_sql_query);
or if you need the data in-place then
data = await FirebirdPromise.aquery(your_sql_query);
Any update about this ?
Any update about this ?
Have some:
// firebird-async.ts
import * as Firebird from "node-firebird";
import promisify = require("../node_modules/util.promisify")
const
fbOptions: Firebird.Options = {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_PATH,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
lowercase_keys: false, // set to true to lowercase keys
role: null, // default
pageSize: 4096, // default when creating database
// cacheQuery: true,
}
export interface ConnectionPoolAsync {
get(callback: Firebird.DatabaseCallback): void;
destroy(): void;
getAsync: () => Promise<DatabaseAsync>
}
export interface DatabaseAsync {
detach(callback?: Firebird.SimpleCallback): Firebird.Database;
transaction(isolation: Firebird.Isolation, callback: Firebird.TransactionCallback);
escape(value: any): string;
detachAsync: () => Promise<void>;
transactionAsync: (/*isolation: Firebird.Isolation*/) => Promise<TransactionAsync>;
}
export interface TransactionAsync {
query(query: string, params: any[], callback: Firebird.QueryCallback): void;
execute(query: string, params: any[], callback: Firebird.QueryCallback): void;
commit(callback?: Firebird.SimpleCallback): void;
rollback(callback?: Firebird.SimpleCallback): void;
queryAsync: (query: string, params: any[]) => Promise<any>;
executeAsync: (query: string, params: any[]) => Promise<any[]>;
commitAsync: () => Promise<void>;
rollbackAsync: () => Promise<void>;
database: DatabaseAsync;
commitAndDetach: () => Promise<void>;
rollbackAndDetach: () => Promise<void>;
}
export function pool(max: number, options: Firebird.Options): ConnectionPoolAsync {
const ap: ConnectionPoolAsync = Firebird.pool(max, options) as ConnectionPoolAsync;
const aget = promisify<Firebird.Database>(ap.get).bind(ap);
ap.getAsync = async () => {
const db: DatabaseAsync = await aget() as unknown as DatabaseAsync;
db.detachAsync = promisify<void>(db.detach).bind(db);
db.transactionAsync = async () => {
const atran = promisify<Firebird.Isolation, Firebird.Transaction>(db.transaction).bind(db);
const transaction = await atran(Firebird.ISOLATION_READ_COMMITED) as unknown as TransactionAsync;
transaction.commitAsync = promisify(transaction.commit).bind(transaction);
transaction.executeAsync = promisify(transaction.execute).bind(transaction);
transaction.queryAsync = promisify(transaction.query).bind(transaction);
transaction.rollbackAsync = promisify(transaction.rollback).bind(transaction);
transaction.database = db;
transaction.commitAndDetach = (async () => {
await transaction.commitAsync();
await transaction.database.detachAsync()
}).bind(transaction);
transaction.rollbackAndDetach = (async () => {
await transaction.rollbackAsync();
await transaction.database.detachAsync()
}).bind(transaction);
return transaction;
}
return db;
}
return ap;
}
export async function transaction(): Promise<TransactionAsync> {
const db = await thePool.getAsync();
const tr = await db.transactionAsync();
return tr;
}
export const thePool = pool(5, fbOptions);
const SQL_SET_USER_CONTEXT = `
execute block(user_id integer = ?)
as
begin
RDB$SET_CONTEXT ('USER_TRANSACTION', 'USER_ID', user_id);
end
`;
export async function userTransaction(userId: string): Promise<TransactionAsync> {
const db = await thePool.getAsync();
const tr = await db.transactionAsync();
await tr.queryAsync(SQL_SET_USER_CONTEXT, [userId]);
return tr;
}
and then
const tr = await transaction();
try {
const r: any[] = await transaction.queryAsync(....
await tr.commitAndDetach();
} catch (e) {
await tr.rollbackAndDetach();
throw(e);
}
Exactly what I was looking for, thanks! Any updates would be welcome.