custom validation (Existing email) - mysql

I wanted to use express-validator to check if the email exists
here is my code:
router.post('/', [
check('username', 'Min 5 chars, Max 20').isLength({ min: 5, max: 20 }),
check('email').custom(async value => {
const db = require('../db');
return await db.query('SELECT id FROM users WHERE email=?', [value], function (err, results, fields) {
if (results.length > 0) {
return false;
} else { return true; }
})
}).withMessage('Email already exists'),
], function(req, res, next) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
....
The problem with async/await that the validation didnt execute at all even if the return is true or false. How to fix it?

You are using bad async/await commands. And to be honest, you don't need them here.
router.post('/', [
check('username', 'Min 5 chars, Max 20').isLength({ min: 5, max: 20 }),
check('email').custom(value => {
const db = require('../db');
return new Promise((resolve, reject) => {
db.query('SELECT id FROM users WHERE email=?', [value], function (err, results, fields) {
if (err)
reject(err)
if (results.length>0)
reject(new Error('Email Already exists'))
resolve()
})
})
}),
], function(req, res, next) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}

Related

How to add Promise value in render() in node js

router.get('/top-website', function (req, res, next) {
// console.log(topSites)
connection.query("SELECT * FROM topsites LIMIT 5", function (err, results, fields) {
// const url =this.rootDomain;
results.forEach(function (item) {
console.log(item.rootDomain)
linkPreview(item.rootDomain)
.then(resp => {
console.log(resp)
res.render('top-website', { sitedata: results,fn:resp });
//console.log(resp)
})
})
})
})
i want to get value resp in render but im getting error,

Calling mysql queries dependent on another query in node

can anyone help me.
I need to get result of queryA [which is an update query that returns ROW_COUNT( )], see if the result is equal to 1.
If not, just return it via res.json
If yes, call queryB [which returns a set of rows].
After which, I have to loop and call queryC to update each row. It has to be one at a time because the queryC is also inserting auditTrails within the stored procedure.
This is the source code:
exports.migrateCustomer = asyncHandler(async (req, res) => {
const { oldCustomerID, newCustomerID, userID } = req.body;
const connection = mysql.createConnection(config);
let sql = `CALL usp_UpdateCustomerCallStatusIdAndIsActive(?,?,?)`;
/*UPDATE Customer*/
const updateCus = connection.query(sql, [oldCustomerID, 'Duplicate', userID], (error, results, fields) => {
if (error) {
return console.error(error.message);
}
return results[0];
});
if (updateCus.rowCount == 1) {
let sql = `CALL usp_GetPurchaseOrderByCustomerIDAndNameSearch(?,?)`;
/*GET rows to be updated*/
const GetRows = connection.query(sql, [oldCustomerID, ''], (error, results, fields) => {
if (error) {
return console.error(error.message);
}
results[0].forEach(element => {
let sql = `CALL usp_UpdatePurchaseOrderByCustomerID(?,?)`;
/*UPDATE rows*/
connection.query(sql, [newCustomerID, userID], (error, results, fields) => {
if (error) {
return console.error(error.message);
}
});
});
});
}
res.json(updateCus);
connection.end();
});
Error:
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Query'
then another one at the bottom:
throw er; //Unhandled 'error' event
You are missing 'await' before the mysql.createConnection(config) and connection.query call, since these are asynchronous functions. Also in your code connection.end() should be inside the callback.
exports.migrateCustomer = asyncHandler(async (req, res) => {
const { oldCustomerID, newCustomerID, userID } = req.body;
const connection = await mysql.createConnection(config);
let sql = `CALL usp_UpdateCustomerCallStatusIdAndIsActive(?,?,?)`;
/*UPDATE Customer*/
const updateCus = await connection.query(sql, [oldCustomerID, 'Duplicate', userID], (error, results, fields) => {
if (error) {
connection.end();
return console.error(error.message);
}
return results[0];
});
if (updateCus.rowCount == 1) {
let sql = `CALL usp_GetPurchaseOrderByCustomerIDAndNameSearch(?,?)`;
/*UPDATE Customer*/
connection.query(sql, [oldCustomerID, ''], (error, results, fields) => {
if (error) {
connection.end();
return console.error(error.message);
}
results[0].forEach(element => {
let sql = `CALL usp_UpdatePurchaseOrderByCustomerID(?,?)`;
/*UPDATE Customer*/
connection.query(sql, [newCustomerID, userID], (error, results, fields) => {
connection.end();
if (error) {
return console.error(error.message);
}
});
});
});
}else{
connection.end();
return res.status(200).json({
customer:updateCus});
}
});

How to wait for a MYSQL query to finish before executing another using Node server?

I am building an Express server to receive request (a dict with 10 items) from my React front end and then save the data to database. Below is my code.
I found that the query may crash during the insertion e.g. 2 queries got the same id by last_insert_id(). I have tried to use setTimeout() to wrap the getConnection function but the issue still exists. How to better solve the problem?
The request data:
{{.....}, {.....}, {.....}, {.....}, {.....}} #10 item
Code:
router.post('/fruit', (req, res) => {
const dict = req.body;
let itemCount = 0;
var err_list = [];
Object.keys(dict).forEach(function(r){
let query = "call sp_insert_fruit();"
setTimeout(function() {
getConnection(function(err, conn){
if (err) {
return res.json({ success: false, error: err })
} else {
conn.query(query, function (err, result, fields) {
if (err) {
err_list.push({'errno':err.errno, 'sql_message':err.sqlMessage});
}
itemCount ++;
if (itemCount === Object.keys(dict).length) {
conn.release()
console.log('released', err_list)
if (err_list .length === 0) {
return res.json({ success: true});
} else {
return res.json({ success: false, error: err_list});
}
}
});
}
});
}, 1000);
});
});
connection.js:
const p = mysql.createPool({
"connectionLimit" : 100,
"host": "example.org",
"user": "test",
"password": "test",
"database": "test",
"multipleStatements": true
});
const getConnection = function(callback) {
p.getConnection(function(err, connection) {
callback(err, connection)
})
};
module.exports = getConnection
You should replace callbacks with Promises and async/await to avoid callback hell. Using Promises, this problem should be easy to solve.
connection.js
const p = mysql.createPool({
"connectionLimit" : 100,
"host": "example.org",
"user": "test",
"password": "test",
"database": "test",
"multipleStatements": true
});
// wrap p.getConnection with Promise
function getConnection() {
return new Promise((resolve, reject) => {
p.getConnection((err, connection) => {
if (err) reject(err);
else resolve(connection);
});
});
};
module.exports = getConnection;
Router code
// wrap conn.query with Promise
function executeQuery(conn, query) {
return new Promise((resolve, reject) => {
conn.query(query, (err, result, fields) => {
if (err) reject(err);
else resolve({ result, fields });
});
});
}
router.post('/fruit', async (req, res) => {
const dict = req.body;
const errList = [];
const query = "call sp_insert_fruit();"
let conn = null;
try {
conn = await getConnection();
} catch (err) {
return res.json({
success: false,
error: err
});
}
for (const r of Object.keys(dict)) {
try {
const { result, fields } = await executeQuery(conn, query);
} catch (err) {
errList.push({
'errno': err.errno,
'sql_message': err.sqlMessage
});
}
}
conn.release();
console.log('released', errList);
// I don't know what err_imnt is, so I guess it's errList?
if (errList.length === 0) {
return res.json({
success: true
});
} else {
return res.json({
success: false,
error: errList
});
}
});

Express-validator check if email existed with MySQL

Im using express-validator to check if the req.body entered is valid and to check if there is duplicate email in the MySQL database
Here is my code:
router.post(
"/signup",
[
body("uemail","email is not valid")
.isEmail()
.normalizeEmail()
.custom(async (email, {req} )=>{
const queryString = "SELECT uid FROM EarlyUsers WHERE `uemail` = ?";
return await connection.query(queryString, [email], (err, rows, fields) => {
if (err) {
console.log(err)
}else {
if (rows.length != 0) {
return false
} else {
return true
}
}
});
})
,
body("uname").isLength({ min: 5 })
],
authControllers.signUp
);
I dont know why this custom validator does not work.
I've tried to throw new Error instead of return false, but it just crash the whole thing . I really need help with this
For it to work correctly instead of returning false you reject the Promise.
if (rows.length != 0) {
return Promise.reject("user already exists.");
}
I have achieved this way it might be helpful for others, I'm using sequelize :)
const User = require("../../models/User");
body('email', 'Invalid email').exists().isEmail().trim().escape().custom(userEmail=> {
return new Promise((resolve, reject) => {
User.findOne({ where: { email: userEmail } })
.then(emailExist => {
if(emailExist !== null){
reject(new Error('Email already exists.'))
}else{
resolve(true)
}
})
})
}),
I found this solution to check that the email is not duplicate:
router.post('/register',
body('email').isEmail().normalizeEmail().withMessage('The email format is not correct.').custom((email) => {
const queryString = `SELECT * FROM users WHERE user_email = "${email}"`;
return getFinalEmail(queryString).then(user => {
console.log(user);
if (user) {
return Promise.reject('E-mail already in use');
}
});
}),
// -- other validations
// .....
(req, res) => {
/* your code for this route */
}); // end of router('/register')
function getFinalEmail(param) {
return new Promise(function(resolve, reject) {
getEmailData(param, function(result) {
console.log(result);
resolve(result);
});
});
}
function getEmailData(query, callback) {
database.query(query, function(error, data){
if(data.length > 0) {
return callback(true);
} else {
return callback(false);
}
});
}
In the above code users is the name of my table and user_email is the column that email data of users are stored.

Return MySQL result after query execution using node.js

I want to return the MySQL result into a variable.
I tried the following but it's not working, as I am getting an empty variable.
const mysql = require('mysql');
const db = require('../config/db');
const connection = mysql.createConnection(db);
module.exports = class Categories {
constructor (res) {
this.res = res;
}
getCategories() {
connection.query("SELECT * FROM `categories`", (error, results, fields) => {
if (error) throw error;
this.pushResult(results);
});
}
pushResult(value) {
this.res = value;
return this.res;
}
};
Just made a callback function first:
var Categories = {
getCategories: function (callback) {
connection.query("SELECT * FROM `categories`", (error, results, fields) => {
if(error) { console.log(err); callback(true); return; }
callback(false, results);
});
}
};
And then used it with route:
app.get('/api/get_categories', (req, res) => {
categories.getCategories(function (error, results) {
if(error) { res.send(500, "Server Error"); return; }
// Respond with results as JSON
res.send(results);
});
});