Trying to make async function get data from database - javascript

So basically I am trying to make a function in javascript that fetches data from my SQLite database. This function is eventually supposed to be exported and used in another script, which will run the function with different SQL querys and send out the results to my web page.
import sqlite3 from "sqlite3";
const db = new sqlite3.Database(
"path/to/my/db.db"
);
function getContent(sqlQuery, whenloaded) {
return new Promise((resolve) => {
resolve(
db.all(sqlQuery, [], (err, rows) => {
if (err) {
console.log("Something went wrong in the db");
} else {
rows.forEach((row) => {
whenloaded(row.page_content);
});
}
})
);
});
}
async function showContent(sqlQuery) {
await getContent(sqlQuery, (result) => {
return result;
});
}
console.log(
showContent(`SELECT page_content FROM fruit WHERE page_name = "apples"`)
);
Console log being: Promise { <pending> }
Since this function seems to need to be an async one, because of the database being involved, I have tried the code above, which didn´t work. I have had the code below as a reference since I don´t have any prior experience of async functions.
function square(a, b) {
return new Promise((resolve) => {
resolve(a + b);
});
}
async function output(a, b) {
const ans = await square(a, b);
console.log(ans);
}
output(10, 20);
I´ve seen a bunch of async function-related questions on here, even some with a db involved like in my case, but it´s just not exactly like mine and I´m not clever enough to implement their solutions in my own project. :)

Related

return results from .then()

Ok, so I need to connect to a MySQL database through SSH and the connection works fine. I am able to execute queries with no problem. I can also get the results and print it out. The thing is, I need something simpler since I will have to send a lot of queries to this database. Below is the code for a promise which creates a connection to this database.
const SSHConnection = new Promise((resolve, reject) => {
sshClient.on('ready', () => {
sshClient.forwardOut(
forwardConfig.srcHost,
forwardConfig.srcPort,
forwardConfig.dstHost,
forwardConfig.dstPort,
(err, stream) => {
if (err) reject(err);
const updatedDbServer = {
...dbServer,
stream
};
const connection = mysql.createConnection(updatedDbServer);
connection.connect((error) => {
if (error) {
reject(error); // Return error
}
resolve(connection); // OK : return connection to database
});
});
}).connect(tunnelConfig);
});
Then I have this piece of code that gives me access to said connection and allows me to send queries. The problem is that I need the return value of my queries and be able to use it in other modules for my project. For example, export a single function to be used to send queries like sendQuery('Enter SQL here').
function sendQuery(sql) {
SSHConnection.then(
function(connection) {
connection.query(
sql,
function(err, results, fields) {
return results; // <---------- I want to return this from the function 'sendQuery()'
}
);
},
function(error) {
console.log("Something wrong happened");
}
);
}
I can work with the results inside SSHConnection.then() but this isn't functional for me.
I would like to have something similar below to work.
// Main function
(async function() {
let res = sendQuery(`SELECT 23+2 AS Sum;`);
console.log(res); // Outputs Sum: 25
})();
So to my question. Is there a way to access the results from a query inside of a promise.then(), from the outside?
I think the problem is you need to add another return statement to your code.
function sendQuery(sql) {
return SSHConnection.then(
function(connection) {
return connection.query(
sql,
function(err, results, fields) {
return results; // <---------- I want to return this from the function 'sendQuery()'
}
);
},
function(error) {
console.log("Something wrong happened");
}
);
}
This should return the results from the query properly IF connection.query returns a promise. I'm not sure if it does. If it does then you can just execute the function like so.
// Main function
(async function() {
let res = await sendQuery(`SELECT 23+2 AS Sum;`);
console.log(res); // Outputs Sum: 25
})();
If connection.query does not return a promise then I suppose you could wrap it in a promise like so.
function sendQuery (sql) {
return SSHConnection.then(
function (connection) {
return new Promise((resolve, reject) => {
connection.query(
sql,
function (err, results, fields) {
if (err)reject(err)
resolve(results) // <---------- I want to return this from the function 'sendQuery()'
}
)
})
},
function (error) {
console.log('Something wrong happened')
}
)
}
love the name by the way...really liked that movie. As to your question, I'd suggest a couple of things:
if you have a lot of queries coming, you might consider moving the connection independent of the query, so that the connection setup and teardown isn't part of the cost of time for the query itself. If you have a single connection, single DB, etc., then you could instantiate the connection once, at startup, and then leave the connection open, and reference it in your queries.
your question:
function sendQuery(sql) {
const resValues = await SSHConnection.then(
function(connection) {
connection.query(
sql,
function(err, results, fields) {
return results; // <---------- I want to return this from the function 'sendQuery()'
}
);
},
function(error) {
console.log("Something wrong happened");
}
);
return(resValues); // or handle error cases
}
Note I added a return value from the ".then()" call, which captures your "results" return value, and then returns that from the parent function (sendQuery)

Express resolving route before API call completes

Ok, full disclosure I am a hobby coder so I understand there to be gaps in my knowledge. However I've tried all sorts of solutions for this and have been unable to get a working answer.
DESIRED RESULT
I make a call to my Express server, it fetches data from an external API and renders once the data has been retrieved.
PROBLEM
I cannot seem to make Express wait no matter how I lay out the async/await pattern. Currently my code is as follows:
Express.js
app.get('/getInventory', async (req, res) => {
try {
let inventory = await api.getInventory(req.query.id)
console.log(inventory)
res.json(inventory)
}
catch(err) {
console.log(err)
}
})
My api.js is currently as such:
exports.getInventory = async function(id){
let data = await manager.getInventoryContents(id, 570, 2, true, (err, inventory) => {
if (err) {
console.log(err)
Promise.reject(err)
}
else {
console.log('Success')
Promise.resolve(inventory)
}
})
return data
}
In case you're wondering I have the console.log() actions just to try and see when something is happening.
WHAT I AM GETTING SO FAR
With just about every variation I am getting the Express.js inventory as undefined (similarly no data being sent to the client), however I AM receiving a Success message (or even the inventory itself) from api.js.
I am guessing the right syntax is obvious once I complete it but I cannot seem to get it to function properly. What am I missing?
Try this:
exports.getInventory = async function(id){
return new Promise((resolve, reject) => {
manager.getInventoryContents(id, 570, 2, true, (err, inventory) => {
if (err) {
console.log(err);
reject(err);
}
else {
console.log('Success');
resolve(inventory);
}
}
}
}

Variable is not storing Promise result in Node [duplicate]

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
How do I access previous promise results in a .then() chain?
(17 answers)
Closed 2 years ago.
I'm developing a script that connects with an API, then with the JSON reponse do some operations and then reformat the JSON to send it to another API.
But now I'm stuck in the first step as I can't deal with the first part as my Promises is not working as expected. How can I store the API's response into a variable? For development puropose I stored one API response into a JSON file. This is my code:
declare var require: any;
let url = './data/big buy/big-bui-product-list.json';
const fs = require('fs');
let counter = 0;
const getProductList = () => {
return new Promise((resolve, reject) => {
fs.readFile(url, 'utf8', (err, data) => {
if(err){
return reject (err);
}
else {
return resolve(JSON.parse(data));
}
})
})
}
const getProductStock = () => {
return new Promise((resolve, reject) => {
fs.readFile('./data/big buy/big-bui-product-stock.json', 'utf8', (err, data) => {
if(err) {
return reject(err);
}
else {
return resolve(JSON.parse(data));
}
})
})
}
try {
let products;
console.log('Products:');
Promise.all([getProductList()])
.then(function(result) {
products = result[0];
});
console.log('Stocks:');
const productStock = Promise.all([getProductStock()]);
console.log(products);
}
catch(e) {
console.log((`Ha ocurrido un error: ${e.message}`));
}
finally {
}
In this code, what I do is getting a list of products and then get the stocks of all the products, later I will add a new function that will filter by stock and get me just a list of products where stock is bigger than X units. Now when I launch it from the terminal I dont' get the response stored into products variable but if I add .then((data) => console.log(data)) into the Promise I see on screen the JSON but as I dont' have it stored it in any variable I don't see how can I work with the objects I'm retrieving.
Promises are asynchronous. They are quite literally promises that a value will be yielded in the future. When you do getProductList().then(x => products = x), you're saying that Javascript should fetch the product list in the background, and once it's finished, it should set the products variable to x. The key words there are "in the background", since the code afterwards keeps running while the product list is being fetched. The products variable is only guaranteed to be set after the .then portion is run. So, you can move things into the .then:
try {
let products;
getProductList().then(list => {
products = list;
return getProductStock(); // leverage promise chaining
}).then(stocks => {
console.log("Products:", products);
console.log("Stocks:", stocks);
});
}
catch(e) {
console.log((`Ha ocurrido un error: ${e.message}`));
}
finally {
}
You seem to be missing some fundamental knowledge about promises. I suggest reading through the MDN Using Promises guide to familiarize yourself a bit with them.
A structure like below never works.
let variable;
promise.then(data => variable = data);
console.log(variable);
This is because it is executed in the following manner.
Create the variable variable.
Add a promise handler to the promise.
Log variable.
Promise gets resolved.
Execute the promise handler.
Set variable variable to data.
If you are using Node.js 10 or higher you can use the promise API of file system to simplify your code quite a bit.
const fs = require('fs/promises');
const readJSON = (path) => fs.readFile(path, "utf8").then((json) => JSON.parse(json));
const getProductList = () => readJSON("./data/big buy/big-bui-product-list.json");
const getProductStock = () => readJSON("./data/big buy/big-bui-product-stock.json");
Promise.all([
getProductList(),
getProductStock(),
]).then(([products, stocks]) => {
console.log({ products, stocks });
}).catch((error) => {
console.log("Ha ocurrido un error:", error.message);
}).finally(() => {
// ...
});

How to wait cordova.plugins.sqlitePorter.exportDbToSql to complete before continuing?

By using the SQLite Porter Cordova/Phonegap Plugin, i am trying to create a backup file of the application database before continuing to execute the code.
However, i am unable to do so, since it is asyncronous and no matter what i try it always complete before the successFn function executes, even though successFn is sort of a callback.
I have already tried using promisses, await/async to no avail. My last attempt was using promise as shown on the example below.
var successFn = function (sql, count) {
console.log("Success")
};
var promise = new Promise(function (resolve, reject) {
cordova.plugins.sqlitePorter.exportDbToSql(db, {
successFn: successFn
})
});
promise.then(
function () { return true; },
function (erro) { return false;}
);
console.log("END");
I was expecting the order of the log to be "Success" then "END", but it return "END" then "Success"
Update
As you are using Ionic 1, then you can wrap the function with a promise and use it:
function exportDbToSql() {
var deferred = $q.defer();
cordova.plugins.sqlitePorter.exportDbToSql(db, {
successFn: function(sql, count) {
deferred.resolve({sql: sql, count: count})
}
});
return deferred.promise;
}
And when you call the function, it will be:
exportDbToSql().then(function(result) {
console.log(result.sql);
console.log(result.count);
});
Old answer
If you are using Ionic 2+, then you can follow their documentation here.
Open the command line and enter
ionic cordova plugin add uk.co.workingedge.cordova.plugin.sqliteporter
npm install #ionic-native/sqlite-porter
then you can use it in this way:
import { SQLitePorter } from '#ionic-native/sqlite-porter/ngx';
constructor(private sqlitePorter: SQLitePorter) { }
...
let db = window.openDatabase('Test', '1.0', 'TestDB', 1 * 1024);
// or we can use SQLite plugin
// we will assume that we injected SQLite into this component as sqlite
this.sqlite.create({
name: 'data.db',
location: 'default'
})
.then((db: any) => {
let dbInstance = db._objectInstance;
// we can pass db._objectInstance as the database option in all SQLitePorter methods
});
let sql = 'CREATE TABLE Artist ([Id] PRIMARY KEY, [Title]);' +
'INSERT INTO Artist(Id,Title) VALUES ("1","Fred");';
this.sqlitePorter.importSqlToDb(db, sql)
.then(() => console.log('Imported'))
.catch(e => console.error(e));
In your case, it should work like this:
this.sqlitePorter.exportDbToSql(db)
.then(() => console.log('success'))
.catch(() => console.log('error'))

Defining asynchrosnous function and using it in a forEach loop

I am trying to compile tex files into PFD using data from a firestore database. After completion the script doens't terminate. I found one can use process.exit() to make it quit. However, it terminates the child processes still cimpling the tex files. So, I need an asynchronous function.
The guides I found on how to make them did not particularly help me. I am still very new to javascript and any bloat is still highly confusion to me.
The guides I found on how to make them did not particularly help me. I am still very new to javascript and any bloat is still highly confusion to me.
prepending below mentioned makePDF function with async and the call of the function with await does not work and is, to my understanding, outdated.
I tried implementing a promise, but don't understand how their syntax works. Does simply appending .then() to the function call in the for loop suffice to make the loop wait for the functions completion?
How do I make this specific asynchronous?
Does it matter that it already uses asynchronous functions in its body?
I understand that a promise is used to return what ever the producer has produced to a consumer. Now, my producer doesn't produce anything to be returned. Does this matter at all?
My function called from the for loop:
function makePDF(object){
let input = fs.readFileSync('main.tex', 'utf8');
const outNameTex = object.ID + '.tex';
const outNamePDF = object.ID + '.pdf';
makeTEX(object, input, outNameTex);
const infile = fs.createReadStream(outNameTex);
const outfile = fs.createWriteStream(outNamePDF);
const pdf = latex(infile);
pdf.pipe(outfile);
pdf.on('error', err => console.error(err));
pdf.on('finish', () => {console.log('PDF generated!')});
}
And my function with the loop:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user');
db.collection('objects').where('printed', '==', false).get().then((snapshot) => {
snapshot.forEach((doc) => {
console.table(doc.data());
makePDF(doc.data());
})
process.exit();
})
.catch((err) => {
console.log('Error getting documents', err);
});
} else {
console.log('no user');
}
});
It outputs a table for each document, but no PDF generated.
async/await can be tricky to use with for loops, that is because async functions return a promise... if you convert the async/await syntax to native promise syntax you might figure out what the issue is.
What you want to do is use Array.map to map/convert each doc to a promise that resolves once the makePDF is done, then use Promise.all to wait for all the promises to resolve..
The solution should look something like this
function makePDF(object){
return new Promise((resolve, reject) => {
let input = fs.readFileSync('main.tex', 'utf8');
const outNameTex = object.ID + '.tex';
const outNamePDF = object.ID + '.pdf';
makeTEX(object, input, outNameTex);
const infile = fs.createReadStream(outNameTex);
const outfile = fs.createWriteStream(outNamePDF);
const pdf = latex(infile);
pdf.pipe(outfile);
pdf.on('error', reject);
pdf.on('finish', () => {console.log('PDF generated!'); resolve();});
}
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user');
db.collection('objects').where('printed', '==', false).get().then((snapshot) => {
const promiseArr = snapshot.docs.map((doc) => {
console.table(doc.data());
return makePDF(doc.data());
})
Promise.all(promiseArr)
.then(() => {
process.exit();
})
})
.catch((err) => {
console.log('Error getting documents', err);
});
} else {
console.log('no user');
}
});

Categories