accessing value of variable outside of async/await iife [duplicate] - javascript

This question already has answers here:
How to export asynchronously loaded data to be used in a different node module?
(1 answer)
How not to forget using await everywhere in Javascript?
(1 answer)
How can I export promise result?
(4 answers)
Closed last year.
I have the code below. I need to use the value of con in other functions but I have no possible solution for this. I tried using .thens and awaits like other stack articles but i kept getting the error that con is not valid.
I am truly stuck and unsure how to handle this.
service.js
async function connectToDatabase(secret) {
try {
const secretValue = await getSecretPromise(secret)
const { host, port, username, password, dbname } = JSON.parse(secretValue);
let con = mysql.createConnection({
host: host,
port: port,
user: username,
password: password,
database: dbname
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected to database!");
});
return con;
} catch (error) {
console.error(error)
}
}
// Start an IIFE to use `await` at the top level
(async function(){
let con = await connectToDatabase(secretName);
})();
function createUser({ data }) {
return new Promise((resolve, reject) => {
var sql = `query`;
con.query(sql, function (err, result) {
//does not work currently because ReferenceError: con is not defined
});
});
}
controller.js
async function getUsers(req, res, next) {
service.getUsers().then(function(val) {
res.json(val)
});
}
getsecretpromise
function getSecretPromise(secretName) {
return new Promise((resolve, reject) => {
client.getSecretValue({SecretId: secretName}, function(err, data)
{
//do stuff
}
}
service.getUsers
//this is in service.js
module.exports = {
createUser,
getUsers,
patchUser,
loginUser,
updateCallForward,
getEmail,
getCallForwardingNumber,
getDB
};
function getUsers() {
return new Promise((resolve, reject) => {
var sql = `sql`;
getDB().then(con => {
con.query(sql, function (err, result) {
if (err) throw err;
resolve(result);
});
});
});
}

You are defining the con variable after it's being returned, your IIFE starts working once it is read. What I am trying to say is you need to move that function up and if thats not an option then you need to define con before returning it. If you alredy defined it before this function then I dont know.
async function connectToDatabase(secret) {
// Start an IIFE to use `await` at the top level
(async function(){
let con = await connectToDatabase(secretName);
})();
try {
const secretValue = await getSecretPromise(secret)
const { host, port, username, password, dbname } = JSON.parse(secretValue);
let con = mysql.createConnection({
host: host,
port: port,
user: username,
password: password,
database: dbname
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected to database!");
});
return con;
} catch (error) {
console.error(error)
}
}
function createUser({ data }) {
return new Promise((resolve, reject) => {
var sql = `query`;
con.query(sql, function (err, result) {
//does not work currently because ReferenceError: con is not defined
});
});
}

You would ideally do something like this. This would hide your instance(not really for this case) from rest of the code as you will access it through a getter function. Of course you need to import your secret as a constant. It doesn't make sense to pass it as a parameter unless you have multiple dbs
let con = null;
async function connectToDatabase(secret) {
try {
const secretValue = await getSecretPromise(secret)
const { host, port, username, password, dbname } = JSON.parse(secretValue);
con = mysql.createConnection({
host: host,
port: port,
user: username,
password: password,
database: dbname
});
con.connect(function (err) {
if (err) throw err;
console.log("Connected to database!");
});
return con;
} catch (error) {
console.error(error)
con = null;
}
}
export async function getDB() {
if (con == null) {
let secretObj = {};
return await connectToDatabase(secretObj);
}
else {
return Promise.resolve(con);
}
}
export function createUser({ data }) {
return new Promise((resolve, reject) => {
var sql = `query`;
getDB().then(con => {
con.query(sql, function (err, result) {
//does not work currently because ReferenceError: con is not defined
});
});
});
}

The code can be simplified (and repaired) by making promise-returning versions of the mysql callback style functions...
async function connect(connection) {
return new Promise((resolve, reject) => {
connection.connect(function (err) {
err ? reject(err) : resolve(connection)
});
})
}
async function query(connection, query) {
return new Promise((resolve, reject) => {
connection.query(query, function (err, results, fields) {
err ? reject(err) : resolve({results, fields});
});
});
}
Only these functions should create new promises explicitly. This cleans up the connectToDatabase function...
async function connectToDatabase(secret) {
try {
const secretValue = await getSecretPromise(secret)
const { host, port, username, password, dbname } = JSON.parse(secretValue);
let con = mysql.createConnection({
host: host,
port: port,
user: username,
password: password,
database: dbname
});
return await connect(con);
} catch (error) {
console.error(error)
}
}
And it cleans up createUser substantially...
async function createUser({ data }) {
try {
const connection = await connectToDatabase(secretName);
let {results, fields} = query(connection, 'query');
// and so on
} catch(error) {
console.log(error);
}
}
Not that getSecretPromise() might require the same treatment, but is not completely specified in the OP.
Other caveats: not tested (or even compiled). Relies on values in scope whose definitions are not shown in the OP (e.g. secretName).

Related

ReferenceError: Can't find variable: require. How can I fix this error?

I want to export some functions from my database.js file and require them into the other file login.js, which is in the same folder. I tried also to declare the require globally and in a function, both ways did not work. I am using node.js/express.js.
DATABASE.JS
let mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
database: 'minigames',
user: 'root',
password: 'root'
});
function connected(){
connection.connect((err) => {
if(err) throw err;
console.log("Connected...");
})
}
function select(attribute){
return new Promise((resolve, reject) => {
let sql = `SELECT ${attribute} FROM player`;
connection.query(sql, (err, result, field) => {
if(err) reject(err);
resolve(Object.values(JSON.parse(JSON.stringify(result))));
})
})
}
async function query(attribute) {
return await select(attribute);
}
module.exports = {connection, connected, select, query};
LOGIN.JS
let userList = [];
function checkLogin(){
const database = require('./database');
let userListPromise = database.query('username, password');
userListPromise
.then()
.then((values) =>{
let i = 0;
while(values[i] != null){
userList.push(values[i]);
i++;
}
console.log("list filled");
console.log(userList);
})
}
checkLogin();

How to connect Dialogflow Fulfillment with MySQL DB?

I tried to connect my Dialogflow agent with MySQL DB at my GCP, but it didn't work well.
I just wanna see the results in console, but there's no results about that.
I can only see the result "Undefined", but since I am not familiar with Node.js, I am not sure what this means.
Since there is no content in the result, I cannot proceed to the next step.
Here is my index.js script :
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const mysql = require('mysql');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function connectToDatabase() {
const connection = mysql.createConnection({
host: '34.64.***.***',
user: 'username',
password: 'password',
database: 'dbname'
});
return new Promise((resolve,reject) => {
connection.connect();
console.log('connection successed.');
resolve(connection);
});
}
function queryDatabase(connection, name){
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM tb_user WHERE name = ?', name, (error, results, fields) => {
console.log('query successed.');
resolve(results);
});
});
}
function queryDatabase2(connection){
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM tb_user', (error, results, fields) => {
if (error) console.log(error);
console.log('results', results);
});
});
}
function handleReadFromMysql(agent) {
const user_name = agent.parameters.name;
console.log(user_name.name);
return connectToDatabase()
.then(connection => {
console.log('connectToDatabase passed');
return queryDatabase(connection, user_name.name)
//return queryDatabase2(connection)
.then(result => {
console.log('queryDatabase passed');
console.log(result);
agent.add(`User name is ${user_name} .`);
//result.map(user => {
//if(user_name === user.name) {
//agent.add(`UserID is ${user.id}`);
//}
//});
connection.end();
});
});
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('findName', handleReadFromMysql);
agent.handleRequest(intentMap);
});
and the logs are :
enter image description here
Please somebody help me...
I solved this problem 4 months ago, so I share my code to help another like me.
I use socketPath of DB info. I forgot the reason.
function connectToDatabase() {
const connection = mysql.createConnection({
socketPath: '/cloudsql/*************:asia-northeast3:****',
user: '****',
password: '****',
database: '****'
});
return new Promise((resolve, reject) => {
connection.connect();
console.log('connection successed.');
resolve(connection);
});
}
And make query function like :
function findNameCountQuery(connection, name) {
return new Promise((resolve, reject) => {
var sql = `SELECT * FROM tb_user WHERE name = ?`;
var execSql = connection.query(sql, [name], (error, results) => {
if (error) throw error;
resolve(results);
});
});
Then I use agent function like :
async function findName(agent) {
const user_name = agent.parameters.person.name;
const connection = await connectToDatabase();
const result = await findNameQuery(connection, user_name);
result.map(user => {
message += `사용자 ID seq number : ${user.seq}\n`;
});
agent.add(message);
connection.end();
}
Hope to be helpful.

Nodejs async/await mysql queries

I have a nodejs project with the current structure below, I need to insert a registry on clients table and return the last inserted ID from this table so I can use it in a second table, but I need to wait until the insert is completed in clients table, before insert the client ID on my second table. I'm trying to use async/await, but I'm always getting a null value.
My MYSQL connection: db.model.js
const config = require('config');
const mysql = require("mysql");
const connection = mysql.createConnection({
host: config.get('mysql.host'),
user: config.get('mysql.user'),
password: config.get('mysql.password'),
database: config.get('mysql.database')
});
connection.connect(function (err) {
if (err) {
console.error(`MySQL Connection Error: ${err.stack}`);
return;
}
console.log(`MySQL connected successfully!`);
});
module.exports = connection;
My CLIENT model
const mysql = require("./db.model");
const Client = function(client) {
this.login = client.login;
};
Client.create = (newClient, result) => {
mysql.query("INSERT INTO clients SET ?", newClient,
(err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
result(null, {
id: res.insertId,
...newClient
});
}
);
};
module.exports = Client;
this is the client controller (i'm trying to use async/await here)
const Client = require('../models/client.model');
exports.create = (login) => {
const client = new Client({
login: login
});
Client.create(client, async (err, data) => {
if(!err) {
return await data.id;
} else {
return false;
}
});
}
And this is another controller, where I want to use methods from my client controller:
const ClientController = require('../controllers/client.controller');
...
utils.connect()
.then(clt => clt.sub.create(data))
.then((sub) => {
let lastInsertedId = ClientController.create(sub.login);
// lastInsertedId always return null here,
// but I know ClientController return a value after some time.
// method below will fail because lastInsertedId cannot be null
TransactionController.transactionCreate(lastInsertedId,
sub.id,
sub.param);
})
.catch(error => res.send(error.response.errors))
any help appreciated.
File to create database connection
const config = require('config');
const mysql = require('mysql2');
const bluebird = require('bluebird');
const dbConf = {
host: config.dbhost,
user: config.dbuser,
password: config.dbpassword,
database: config.database,
Promise: bluebird
};
class Database {
static async getDBConnection() {
try {
if (!this.db) {
// to test if credentials are correct
await mysql.createConnection(dbConf);
const pool = mysql.createPool(dbConf);
// now get a Promise wrapped instance of that pool
const promisePool = pool.promise();
this.db = promisePool;
}
return this.db;
} catch (err) {
console.log('Error in database connection');
console.log(err.errro || err);
}
}
}
module.exports = Database;
Use connection to execute your native query
const database = require('./database');
let query = 'select * from users';
let conn = await dl.getDBConnection();
let [data, fields] = await conn.query(query);
So I'm still using only the npm mysql package, but now I transformed all my queries into promises like below, so I can just wait until all the queries are completed.
const create = (idCliente, transactionId, amount, status) => {
const sql = "INSERT INTO transactions SET ?";
const params = {
id_cliente: idCliente,
transaction_id: transactionId,
amount: amount,
status: status
};
return new Promise((resolve, reject) => {
pool.query(sql, params, (err, result) => {
if (err) {
return reject(err);
}
resolve(result);
});
});
};
then I use like this:
create(params)
.then((result) => {
//call more queries here if needed
})
.catch((err) => { });
You can use sync-sql package of npm for execute async queries.
https://www.npmjs.com/package/sync-sql
Here is an example of it:
const express = require('express')
const mysql = require('mysql')
const app = express()
var syncSql = require('sync-sql');
// Create Connection
const connect = {
host: 'localhost',
user: 'root',
password: '',
database: 'ddd_test'
}
const db = mysql.createConnection(connect)
db.connect((err) => {
if (err) {
throw err
}
console.log("Connected");
})
function getDbData(query) {
return syncSql.mysql(connect, query).data.rows
}
app.get("/getData", async (req, res, next) => {
let sql = 'SELECT * from registration';
res.json({
data:getDbData(sql)
});
})
app.listen(3000, () => {
console.log('App listening on port 3000!');
});

I want to take out the result from mysql's connection.query and save it in global scope chain in nodejs

I tried bringing out result by storing in variable current product. But I cant use it outside the function, so my array returns empty
var connection = mysql.createConnection({
host: config.config.mysql.opencart_local.host,
user: config.config.mysql.opencart_local.user,
password: config.config.mysql.opencart_local.password,
database: config.config.mysql.opencart_local.database
})
var query_current_products = 'select * from table;';
var current_products = [];
connection.connect(function(err) {
if (err) throw err;
console.log("Connected!");
connection.query(query_current_products, function (err, result) {
if (err) throw err;
//console.log(result);
current_products = result;
});
}
)
console.log(current_products);
enter image description here
Try to use async/await syntax to get your results
const mysql = require('mysql'); // or use import if you use TS
const util = require('util');
const conn = mysql.createConnection({
host: config.config.mysql.opencart_local.host,
user: config.config.mysql.opencart_local.user,
password: config.config.mysql.opencart_local.password,
database: config.config.mysql.opencart_local.database
});
var current_products = [];
//
var query_current_products = 'select * from table;';
(async function getProducts () => {
try {
const rows = await query( query_current_products);
console.log(rows);
current_products=rows;
} finally {
conn.end();
}
})()
use this code:
var query_current_products = 'select * from users';
var current_products = [];
function f() {
return new Promise(resolve => {
con.connect(function (err) {
if (err) throw err;
console.log("Connected!");
con.query(query_current_products, function (err, result) {
if (err) throw err
resolve(result);
});
});
})
}
async function asyncCall() {
current_products = await f();
console.log("outside callback : ", current_products);
}
asyncCall();

how to wait till DB connection is made and queries are executed for each database in an array

A file contains json data with details of database.
For each database connection, a series of queries need to be executed.
Currently, the map function is waiting for the database connection.
Below is the start function
function start() {
console.log('function initiated');
try {
let jsonData = fs.readFileSync('../request.json');
let jsonString = JSON.parse(jsonData);
//jsonString['request'].forEach(async function(json) {
jsonString['request'].map(async json => {
dbdetails = json.dbdetails;
//dbdetails.forEach(async function(db){
await dbbdetails.map(async db => {
console.log('pdbdetails: ' + db);
connString = json.connString;
//makes the DB connection
await connectDB(db.userId, db.Password, connString)
.then(async conn => {
await execution(conn, pdbDetails, vmUser, vmPassword, ip);
})
.catch(err => {
console.log(err);
});
console.log('after each execution');
//}
});
});
} catch (err) {
console.log(err.message);
return;
}
}
Below function is to make a database connection and return the connection
function connectDB(oUser, oPassword, connString) {
console.log('inside connectDB');
return new Promise((resolve, reject) => {
oracledb.getConnection(
{
user: oUser,
password: oPassword,
connectString: connString
},
function(err, connection) {
if (err) {
console.error(err.message);
reject(err);
//throw err;
}
console.log('returning connection');
//console.log(connection);
resolve(connection);
//return connection;
}
);
});
}
below is the function which executes servies of queries on database
function execution() {
/// series of sql query execution
}
Not sure what you’re trying to do exactly, but sounds like the problem is that .map doesn’t wait for your async functions. If you have to do them one at a time, use a for loop:
for ( var item of array ) {
await item.something();
}
To do them all at once:
var results = await Promise.all( array.map( item => item.something() )

Categories

Resources