I am declaring a function, but it is non callable, why? - node.js

I am declaring a function using Node.js, but it is being non callable.
I do not understand what is wrong since I declared it as the same way as the other functions and this is the only one that is being non callable.
My code:
const mysql = require('mysql');
const mainKey = '';
const con = mysql.createConnection({
host: "localhost",
user: "root",
database: "hotels"
});
function getUsers() {
return new Promise(function(resolve, reject) {
var users = new Array();
const sql = "SELECT * FROM users";
con.query(sql, function(err, result, fields) {
if(err) throw err;
users = [];
for(var i = 0; i<result.length; i++) {
users.push([result[i].id, result[i].user, result[i].password]);
}
resolve(users);
});
});
}
function regUser(user, password, key) { //this function is non callable
return new Promise(function(resolve, reject){
console.log(test)
});
}
function getHotelNames(idUser) {
return new Promise(function(resolve, reject){
var hotelNames = new Array();
const sql = "SELECT * FROM hotels WHERE user=" + idUser;
con.query(sql, function (err, result, fields) {
if (err) throw err;
hotelNames = [];
for(var i=0; i<result.length; i++) {
hotelNames.push(escape(result[i].name));
}
resolve(hotelNames);
});
})
}
function getURLs() {
return new Promise(function(resolve, reject){
var urlsHotels = new Array();
const sql = "SELECT * FROM hotels";
con.query(sql, function (err, result) {
if (err) throw err;
urlsHotels = [];
for(var i=0; i<result.length; i++) {
urlsHotels.push(result[i].url);
}
resolve(urlsHotels);
});
})
}
function insertValues(hotelNames, url, name, idUser) {
return new Promise(function(resolve, reject){
const id = hotelNames.length+1
const sql = "INSERT INTO hotels (id, name, url, user) VALUES (" + id + ", '" + name + "', '" + url + "', " + idUser +")";
con.query(sql, function (err, result) {
if (err) resolve(['errorNewHotel']); //throw err;
resolve(['NewHotel'])
});
})
}
function deleteValues(name) {
return new Promise(function(resolve, reject){
const sql = "DELETE FROM hotels WHERE name = '" + name + "'";
console.log(sql)
con.query(sql, function (err, result) {
if (err) resolve(['errorDeletingHotel']); //throw err;
resolve(['deletedHotel'])
});
})
}
const funcGetUsers = async ()=> {
const users = await getUsers();
return users;
}
const funcRegisterUser = async (user, password, key)=> {
const regUser = await regUser(user, password, key); //I am calling the function here
return regUser;
}
const funcGetHotelNames = async (idUser)=> {
const hotelNames = await getHotelNames(idUser);
return hotelNames;
}
const funcGetURLs = async ()=> {
const urls = await getURLs();
return urls;
}
const funcInsertValues = async(hotelNames, url, name, idUser)=> {
const message = await insertValues(hotelNames, url, name, idUser);
return message;
}
const funcDeleteValues = async(name)=> {
const message = await deleteValues(name);
return message;
}
module.exports.funcGetUsers = funcGetUsers;
module.exports.funcRegisterUser = funcRegisterUser;
module.exports.funcGetHotelNames = funcGetHotelNames;
module.exports.funcGetURLs = funcGetURLs;
module.exports.funcInsertValues = funcInsertValues;
module.exports.funcDeleteValues = funcDeleteValues;
Even my code editor, Visual Studio Code says it is never read
That is what I get when I try to run function:
I do not think the issue comes from the main file (server.js), so I have tried to copy all the code in a new file and Visual Studio was still saying that it is never read while the other functions were fine.
What am I doing wrong? I do not get it.
Thank you in advance.

The real Javascript error is:
ReferenceError: regUser is not defined
In
const funcRegisterUser = async (user, password, key)=> {
const regUser = await regUser(user, password, key); //I am calling the function here
return regUser;
}
You're trying to assign to a variable named regUser while also calling a function named regUser. But, because you declare a variable named regUser inside that function, any references to a variable named regUser inside that function will refer to that regUser variable. So your await regUser(...) is trying to await the variable which has not been assigned to yet - it's in the temporal dead zone.
Just use a different variable name, and you'll avoid the name collision:
const funcRegisterUser = async (user, password, key)=> {
const result = await regUser(user, password, key);
return result;
}
Or, just return the Promise itself, no need to await something you immediately return:
const funcRegisterUser = (user, password, key) => (
regUser(user, password, key)
);
Or, even better, since funcRegisterUser is just calling regUser, maybe leave out funcRegisterUser entirely, and just export regUser:
module.exports.funcRegisterUser = regUser;

The problem is not in the function, but how you call it.
const regUser = await regUser(user, password, key);
This line will create a new constant regUser as undefined, then try to invoke it as a function. Your function is shadowed in outer scope, and thus inaccessible. The solution is simple: change the name of your constant.

Related

Return items from text file as list in nodeJS

Can someone tell me how to return items in a text file as a list. I'm writing code for basic authentication. It registers users then stores their information(first name, last name, gender, password) in a .txt file. I want to be able to confirm a user's password from their file in order to log them in. I'm using the str.split method but it just returns 'undefined'. The 'username' argument in the code below indicates the file name without .txt added to it
const read = (username) => {
fs.readFile(`${dirPath}/${username}.txt`, 'utf8', (err, item) => {
console.log(item);
})
};
const authenticatedUser = (username) => {
var validUser = doesUserExist("./Database", username);
if (validUser = true) {
var user = read(username);
var userArray = String(user).split(",");
console.log(userArray);
}
};
function doesUserExist (userPath, username) {
fs.readdir(userPath, (err, files) => {
if (err) {
console.log("error");
} else {
files.forEach(file => {
if (file == `${username}.txt`) {
return true;
} else if (file !== `${username}.txt`) {
return false;
}
});
}
});
};
You are calling read() as a function that returns a string when it in fact just executes a fs.readFile() and then returns nothing.
The quickest way to fix this would be to use fs.readFileSync() and make sure to return that value from read().
const read = (username) => {
return fs.readFileSync(`${dirPath}/${username}.txt`, {encoding:'utf8'});
};
A function that does not return a value intrinsically returns undefined.
A more idiomatically correct solution might involve switching to async code:
const read = async (username) => {
return await fs.promises.readFile(`${dirPath}/${username}.txt`, {encoding:'utf8'});
};
const authenticatedUser = async (username) => {
var validUser = await doesUserExist("./Database", username);
if (validUser = true) {
var user = await read(username);
var userArray = String(user).split(",");
console.log(userArray);
}
};
const doesUserExist = async (userPath, username) {
let returnVal = false;
const files = await fs.promises.readdir(userPath);
files.forEach(file => {
if (file == `${username}.txt`) {
returnVal = true;
});
return returnVal;
};
Using async and await, you can read your code as if it was synchronous.

Store the result of async function into a variable without all the wrappings

This is my code as of now:
function doquery(select,from,where,value){
return new Promise((resolve, reject) => {
con.query("SELECT " + select + " FROM " + from + " WHERE " + where + " = " + value, (err, res, fields) => {
resolve(res);
});
});
};
const username = async function() {
const data = await doquery('name','members','id',1);
return (data);
};
username().then(v => {
console.log(v);
});
what I want is to be able to have console.log(v) OUTSIDE the function and still produce the same result, something like:
console.log(username);
is it possible?
Thank you.
If your project supports top-level await (for example, node 14.17.1), you can do:
const username = async function() {
const data = await doquery('name','members','id',1); // doquery must be async or return a promise (i.e fetch)
return (data);
};
const myVar = await username();
console.log(myVar)
A working example:
const username = async function() {
const data = await fetch('https://dog.ceo/api/breeds/image/random');
return await data.json();
};
const myVar = await username();
console.log(myVar.message)

Undefined value after returning an array of values from a MySQL query in a different file

I'm using the Mysql connector because I need to get some data from my database, but I'm having the following issue:
I have two files server.js and dbConnection.js and I have a return in the dbConnection.js file which should return an array and it should show it in the server.js file. However, it prints out an undefined array. I don't understand what I'm doing wrong since I also tried to print out the array before reurning it in the dbConnection.js file and it's shown with the data.
server.js:
const express = require('express');
const dbConnection = require('./dbConnection.js');
app.get('/', function (req, res) {
const val1 = new Promise((resolve, reject) => {
dbConnection
.getData()
.then(data => {
resolve(data)
})
.catch(err => reject('error'))
});
Promise.all([val1])
.then(data => {
console.log(data) //here it prints out [undefined]
});
});
dbConnection.js:
const mysql = require('mysql');
const con = mysql.createConnection({
host: "localhost",
user: "root",
database: "db1"
});
const getData = async ()=> {
var array = new Array();
const sql1 = "SELECT * FROM table1 WHERE active=1";
con.query(sql1, function (err, result, fields) {
if (err) throw err;
array = [];
for(var i=0; i<result.length; i++) {
array.push(result[i].active);
}
console.log(array) //here it prints out the array with its values
return array;
});
}
module.exports.getData = getData;
Edit: Maybe this will be helpful in order to figure out what's happening. I have just tried this and it prints out an empty array []:
const mysql = require('mysql');
var array = new Array();
const con = mysql.createConnection({
host: "localhost",
user: "root",
database: "db1"
});
const getData = async ()=> {
const sql1 = "SELECT * FROM table1 WHERE active=1";
con.query(sql1, function (err, result, fields) {
if (err) throw err;
//array = [];
for(var i=0; i<result.length; i++) {
array.push(result[i].active);
}
console.log(array) //here it prints out its data
//return array;
});
console.log(array); //here it prints out []
}
module.exports.getData = getData;
When I print the array out in the dbConnection.js file:
When I print it out in the server.js file:
Why is this happening and how to fix it?
Thanks in advance.
Use Async/Await with promises. You cannot use the syntax with callback. You have to change your dbConnection.js as below. You have to promisify your callback.
function myQuery(){
return new Promise(function(resolve, reject){
var array = new Array();
const sql1 = "SELECT * FROM table1 WHERE active=1";
con.query(sql1, function (err, result, fields) {
if (err) throw err;
array = [];
for(var i=0; i<result.length; i++) {
array.push(result[i].active);
}
console.log(array) //here it prints out the array with its values
resolve(array);
});
})
}
const getData = async ()=> {
var array= await myQuery();
return array;
}
module.exports.getData = getData;

why does my async function returns undefine while working with mysql2?

I've been trying non-stop to work on this query for my datatables front end.
this is my config.js
var config = {
host : 'localhost',
user : 'root',
password : '',
database : 'ef45db'
}
module.exports = config;
this is the function I want to work with async (wait for the query to return the table's columns name)
async function getColumnNames()
{
try{
aColumns = [];
await connection.query('SHOW COLUMNS FROM '+sTable,
function selectCb(err, results, fields){
console.log("entro a getColumnNames");
if(err){
console.log(err);
}
for(var i in results)
{
aColumns.push(results[i]['Field']);
}
connection.end();
});
}catch (e){
console.log(e);
}
}
and this is the controller code to execute that function:
var mysql = require('mysql2');
var config = require('.././database/config');
var connection = mysql.createConnection(config);
var sIndexColumn = '*';
var sTable = 'users';
var aColumns = [];
module.exports = {
getInfo : async function(req,res,next)
{
var request = req.query;
(async () => await getColumnNames());
console.log(aColumns);
}
I'm trying to get the column's name so I can work with datatable's filtering for backend, since node is async this query was getting executed, but the value was undefined (and still is), I've read hundreds of post regarding promises, bluebird and async methods and trying to make this work, the last I've read a lot thats the best and I choosed it because the code seems cleaner. Any ideas whats happening?
For getColumnNames(), you shouldn't use await because connection.query doesn't return promise. It is a callback function.
However, we can make getColumnNames to return promise.
function getColumnNames() {
const aColumns = [];
return new Promise((resolve, reject) => {
connection.query('SHOW COLUMNS FROM ' + sTable,
function selectCb(err, results, fields) {
console.log("entro a getColumnNames");
if (err) {
console.log(err);
reject(err); // if error happens, reject
}
for (var i in results) {
aColumns.push(results[i]['Field']);
}
connection.end();
resolve(aColumns); // resolve with our database columns
});
});
}
and for your controller we can use async await since getColumnNames returns promise as in
module.exports = {
getInfo: async function (req, res, next) {
var request = req.query;
const aColumns = await getColumnNames();
console.log(aColumns);
}
}
Let me know if it works for you.

Chaining Promises In Loop

I am struggling to loop through the array periods whilst querying the DB and inserting data. The problem I am facing can be seen on the 5th from last line. The final db.queryPromise does not get invoked.
Please see comment 5 lines from the bottom for where the problem is.
// db.js
const mysql = require('mysql');
const connection = mysql.createConnection({
host : 'localhost',
user : ****,
password : ****,
database : ****,
});
module.exports = connection;
module.exports.queryPromise = function (args) {
return new Promise((resolve, reject) => {
connection.query(args, (err, rows, fields) => {
if (err) return reject(err);
resolve(rows);
});
});
};
module.exports.connectPromise = new Promise((resolve, reject) => {
connection.connect(err => {
if (err) reject(err);
resolve();
});
});
// app.js
const db = require('../config/db');
const periods = ['1h','12h','24h','1w','1m','3m','1y','all'];
const sqlCarIds = `SELECT id FROM car_models ORDER BY id DESC LIMIT 200;`;
return db.queryPromise(sqlCarIds)
.then((rows) => {
const car_ids = [];
for (let i = rows.length - 1; i >= 0; i--) {
car_ids.push(rows[i].car_id);
};
for (let i = periods.length - 1; i >= 0; i--) {
const sqlSnapshot = `SELECT price FROM car_models;`;
db.queryPromise(sqlSnapshot)
.then(([row]) => {
if (!row) {
throw new Error('API call found nothin');
}
const highPrice = row.high;
const sqlInsert = `INSERT into price_cache (high) VALUES (` + highPrice` + )`;`
console.log(sqlInsert); // logs correctly formed query
db.queryPromise(sqlInsert)
.then(() => {
console.log('this should fire'); // doesn't fire
});
});
}
});
The SQL syntax for the sqlInsert is invalid. You will need to write it like following example. You need to use the ${expression} literals to add the value of an expression into a "Template String". Your promise doesn't get resolved because there is an error which rejects it.
const sqlInsert = `INSERT into price_cache (high) VALUES (${highPrice})`;

Resources