Why does this promise code never run? - node.js

As you can see in the .gif below, I call tape.js twice in my integration tests and it works fine. But the second time I run the tests, after I've commented out the code to insert test data into my database, the body of the tape.js function never runs.
Why does this happen?
I've put a breakpoint in my database code and it finishes and calls resolve() before the next tape.js test runs so I don't get it.
Here's my test class, followed by database class:
import tape = require('tape');
const testData = require('../../../helper/data');
import * as db from '../../../helper/integration/database';
helper.setTestEnvironmentVariableOn();
const startedServer : hapi.Server = require('../../../../src/app');
(async function runTests() {
recreateDatabase();
await db.runQuery(getInsertGetRolesTestPermissionsSql());
await test_getRoles_returnsAllRoles();
recreateDatabase();
await db.runQuery(getInsertGetUsersRolesTestPermissionsSql());
await test_getUsersRoles_userCanGetHerOwnRoles();
await startedServer.stop();
})();
function test_getRoles_returnsAllRoles() {
return new Promise( (resolve, reject) => {
tape(testeeName + 'GET /roles returns all, and only, Ekaya roles', async (assert) => {
await helper.createNewUser();
superagent
.get(testData.url + `roles`)
.set('token', testData.token)
.end( (error: any , result: superagent.Response) => {
assert.equals(error, null);
assert.end();
resolve();
});
});
});
}
function test_getUsersRoles_userCanGetHerOwnRoles() {
return new Promise( (resolve, reject) => {
tape(testeeName + 'GET /users/id/roles gives a user her own roles', async (assert) => {
const userid = '635de6dc-0df9-43f4-96dc-922bca541515';
const token = await helper.getTokenForUser(userid);
superagent
.get(testData.url + `users/`+userid+`/roles`)
.set('token', token)
.end( (error: any , result: superagent.Response) => {
assert.equals(error, null);
assert.end();
resolve();
});
});
});
}
function getInsertGetUsersRolesTestPermissionsSql() : string {
return `
INSERT INTO enum.permissions(permissions_id, name,...
`;
}
function getInsertGetRolesTestPermissionsSql() {
return `
delete fr...`;
}
Database class:
import * as pg from "pg";
import 'reflect-metadata';
const Config = require('../../../src/config');
const config = new Config();
export function runQuery(sql: string) : Promise<any> {
return new Promise<any>(async (resolve, reject) => {
try {
const _db = new pg.Client(config.ekaya_local_connection_string);
await connect(_db);
_db.query(sql, function(error, result) {
if (error) {
console.error('Error running query', error);
_db.end();
reject(error);
return;
}
_db.end();
resolve(result);
});
}
catch (error) {
reject(error);
}
});
}
function connect(_db: pg.Client) : Promise<void> {
return new Promise<void>( function(resolve, reject) {
try {
_db.connect(function(error) {
if (error) {
console.error('Could not connect to postgres in integration test helper', error);
reject(error);
return;
}
resolve(null);
});
}
catch (error) {
reject(error);
}
});
}
UPDATE - after vitaly-t's suggestion
New database code, no effect on the problem:
import 'reflect-metadata';
const Config = require('../../../src/config');
const config = new Config();
const pgp = require("pg-promise")();
export function runQuery(sql: string) : any {
return new Promise<any>(async (resolve, reject) => {
try {
const _db = pgp(config.ekaya_local_connection_string);
const result = await _db.query(sql);
pgp.end();
resolve({rows: result});
}
catch (error) {reject(error);}
});
}

Related

Async await in typescript not working as expected

I wrote a method in typescript which is supposed to return collection list name of mongo db.
public async getTables(): Promise<String[]> {
let collectionNames = [];
const connection = await mongoose.connect("mongodb://localhost/test");
await mongoose.connection.on('open', async function () {
mongoose.connection.db.listCollections().toArray(function (err, tables) {
console.log(tables);
tables.forEach(element => {
collectionNames.push(element["name"]);
});
console.log(collectionNames);
mongoose.connection.close();
});
});
return collectionNames;
}
Problem is instead of awaiting it returns directly empty collection list name.What is the issue here.
Because you use "await" in here,
const connection = await mongoose.connect("mongodb://localhost/test");
So, you miss "open" event that mongoose connection emit.
You can remove "await" for your program run as you expected
public async getTables(): Promise<String[]> {
let collectionNames = [];
const connection = mongoose.connect("mongodb://localhost/test");
await mongoose.connection.on('open', async function () {
mongoose.connection.db.listCollections().toArray(function (err, tables) {
console.log(tables);
tables.forEach(element => {
collectionNames.push(element["name"]);
});
console.log(collectionNames);
mongoose.connection.close();
});
});
return collectionNames;
}
Or you can write as below
public getTables(): Promise<String[]> {
return new Promise(async (resolve, reject) => {
try {
let collectionNames = [];
const connection = await mongoose.connect("mongodb://localhost/test");
mongoose.connection.db.listCollections().toArray(function (err, tables) {
console.log(tables);
tables.forEach(element => {
collectionNames.push(element["name"]);
});
console.log(collectionNames);
mongoose.connection.close();
resolve(collectionNames);
});
} catch (e) {
reject(e);
}
})
}

Node.js MS SQL transaction

Can anyone help to implement MS SQL transactions in Node.js . I am try to execute multiple stored procedures inside a promise.
Method 1
const executeProcedure = async (data1, data2) => {
try {
// sql connection
let dbConn = new sql.ConnectionPool(config));
await dbConn.connect();
let transaction = new sql.Transaction(dbConn);
await transaction.begin().then(async()=> {
// tranaciton create
// begin tran
let result = await insertOperation(transaction, data1);
let result2 = await updateOperation(transaction, data2);
let result1 = await Promise.all([result, result2]);
await transaction.commit();
dbConn.close();
}).catch(async(err)=> {
await transaction.rollback();
dbConn.close();
throw err;
});
return {};
}
catch (error) {
throw(error);
}
}
method 2
const insertOperation = async (transaction,data1) => {
return new Promise((resolve, reject) => {
try {
var request = new sql.Request(transaction);
request.input('data1' , sql.NVarChar(40) , data1)
.execute('dbo.insertOperation').then((recordSet) => {
resolve(recordSet.recordsets);
}).catch((err) => {
reject(err);
});
}
catch (error) {
reject(error);
}
});
}
method 3
const updateOperation = async (transaction,data2) => {
return new Promise((resolve, reject) => {
try {
var request = new sql.Request(transaction);
request.input('data2' , sql.NVarChar(40) , data2)
.execute('dbo.updateOperation').then((recordSet) => {
resolve(recordSet.recordsets);
}).catch((err) => {
reject(err);
});
}
catch (error) {
reject(error);
}
});
}
Now I get this error
Can't rollback transaction. There is a request in progress.
anybody please help me to solve this problem
You make some unnecessary Promise wrapper.
Example below:
const insertOperation = async (request, data1) => {
request.input("data1", sql.NVarChar(40), data1);
const result = await request.execute("dbo.insertOperation");
return result.recordsets;
};
const updateOperation = async (request, data2) => {
request.input("data2", sql.NVarChar(40), data2);
const result = await request.execute("dbo.updateOperation");
return result.recordsets;
};
const executeProcedure = async (data1, data2) => {
// sql connection
const dbConn = new sql.ConnectionPool(config);
await dbConn.connect();
let transaction;
try {
transaction = new sql.Transaction(dbConn);
await transaction.begin();
const request = new sql.Request(transaction);
const results = await Promise.all([
insertOperation(request, data1),
updateOperation(request, data2),
]);
await transaction.commit();
return results;
} catch (err) {
await transaction.rollback();
throw err;
} finally {
await dbConn.close();
}
};
#ikhvjs please check the below use case as well
try {
request.input("data", sql.NVarChar(40), data1);
const result = await request.execute("dbo.insertOperation");
return result.recordsets;
} catch (err) {
throw err;
}
};
const updateOperation = async (request, data2) => {
try {
request.input("data", sql.NVarChar(40), data2);
const result = await request.execute("dbo.updateOperation");
return result.recordsets;
} catch (err) {
throw err;
}
};
const executeProcedure = async (data1, data2) => {
try {
// sql connection
const dbConn = new sql.ConnectionPool(config);
await dbConn.connect();
const transaction = new sql.Transaction(dbConn);
try {
await transaction.begin();
const request = new sql.Request(transaction);
const results = await Promise.all([
insertOperation(request, data1),
updateOperation(request, data2),
]);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
} finally {
await dbConn.close();
}
} catch (error) {
throw error;
}
};```

Nodejs Multiple pools created on refresh

I have several DBs for which i am using connection pools in node.js. Every time i refresh page i think pools are created again. i refresh page 3 times and 3 times promises resolved. i have removed several databases just to make it little bit easier to read here.
and if i un-comment connection close line my app crashes. i can't seem to figure out why
const config = require("../config/config");
const oracledb = require("oracledb");
var crm1connPromise = new Promise((resolve, reject) => {
oracledb.createPool({
user: config.crm1.user,
password: config.crm1.password,
connectString: config.crm1.connectString,
poolAlias: config.crm1.poolAlias,
poolMin: 0,
poolMax: 10,
poolTimeout: 300
}, (error, pool) => {
if (error) {
reject(err);
}
resolve("CRM1 Promise resolved")
});
});
var query2connPromise = new Promise((resolve, reject) => {
oracledb.createPool({
user: config.query2.user,
password: config.query2.password,
connectString: config.query2.connectString,
poolAlias: config.query2.poolAlias,
poolMin: 0,
poolMax: 10,
poolTimeout: 300
}, (error, pool) => {
if (error) {
reject(err);
}
resolve("QUERY2 Promise resolved --------")
});
});
var promiseArray = [crm1connPromise, crm2connPromise, crm3connPromise, crm4connPromise, csfp1connPromise, csfp2connPromise, csfp3connPromise, csfp4connPromise, cact1connPromise, cact2connPromise, cact3connPromise, cact4connPromise, cospconnPromise, cchnconnPromise, bbaseconnPromise, bcdrconnPromise, vcdbconnPromise, crptconnPromise, query2connPromise];
function getDBConnection (dbname) {
return new Promise((resolve, reject) => {
try {
Promise.all(promiseArray).then((message) => {
console.log(message);
const pool = oracledb.getPool(dbname);
pool.getConnection( (err, connection) => {
if (err) {
reject(err);
console.log(err);
}
resolve(connection);
});
});
} catch (error) {
reject(error);
}
});
}
module.exports.query = function(dbname, sql, bind = []){
return new Promise ((resolve,reject) =>{
var conn
try {
getDBConnection(dbname).then((connection) =>{
connection.execute(sql,bind,(err,result)=>{
if (err){
reject(err);
}
resolve(result);
})
//connection.close(0);
})
} catch (error) {
reject(error);
}
})
}
you can use 'Singleton'
please google 'Singleton pattern' and examples.
like this:
dataBaseManager.js:
'use strict'
var Singleton = (function () {
var instance;
function createInstance() {
var object = new dataBaseManager();
return object;
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
function dataBaseManager() {
this.connected = false;
this.client = null;
this.dataBase = null;
//public methods
this.connect = function () {
try {
your_database.connect({}, (err, client) => {
if (err) {
this.connected = false;
this.client = null;
this.dataBase = null;
return;
}
this.connected = true;
this.client = client;
this.dataBase = client.db();
});
} catch (error) {
}
};
this.disconnect = function () {
try {
if (this.client) {
this.client.close();
this.connected = false;
this.client = null;
this.dataBase = null;
}
} catch (error) {
}
}
}
module.exports = Singleton;
repository.js:
const dataBaseManager = require("./dataBaseManager").getInstance();
your_get_dample_data_from_data_base_func = function (data) {
dataBaseManager.dataBase
.find({})
.toArray(function (err, result) {
if (err) {
return callback(err, null);
}
callback(null, result);
});
};
index.js:
const dataBaseManager = require("./dataBaseManager").getInstance();
function connect() {
dataBaseManager.connect();
}
function disconnect() {
dataBaseManager.disconnect();
}
Look at the node-oracledb example webappawait.js which starts the pool outside the web listener code path.
async function init() {
try {
await oracledb.createPool({
user: dbConfig.user,
password: dbConfig.password,
connectString: dbConfig.connectString
});
const server = http.createServer();
server.on('error', (err) => {
console.log('HTTP server problem: ' + err);
});
server.on('request', (request, response) => {
handleRequest(request, response);
});
await server.listen(httpPort);
console.log("Server is running at http://localhost:" + httpPort);
} catch (err) {
console.error("init() error: " + err.message);
}
}
async function handleRequest(request, response) {
. . .
}

How to return a promise using web sockets?

I have this function:
function authentification(jsonHeder: any): Promise<boolean> {
return new Promise(function(resolve, reject) {
const ws = new WebSocket('ws://localhost:8000');
if (!jsonHeder.email || !jsonHeder.password) reject(new Error('bad request'));
ws.onopen = async function() {
ws.send(JSON.stringify({
command: '-userLogin',
instanceIdentifier: jsonHeder.email,
password: jsonHeder.password
})
);
};
ws.onmessage = async function(message) {
const json = JSON.parse(message.data.toString());
if (json.isError === false) {
resolve();
} else {
reject(new Error('bad request'));
}
}
});
}
and I'm trying to get the approval for an authentification, and when I am trying to print the result I receive a Promise { }.
the call function is like this:
const result = authentification(jsonHeder);
console.log('result: ', result);
and when I'm trying to put await operator I received a compile error. What can I do?

nodejs mssql transaction pool

I have a typescript module.
public multipleQuery(queries: string[]) {
return new Promise(async (resolve, reject) => {
const cPool = new sql.ConnectionPool(this.room.db);
await cPool.connect().then((pool: any) => {
const transaction = new sql.Transaction(pool);
return transaction.begin(async (err: any) => {
const request = new sql.Request(transaction, { stream: true });
try {
queries.forEach(async (q) => {
await request.query(q);
});
transaction.commit((err2: any) => {
pool.close();
if (err2) {
reject(err2);
} else {
resolve(true);
}
});
} catch (err) {
transaction.rollback(() => {
pool.close();
reject(err);
});
}
});
}).catch((err: Error) => {
cPool.close();
reject(err);
});
});
}
queries variable is an array of string, I put inside a lot of sql insert queries.
No matter what I write in queries, I still receive this error, why?
RequestError: Requests can only be made in the LoggedIn state, not the
SentClientRequest state TransactionError: Can't acquire connection for
the request. There is another request in progress.
the solutions is to use async
const async = require("async");
public multipleQuery(queries: string[]) {
return new Promise((resolve, reject) => {
const pool = new sql.ConnectionPool(this.room.db);
return pool.connect().then((p: any) => {
const transaction = new sql.Transaction(p);
return transaction.begin((err: any) => {
const request = new sql.Request(transaction);
if (err) {
reject(err);
}
return async.eachSeries(queries, async (query: any, callback: any) => {
return request.query(query);
}, async (err2: any) => {
if ( err2 ) {
await transaction.rollback(() => {
pool.close();
reject(err2);
});
} else {
await transaction.commit(() => {
pool.close();
resolve(true);
});
}
});
});
});
});
}

Resources