Do I use promises correctly? - javascript

I'm working on a school project right now, I want to use promises for my "matching functions" but apparently I'm doing this wrong.
I have a dating website where users can meet other people and "match" with them. This is the idea. I'm doing a suggestion thing so it will suggest profiles automatically. So far, I can suggest people for 'straight users' but here i'm trying to do it for 'bi users' and I can't make it work.
I have a function called getPotentialsLocation(), it works perfectly if i'm giving it my table of 'straight users' (straightPotentials) but it can get into my other condition (else if (biPotentials))
Why ? Everyone around me tried but we can't find any answer.
So if I'm trying to get 'straight users' it will return me the rows with the location and everything. If I'm trying to 'bi users' it will block because it can't get into the other condition event though I can console.log(biPotentials) all the way up.
I hope my code makes sense, if it doesn't please tell me. Because I'm going to link a lot of code here
router.post('/matchaSearch', function (req, res) {
var username = session.uniqueID;
var searcherInfos = {};
var straightPotentials = [];
var biPotentials = [];
function suggestUsers(){
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
var query = 'SELECT sex, orientation FROM usersinfo WHERE username = ?';
connection.query(query, [username], (err, rows, fields) => {
connection.release()
return err ? reject(err) : resolve(rows)
})
})
})
}
suggestUsers()
.then((rows) => {
searcherInfos = rows;
if (searcherInfos[0].sex === 'm' && searcherInfos[0].orientation === 's'){
console.log("searcher is straight");
lookForSF()
.then((rows) => {
if (rows) {
for (var i = 0; i < rows.length; i++) {
straightPotentials.push(rows[i].username)
}
if (straightPotentials){
console.log("straightPotentials" + straightPotentials);
getPotentialsLocation()
.then((rows) => {
console.log(rows);
}).catch((err) => {
throw err;
})
}
}
}).catch((err) => {
throw err;
});
} else if ((searcherInfos[0].sex) && searcherInfos[0].orientation === 'b'){
console.log("searcher is bi");
lookForbothCauseImB()
.then((rows) => {
if (rows) {
for (var i = 0; i < rows.length; i++) {
biPotentials.push(rows[i].username)
}
if (biPotentials){
console.log("biPotentials" + biPotentials);
getPotentialsLocation()
.then((rows) => {
console.log(rows);
}).catch((err) => {
throw err;
})
}
}
}).catch((err) => {
throw err;
})
}
//this is the .catch for my first function (suggestUsers())
}).catch((err) => {
throw err;
})
function lookForSF(){
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
var query = 'SELECT username FROM usersinfo WHERE sex = "f" AND orientation = "s" AND username != ?';
connection.query(query, [username], (err, rows, fields) => {
connection.release()
return err ? reject(err) : resolve(rows)
})
})
})
}
function lookForbothCauseImB(){
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
var query = 'SELECT username FROM usersinfo WHERE sex = "f" OR sex = "m" AND orientation = "s" OR orientation = "b" AND username != ?';
connection.query(query, [username], (err, rows, fields) => {
connection.release()
return err ? reject(err) : resolve(rows)
})
})
})
}
function getPotentialsLocation(){
if (straightPotentials) {
var string = '('
for (var i =0; i <straightPotentials.length - 1; i++){
string += '\'' + straightPotentials[i] + '\', ';
}
string += '\'' + straightPotentials[straightPotentials.length - 1] + '\')';
return new Promise((resolve, reject) =>{
pool.getConnection((err, connection) => {
var query = 'SELECT * FROM userlocation WHERE username IN ' + string;
console.log("this is our query " + query);
connection.query(query, (err, rows, fields) => {
connection.release();
return err ? reject(err) : resolve(rows)
})
})
})
} else if (biPotentials) {
var string = '('
for (var i =0; i <biPotentials.length - 1; i++){
string += '\'' + biPotentials[i] + '\', ';
}
string += '\'' + biPotentials[biPotentials.length - 1] + '\')';
console.log("this is string" + string);
return new Promise((resolve, reject) =>{
pool.getConnection((err, connection) => {
var query = 'SELECT * FROM userlocation WHERE username IN ' + string;
console.log("this is our query " + query);
connection.query(query, (err, rows, fields) => {
connection.release();
return err ? reject(err) : resolve(rows)
})
})
})
}
}
})

as you suppose, you don't.
the mistake is nested promises anti-pattern (google it)
Your piece of code is huge and need a massive refactor to be set in the right way
Here you are
function query (pool, sql, values) {
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
var query = sql
connection.query(query, values, (err, rows) => {
connection.release()
err ? reject(err) : resolve(rows)
})
})
})
}
function suggestUsers (pool, username) {
return query(pool, 'SELECT sex, orientation FROM usersinfo WHERE username = ?', [username])
}
function lookForSF (pool, username) {
return query(pool, 'SELECT username FROM usersinfo WHERE sex = "f" AND orientation = "s" AND username != ?', [username])
}
function lookForbothCauseImB (pool, username) {
return query(pool, 'SELECT username FROM usersinfo WHERE sex = "f" OR sex = "m" AND orientation = "s" OR orientation = "b" AND username != ?', [username])
}
function getPotentialsLocation (pool, potentials) {
var usernames = potentials.map((potential) => {
return "'" + potential + "'"
})
return query(pool, 'SELECT * FROM userlocation WHERE username IN (' + usernames.join(',') + ')')
}
function matchaSearch (pool, username) {
return suggestUsers(pool, username)
.then((searcherInfos) => {
if (searcherInfos[0].sex === 'm' && searcherInfos[0].orientation === 's') {
return lookForSF(pool, username)
} else if ((searcherInfos[0].sex) && searcherInfos[0].orientation === 'b') {
return lookForbothCauseImB(pool, username)
}
})
.then((rows) => {
var potentials = rows.map((row) => {
return row.username
})
console.log('potentials' + potentials)
return getPotentialsLocation(pool, potentials)
})
}
router.post('/matchaSearch', function (req, res) {
matchaSearch(pool, session.uniqueID)
.then((results) => {
console.log('result', results)
res.send(JSON.stringify(results))
})
.catch((err) => {
console.error('error', err)
res.status(500).send('something wrong')
})
})

I see at least two places where you have functions within a .then chain that do not return anything.
This will break the promise chain.
See e.g.:
lookForbothCauseImB().then(...)
and
getPotentialsLocation().then(...)
both of which appear to need a return in front of them.

Related

Wait for mysql to finish queries in a for loop before finishing a function in nodeJS

I am trying to run a query to get some data from a table, then use that array of data to get some data from another table to then return it as JSON.
I have been trying for a while but I cannot seem to figure out async and await. Right now it does sort of work but doesn't wait for my second query in the for loop to finish before returning data.
app.get("/get-top-trending", (request, response) => {
const req = request.query
let query = 'SELECT Ticker, Mentions FROM trend_data ORDER BY Date DESC, ' + req.by + ' DESC LIMIT 3';
let returnData = {};
cryptoDB.query(query, (err, tickers) => {
if (err) throw err;
getData(tickers).then(function() {
response.send(returnData)
});
});
async function getData(tickers) {
for (let i = 0; i < tickers.length; i++) {
cryptoDB.query('SELECT HistoricalJSON FROM historical_trend_data WHERE Ticker=? LIMIT 1', [tickers[i]['Ticker']], (err, rows2) => {
if (err) throw err;
returnData[tickers[i]['Ticker']] = rows2[0]['HistoricalJSON'];
});
}
}
});
I assume that something has to be done in the getData async function, however I am not particularly sure how to implement a working solution. I have tried promises but they don't seem to work the way that I expect.
Any guidance would be appreciated.
first solution:
app.get("/get-top-trending", (request, response) => {
const req = request.query
let query = 'SELECT Ticker, Mentions FROM trend_data ORDER BY Date DESC, ' + req.by + ' DESC LIMIT 3';
cryptoDB.query(query, (err, tickers) => {
if (err) throw err;
getData(tickers).then(function (returnData) {
response.send(returnData)
});
});
async function getData(tickers) {
const returnData = {};
const querys = ((ticker) => {
return new Promise((resolve, reject) => {
cryptoDB.query('SELECT HistoricalJSON FROM historical_trend_data WHERE Ticker=? LIMIT 1', [ticker['Ticker']], (err, rows2) => {
if (err) reject(err);
returnData[ticker['Ticker']] = rows2[0]['HistoricalJSON'];
resolve();
});
})
})
for (let i = 0; i < tickers.length; i++) {
await querys(tickers[i]);
}
return returnData
}
});
second solution:
app.get("/get-top-trending", (request, response) => {
const req = request.query
let query = 'SELECT Ticker, Mentions FROM trend_data ORDER BY Date DESC, ' + req.by + ' DESC LIMIT 3';
cryptoDB.query(query, (err, tickers) => {
if (err) throw err;
getData(tickers).then(function(returnData) {
response.send(returnData)
}).catch(error => throw error);
});
async function getData(tickers) {
let returnData = {};
for (let i = 0; i < tickers.length; i++) {
returnData[tickers[i]['Ticker']] = await getTickerQuery([tickers[i]['Ticker']]);
}
return returnData;
}
function getTickerQuery(ticker) {
return new Promise((resolve, reject) => {
cryptoDB.query('SELECT HistoricalJSON FROM historical_trend_data WHERE Ticker=? LIMIT 1', ticker, (err, rows2) => {
if (err) throw reject(err);
resolve(rows2[0]['HistoricalJSON']);
});
})
}
});
I recommend second solution for readability

"syntax error at or near \"SET\"" when creating a user using node with Postgresql

I'm trying to translate my old mysql app to Postgresql, it was very difficult to connect to the server, but when i think it worked, this message appears on insomnia.
The message
I tried using different methods that i found on Google but they didn't work for me.
I think that the problem is how i'm connecting to the server.
I'm new using postgresql.
const { Pool, Client } = require("pg")
const config = require("../config")
const connection = new Pool({
host: config.postgresql.host,
user: config.postgresql.user,
password: config.postgresql.password,
database: config.postgresql.database,
port: "5432",
ssl: true
})
function list(table) {
return new Promise((resolve, reject) => {
connection.query(`SELECT * FROM ${table}`, (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
}
function get(table, id) {
return new Promise((resolve, reject) => {
connection.query(`SELECT * FROM ${table} WHERE id=${id}`, (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
}
function insert(table, data) {
return new Promise((resolve, reject) => {
connection.query(`INSERT INTO ${table} SET ${data}`, (err, result) => {
if (err) return reject(err)
resolve(result)
})
})
}
function update(table, data) {
return new Promise((resolve, reject) => {
connection.query(
`UPDATE ${table} SET ${data} WHERE id=${data.id}`,
(err, result) => {
if (err) return reject(err)
resolve(result)
}
)
})
}
const upsert = async (table, payload) =>
new Promise((resolve, reject) => {
connection.query(
`INSERT INTO ${table} SET ${payload} ON DUPLICATE KEY UPDATE ${payload}`,
(error, data) => {
console.log("UPDATE DATA: ", data)
if (error) {
return reject(error)
}
resolve(data)
}
)
})
function query(table, query, join) {
let joinQuery = ""
if (join) {
const key = Object.keys(join)[0]
const val = join[key]
joinQuery = `JOIN ${key} ON ${table}.${val} = ${key}.id`
}
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM ${table} ${joinQuery} WHERE ${table}.${query}`,
(err, res) => {
if (err) return reject(err)
resolve(res[0] || null)
}
)
})
}
module.exports = {
list,
get,
upsert,
query
}
The insert query is wrong, Please change it to the below syntax. You cannot use SET in insert. SET should be used in update.
Wrong:
connection.query(`INSERT INTO ${table} SET ${data}`, (err, result)
Insert query syntax:
INSERT INTO TABLE_NAME (column1, column2, column3,...columnN)
VALUES (value1, value2, value3,...valueN);

My promise is being resolved before my second query is able to run inside of a .map function

const getAdditionalInfosPromise = (ProgramID, LeadId) => {
return new Promise((resolve, reject) => {
connection.query(`SELECT * FROM crm_additionalLeadInfoFields WHERE ProgramID= ${ProgramID};`, (error, response) => {
if (error) reject(console.error(error, 'SQL ERROR IN GETADDITIONALINFOPROMISE'));
else {
let getAdditionalInfosData = [];
const getAdditionalInfos = response;
getAdditionalInfos.map((data, i) => {
​
let tableNameData;
// checking to see what our table name is
if (data.TableName === 'leads') {
tableNameData = `WHERE id= ${LeadId};`
}
else {
tableNameData = `Where LeadId = ${LeadId};`
}
​
// Remove any white spaces
​
const columnName = data.ColumnName.replace(/ +/g, "")
​
connection.query(`SELECT ${columnName} as pertinentValue
FROM ${data.TableName}
${tableNameData}`, (err, res) => {
if (err) console.error(err, 'MY SQL ERR IN GETADDITIONALINFOSPROMISE');
else {
console.log(data);
if (data.DisplayName !== 'Dealer Name') {
const pertinentValue = res[0].pertinentValue
​
getAdditionalInfosData.push({
'id': `additionalItem${i}`,
'label': data.DisplayName,
'value': `${pertinentValue !== null ? pertinentValue : ''}`,
'class': ''
})
​
}
}
})
})
resolve(getAdditionalInfosData)
}
})
​
})
}
Any Idea how to make this asynchronous? I tried using the async npm package but was having issue with getting any type of response back from the async.map(array, function (result,callback) {// Was null here} ). As it is right now it is returning an empty object and then logging my data afterwards Thanks to all who help! :)
Have you tried converting the items in the array you're mapping into promises? Then, using something like Promise.all (see below)? I also went ahead and moved a few items around to make it easier for me to read.
const getAdditionalInfosPromise = (ProgramID, LeadId) => {
return new Promise((resolve, reject) => {
connection.query(`SELECT * FROM crm_additionalLeadInfoFields WHERE ProgramID= ${ProgramID};`, (error, response) => {
if (error) reject(console.error(error, 'SQL ERROR IN GETADDITIONALINFOPROMISE'));
let getAdditionalInfosData = [];
const getAdditionalInfos = response;
const allPromises = getAdditionalInfos.map((data, i) => {
if (data.DisplayName !== 'Dealer Name') {
const tableNameData = data.TableName === 'leads' ? `WHERE id= ${LeadId};` : `Where LeadId = ${LeadId};`;
const columnName = data.ColumnName.replace(/ +/g, "")​
return new Promise((resolve, reject) => {
connection.query(`SELECT ${columnName} as pertinentValue FROM ${data.TableName} ${tableNameData}`, (err, res) => {
if (err) console.error(err, 'MY SQL ERR IN GETADDITIONALINFOSPROMISE');
console.log('within the select query', data);
const pertinentValue = res[0].pertinentValue​
resolve({
'id': `additionalItem${i}`,
'label': data.DisplayName,
'value': `${pertinentValue !== null ? pertinentValue : ''}`,
'class': ''
})​
})
})
}
reject({});
});
console.log(allPromises)
resolve(getAdditionalInfosData)
})​
})
}
Then you can do something like:
Promise.all(allPromises).then(function(values) {
console.log(values);
// do anything you need with your data here
});

Sqlite wait for database to open

I recently started to use javascript and electron. I want to use sqlite as a database technology. My problem is when I call:
OpenDB(dbPath);
CreateTable("sampleTable", "Column1 TEXT NOT NULL, Column2 TEXT NOT NULL");
Program actually calls CreateTable function without waiting database to open. If I call these two functions with delay program works as intended. I wrote function definitions below:
export function OpenDB(dbPath) {
projectDB = new sqlite3.Database(dbPath, (err) => {
if (err) {
console.error(err.message)
this.result = false;
return;
}
console.log('SQlite project database created.');
});
}
export function CreateTable(tableName, tableColumns) {
configDB.run('CREATE TABLE IF NOT EXISTS ' + tableName + ' (' + tableColumns + ')' , (err) => {
if(err) {
console.error(err);
console.log("Table couldn't created.")
return;
}
console.log("Table created.")
})
}
So my question is how can I make CreateTable function wait until the database actually opened?
From what I understand from my readings I need to create callback function but I couldn't manage to do it successfully. And more I read more I confused. Thanks in advance.
let db;
export function OpenDB(dbPath, cb) {
db = new sqlite3.Database(dbPath, cb);
}
export function CreateTable(tableName, tableColumns, cb) {
db.run('CREATE TABLE IF NOT EXISTS ' + tableName + ' (' + tableColumns + ')', cb);
}
And welcome to callback hell
OpenDb(dpPath, function (err) {
if (err)
return console.error(err.message);
CreateTable("sampleTable", "Column1 TEXT NOT NULL, Column2 TEXT NOT NULL", function (err) {
if (err)
return console.error(err);
});
})
If this way is inappropriate then use promisification
let db;
export function OpenDB(dbPath) {
return new Promise(function (resolve, reject) {
db = new sqlite3.Database(dbPath, err => err ? resolve() : reject(err));
});
}
export function CreateTable(tableName, tableColumns) {
return new Promise(function (resolve, reject) {
db.run('CREATE TABLE IF NOT EXISTS ' + tableName + ' (' + tableColumns + ')',
err => err ? resolve() : reject(err));
});
}
And usage
OpenDb(dbPath)
.then(() => CreateTable("sampleTable", "Column1 TEXT NOT NULL, Column2 TEXT NOT NULL"))
.then(() => CreateTable("sampleTable2", "Column1 TEXT NOT NULL, Column2 TEXT NOT NULL"))
.then(() => console.log('Complete'))
.catch(err => console.error(err));
#Aikon Mogwai's answer is good. My suggestion using async/await:
async function createTables() {
let db = new sqlite3.Database(tbpath);
await create_table(db, 'CREATE TABLE IF NOT EXISTS sampleTable(Column1 TEXT NOT NULL, Column2 TEXT NOT NULL)')
await create_table(db, 'CREATE TABLE IF NOT EXISTS sampleTable2(Column1 TEXT NOT NULL, Column2 TEXT NOT NULL)')
db.close();
logger.info("Created database.")
}
async function create_table(db: any, query: any) {
return new Promise(function (resolve, reject) {
db.run(query, function (err: any, rows: any) {
if (err) {
console.log("promise rejected")
return reject(err);
}
resolve(rows);
});
});
}
The new sqlite3.Database(tbpath) doesn't have to be awaited. At least I don't have problems with that.

How to check if database entry (table row) already exists

I am trying to check whether a table entry exists in a database, but what I have so far always returns true even if there is no entry. What am I doing wrong?
Thank you all.
This will always console.log >>>> true
let myPersLocalEntityExistsPromise = function (localEntityGUID) {
return new Promise(function (resolve, reject) {
let myEntityExists = true;
const client = myDb.mySQLDbLocalConnection();
let stmt = "SELECT EXISTS(SELECT 1 FROM MY_ENTITY_TABLE WHERE LOCAL_MY_ENTITY_GUID = ?)";
let todo = [
localEntityGUID
];
client.query(stmt, todo, function (err, row) {
if (err) {
return ("myPersLocalEntityExists: " + err.message);
} else {
if (row && row.length) {
console.log(localEntityGUID + ' Case row was found!');
} else {
myEntityExists = false;
console.log(localEntityGUID + ' Case row was NOT found!');
}
}
});
client.end(function (err) {
if (err) {
console.log('ERRR');
}
});
if (myEntityExists) {
resolve(myEntityExists);
} else {
reject(myEntityExists);
}
})
}
function myPersLocalEntityExists(localEntityGUID, callback) {
let responsePromises = []
responsePromises.push(myPersLocalEntityExistsPromise(localEntityGUID))
Promise.all(responsePromises).then(fromResolve => {
console.log(">>>> " + fromResolve);
return fromResolve;
}).catch(fromReject => {
console.log(">>>> " + fromReject);
return fromReject;
});
}

Categories