learning and implementing async await - javascript

I've been reading about async and await in JS and tried to implement them in my code (which I totally messed up).
Here is my JS.
var express = require('express');
var router = express.Router();
var jsforce = require('jsforce');
const SEC_TOKEN = 'SEC_TOKEN';
const USER_ID = 'USER_ID';
const PASSWORD = 'PWD';
const { default: axios } = require('axios');
router.get("/", async (req, res, next) => {
await initConnect;
await soqlData;
await slackPostTest;
});
initConnect = async () => {
var conn = new jsforce.Connection({
loginUrl: 'https://login.salesforce.com'
});
await conn.login(USER_ID, PASSWORD + SEC_TOKEN, (err, userInfo) => {
if (err)
console.log(err);
else {
console.log(userInfo.Id);
}
});
}
soqlData = async () => {
await conn.query('Select Id, Name from Account LIMIT 1', (err, data) => {
if (err)
console.log(err);
else
return data.records[0];
})
}
slackPostTest = async () => {
await axios.post('SLACK_WEBHOOK', {
"text": "soqlRes"
})
}
module.exports = router;
What I am trying to achieve?
Initialize my connection by passing in SEC_TOKEN, USER_ID, PASSWORD to my initConnect function this will give me a connection (conn).
Use this conn and query my salesforce instance and get some other data.
post some message(currently irrelevant, but will hook up with the above response later) to my slack endpoint.
Also can someone please give me a little detailed explanation of the solution (in terms of async/await)?
Thanks

Assuming everything else about your JsForce API usage was correct (I have no experience with it, so I can't say), here's how to promisify those callback-based APIs and call them.
var express = require("express");
var router = express.Router();
var jsforce = require("jsforce");
const SEC_TOKEN = "SEC_TOKEN";
const USER_ID = "USER_ID";
const PASSWORD = "PWD";
const { default: axios } = require("axios");
router.get("/", async (req, res, next) => {
const { conn, userInfo } = await initConnect();
const data = await soqlData(
conn,
"Select Id, Name from Account LIMIT 1",
);
await slackPostTest(data.records[0]);
});
function initConnect() {
const conn = new jsforce.Connection({
loginUrl: "https://login.salesforce.com",
});
return new Promise((resolve, reject) => {
conn.login(USER_ID, PASSWORD + SEC_TOKEN, (err, userInfo) => {
if (err) return reject(err);
resolve({ conn, userInfo });
});
});
}
function soqlData(conn, query) {
return new Promise((resolve, reject) => {
conn.query(query, (err, data) => {
if (err) return reject(err);
resolve(data);
});
});
}
function slackPostTest(soqlRes) {
return axios.post("SLACK_WEBHOOK", {
text: soqlRes,
});
}
module.exports = router;

Related

Convert Promise to async

I am trying to convert mySQL connection from promise to asycn await so far I have the following setup:
const mysql = require("mysql");
const pool = mysql.createPool({
connectionLimit: 10,
password: "",
user: "root",
database: "usersdb",
host: "localhost",
port: "3306",
});
let usersDB = {};
usersDB.all = () => {
return new Promise((resolve, reject) => {
pool.query("SELECT * FROM users", (err, results) => {
if (err) {
return reject(err);
}
return resolve(results);
});
});
};
usersDB.one = (id) => {
return new Promise((resolve, reject) => {
pool.query("SELECT * FROM users WHERE id = ?", [id], (err, results) => {
if (err) {
return reject(err);
}
return resolve(results[0]);
});
});
};
module.exports = usersDB;
Is there a way to convert this codes:
return new Promise((resolve, reject) => {
pool.query("SELECT * FROM users", (err, results) => {
if (err) {
return reject(err);
}
return resolve(results);
});
to async await and make the code more compress or succint?
UPDATE: on my router, I have these codes:
const router = express.Router();
router.get("/", async (req, res) => {
try {
let results = await db.all();
res.json(results);
} catch (error) {
console.log(error);
res.sendStatus(500);
}
});
router.get("/:id", async (req, res) => {
try {
let results = await db.one(req.params.id);
res.json(results);
} catch (error) {
console.log(error);
res.sendStatus(500);
}
});
So it just fine calling async await twice?
You can convert any callback function to promise by using util.promisify
const util = require('util')
// ....
const query = util.promisify(pool.query)
// ... inside some async function
const users = await query("SELECT * FROM users;")
// or promise style
query("SELECT * FROM users;")
.then((users) => {
console.log(users)
})
.catch(console.error)
usersDB.one = (id) => {
try {
const users = pool.query("SELECT * FROM users WHERE id = ?", [id]);
return users;
} catch (e) {
throw e;
}
};
Or more simply,
usersDB.one = (id) => pool.query("SELECT * FROM users WHERE id = ?", [id]);
What you want to do is to promisify the DB call. You can acheive this by factorisation :
const mysql = require("mysql");
const pool = mysql.createPool({
connectionLimit: 10,
password: "",
user: "root",
database: "usersdb",
host: "localhost",
port: "3306",
});
function promisify(...args){
return new Promise((resolve, reject) => {
pool.query(...args, (err, result) => {
if(err) reject(err);
resolve(result);
});
});
}
let usersDB = {};
//Then you can call it this way :
usersDB.all = async () => {
return await promisify("SELECT * FROM users");
//Note that you can avoid to await there.
};
usersDB.one = async (id) => {
return await promisify("SELECT * FROM users WHERE id = ?", [id]);
};
module.exports = usersDB;

Getting API resolved without sending a response error even when sending response

I am trying to send res.json after I successfully save data in database and save the upload the image but I am constantly getting API resolved without sending a response for /api/auth/registeration, this may result in stalled requests.. Also I am using formidable for image upload in Next.js.
code:
import connection from "../../../utils/connection/getConnection";
import formidable from "formidable";
const signupSchema = require("../../../models/signup");
import mkdirp from "mkdirp";
import bcrpt, { genSaltSync } from "bcrypt";
import fs from "fs";
export const config = {
api: {
bodyParser: false,
},
};
const handlePost = async (req, res) => {
const form = formidable.IncomingForm();
form.parse(req, async function (err, field, files) {
await fileSavour(field, files);
return res.json({
message: "success",
});
});
};
const fileSavour = async (fields, files) => {
let { email, password } = fields;
let imageName = files.image.name;
let newPassword = await bcrpt.hash(password, genSaltSync(10));
const newUser = new signupSchema({
email,
password: newPassword,
image: imageName,
});
const Nuser = await newUser.save();
if (Nuser) {
await mkdirp("public/profileImages/" + Nuser._id);
if (imageName) {
const data = fs.readFileSync(files.image.path);
const pathToSave = "public/profileImages/" + Nuser._id + "/" + imageName;
fs.writeFileSync(pathToSave, data);
await fs.unlinkSync(files.image.path);
return;
}
}
};
const Register = async (req, res) => {
req.method === "POST"
? handlePost(req, res)
: req.method === "PUT"
? console.log("PUT")
: req.method === "DELETE"
? console.log("DELETE")
: req.method === "GET"
? console.log("GET")
: res.status(404).send("");
};
export default Register;
The handlePost handler function will not wait for the form.parse callback to execute (and subsequently for res.json to be called), and will return immediately. To prevent this, you can wrap the form.parse with a Promise to ensure the handler waits for the callback function to execute.
const handlePost = async (req, res) => {
const form = formidable.IncomingForm();
await new Promise(function(resolve, reject) {
form.parse(req, async function(err, fields, files) {
await fileSavour(field, files);
resolve();
});
});
res.json({ message: "success" });
};
You need to promisify the form.parse function. Currently, your request is returned before the form is parsed.
Let's define a function which promisifies the form parse using formidable, and use it to parse all the requests. The function should look like this -
const promisifiedParseForm = (req) => {
const form = formidable.IncomingForm();
return new Promise((resolve, reject) => {
form.parse(req, function (err, field, files) {
if (err) {
reject(err)
} else {
resolve({ field, files })
}
});
});
}
Use the promisifiedParseForm function in the handlePost function, like this -
const handlePost = async (req, res) => {
const { field, files } = await promisifiedParseForm(req);
await fileSavour(field, files);
return res.json({
message: "success",
});
};

Trying to select every document with the same ID using MongoDB

So I'm trying to fetch every document which matches the same ID.
Here is what did I do:
app.get('/comments/:id', async (req,res)=>{
let db = await connect();
let id = req.params.id;
console.log(id);
let results = await db.collection('comments').find({postID: id});
console.log(results);
res.json(results);
});
How to send more than one documents with the same ID?
I want to select every postID property with the same ID
My code while connecting with MongoDB:
const { MongoClient } = require('mongodb');
let connection_string = 'mongodb+srv://user:pass#host/myFirstDatabase?retryWrites=true&w=majority';
let client = new MongoClient(connection_string, {
useNewUrlParser: true,
useUnifiedTopology: true
});
let db = null
export default () => {
return new Promise((resolve, reject) =>{
if (db /*&& client.isConnected()*/){
resolve(db)
}
client.connect(err => {
if(err){
reject("Error while connecting: " + err)
}
else{
console.log("Successful connection!")
db = client.db("posts")
resolve(db)
}
});
})
};
Make sure you are importing client from the file where you are making the connection.
app.get("/comments/:id", async (req, res) => {
await client.connect(); // Simply connect() won' work.
const db = client.db("posts"); // Specify the db here
let id = req.params.id;
console.log(id);
let results = await db.collection("comments").find({ postID: id }).toArray(); // Without toArray(), it returns a cursor to the array.
console.log(results);
res.json(results);
});
db.js
const { MongoClient } = require("mongodb");
let connection_string = "mongodb+srv://admin:admin#cluster0.3ctoa.mongodb.net/myFirstDatabase?retryWrites=true&w=majority";
let client = new MongoClient(connection_string, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = function () {
return new Promise((resolve, reject) => {
client.connect((err) => {
if (err) {
reject("Došlo je do greške prilikom spajanja: " + err);
} else {
resolve("Successful connection!");
}
});
});
};
module.exports = { client, db };
And instead of importing connect, import both client and db from db.js.
If you are talking about the id created by mongoose.scheme.Types.objectId, There is only one entry with that ID

Making a jest test file for mysql database calls

I'm very new to testing with Jest. I want to make a test to see if the following function returns user data from the database I have:
let dbConnect = require('../config/dbConnect');
let findUserByEmail = (email) => {
return new Promise(async (resolve, reject) => {
try {
dbConnect.query("SELECT * FROM user_login WHERE email = ?", email, function (error, results) {
if (error) reject(error);
let user = results[0];
if(user == undefined){
resolve()
}
resolve(user);
})
} catch (e) {
reject(e);
}
})
}
How would I go about making mock data to use in testing?
EDIT: Here is dbConnect:
let mysql = require('mysql');
let dotenv = require('dotenv');
dotenv.config({path: '../.env'});
let db = mysql.createConnection({
host: process.env.DATABASE_HOST,
database: process.env.DATABASE,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
});
db.connect(function (error) {
if (error) console.log(error);
else console.log("MYSQL Connected...");
});
module.exports = db;
Edit: fixed mistake
const mysql = require('mysql')
const mockQuery = jest.fn()
jest.mock('mysql', () => ({
createConnection: () => ({
connect: () => undefined,
query: mockQuery
}),
}))
describe('findUserByEmail', () => {
it('should resolve with the user when query suceeds', async () => {
mockQuery.mockImplementationOnce((sql, email, callback) => callback(null, ['TEST USER']));
expect(await findUserByEmail()).toBe('TEST USER');
})
});

Nodejs api structure on calling sql helpers inside another helper all called by a controller

I'm studying to create a simple API with mysql. I've understood and implemented the simple structure in which the app call the router, that call the controller, that call the service. But now i'm developing a multiple tag service module and I've realized that I need to call the same sql queries services declared in it. I show you the code for a better understanding:
tag_service.js:
const mysql = require("../../config/database");
module.exports = {
insertTags: async (data, callBack) => {
const connection = await mysql.connection();
let results = '';
const tagsArray = data.tags.map(tag => [data.id_manager,data.cod_table,data.id_record,tag])
try {
//console.log("at insertCallout...");
await connection.query("START TRANSACTION");
results = await connection.query(
`INSERT INTO s_com_tags (id_manager,cod_table,id_record,tag)
VALUES (?,?,?)`,
[tagsArray]
);
await connection.query("COMMIT");
} catch (err) {
await connection.query("ROLLBACK");
//console.log('ROLLBACK at insertCallout', err);
throw err;
} finally {
await connection.release();
return callBack(null, results);
}
},
deleteTags: async (data, callBack) => {
//console.log(data);
let results = '';
const connection = await mysql.connection();
try {
//console.log("at deleteCallouts...");
await connection.query("START TRANSACTION");
results = await connection.query(
`DELETE FROM s_com_tags
WHERE cod_table = ? AND id_record = ? AND tag IN (?)`,
[data.code_table, data.id_record,data.tags]
);
//console.log(res);
await connection.query("COMMIT");
} catch (err) {
await connection.query("ROLLBACK");
//console.log('ROLLBACK at deleteCallouts', err);
throw err;
} finally {
await connection.release();
return callBack(null, Callouts);
}
},
};
controller's structure that will use the service:
module.exports = {
updateLabDesc: async (req, res, next) => {
try {
const body = req.body;
if(!body.internal_code){
updateLabDesc(body.manager, async (err, results) => {
if (err) {
return next(createError.InternalServerError())
}
});
}
updateTags(body, async (err, results) => {
if (err) {
return next(createError.InternalServerError())
}
return res.json({
success: (results ? 1 : 0 ),
message: (results || 0) + " LabDesc inserted successfully"
});
});
} catch (error) {
next(error)
}
},
};
But the update is something like
updateTag function => {
try {
const current_tags = await getTags(req.body);
let newTags = [];
let oldTags = [];
req.body.tags.forEach(tag => {
if(!current_tags.includes(tag))
newTags.push(tag)
});
await insertTags(newTags);
current_tags.tags.forEach(tag => {
if(!req.body.tags.includes(tag))
oldTags.push(tag)
});
await deleteTags(oldTags);
} catch (error) {
next(error)
}
},
Basically, the tag_service has insertTags and deleteTags but I need the updateTags to call these functions as well. The final controller will call insertTags, deleteTags and updateTags. How can I structure these calls?
It is a controller that could call 2 helpers (insertTag and deleteTags) and another helper (updateTags) that call these 2 helpers. Any ideas?

Categories