How can I resolve a promised mysql query in express.js? - mysql

I'm trying to use the npm package promise-mysql and return json data (or a string doesn't matter) but I'm having issues following the promise chain with await/async.
With the current code i'm receiving Promise { undefined } in the console.log I have right before the response to the user. The response just sends nothing to the user and closes it. Can anyone point in the right direction of how to debug this?
index.js
app.get("/", async (req, res) => {
console.log( Promise.resolve(await getLogs()) )
res.send(await getLogs());
});
mysql.js
const mysql = require("promise-mysql");
let pool;
async function startDatabasePool() {
pool = await mysql.createPool({
connectionLimit: 10,
host: "xxx",
user: "xxx",
password: "xxx",
database: "xxx"
});
}
async function getDatabasePool() {
if (!pool) await startDatabasePool();
return pool;
}
module.exports = {
getDatabasePool,
startDatabasePool
};
users.js
const { getDatabasePool } = require("./mysql");
async function getLogs() {
let pool = await getDatabasePool();
pool.query("SELECT * from logs order by logdate desc", function(
error,
results,
fields
) {
if (error) throw error;
return JSON.stringify(results);
});
}
module.exports = {
getLogs
};

index.js
app.get("/", async (req, res) => {
const result = await getLogs();
res.send(result);
});
mysql.js
const mysql = require("promise-mysql");
let pool;
module.exports.startDatabasePool = async () => {
pool = await mysql.createPool({
connectionLimit: 10,
host: "xxx",
user: "xxx",
password: "xxx",
database: "xxx"
});
}
module.exports.getDatabasePool = async () => {
if (!pool) await startDatabasePool();
return pool;
}
// convert function as promise
module.exports.executeQuery = async(params) => {
return new Promise((resolve, reject) => {
pool.query(params, function (error, result, fields) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
};
users.js
const { executeQuery } = require("./mysql");
module.exports.getLogs = async () => {
return await executeQuery("SELECT * from logs order by logdate desc");
}

First I'd try it like:
app.get("/", async (req, res) => {
let logs = await getLogs()
console.log(logs)
res.send(logs);
});
I hope it helps!

Related

MySQL async await db connection: TypeError: pool.query is not a function

require('dotenv').config()
const AWS = require('aws-sdk');
const ssm = new AWS.SSM({
region: 'us-east-1',
});
const mysql = require('mysql');
const pool = async () => await dbConnection();
async function key(param) {
const parameter = await ssm.getParameter({
Name: param,
WithDecryption: true
})
.promise()
.catch((err) => {
console.error('Failed getting parameter');
console.error(err);
});
const data = parameter.Parameter.Value;
console.log(data);
return data;
}
async function dbConnection() {
const pool = mysql.createPool({
connectionLimit: 10,
host: await key("host-d"),
user: await key("user-d"),
password: await key("pw-d"),
database: await key("db-d")
});
return pool;
};
async function executeSQL(sql, params) {
return new Promise(function (resolve, reject) {
pool.query(sql, params, function (err, rows, fields) {
if (err) throw err;
resolve(rows);
});
});
}
Trying to get credentials from AWS before creating mysql pool connection. I keep getting the follwing error "TypeError: pool.query is not a function" when executeSQL is called not sure why

Await/Async nodejs with mysql db won't giving result what is expected

const con = mysql.createConnection({
host: "localhost",
user: "root",
password: "anujsingh",
database: "test",
});
con.connect(function (err) {
if (err) throw err;
console.log("Connected!");
});
const selectCountries = async () => {
let sql = "SELECT countries.* FROM countries";
try {
let result = await con.query(sql);
console.log(result);
} catch (err) {
console.log(err);
}
};
selectCountries();
Attached screenshot of console, I am not getting what exactly I am getting, I want to call a function where I am consoling and send that data to a function which make insert queries based on that data.
You can not use con.query in such a way as it returns a function with more than just results. You also do not need to call con.connect() - it is implicit with every .query()
The following should work for you. I've included additional functions to illustrate the async nature of the approach.
var mysql = require('mysql');
var connection = mysql.createConnection({
host: process.env.HOST || '127.0.0.1',
user: process.env.USER || 'local_user',
password: process.env.PASSWORD || 'local_password',
database: process.env.NAME || 'local_database'
});
const do_thing_one = async (payload) => {
return new Promise((resolve, reject) => {
payload.one = 'thing one';
resolve(payload)
});
};
const selectCountries = async (payload) => {
return new Promise((resolve, reject) => {
connection.query('SELECT countries.* FROM countries', function (error, results, fields) {
if (error) reject(error);
payload.countries = results
resolve(payload);
});
});
};
const do_thing_three = async (payload) => {
return new Promise((resolve, reject) => {
payload.three = 'thing three'
resolve(payload)
});
};
const execute = async () => {
let payload = {}
await do_thing_one(payload)
await selectCountries(payload)
await do_thing_three(payload)
console.log(payload);
}
execute();
Will log…
{
one: 'thing one',
countries: [
RowDataPacket { id: 1, name: 'Brazil' },
RowDataPacket { id: 2, name: 'China' },
RowDataPacket { id: 3, name: 'Japan' }
],
three: 'thing three'
}

web browser crashes when using mysql prepared query with nodejs

I want to return the result of query to DB, which I think would be a promise and then consume that promise in another file.Here is my model code (User.js) :
User.prototype.login = function () {
return new Promise((resolve, reject) => {
pool.execute('SELECT * FROM `users` WHERE `username` = ? AND `password` = ?', [this.data.username, this.data.password], (err, attemptedUser) => {
if (err) {
pool.release();
return reject(err);
} else {
pool.release();
return resolve(attemptedUser);
}
});
});
}
and the code in my controller file (userController.js):
const User = require('../models/User');
exports.login = (req, res) => {
let user = new User(req.body);
user.login()
.then((result) => {
res.send(result);
})
.catch((err) => {
res.send(err);
});
};
But when I click on the login button the page doesn't go to the specified URL and keeps working until crash.
Where is the problem?
UPDATE-1
This is my db.js :
const mysql = require('mysql2/promise');
const dotenv = require('dotenv');
dotenv.config();
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
connectionLimit: 100
});
module.exports = pool;

How do I pass mysql database content to a different page?

I am trying to display my database content to an ejs web page. However, I am running into a problem when trying to pass the content between pages.
I have a JavaScript page "store.js" which has the server running:
store.js-
var express = require('express');
var dbcon = require('./app/db/databaseconnection');
//var path = require('path');
//dbcon.connection;
var app = express();
var router = express.Router();
dbcon.connect();
console.log(dbcon.getproducts());
//var filepath = path.join(__dirname, '../../views/')
var filepath = __dirname + '/views/';
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));
app.use('/', router);
router.get('/', (request, response) => response.render(filepath + 'index', { page_name: 'home' }));
router.get('/store', (request, response) => response.render(filepath + 'store', { page_name: 'store' }));
router.get('/about', (request, response) => response.render(filepath + 'about', { page_name: 'about' }));
router.get('/contact', (request, response) => response.render(filepath + 'contact', { page_name: 'contact' }));
router.get('/build', (request, response) => response.render(filepath + 'build/build'));
router.get('/learn', (request, response) => response.render(filepath + 'learn/learn'));
app.use('*', (request, response) => response.render(filepath + '404', { page_name: '404' }));
app.listen(3000, () => console.log("Server running at Port 3000"));
Then I have a JavaScript page which includes the database connection:
databaseconnection.js-
var mysql = require('mysql');
var connection = mysql.createConnection(conObject = {
host: "localhost",
user: "root",
password: "LOTOS123l",
database: "dbComputerStore"
});
module.exports = {
connect: () =>
{
connection.connect((error) => {
if (error) throw error;
console.log(conObject.database + " connected!");
});
},
// The display method prints the returned result to the console.
// Change this to return the result. Maybe a toString() ?
getproducts: () => {
/*var result = */connection.query('SELECT * FROM products', (error, result) => {
return result;
//return result;
// console.log(result);
// How to get certain properties
// console.log(result[0].brand);
// console.log(result[0].series);
// console.log(result[0].model);
});
//return result.result;
},
createdb: () => {
},
createtable: () => {
},
populatetable: () => {
}
}
So on the store.js page I have the console.log(dbcon.getproducts()); Which I was hoping would display the database content of the "products" table. However I keep getting undefined. Basically, I can't get it to pass from the database connection page to the store.js page.
If I get this to work, my next step would be to find a way to display the products table to an ejs page. I've been trying to solve this for a while now so any help would be appreciated! Thank You!
Following up my comments, here's how you can modify databaseconnection.js module to use a connection pool and return query results via Promises:
Note: the code is mostly untested
const mysql = require("mysql");
const pool = mysql.createPool({
connectionLimit: 10, // adjust this according to your needs
host: "localhost",
user: "root",
password: "LOTOS123l",
database: "dbComputerStore"
});
module.exports = {
// you don't need the connect method anymore
getProducts: () => new Promise((resolve, reject) => {
pool.query("SELECT * FROM products", (error, results, fields) => {
if (error) {
reject(error);
} else {
resolve(results);
}
});
}),
// ...
};
then in store.js, you can do:
const dbcon = require('./app/db/databaseconnection');
dbcon.getProducts()
.then(results => {
console.log(results);
})
.catch(err => {
console.error(err);
});
// or you could use async/await syntax:
const asyncFn = async () => {
try {
const results = await dbcon.getProducts();
console.log(results);
} catch (ex) {
console.error(err);
}
};
asyncFn();

Node.js returning a promise from a function

I'm exploring the possibilities of promises and callbacks in node.js
I'm trying to find a way for this code to work. Currently the issue I'm facing is that when I'm calling a function and want to use the return value, it is not ready yet. I know what I have to do, but don't know how. Basically, I have to make that insertAddress() returns a promise (so I can use the .then() on it), or takes a callback as a param. To do this, I also think databaseWork() should return a promise. But I don't know where to add it.
The issue is located in the 'console.log(out)', that runs before out variable is set (because insertAddress is still running).
Here is my code
app.js
-----
const databaseWork = require('./db/mysql.js').databaseWork;
app.use('/test', (req, resp) => {
var address = {
country : "Country",
city : "Randomcity",
street : "Random",
number : 6,
postalcode : "A789",
province : "a province"
}
var out = insertAddress(address); //<== takes time to finish, is not ready when the next console.log finishes
console.log(out);
});
function insertAddress(address){
var rows
databaseWork(
//Following anonymous function contains the actual workload. That has to be done inside a transaction
async (connection) => {
rows = await insertAddressQuery(address,connection);
console.log(rows); //this one waits for insertAddressQuery to be complete
})
return rows; //this will run before insertAddressQuery is complete
}
function insertAddressQuery(address,connection) {
return new Promise( (resolve, reject) => {
//async job
connection.query('INSERT INTO address (country,city,Street,number,postalcode,province) VALUES(?,?,?,?,?,?)', [address.country,'4','5',6,'7','8'] , (err, rows) => {
if (err) {reject(err);}
resolve(rows);
});
});
};
/db/mysql.js
------------
var mysql = require('mysql');
var dbpool = mysql.createPool({
host: process.env.HOST_DB,
user: process.env.USER_DB,
password: process.env.PWD_DB,
database: process.env.DB
});
function databaseWork(workload){
dbpool.getConnection( async (err, connection) => {
await beginTransaction(connection);
await workload(connection);
await commitTransaction(connection)
connection.release();
});
}
function beginTransaction(connection){
return new Promise( (resolve, reject) => {
//async job
connection.beginTransaction( (err) => {
if (err) {reject(err);}
resolve();
});
});
};
function commitTransaction(connection) {
return new Promise( (resolve, reject) => {
//async job
connection.commit( (err) => {
if (err) {reject(err);}
resolve();
});
});
};
exports.databaseWork = databaseWork;
You would do that in your databaseWork:
function databaseWork(workload) {
return new Promise((resolve, reject) => {
dbpool.getConnection(async (err, connection) => {
try {
await beginTransaction(connection);
var result = await workload(connection);
await commitTransaction(connection)
resolve(result);
} catch( err ) {
reject(err)
} finally {
connection.release();
}
});
})
}
The Promise returned by databaseWork will be resolved by the result of workload. And now you can change insertAddress to this:
async function insertAddress(address){
return databaseWork(connection => {
return insertAddressQuery(address,connection);
})
}
You then need to change the route to this:
app.use('/test', async (req, resp) => {
var address = {
country: "Country",
city: "Randomcity",
street: "Random",
number: 6,
postalcode: "A789",
province: "a province"
}
var out = await insertAddress(address); // use await here to wait for insertAddress to be finished
console.log(out);
});
*UPDATE code with an getConnection function that returns a Promise:
function getConnection() {
return new Promise((resolve, reject) => {
dbpool.getConnection((err, connection) => {
if (err) {
reject(err)
} else {
resolve(connection);
}
})
});
}
async function databaseWork(workload) {
var connection = await getConnection();
var result;
try {
await beginTransaction(connection)
result = await workload(connection)
await commitTransaction(connection)
} catch (err) {
// a rollback might be neccesaary at that place
throw err
} finally {
connection.release();
}
return result;
}
One way you can do this is by using async await.
var example = async (req, res) => {
var response = await myAsyncTask();
// this will get logged once the async task finished running.
console.log(response)
}
// Use async await to get response
var myAsyncTask = async () => {
try {
var response = await asyncTaskINeedDataFrom()
return response;
}
catch(err) {
return console.log(err);
}
}
Here's the npm module: https://www.npmjs.com/package/async