JS await not working as expected with pg query - javascript

I want to use the return of a query to a postgresSQL database. I don't want to just print it. I want to use it in another function. The problem is that the function here returns before it is finished with executing the code.
async function create_base_config(user_id, service_id, timer_seconds) {
var ret
var line
await db_adm_conn.query(`
INSERT INTO base_config (user_id, service_id, timer_seconds)
VALUES ('` + user_id + "', '" + service_id + "', '" + timer_seconds + "') RETURNING id;", (err, result) => {
if (err) {
ret = false
line = err
console.log("line2 err : " + line)
}
else {
ret = true
line = result.rows
console.log("line2 : " + line)
// json_return = JSON.parse(result)
// console.log(result.rows)
}
});
console.log("line: " + line)
return { ret_value: ret, line_value: line };
}
To test it i inserted debug prints. The output is:
server_1 | line: undefined
server_1 | line2 : [object Object]
so I am exectuting the code after the await before the await is finished. How can i fix that, so that he first executes all the code from the await and then the rest?

you should not use a callback function as the arrow function. You should use try catch like this:
async function create_base_config(user_id, service_id, timer_seconds) {
var ret
var line
try {
line = await db_adm_conn.query(`
INSERT INTO base_config (user_id, service_id, timer_seconds)
VALUES ('` + user_id + "', '" + service_id + "', '" + timer_seconds + "') RETURNING id;")
ret = true
}
catch (err) {
ret = false
line = err
}
return { ret_value: ret, line_value: line };
}

Related

TypeError: req.next is not a function node.js

I cannot seem to figure out this issue, it literally just started happening, no code changed!
TypeError: req.next is not a function
The code is failing on line 120. Here is the corresponding sql query, as well as line 120
// Setup form response endpoint
router.get('/form_submit', function (req, res, next) {
var parentFirstName = req.query.employee_First_name
var parentLastName = req.query.employee_last_name
var parentEmail = req.query.employee_email_address
childFirstName = req.query.Child_name
childLastName = req.query.Child_last_name
var relations = req.query.relations
var number = req.query.phone_number
var allergies = req.query.Allergies
var restrictions = req.query.Dietary_Restrictions
const user = JSON.parse(req.session.passport.user)
var queryw = "SELECT * from table"
var numrows = 0
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return console.log(err);
conn.query(queryw, function (err, data) {
if (err) console.log(err);
else console.log(data);
numrows = data.length
conn.close(function () {
console.log("DOING COUNT:");
var crypto = require("crypto");
var id = crypto.randomBytes(3).toString('hex');
console.log(id)
var realIndex = id
var permission = req.query.permission;
console.log(permission)
if (permission == null || permission == " " + undefined || permission == " undefined" || permission == undefined) {
permission = "No"
console.log("inside permission")
}
if (numrows <= 5) {
var query2="insert into table (FIRST_NAME, LAST_NAME, CHILD_FIRST_NAME, CHILD_LAST_NAME, RELATIONSHIP_CHILD, CONTACT_CELLNUMBER, ALLERGIES, DIETARY_RESTRICTIONS, STATUS, EMAIL, PERMISSION, REALINDEX) Values ('" + parentFirstName + "', '" + parentLastName + "', '" + childFirstName + "', '" + childLastName + "', '" + relations +"', '" + number + "', '" + allergies + "', '" + restrictions + "', 'ACTIVE', '" + parentEmail + "', '" + permission + "', '" + realIndex + "')"
console.log(req.body.permission)
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return console.log(err);
conn.query(query2, function (err, data) {
if (err) console.log(err);
else console.log(data);
conn.close(function () {
console.log(numrows);
const user = JSON.parse(req.session.passport.user)
res.render('done', { title: 'Express', user });
console.log(query2);
res.render('done');
});
});
});
}
else if (numrows > 5) {
console.log('CALLNG WAITLIST')
var query3="insert into table (FIRST_NAME, LAST_NAME, CHILD_FIRST_NAME, CHILD_LAST_NAME, RELATIONSHIP_CHILD, CONTACT_CELLNUMBER, ALLERGIES, DIETARY_RESTRICTIONS, STATUS, EMAIL, PERMISSION, REALINDEX) Values ('" + parentFirstName + "', '" + parentLastName + "', '" + childFirstName + "', '" + childLastName + "', '" + relations +"', '" + number + "', '" + allergies + "', '" + restrictions + "', 'WAITLIST', '" + parentEmail + "', '" + permission + "', '" + realIndex + "')"
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return console.log(err);
conn.query(query3, function (err, data) {
if (err) console.log(err);
else console.log(data);
conn.close(function () {
console.log("GOING INTO ELSE STATEMENT");
console.log("THIS IS THE NUMROW COUNT", numrows)
});
const user = JSON.parse(req.session.passport.user)
console.log(user)
res.render('done', { title: 'done', user: user });
});
});
}
});
});
});
console.log('Attempting to send email')
try {
// Read more here for Message Options https://nodemailer.com/message/
// Please change these to your email
const user = JSON.parse(req.session.passport.user)
const message = {
from: "my email", // <= should be verified and accepted by service provider. ex. 'youremail#'
to: req.query.employee_email_address, //
subject: "Registration for " + user.firstName, // <= email subject ex. 'Test email' var parentFirstName = req.query.employee_First_name
text: "Thank you " + user.firstName + " " + user.lastName + " for registering for ",
};
// send mail with defined transport object
transporter.sendMail(message, (error, info) => {
if (error) {
res.status(500).send(`Failed to Send Email: ${error}`)
}
console.log(`Successfully Sent Email ${info.messageId}`)
res.status(200).send(`Successfully Sent Email ${info.messageId}`)
});
} catch (error) {
console.log(`We failed to send Email: ${error}`)
res.status(500).send(error)
}
JSON.parse(req.session.passport.user)
res.render('done', { title: 'Express', user });
})
Line 120: res.render('done', { title: 'done', user: user });
Why is this happening?
I am not sure what is going wrong. It literally just stopped working. No code changes, nothing.
And yes, I know my code is subject to sql injection. It is being fixed
I find multiple errors here.
You can only perform res.send/res.render once in the same request.
If you need to use both, you must clearly differentiate for what type of request you will return JSON, html, etc, (and call send or render only once)
I think you should read about asynchronous programming, since in this case you are invoking functions that will be executed asynchronously and it may be that you execute res.render when the response has already been sent.

Promises problem: Trying to wrap mysql queries to use it on NodeJS / Express

My goal is to wrap MySQL queries, pass the parameters to a function and another function does the MySQL job, returning the results.
Here's my code so far:
//mysql lib
var mysql = require('mysql');
//database credentials
exports.pool = mysql.createPool({
connectionLimit: 50,
host: 'localhost',
user: 'root',
password: 'password',
database: '_app',
debug: false
});
//my wrapper =(
var returnResultset = exports.returnResultset = function (qry) {
return new Promise(function (resolve, reject) {
try {
mysql_.pool.getConnection(function (err, connection) {
if (err) {
console.log("Error on function returnResultset - MYSQL ERROR: " + err);
return reject(err);
}
connection.query(qry, [], function (error, results, fields) {
connection.release();
if (error) {
console.log("Error on function returnResultset - MYSQL ERROR: " + error);
return reject(error);
}
return resolve(results);
});
});
}
catch (e) {
console.log('error:' + e);
}
});
};
//wrapper function for testing purposes
var selectOneField = exports.selectOneField = function (tbl, field, pk, pkval) {
var qry_ = "SELECT " + field + " FROM " + tbl + " WHERE " + pk + " = '" + pkval + "'";
returnResultset(qry_).then(function (results) {
return results;
}, function (error) {
console.log("Error: " + error);
})
};
//...and on another page I want to be able to receive the results from the function above:
var isExpired = exports.isExpired = function (cod) {
var rtf = db_.selectOneField('view_expiredusers', 'cod', 'cod', cod);
console.log(rtf);
return rtf;
};
The code above returns undefined. I can't get to make this function working properly.
I have tried console.log(results). The query works like a charm. Only thing I can't get to work is to catch the result from an external function.
Any thoughts? Thanks in advance!
You should return the promise and chain it inside isExpired function.
//wrapper function for testing purposes
var selectOneField = exports.selectOneField = function (tbl, field, pk, pkval) {
var qry_ = "SELECT " + field + " FROM " + tbl + " WHERE " + pk + " = '" + pkval + "'";
return returnResultset(qry_);
};
//...and on another page I want to be able to receive the results from the function above:
var isExpired = exports.isExpired = function (cod) {
return db_.selectOneField('view_expiredusers', 'cod', 'cod', cod)
};
When you call the isExpired in other files you should use the then method of the promise and return the results. do it as follows
var cod_customer = 1;
var isexpired;
isExpired(cod_customer).then(function (results) {
isexpired = results;
console.log(isexpired);
}, function (error) {
console.log("Error: " + error);
});
you are not returning the promise in selectOneField function it must return the promise and also you cant simply do
rtf = db_.selectOneField('view_expiredusers', 'cod', 'cod', cod);
.you will have to use async-await or then
Must be handled this way
//wrapper function for testing purposes
var selectOneField = exports.selectOneField = function (tbl, field, pk, pkval) {
var qry_ = "SELECT " + field + " FROM " + tbl + " WHERE " + pk + " = '" + pkval + "'";
return returnResultset(qry_).then(function (results) {
return results;
}).catch(error) {
console.log("Error: " + error);
})
};
//...and on another page I want to be able to receive the results from the function above:
var isExpired = exports.isExpired = function (cod) {
var rtf = db_.selectOneField('view_expiredusers', 'cod', 'cod', cod).then(rtf => {
console.log(rtf);
return rtf;
});
};

Insert into database using knex

I am using knex 0.13.0 and I am trying to insert into a mysql database with the following function:
async function create(title, description) {
//trim spaces
console.log("title: " + title)
console.log("description: " + description)
title = title.trim()
description = description.trim()
createdAt = _.now()
deleted = false
console.log("Create Post: " + title + " " + description + " " + createdAt + " " + deleted)
if (title.length < 1 || title.length > 255) throw new Error('Title is not valid.')
if (description.length < 1) throw new Error('Description is not valid.')
try {
await knex('posts').insert({
title,
description,
createdAt,
deleted
})
console.log("added to db")
return true;
} catch (e) {
return "An error occured: " + e;
}
}
The last console output with Create Post: Title Description 1505062847788 falseis shown right, but nothing is happening, even after waiting
I guess it is the asynch part of the function, but what else to do in the meanwhile?
Is there a standard way to create an entry when using knex?
Appreciate your reply!
I'm using Node 6, so can't test 'await' at the moment (came in node 7) but from this post it looks like you should assign the await response to a variable. Like:
...
var awResponse; // new variable
try {
awResponse = await knex('posts').insert({
...
In detail:
async function create(title, description) {
//trim spaces
console.log("title: " + title)
console.log("description: " + description)
title = title.trim()
description = description.trim()
createdAt = _.now()
deleted = false
console.log("Create Post: " + title + " " + description + " " + createdAt + " " + deleted)
if (title.length < 1 || title.length > 255) throw new Error('Title is not valid.')
if (description.length < 1) throw new Error('Description is not valid.')
var awResponse; // new variable
try {
awResponse = await knex('posts').insert({
title,
description,
createdAt,
deleted
})
console.log("added to db")
return true;
} catch (e) {
return "An error occured: " + e;
}
}
What you have should work just fine, but what I've been doing (as an alternative for you) is just directly using promises, and constructing my data access functions generally as follows:
function create(title, description) {
return Promise.resolve().then(function () {
// This first section is for preping the record for insert.
//
//trim spaces
console.log("title: " + title)
console.log("description: " + description)
title = title.trim()
description = description.trim()
// createdAt = _.now() // I have a error that "_" is not valid
createdAt = (new Date()).toISOString();
deleted = false
console.log("Create Post: " + title + " " + description + " " + createdAt + " " + deleted)
if (title.length < 1 || title.length > 255) throw new Error('Title is not valid.')
if (description.length < 1) throw new Error('Description is not valid.')
return { "title": title,
"description": description,
"createdAt": createdAt,
"deleted": deleted };
})
.then(function (recordToInsert) {
// This second section is for the insert.
//
console.log("Part #2");
return knex('posts').insert(recordToInsert)
.on('query-error', function(ex, obj) {
// console.log("KNEX query-error ex:", ex);
// console.log("KNEX query-error obj:", obj);
// Below logs db errors into my custom encapsulation of winston logging.
// ... and the .catch further down will still be executed.
log.logMsg('error', "DBA.INS88", "KNEX create.on.query-error", {"fnc": "create", "obj":obj, "ex":ex} );
})
})
.then(function (insertResult) {
// This third section is for post-processing the result (if needed).
//
console.log("Part #3 added to db :", insertResult);
return insertResult; // returns id value from insert;
})
.catch(function (e) {
// I omit this .catch to let the caller know about and handle the exceptions
console.log( "An error occured: " + e);
});
};
Hope this helps!

Loop through Array and perform My SQL query based on result of previous query for each entry in the array

I have an array of items:
var myArr = ['item1', 'item2', 'item3'];
I'm attempting to loop over these items and check if they exist in my database. If the item does not exist, then I add it to the database.
var sql = 'Select * from DB where item="' + myArr[i] + '"';
connection.query(sql, function(e, r, f) {
if(!e && r.length <= 0) {
performInsertOnDB(myArr[i]);
}
});
My trouble is, the reference to variable i will not stay as connnection.query is asynchronous. I need to wait until the first select finishes before I can continue. I'm trying to use the Async library to accomplish this, but I must not be fully grasping how to perform the task.
This is what I have so far:
async.each(lootArray, function(lootItem, addLootItem) {
var sql = "SELECT * FROM loot_history WHERE date = DATE('" + moment(lootItem[1]).format('YYYY-MM-DD') + "') AND time = '" + lootItem[2] + "' AND itemId = " + lootItem[4];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
return false;
} else {
if (results.length > 0) {
//duplicates.push(lootArray[i]);
} else {
addLootItem(lootItem);
}
}
});
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if (err) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
function addLootItem(lootItem) {
var sql = "INSERT INTO loot_history SET player = " + lootItem[0] + ", date = " + moment(lootItem[1]).format('YYYY-MM-DD') + ", time = '" + lootItem[2] + ", item = " + lootItem[3] + ", itemId = " + lootItem[4] + ", itemString=" + lootItem[5] + ", response= " + lootItem[6] + ", votes= " + lootItem[7] + ", class= " + lootItem[8] + ", instance=" + lootItem[9] + ", boss=" + lootItem[10] + ", gear1=" + lootItem[11] + ", gear2=" + lootItem[12] + ", reasponseId=" + lootItem[13] + ", isAwardReason=" + lootItem[14];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
}
});
}
EDIT: Everything works, except the callback AddLootItem is not firing. Why is this callback not getting called? I can set log events in that if statement that execute, but the function itself never fires.
The problem is that the name of async callback is the same as the function you want to be called when the item does not exist. Try to change the name in the function to something else let's say: callback, and call it in your if statement or pass it to addLootItem, and call it there once the item added.
async.each(lootArray, function(lootItem, callback) {
var sql = "SELECT * FROM loot_history WHERE date = DATE('" + moment(lootItem[1]).format('YYYY-MM-DD') + "') AND time = '" + lootItem[2] + "' AND itemId = " + lootItem[4];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
calback(err);
} else {
if (results.length > 0) {
//duplicates.push(lootArray[i]);
callback();
} else {
addLootItem(lootItem, callback);
}
}
});
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if (err) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
function addLootItem(lootItem, done) {
var sql = "INSERT INTO loot_history SET player = " + lootItem[0] + ", date = " + moment(lootItem[1]).format('YYYY-MM-DD') + ", time = '" + lootItem[2] + ", item = " + lootItem[3] + ", itemId = " + lootItem[4] + ", itemString=" + lootItem[5] + ", response= " + lootItem[6] + ", votes= " + lootItem[7] + ", class= " + lootItem[8] + ", instance=" + lootItem[9] + ", boss=" + lootItem[10] + ", gear1=" + lootItem[11] + ", gear2=" + lootItem[12] + ", reasponseId=" + lootItem[13] + ", isAwardReason=" + lootItem[14];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
}
done();
});
}

Code only works if I alert out before the code that's bombing out?

This is just freakin weird to me. So if I don't
function BindAlbumAndPhotoData()
{
// Get an array of all the user's Albums
var aAlbums = GetAllAlbums(userID, token);
alert("aAlbums: " + aAlbums);
if (aAlbums == null || aAlbums == "undefined")
return;
// Set the default albumID
var defaultAlbumID = aAlbums[0].id;
};
So I get an undefined error on the line var defaultAlbumID = aAlbums[0].id; if I don't uncomment the alert("aAlbums: " + aAlbums);
what the heck? If I comment out alert("aAlbums: " + aAlbums); then I get an undefined for the var defaultAlbumID = aAlbums[0].id;
This is so weird. I've been working all night to figure out why I kept getting an undefined for the aAlbum[0] and as soon as I add back an alert that I used to have above it, all is fine...makes no sense to me.
Here's the full code of GetAllAlbums:
function GetAllAlbums(userID, accessToken)
{
var aAlbums = []; // array
var uri = "/" + userID + "/albums?access_token=" + accessToken;
alert("uri: " + uri);
FB.api(uri, function (response)
{
// check for a valid response
if (!response || response.error)
{
alert("error occured");
return;
}
for (var i = 0, l = response.data.length; i < l; i++)
{
alert("Album #: " + i + "\r\n" +
"response.data[i].id: " + response.data[i].id + "\r\n" +
"response.data[i].name: " + response.data[i].name + "\r\n" +
"response.data[i].count: " + response.data[i].count + "\r\n" +
"response.data[i].link: " + response.data[i].link
);
aAlbums[i] = new Album(
response.data[i].id,
response.data[i].name,
response.data[i].count,
response.data[i].link
);
alert("aAlbums[" + i + "].id : " + aAlbums[i].id);
}
});
return aAlbums;
}
so I'm not returning the array until I hit the callback of the FB.api async call so I don't see how my defaultAlbumID = aAlbums[0].id; line of code is executing before I have a valid array of data back. When I put in the alert, ovbvioulsly it's delaying before it hits my line defaultAlbumID = aAlbums[0].id; causing it to I guess luckily have data beacuse the async FB.api call is done but again I don't see how that's even possible to have an issue like this when I'm waiting for the call before proceeding on and returning the array to aAlbums in my BindAlbumAndPhotoData() method.
UPDATE #3
function BindAlbumAndPhotoData()
{
GetAllAlbums(userID, accessToken, function (aAlbums)
{
alert("we're back and should have data");
if (aAlbums === null || aAlbums === undefined) {
alert("array is empty");
return false;
}
var defaultAlbumID = aAlbums[0].id;
// Set the default albumID
var defaultAlbumID = aAlbums[0].id;
// Bind the album dropdown
alert(" defaultAlbumID: " + defaultAlbumID);
});
};
function GetAllAlbums(userID, accessToken, callbackFunctionSuccess)
{
var aAlbums = []; // array
var uri = "/" + userID + "/albums?access_token=" + accessToken;
FB.api(uri, function (response)
{
// check for a valid response
if (!response || response.error)
{
alert("error occured");
return;
}
for (var i = 0, l = response.data.length; i < l; i++)
{
alert("Album #: " + i + "\r\n" +
"response.data[i].id: " + response.data[i].id + "\r\n" +
"response.data[i].name: " + response.data[i].name + "\r\n" +
"response.data[i].count: " + response.data[i].count + "\r\n" +
"response.data[i].link: " + response.data[i].link
);
aAlbums[i] = new Album(
response.data[i].id,
response.data[i].name,
response.data[i].count,
response.data[i].link
);
alert("aAlbums[" + i + "].id : " + aAlbums[i].id);
}
// pass the array back to the callback function sent as a param to the GetAllAlbums method here
callbackFunctionSuccess(aAlbums);
});
}
It's not hitting my alert in the callback. I must still be doing something wrong here.
UPDATE #4 - for some reason it's not hitting my FB.api callback now.
function GetAllAlbums(userID, accessToken, callbackFunctionSuccess)
{
var aAlbums = []; // array
var uri = "/" + userID + "/albums?access_token=" + accessToken;
alert("uri: " + uri);
FB.api(uri, function (response)
{
// check for a valid response
if (!response || response.error)
{
alert("error occured");
return;
}
for (var i = 0, l = response.data.length; i < l; i++) {
alert("Album #: " + i + "\r\n" +
"response.data[i].id: " + response.data[i].id + "\r\n" +
"response.data[i].name: " + response.data[i].name + "\r\n" +
"response.data[i].count: " + response.data[i].count + "\r\n" +
"response.data[i].link: " + response.data[i].link
);
aAlbums[i] = new Album(
response.data[i].id,
response.data[i].name,
response.data[i].count,
response.data[i].link
);
alert("aAlbums[" + i + "].id : " + aAlbums[i].id);
}
alert("about to pass back the array to the callback function");
// pass the array back to the callback function sent as a param to the GetAllAlbums method here
callbackFunctionSuccess(aAlbums);
});
}
function BindAlbumAndPhotoData()
{
// Get an array of all the user's Albums
GetAllAlbums(userID, token, function(aAlbums){
// Set the default albumID
var defaultAlbumID = aAlbums[0].id;
});
};
and then in the GetAllAlbums function call the success function when you have the data back
//********* AFTER THE BREAK *******//
In response to the updated question: The FB API is mostly asynchronous, and will keep executing other code while it waits. So using your code, all I have done is passed in the function, and then call the function you've passed it at the end
function GetAllAlbums(userID, accessToken, funcSuccess)
{
var aAlbums = []; // array
var uri = "/" + userID + "/albums?access_token=" + accessToken;
alert("uri: " + uri);
FB.api(uri, function (response)
{
// check for a valid response
if (!response || response.error)
{
alert("error occured");
return;
}
for (var i = 0, l = response.data.length; i < l; i++)
{
alert("Album #: " + i + "\r\n" +
"response.data[i].id: " + response.data[i].id + "\r\n" +
"response.data[i].name: " + response.data[i].name + "\r\n" +
"response.data[i].count: " + response.data[i].count + "\r\n" +
"response.data[i].link: " + response.data[i].link
);
aAlbums[i] = new Album(
response.data[i].id,
response.data[i].name,
response.data[i].count,
response.data[i].link
);
alert("aAlbums[" + i + "].id : " + aAlbums[i].id);
}
funcSuccess(aAlbums);
});
}
Is your function GetAllAlbums() doing some HTTP requests? If so then you need to either make that call synchronous or you need to put your code into a function and pass that as a callback to the Ajax request.
Try three equals signs instead of two, and also... return false rather than nothing at all.
if (aAlbums === null || aAlbums === undefined)
return false;
Also, undefined doesn't need to be in quotes, otherwise, it's just considered a string with a value of "undefined"
On an added note, it's probably better to ALSO check if aAlbums is actually an array before you decide to return a key from it.
if ( aAlbums === null
|| aAlbums === undefined
|| (typeof(aAlbums)=='object'&& !(aAlbums instanceof Array))
} return false;
Try modifying your condition like this:
if (typeof aAlbums == 'undefined')
return;
Also make sure that aAlbums has values and is an array:
alert(aAlbums.length);
Or:
for(var i = 0; i < aAlbums.length; i++)
{
alert(aAlbums[i].id);
}

Categories

Resources