Node mysql error is not being caught by Promise reject - mysql

I'm making a simple database call wrapped in a promise, and trying to catch the error and pass it through to the promise reject(), but the reject isn't being handled or bubbled back up by the calling code. The code just stops executing when the mysql call fails.
The error within the mysql callback is:
REJECTING QUERY { Error: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1
Here is the database query code:
this.query = function(sql, params) {
return new Promise((resolve, reject) => {
_pool.query(sql, params, function(err, result) {
if (err) {
console.log("REJECTING QUERY", err);
return reject(err);
}
resolve(result);
});
});
}
Here is the calling code:
this.createUser = function(data) {
var query = "INSERT into users SET ?";
return new Promise((resolve, reject) => {
Container.DB.query(query, data)
.then((response) => {
console.log("Resolved", response);
return resolve(response);
},(error) => {
console.log("REJECTION ERROR", error);
return reject('An unknown error occurred and has been reported.');
})
.catch((err) => {
console.log("CAUGHT ERROR", err);
});
});
}
I get to "REJECTING QUERY" within the database query code, but nothing in the calling code is reached (ie. .then, or the error handler, or the .catch handler).
Is it possible to get the mysql error to reach these points in code so I can respond to the user? Am I doing something wrong?

The anti-pattern mentioned by #JaromandaX is forcing you to unnecessarily jump through flaming hoops to accommodate it... and your getting burned.
But, first, you are rejecting to the outer (redundant) promise from the then before the catch so the catch is by-passed. After an error is thrown in a promise chain, the first thenable with a second argument (onRejected) will consume it: so it won't be propagated beyond that. But, anyway, you need to trap the error on the outer promise which you are rejecting.
this.createUser = function (data) {
var query = "INSERT into users SET ?";
return new Promise((resolve, reject) => { // the first 'then' rejects to here
Container.DB.query(query, data) // broken promise: anti-pattern
.then((response) => {
console.log("Resolved", response);
return resolve(response);
}, (error) => {
console.log("REJECTION ERROR", error);//<--the error is consumed here and will
// not go any further on this chain
return reject('An unknown error occurred and has been reported.');
})
.catch((err) => { // this will not be called
console.log("CAUGHT ERROR", err); // because it is the 'onRejected'
// argument of a then
});
})
.catch((err) => { // this will be called and the error will be consumed
console.log("CAUGHT ERROR", err);
return 'An unknown error occurred and has been reported.';
});
;
}
Less worse, you can log and re-throw the error in one catch...
this.createUser = function (data) {
var query = "INSERT into users SET ?";
return new Promise((resolve, reject) => { // this is still redundant
Container.DB.query(query, data) // broken promise: anti-pattern
.then((response) => { // on error, skip this because it has no
console.log("Resolved", response); // 'onRejected' argument
return resolve(response);
})
.catch((err) => { // this will be called and the error
console.log("CAUGHT ERROR", err); // will be consumed
return reject('An unknown error occurred and has been reported.');
});
})
;
}
Better, eliminate the anti-pattern and propagate the message with a throw instead of a reject on the (redundant) promise wrapper...
this.createUser = function (data) {
var query = "INSERT into users SET ?";
return Container.DB.query(query, data)
.then((response) => { // on error, skip this because it has no
console.log("Resolved", response); // 'onRejected' argument
return resolve(response);
})
.catch((err) => { // this will be called and the error
console.log("CAUGHT ERROR", err); // will be consumed so need to re-throw
throw new Error('An unknown error occurred and has been reported.');
});
}
Bearing in mind that a catch is just syntactic sugar for then(undefined, reject) and that, once rejected, a promise is no longer pending, calling it's then method will return undefined 'as soon as possible'. So you can chain another then after the catch if you prefer not to throw...
this.createUser = function (data) {
var query = "INSERT into users SET ?";
return Container.DB.query(query, data)
.then((response) => { // on error, skip this because it has no
console.log("Resolved", response); // 'onRejected' argument
return resolve(response);
})
.catch((err) => { // this will be called and the error
console.log("CAUGHT ERROR", err); // will be consumed. The returned promise
}) // state will be rejected but not pending
// It's then method returns 'undefined' as
// soon as possible
.then(() => 'An unknown error occurred and has been reported.');
}
Taking it one step further, bearing in mind that the value returned by a resolved or rejected promise is the return value of whichever of those is called, you can pass any value you like to the consumer via the return in the catch...
this.createUser = function (data) {
var query = "INSERT into users SET ?";
return Container.DB.query(query, data)
.then((response) => { // on error, skip this because it has no
console.log("Resolved", response); // 'onRejected' argument
return resolve(response);
})
.catch((err) => { // this will be called and the error
console.log("CAUGHT ERROR", err); // will be consumed. The returned promise
// state will be rejected but not pending
// but you can still return any value
return 'An unknown error occurred and has been reported.'
})
}

Related

How can i stop further execution of express middleware

I want to get this functionality if(thereIsSomeError) //stop executing further. for example if there some error accurs in middleware or in the callback then i don't want to execute callback(in the app.route) and the middleware further
I tried this code. But i'm still getting req.err as true. how can i fix this issue
// My MiddleWare
export let Middleware=()=> {
return (req,res,next)=>{
next()
console.log(req.err) // Problem is here.. i'm still getting req.err(true)
if(!req.err){
db.query(`query`,(error, responseData)=>{
if(error) console.log(error)
db.query(`second query`,{...// send data to the
database})
})
}
}
}
//End point
app.post('/addStudent',Middleware, (req, res) => {
//setting error to true initially
req.err=true;
let data = req.body
db.query(`query `, data.username, (err, d) => {
if (err) return res.json(err)
else {
// since no Error accured so set the error to false
req.err=false;
let q = 'query';
let values = {//data here}
db.query(q, values, (err, data) => {
if (err) return res.status(200).json(err)
else return res.status(200).json({ data })
})
}
})
})
First, a middleware runs BEFORE a request, NOT AFTER. If you set req.err = true in your POST endpoint, IT WILL STAY TRUE, meaning your database call will certainly return an error.
Second, to successfully abort a middleware call, use return. Returning a function stops it immediately. You can choose either to return next(err) to forward the error to the handler, or to use return res.send('Error') to terminate the response in the middleware.

try/catch block can't stop ER_DUP_ENTRY error from crashing my appliction

Im adding a duplicate to a mysql table and I want to handle elicited ER_DUP_ENTRY error comming back with a Try/Catch block but its just crashing anyway , is there any possible way to handle error and stop application from crashing using a try/catch block?
async function init() {
try {
connection.query(
'SOME INSERT QUERY',
(err, result, feilds) => {
if (err) throw err
console.log(result);
}
);
} catch (e) {
console.log(e);
}
}
init();
The node mysql-library does not support promises out of the box, which means query does not return a promise which you can await. So you can either wrap the query function in a promise yourself:
async function init() {
try {
const duplicateResult = await new Promise((resolve, reject) => {
connection.query(
'SOME INSERT QUERY',
(err, result, fields) => {
if (err) {
return reject(err);
}
resolve(result);
});
});
} catch (e) {
console.log(e);
}
}
or use util.promisify as Always Learning posted alternatively.
The problem is that connection.query returns undefined right away. Your catch is not involved because the call ends before the work is done and will call your callback function later. An exception that occurs during your callback is too late. You try/catch block has already completed.
You can use promisify to wait on it like this though:
const util = require("util");
function init() {
const queryPromise = util.promisify(connection.query);
return queryPromise('SOME INSERT QUERY')
.catch(e => {
console.log("It failed", e);
});
}
init().then(result => {
if (result) console.log("It worked", result);
else console.log("Aww, it didn't work");
});

insert in for each with async await

error on query execution
var records = [{name:'John',age:24},{name:'Sarah',age:28},{name:'Linda',age:23}];
connection.getSession().then(session => {
async function insertRecords() {
await Promise.all(records.map(async function (element) {
let util = {};
util['name'] = element['name'];
util['age'] = element['age'] || null;
let query = `INSERT INTO users SET
name =?,
age=?
ON DUPLICATE KEY UPDATE
name=VALUES(name),
age=VALUES(age)`;
session.sql(query).bind([util.name, util.age]).execute()
.then(() => {})
.catch((error) => {
console.error('cannot execute the query');
console.error('error', error);
});
}))
}
insertRecords()
.then(data => console.log('data', data))
.catch(err => console.log('err', err))
}).catch((err) => {
console.error(err);
session.close();
});
I am getting the following error on execution.
{ severity: 0,
code: 5015,
sqlState: 'HY000',
msg: 'Too many arguments' } }
In your Promise.all, you map on records but your resolver function doesn't return anything. You would need to return a promise. To do so, you should just replace your session.sql block with the following: return session.sql(query).bind([util.name, util.age]).execute().
That would return an array of Promises to Promise.all, and it would work. The error handling is already done when you call your insertRecords function so you don't need to worry about it in your resolver.

Stop another .then() execution in chain of promises

I have programme in nodejs & mysql like below
db.query()
.then(1)
.then(2)
.then(3)
.catch()
I am checking a value from database in then(1) and trying to return response from there.In then(2) , I am executing another code that uses some data from result of then(1) and so on..
My problem: When returning response from then(1), catch() is calling(because then(2) have error, not getting data from then(1)) . So is there any way I can stop further execution in then(1) so that then(2) and catch() couldn't call ?
db.query('query......', [val1, val2])
.then(rslt => { return res.json({ mssg: "Email already exists!", error: "Email already exists!" }) })
.then(user => { return db.query('INSERT INTO ', value, (err, res, flds) => { err ? reject(err) : resolve(res) }) })
.then(user => { return res.json({ mssg: "Success", success: true}) })
.catch( (err) => { console.log(err) })
You can (and should) use an async function, instead of using the lower-level .then() API of the Promise object:
async function doTheThing() {
try {
const result = await db.query('...');
if (result) { // user exists
return res.json({...}); // this will end the entire function
}
const user = await db.query('...');
return res.json({...}); // success
} catch (err) {
console.log(err); // I don't recommend doing this. try/catch should be for recovery
}
}

javascript promise catch confusion [duplicate]

What is the best way to handle this scenario. I am in a controlled environment and I don't want to crash.
var Promise = require('bluebird');
function getPromise(){
return new Promise(function(done, reject){
setTimeout(function(){
throw new Error("AJAJAJA");
}, 500);
});
}
var p = getPromise();
p.then(function(){
console.log("Yay");
}).error(function(e){
console.log("Rejected",e);
}).catch(Error, function(e){
console.log("Error",e);
}).catch(function(e){
console.log("Unknown", e);
});
When throwing from within the setTimeout we will always get:
$ node bluebird.js
c:\blp\rplus\bbcode\scratchboard\bluebird.js:6
throw new Error("AJAJAJA");
^
Error: AJAJAJA
at null._onTimeout (c:\blp\rplus\bbcode\scratchboard\bluebird.js:6:23)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
If the throw occurs before the setTimeout then bluebirds catch will pick it up:
var Promise = require('bluebird');
function getPromise(){
return new Promise(function(done, reject){
throw new Error("Oh no!");
setTimeout(function(){
console.log("hihihihi")
}, 500);
});
}
var p = getPromise();
p.then(function(){
console.log("Yay");
}).error(function(e){
console.log("Rejected",e);
}).catch(Error, function(e){
console.log("Error",e);
}).catch(function(e){
console.log("Unknown", e);
});
Results in:
$ node bluebird.js
Error [Error: Oh no!]
Which is great - but how would one handle a rogue async callback of this nature in node or the browser.
Promises are not domains, they will not catch exceptions from asynchronous callbacks. You just can't do that.
Promises do however catch exceptions that are thrown from within a then / catch / Promise constructor callback. So use
function getPromise(){
return new Promise(function(done, reject){
setTimeout(done, 500);
}).then(function() {
console.log("hihihihi");
throw new Error("Oh no!");
});
}
(or just Promise.delay) to get the desired behaviour. Never throw in custom (non-promise) async callbacks, always reject the surrounding promise. Use try-catch if it really needs to be.
After dealing with the same scenario and needs you are describing, i've discovered zone.js , an amazing javascript library , used in multiple frameworks (Angular is one of them), that allows us to handle those scenarios in a very elegant way.
A Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for JavaScript VMs
Using your example code :
import 'zone.js'
function getPromise(){
return new Promise(function(done, reject){
setTimeout(function(){
throw new Error("AJAJAJA");
}, 500);
});
}
Zone.current
.fork({
name: 'your-zone-name',
onHandleError: function(parent, current, target, error) {
// handle the error
console.log(error.message) // --> 'AJAJAJA'
// and return false to prevent it to be re-thrown
return false
}
})
.runGuarded(async () => {
await getPromise()
})
Thank #Bergi. Now i know promise does not catch error in async callback. Here is my 3 examples i have tested.
Note: After call reject, function will continue running.
Example 1: reject, then throw error in promise constructor callback
Example 2: reject, then throw error in setTimeout async callback
Example 3: reject, then return in setTimeout async callback to avoid crashing
// Caught
// only error 1 is sent
// error 2 is reached but not send reject again
new Promise((resolve, reject) => {
reject("error 1"); // Send reject
console.log("Continue"); // Print
throw new Error("error 2"); // Nothing happen
})
.then(() => {})
.catch(err => {
console.log("Error", err);
});
// Uncaught
// error due to throw new Error() in setTimeout async callback
// solution: return after reject
new Promise((resolve, reject) => {
setTimeout(() => {
reject("error 1"); // Send reject
console.log("Continue"); // Print
throw new Error("error 2"); // Did run and cause Uncaught error
}, 0);
})
.then(data => {})
.catch(err => {
console.log("Error", err);
});
// Caught
// Only error 1 is sent
// error 2 cannot be reached but can cause potential uncaught error if err = null
new Promise((resolve, reject) => {
setTimeout(() => {
const err = "error 1";
if (err) {
reject(err); // Send reject
console.log("Continue"); // Did print
return;
}
throw new Error("error 2"); // Potential Uncaught error if err = null
}, 0);
})
.then(data => {})
.catch(err => {
console.log("Error", err);
});