How to connect to mssql server synchronously in node.js - javascript

All of the examples for using the mssql client package/tedious driver are for async/callbacks/promises but I'm only developing a microservice that will see limited use and my understanding of asynchronous functions is still a bit fuzzy.
Here's what I have for trying to use async/await :
Report generation class:
const mssql = require('mssql');
const events = require('events');
class reporter {
constructor(searcher, logger) {
// Pass in search type and value or log the error of none defined
this.lg = logger
if (searcher.type && searcher.content) {
this.lg.lg("reporter created", 3)
this.srchType = searcher.type;
this.srchContent = searcher.content;
} else {
this.lg.lg("!MISSING SEARCH PARAMETERS", 0);
this.err = "!MISSING SEARCH PARAMETERS";
}
}
proc() {
//DB Connect async
async () => {
try {
await mssql.connect('mssql://username:password#localhost/database')
this.result = await mssql.query`select * from mytable where id = ${this.searcher}`
} catch (err) {
// ... error checks
}
}
return this.result;
}
}
Then called:
//Pass to reporter for resolution
var report1 = new reporter(searcher, logs);
report1.proc();
I'm sure this is probably a pretty bad way to accomplish this, so I'm also open to any input on good ways to accomplish the end goal, but I'd still like to know if it's possible to accomplish synchronously.

You can't do it synchronously. Figuring out this async stuff is definitely worth your time and effort.
async / await / promises let you more-or-less fake doing it synchronously
const report1 = new reporter(searcher, logs);
report1.proc()
.then ( result => {
/* in this function, "result" is what your async function returned */
/* do res.send() here if you're in express */
} )
.catch ( error => {
/* your lookup failed */
/* inform the client of your web service about the failure
* in an appropriate way. */
} )
And, unwrap the async function in your proc function, like so:
async proc() {
try {
await mssql.connect('mssql://username:password#localhost/database')
this.result = await mssql.query`select * from mytable where id = ${this.searcher}`
} catch (err) {
// ... error checks
}
return this.result;
}
await and .then are analogous.

Kind of an updated answer that continues off of O. Jones' answer.
The current version of Node.js (v15+) has support for top-level await, meaning you can run it all sequentially.
import mssql from 'mssql';
await mssql.connect('mssql://username:password#localhost/database')
const result = await mssql.query`select * from mytable where id = ${this.searcher}`
But it should still be avoided since you want to catch for errors instead of letting it crash.
In current versions of Node.js, if an await/promise rejects, and isn't caught with a .catch(), then the uncaught promise will terminate your application with the error

Related

Problems with MongoDB + async await

I am currently working on a little JS game (node.js, socket.io) and I need to retrieve data from my MongoDB (currently using Mongoose). Getting the data itself seems not to be the problem since I can console log it.
The problem is the timing. I need the data before the programm continues running. I've tryed using async await, but I think I might still be using it wrong since It doesn't work.
card.controller.js:
exports.CRUD = {
getCardById : async (id) => {
try {
let cards = await Card.find({number:id}).exec();
return cards ;
} catch (err) {
return 'error occured';
}
}
}
game.js:
/* Code is within a normal function (not async) */
(async () => {
game.card = await CRUD.getCardById(cardId - 1);
console.log("Game-Card: ",game.card); // Data gets logged here, but only after it already returned game
})();
/*return game*/

How to execute synchronous HTTP requests in JavaScript

I need to execute unknown number of http requests in a node.js program, and it needs to happen synchronously. only when one get the response the next request will be execute. How can I implement that in JS?
I tried it synchronously with the requset package:
function HttpHandler(url){
request(url, function (error, response, body) {
...
})
}
HttpHandler("address-1")
HttpHandler("address-2")
...
HttpHandler("address-100")
And asynchronously with request-promise:
async function HttpHandler(url){
const res = await request(url)
...
}
HttpHandler("address-1")
HttpHandler("address-2")
...
HttpHandler("address-100")
Non of them work. and as I said I can have unknown number of http request over the program, it depends on the end user.
Any ideas on to handle that?
Use the got() library, not the request() library because the request() library has been deprecated and does not support promises. Then, you can use async/await and a for loop to sequence your calls one after another.
const got = require('got');
let urls = [...]; // some array of urls
async function processUrls(list) {
for (let url of urls) {
await got(url);
}
}
processUrls(urls).then(() => {
console.log("all done");
}).catch(err => {
console.log(err);
});
You are claiming some sort of dynamic list of URLs, but won't show how that works so you'll have to figure out that part of the logic yourself. I'd be happy to show how to solve that part, but you haven't given us any idea how that should work.
If you want a queue that you can regularly add items to, you can do something like this:
class sequencedQueue {
// fn is a function to call on each item in the queue
// if its asynchronous, it should return a promise
constructor(fn) {
this.queue = [];
this.processing = false;
this.fn = fn;
}
add(...items) {
this.queue.push(...items);
return this.run();
}
async run() {
// if not already processing, start processing
// because of await, this is not a blocking while loop
while (!this.processing && this.queue.length) {
try {
this.processing = true;
await this.fn(this.queue.shift());
} catch (e) {
// need to decide what to do upon error
// this is currently coded to just log the error and
// keep processing. To end processing, throw an error here.
console.log(e);
} finally {
this.processing = false;
}
}
}
}

Postgres query does not return large records using Async / Await

I have a query that runs perfectly for a small amount of records. However if I try to run a query with a large amount of records, it does not return any output. I suspect it is because I am not properly using Async/Await.
Here is the code for my class with the exception of the actual connecting string:
sql.js
class SQL {
get connectionString() { return 'postgres://user:pass#server:port/db'; }
async queryFieldValue(query) {
const pgs = require('pg');
const R = require('rambda');
const client = new pgs.Client(this.connectionString);
await client.connect();
await client.query(query).then(res => {
const result = R.head(R.values(R.head(res.rows)));
console.log("The Result is: " + result);
}).finally(() => client.end());
}
}
export default new SQL();
Any help is appreciated =)
Well, your usage of async/await is incorrect, but I don't think that's why you're getting results from small queries vs. large ones. When using Promises, try to stick to either async/await or chained promise resolution methods and not mix them together.
const pgs = require('pg');
const R = require('rambda');
class SQL {
get connectionString() { return 'postgres://user:pass#server:port/db'; }
get client() { return new pgs.Client(this.connectionString); }
async queryFieldValue(query) {
try {
await this.client.connect();
const { rows } = await this.client.query(query);
const result = R.head(R.values(R.head(rows)));
console.log("The Result is: " + result);
} catch(e) {
console.log('Some error: ', e);
} finally {
await client.end();
}
}
}
export default new SQL();
Preferences on code style aside, the above is a cleaner usage of async/await without blending in chained resolvers.
As for the actual problem you're having, based on your code you're only logging the first column value from the first row returned, so maybe just slap a limit on there? I imagine you're trying to do something a little more involved with the resultant rows than just logging that value, additional information would help. I think you might be swallowing an error by using that .finally and no catch, but that's a guess.

How to avoid an infinite loop in JavaScript

I have a Selenium webdriverIO V5 framework. The issue I am facing here is, the below code works fine on Mac OS, but it does not work correctly on the Windows OS. In the Windows OS it gets stuck with an infinite loop issue.
The below code functionality is: Merge yaml files (which contains locators) and return the value of the locator by passing the key:
const glob = require('glob');
const yamlMerge = require('yaml-merge');
const sleep = require('system-sleep');
let xpath;
class Page {
getElements(elementId) {
function objectCollector() {
glob('tests/wdio/locators/*.yml', function (er, files) {
if (er) throw er;
xpath = yamlMerge.mergeFiles(files);
});
do {
sleep(10);
} while (xpath === undefined);
return xpath;
}
objectCollector();
return xpath[elementId];
}
}
module.exports = new Page();
Since you are waiting on the results of a callback, I would recommend returning a new Promise from your getElements function and resolve() the value you receive inside the callback. Then when you call getElements, you will need to resolve that Promise or use the await notation. The function will stop at that point and wait until the Promise resolves, but the event loop will still continue. See some documentation for more information.
I'll write an example below of what your code might look like using a Promise, but when you call getElements, you will need to put the keyword await before it. If you want to avoid that, you could resolve the Promise from objectCollector while you're in getElements and remove the async keyword from its definition, but you really should not get in the way of asynchronous JavaScript. Also, you can probably shorten the code a bit because objectCollector looks like an unnecessary function in this example:
const glob = require('glob')
const yamlMerge = require('yaml-merge')
const sleep = require('system-sleep')
let xpath
class Page {
function async getElements(elementId) {
function objectCollector() {
return new Promise((resolve,reject) => {
glob('tests/wdio/locators/*.yml', function (er, files) {
if (er) reject(er)
resolve(yamlMerge.mergeFiles(files))
})
})
}
let xpath = await objectCollector()
return xpath[elementId]
}
}
module.exports = new Page();

external function call, promise, async and Mongo - confused

Beginning to feel really thick here. Read a lot and I believe I understand promises and async-await decently well. However, I seem to struggle to use the function elsewhere, such that I can obtain the result (e.g. i get pending in another js file with: let dbConnection = dbOperations.openDatabaseConnection();).
Could someone explain to me why do I keep getting pending from the below functions (same function written with promise and asyncawait)? I can console.log the dbConnection result as expected prior to my return within the function. Also, I am particularly keen to understand promises in this sense, as it seems that many npm packages seem to return promises (and with my experience at least the async-await does not sit well with that? -> using async does not wait for resolve in my experience).
// Establish database connection
function openDatabaseConnection() {
let dbConnection = {};
return mongodb.connect(dbUri).then(conn => {
dbConnection.connection = conn;
return dbConnection;
})
.then(() => {
dbConnection.session = dbConnection.connection.db(dbName);
//console.log(dbConnection);
return dbConnection;
})
.catch(err => {
throw err;
});
};
// Establish database connection
async function openDatabaseConnection() {
let dbConnection = {};
try {
dbConnection.connection = await mongodb.connect(dbUri);
dbConnection.session = await dbConnection.connection.db(dbName);
} finally {
//console.log(dbConnection);
return dbConnection;
};
};
Both functions return again a promise.
So in your statement let dbConnection = dbOperations.openDatabaseConnection();
you assign a promise.
Thus you need to do something like:
dbOperations.openDatabaseConnection().then((dbConn) => ..)
or
let dbConnection = await dbOperations.openDatabaseConnection();
(note this requires to be wrapped in an async function)
Async/await is just another way to work with Promises, just don't wait for something that isn't a Promise.
async function openDatabaseConnection() {
let dbConnection = {};
try {
dbConnection.connection = await mongodb.connect(dbUri);
// await here does not make sense, this function does not return a Promise
// dbConnection.session = await dbConnection.connection.db(dbName);
dbConnection.session = dbConnection.connection.db(dbName);
} finally {
//console.log(dbConnection);
// return will always execute, keep here only when it should
// return an empty object if the connection fails
return dbConnection;
};
};
More info on async/await

Categories

Resources