Express : async, await : Cannot access 'result' before initialization - javascript

The login function uses the ExecuteSQL function is used to check whether a user exists? I'm getting the following error while I'm running this file. async await.
ReferenceError: Cannot access 'result' before initialization
at /Users/naseefali/Documents/Projects/common_express_api/data/DL.js:100:25
at async login (/Users/naseefali/Documents/Projects/common_express_api/data/DL.js:99:24)
SELECT fUserPwd FROM tblUser WHERE fUserID ='ADMIN'
{
recordsets: [ [ [Object] ] ],
recordset: [ { fUserPwd: '006060061500675006630067300667' } ],
output: {},
rowsAffected: [ 1 ]
}
Code
async function testConnection() {
try {
const pool = await getConnection();
if (pool) {
const result = await pool.request()
.query('SELECT * FROM tblUser', function (err, sqlResult) {
if (err) {
console.log(err);
}
else {
console.log(sqlResult);
}
});
}
else console.log(pool);
} catch (err) {
console.log(err);
}
};
async function ExecuteSQL(strSQL) {
try {
const pool = await getConnection();
if (pool) {
const result = await pool.request()
.query(strSQL, async function (err, sqlResult) {
if (err) {
console.log(err);
}
else {
console.log(strSQL);
console.log(sqlResult);
return sqlResult;
}
});
}
else console.log(pool);
} catch (err) {
console.log(err);
}
};
async function login(strUID) {
const strSQL = `SELECT fUserPwd FROM tblUser WHERE fUserID ='${strUID}'`;
try {
const result = await ExecuteSQL(strSQL).then(await function () {
console.log(result);
});
} catch (err) {
console.log(err);
}
};
login('ADMIN');

because you didn't return a value on then, and access result before assigning it
async function login(strUID) {
const strSQL = `SELECT fUserPwd FROM tblUser WHERE fUserID ='${strUID}'`;
try {
const result = await ExecuteSQL(strSQL).then(await function () {
console.log(result);
});
} catch (err) {
console.log(err);
}
};
try change it to
const result = await ExecuteSQL(strSQL).then(function (data) {
return data
});
console.log(result);
or just
const result = await ExecuteSQL(strSQL);
console.log(result);

here I'm just returning anything from ExecuteSQL.
I did
async function ExecuteSQL(strSQL) {
try {
const pool = await getConnection();
//you don't need to check for the pool, because getConnection() will throw if there is an error
const result = await pool.request().query(strSQL);
return result;
} catch (err) {
console.log(err);
}
};
async function login(strUID) {
const strSQL = `SELECT fUserPwd FROM tblUser WHERE fUserID ='${strUID}'`;
try {
const result = await ExecuteSQL(strSQL);
console.log(result);
return result;
} catch (err) {
console.log(err);
}
};

Related

Nodejs api structure on calling sql helpers inside another helper all called by a controller

I'm studying to create a simple API with mysql. I've understood and implemented the simple structure in which the app call the router, that call the controller, that call the service. But now i'm developing a multiple tag service module and I've realized that I need to call the same sql queries services declared in it. I show you the code for a better understanding:
tag_service.js:
const mysql = require("../../config/database");
module.exports = {
insertTags: async (data, callBack) => {
const connection = await mysql.connection();
let results = '';
const tagsArray = data.tags.map(tag => [data.id_manager,data.cod_table,data.id_record,tag])
try {
//console.log("at insertCallout...");
await connection.query("START TRANSACTION");
results = await connection.query(
`INSERT INTO s_com_tags (id_manager,cod_table,id_record,tag)
VALUES (?,?,?)`,
[tagsArray]
);
await connection.query("COMMIT");
} catch (err) {
await connection.query("ROLLBACK");
//console.log('ROLLBACK at insertCallout', err);
throw err;
} finally {
await connection.release();
return callBack(null, results);
}
},
deleteTags: async (data, callBack) => {
//console.log(data);
let results = '';
const connection = await mysql.connection();
try {
//console.log("at deleteCallouts...");
await connection.query("START TRANSACTION");
results = await connection.query(
`DELETE FROM s_com_tags
WHERE cod_table = ? AND id_record = ? AND tag IN (?)`,
[data.code_table, data.id_record,data.tags]
);
//console.log(res);
await connection.query("COMMIT");
} catch (err) {
await connection.query("ROLLBACK");
//console.log('ROLLBACK at deleteCallouts', err);
throw err;
} finally {
await connection.release();
return callBack(null, Callouts);
}
},
};
controller's structure that will use the service:
module.exports = {
updateLabDesc: async (req, res, next) => {
try {
const body = req.body;
if(!body.internal_code){
updateLabDesc(body.manager, async (err, results) => {
if (err) {
return next(createError.InternalServerError())
}
});
}
updateTags(body, async (err, results) => {
if (err) {
return next(createError.InternalServerError())
}
return res.json({
success: (results ? 1 : 0 ),
message: (results || 0) + " LabDesc inserted successfully"
});
});
} catch (error) {
next(error)
}
},
};
But the update is something like
updateTag function => {
try {
const current_tags = await getTags(req.body);
let newTags = [];
let oldTags = [];
req.body.tags.forEach(tag => {
if(!current_tags.includes(tag))
newTags.push(tag)
});
await insertTags(newTags);
current_tags.tags.forEach(tag => {
if(!req.body.tags.includes(tag))
oldTags.push(tag)
});
await deleteTags(oldTags);
} catch (error) {
next(error)
}
},
Basically, the tag_service has insertTags and deleteTags but I need the updateTags to call these functions as well. The final controller will call insertTags, deleteTags and updateTags. How can I structure these calls?
It is a controller that could call 2 helpers (insertTag and deleteTags) and another helper (updateTags) that call these 2 helpers. Any ideas?

undefined response on async action

I'm trying to launch an exe file from an Electron app with React/Redux.
From the component i'm doing dispatch(launch(titleId, titleName))
The problem is i'm getting path undefined when i'm waiting for readFolders() async.
Any idea what i'm doing wrong and what should i change in my aproach?
Thanks in advance!
launch.js
export const launch = async (titleId, titleName) => {
const path = await readFolders(titleId);
console.log('path:', path) //undefined
execFile(path, (err, data) => {
if (err) {
console.log('err', err);
} else if (data) {
console.log('data:', data)
} else {
console.log('success');
}
});
return {
type: 'LAUNCH',
};
};
readFolders.js
import fs from 'fs';
import { homedir } from 'os';
const fsPromises = fs.promises;
const isExeFile = file => file.match(/.*\.exe$/i);
export const readFolders = async titleId => {
const userDir = homedir();
const folderPath = `${userDir}/downloads`;
const fullPath = `${folderPath}/${titleId}`;
try {
const contents = await fsPromises.readdir(fullPath);
contents.forEach(async item => {
if (isExeFile(item)) {
console.log('isExeFile');
return `${fullPath}/${item}`;
}
try {
const nestedFolder = await fsPromises.readdir(`${fullPath}/${item}`);
nestedFolder.forEach(nestedItem => {
if (isExeFile(nestedItem)) {
return `${fullPath}/${item}/${nestedItem}`;
}
return null;
});
} catch (err) {
console.log('err:', err);
}
});
} catch (err) {
console.log('err main:', err);
}
};
Edit:
I also tried this way and now const path = await readFolders(titleId); returns the correct result, but this way eslint is complaining (https://eslint.org/docs/rules/no-async-promise-executor) and it doesn't feel like a good solution.
return new Promise(async (resolve, reject) => {
try {
const contents = await fsPromises.readdir(fullPath);
contents.forEach(async item => {
if (isExeFile(item)) {
console.log(`${fullPath}/${item}`);
return resolve(`${fullPath}/${item}`);
}
try {
const nestedFolder = await fsPromises.readdir(`${fullPath}/${item}`);
nestedFolder.forEach(nestedItem => {
if (isExeFile(nestedItem)) {
console.log(`${fullPath}/${item}/${nestedItem}`);
return resolve(`${fullPath}/${item}/${nestedItem}`);
}
return null;
});
} catch (err) {
console.log('err:', err);
reject(err);
}
});
} catch (err) {
console.log('err main:', err);
reject(err);
}
});
Missing return at the end. When you return in forEach, It returns from callback anonymous function only. return ${fullPath}/${item}/${nestedItem};
For more you can read my blog on it:
https://medium.com/#deepak_v/weird-part-how-to-break-the-loop-in-javascript-8bba3e658267
Updated code:
export const readFolders = async (titleId) => {
const userDir = homedir();
const folderPath = `${userDir}/downloads`;
const fullPath = `${folderPath}/${titleId}`;
try {
const contents = await fsPromises.readdir(fullPath);
let path = "";
contents.some(async (item) => {
if (isExeFile(item)) {
console.log("isExeFile");
path = `${fullPath}/${item}`;
return path;
}
try {
const nestedFolder = await fsPromises.readdir(`${fullPath}/${item}`);
const found = nestedFolder.some((nestedItem) => {
if (isExeFile(nestedItem)) {
path = `${fullPath}/${item}/${nestedItem}`;
return path;
}
return false;
});
if (found) return path;
else return false;
} catch (err) {}
});
return path;
} catch (err) {
console.log("err main:", err);
}
};

How can integrate multiple functions into my post route and pass on objects

I want to integrate the Stripe api with my project. I am already collecting all needed data and sending it to my post route.
I want to make charges to a customer and have all functions to do so, if I would invoke them all one by one. How can I integrate all functions into my post route, so it is processed all at once. Also, I do not how to pass data from one function to another, so in the end there would be a function chain with the same data. My post route and functions:
router.post("/checkout", async function (req, res, next) {
if (!req.session.cart) {
return res.redirect("/shopping-cart");
}
// You can return promise directly
let createCustomer = function () {
var param ={};
param.email = req.body.email;
param.name= req.body.name;
param.description ="";
return stripe.customers.create(param, function (err, customer) {
if (err) {
console.log("err:" + err);
}
if (customer) {
console.log("success: " + JSON.stringify(customer, null, 2));
} else {
console.log("something went wrong");
}
});
};
let createToken = function () {
let param ={};
param.card = {
number: req.body.card,
exp_month: req.body.exp_month,
exp_year: req.body.exp_year,
cvc: req.body.security
}
return stripe.tokens.create(param, function (err, token) {
if (err) {
console.log("err:" + err);
console.log(param);
}
if (token) {
console.log("success: " + JSON.stringify(token, null, 2));
console.log(req.body);
} else {
console.log("something went wrong");
}
});
};
let addCardToCustomer = function () {
console.log(createdCustomer);
return stripe.customers.createSource(customer.id, {source: token.id}, function (err, card) {
if (err) {
console.log("err:" + err);
console.log(param);
}
if (card) {
console.log("success: " + JSON.stringify(card, null, 2));
} else {
console.log("something went wrong");
}
});
};
try {
const createdCustomer = await createCustomer(); // promise 1
const createdToken = await createToken();
const addedCardToCustomer = await addCardToCustomer(createdCustomer,createdToken ); // await addCardToCustomer(createdCustumer); to pass created customer info to next request
// const chargeCustomerThroughCustomerID = await chargeCustomerThroughCustomerID(); // promise 3
// more things...
res.send("success");
} catch (e) {
console.log(`error ${e}`)
};
});
you can chain your promises... / use async await and do one task at time in order you need. you can also pass data from one promise to another as shown below.
// You can return promise directly
let createCustomer = function () {
return stripe.customers.create(param);
}
let addCardToCustomer = function(){
return stripe.customers.createSource(customer.id,{source:token.id});
};
// or use async /await
let chargeCustomerThroughCustomerID = async function () {
const data = await stripe.charges.create(param).catch((e) => { console.log(`error ${e}`); throw e })
// do something with data
return data;
}
let chargeCustomerThroughTokenID = async function () {
const data = await stripe.charges.create(param).catch((e) => { console.log(`error ${e}`); throw e });
// do something with data
return data;
}
router.post("/checkout", async function(req, res, next) { // Async
if (!req.session.cart) {
return res.redirect("/shopping-cart");
}
var cart = new Cart(req.session.cart);
try {
const createdCustumer = await createCustomer(); // promise 1
const addCardToCustomer = await addCardToCustomer(); // await addCardToCustomer(createdCustumer); to pass created customer info to next request
const chargCustomer = await chargeCustomerThroughCustomerID(); // promise 3
// more things...
res.send(...);
}
catch(e) {
console.log(`error ${e}`)
}
});

Why I can't use ctx.body in the callback of save()?

I can use ctx.body in find()'s callback:
router.post("/register/isNameUsed", async (ctx, next) => {
let username = ctx.request.body.username;
await userInfo.find({ username: username }, function(err, doc) {
if (err) {
console.log(err);
} else {
if (doc.length > 0) {
ctx.body = { isNameUsed: true };
} else {
ctx.body = { isNameUsed: false };
}
}
});
await next();
});
But I can't use it in save()'s callback:
router.post("/register", async (ctx, next) => {
let username = ctx.request.body.name;
let password = ctx.request.body.password;
var ui = new userInfo({
username,
password
});
await ui.save(function(err, doc) {
if (err) {
console.log(err);
} else {
ctx.body = { registerSuccess: true };//It doesn't work
}
});
await next();
});
The code runs successfully,just the ctx.body doesn't work, why?
OK,I changed my code to this:
router.post("/register", async (ctx, next) => {
let username = ctx.request.body.name;
let password = ctx.request.body.password;
var ui = new userInfo({
username,
password
});
try {
let insertRes = await ui.save();
ctx.body = { registerSuccess: true };
} catch (error) {
ctx.body = { registerSuccess: false };
}
await next();
});
Then the ctx.body worked.
And I'll never write ctx.body in the callback, it's so queasily...
But I still don't know why the ctx.body can work in the find()'s callback but not in the save()s?

getrows method of the recordset object does not call in sequence

Calling Oracle SP which fills the data in the record set.
Fetching rows through the recordset getrows() method.
When called the getrows method and pass a function for fetching the inner methods always run in the end.
The first method calls the inner method, and the inner method received the data, and recordset is being send to inner function.
Example in below code functioncall method return empty data and then responseObj.push run. After this the getrows method process.
function lookups(req, res, next) {
rows = functioncall(context);
responesObj.push({ "Return Data": rows });
}
function simpleProcedureExecute(query, bindvars, opts = {}) {
return new Promise((resolve, reject) => {
oracledb.getConnection(
conn,
function (err, connection) {
if (err) throw err;
connection.execute(
query,
bindvars,
function (err, result) {
if (err) {
console.error(err.message);
reject(err);
}
procJson = [];
function processResultSet() {
console.log("internal method");
console.log(result.outBinds.result);
try {
result.outBinds.result.getRows(1000, function (err, rows) {
if (err) console.log(err);
if (rows.length) {
for (var i = 0; i < rows.length; i++) {
procJson.push({});
for (var j = 0; j < result.outBinds.result.metaData.length; j++) {
procJson[i][result.outBinds.result.metaData[j].name.toLowerCase()] = rows[i][j];
}
}
processResultSet();
return;
}
resultSet.close(function (err) {
if (err) console.error(err.message);
conn.release(function (err) {
if (err) console.error(err.message);
});
});
});
}
catch (err) {
console.log(err);
}
}
processResultSet();
}
);
}
);
resolve(procJson);
});
}
The most obvious issue is the timing of when you're resolving the promise - which is way too soon. You're invoking resolve outside of the call to oracledb.getConnection. You don't have the connection yet, haven't executed the query yet, and haven't collected the rows yet. You have to do all of that first, then invoke resolve and pass along the data.
This is one of the harder things to wrap your head around when you're new to Node.js. See this video, it may help some: https://www.youtube.com/watch?v=iAdeljxq_hs&t=0s&index=2&list=PL_lVOJzXeE__1Kh3ko0F-39-cpNLPXbJL
Also, see this series which covers different async patterns in Node.js. Most Node.js developers start with callbacks and then move to alternative patterns for async work: https://jsao.io/2017/06/how-to-get-use-and-close-a-db-connection-using-various-async-patterns/
Finally, here's an example of how one can iterate a result set with async/await:
const oracledb = require('oracledb');
const config = require('./dbConfig.js');
async function runTest() {
let conn;
let result;
try {
conn = await oracledb.getConnection(config);
result = await conn.execute(
'select * from all_objects where rownum < 100',
[],
{
resultSet: true
}
);
let row;
while (row = await result.resultSet.getRow()) {
console.log(row);
}
} catch (err) {
console.error(err);
} finally {
if (result && result.resultSet) {
try {
await result.resultSet.close();
} catch (err) {
console.error(err);
}
}
if (conn) {
try {
await conn.close();
} catch (err) {
console.error(err);
}
}
}
}
runTest();
Depending on the workload, it may be better to get more rows at once with getRows:
const oracledb = require('oracledb');
const config = require('./dbConfig.js');
async function runTest() {
let conn;
let result;
try {
conn = await oracledb.getConnection(config);
result = await conn.execute(
'select * from all_objects where rownum < 100',
[],
{
resultSet: true
}
);
let rows = await result.resultSet.getRows(50);
while (rows.length) {
for (let x = 0; x < rows.length; x += 1) {
console.log(rows[x]);
}
rows = await result.resultSet.getRows(50);
}
} catch (err) {
console.error(err);
} finally {
if (result && result.resultSet) {
try {
await result.resultSet.close();
} catch (err) {
console.error(err);
}
}
if (conn) {
try {
await conn.close();
} catch (err) {
console.error(err);
}
}
}
}
runTest();
After getting direction from Dan to use getrows directly without calling inner function. Find below my code to resolve it.
async function simpleProcedureExecute(query, bindvars, opts = {}) {
let rowss;
let conn;
let procJson = [];
try {
conn = await oracledb.getConnection();
result = await conn.execute(query, bindvars);
rowss = await result.outBinds.result.getRows(1000);
if (rowss.length) {
for (var i = 0; i < rowss.length; i++) {
procJson.push({});
for (var j = 0; j < result.outBinds.result.metaData.length; j++) {
procJson[i][result.outBinds.result.metaData[j].name.toUpperCase()] = rowss[i][j];
}
}
}
return procJson;
} catch (err) {
console.log(err);
} finally {
if (conn) { // conn assignment worked, need to close
try {
await conn.close();
} catch (err) {
console.log(err);
}
}
}
}

Categories