I have a nodeJS application using the mssql driver to interact with my SQL database. I want to have a single function to get a value from a database, however, on first use, the table won't exist, so if there is a specific error, I want to call my createValue() function. The code below works, but I have to call it twice to get the value. Basically, if the condition in the .catch is met, I would like to call the Request again. Is there a neat way of doing this?
var value;
new sql.Request().query('select * from _table')
.then(function (recordset) {
value = recordset;
})
.catch(function (err) {
console.log("Query Error: " + err);
if (err.message == "Invalid object name '_table") {
createValue();
}
})
Update:
I now have the following function, but how should I best get it to return recordset?
function getData() {
sql.connect("mssql://username:password#localhost/mytestdatabase").then(function () {
return new sql.Request().query('select * from _table')
.then(function (recordset) {
console.log(recordset); // <-- THIS IS WHAT I WANT TO RETURN
})
.catch(function (err) {
console.log("Query Error: " + err);
if (err.message == "Invalid object name '_table") {
updateValue();
return getData();
}
return null;
})
}).catch(function (err) {
console.log("Connection Error: " + err);
})
};
You can wrap it in a function, which you can then call recursively.
I'm assuming createValue() is synchronous.
function getData(){
return new sql.Request().query('select * from _table')
.catch(function (err) {
if (err.message == "Invalid object name '_table") {
createValue();
return getData();
}
throw err;
});
}
...
var resultsetPromise = getData();
resultsetPromise.then( function(resultset){
// do something with your data
}).catch( function(err){
console.log("Query Error: " + err);
});
Related
i'm trying create first node js api.
i wroted this code but when i start server.js it's not working.
here code :
var executeQuery = function(res, query){
sql.connect(dbConfig, function (err) {
if (err) {
console.log("Error while connecting database :- " + err);
res.send(err);
}
else {
// create Request object
var request = new sql.Request();
// query to the database
request.query(query, function (err, res) {
if (err) {
console.log("Error while querying database :- " + err);
res.send(err);
}
else {
res.send(res);
}
});
}
});
}
when i start it error say :
C:\node\atlasErpApi\server.js:47 res.send(res);
TypeError: res.send is not a function at C:\node\atlasErpApi\server.js:47:43
You are declaring a new variable res as argument to your request.query callback which shadows the res the comes as argument to your executeQuery function.
This should be most obvious at the line res.send(res) which, if you think about it, doesn't make sense at all.
Use different variable names for the two. For example, change the inner one to sqlRes:
var executeQuery = function(res, query) {
sql.connect(dbConfig, function(err) {
if (err) {
console.log("Error while connecting database :- " + err);
res.send(err);
} else {
// create Request object
var request = new sql.Request();
// query to the database
request.query(query, function(err, sqlRes) { // <<< CHANGED to sqlRes
if (err) {
console.log("Error while querying database :- " + err);
res.send(err);
} else {
res.send(sqlRes); // This makes more sense now :-)
}
});
}
});
}
Note: Technically this also happens for err - you have an err from request.query's callback shadowing the err from sql.connect's callback. But this usually doesn't matter because you won't need to use the outer err in the inner callback.
I have picked up a project where when a node.js program starts for the first time, no database will exist. The program should create the database tables if they don't already exist.
However, in the sample program below, the data is not inserted if the database did not exist on first run because the select statement fails.
The output of the code below is:
$ node dbtest.js
finished initialise_database
program ended.
select err: { Error: SQLITE_ERROR: no such table: mytable errno: 1, code: 'SQLITE_ERROR' }
successfully created mytable table
database closed.
As you can see from the logging, the code assumes a synchronous execution.
I assume that what is happening is that the node.js runtime system uses different threads to schedule the database functions to run in parallel.
I need the CREATE TABLE command to complete before proceding. How would I achieve this?
Is there some standard way to achieve such a thing in node.js?
code below:
// npm install sqlite3 - to install sqlite3
const sqlite3 = require('sqlite3').verbose();
let db = initialise_database();
check_and_update(db); //Calling this function upon starting the server.
close_database(db);
console.log('program ended.');
function initialise_database() {
//Establishing a database connection.
let db = new sqlite3.Database('database1.db', (err)=>{
if(err) {
return console.error(err.message);
}
});
// // new db always succeeds even if no file exists - if empty file have to generate table structure
db.run("CREATE TABLE IF NOT exists 'mytable' ('num1' INTEGER, 'num2' INTEGER, 'text1' TEXT);", function(err) {
if (err) {
console.log("Create table error: ", err);
}
console.log("successfully created mytable table");
});
console.log("finished initialise_database");
return db;
}
function check_and_update(db) {
db.all("SELECT * FROM mytable", function(err, data){
if(err) {
console.log("select err: ", err);
} else {
db.run('INSERT INTO mytable (num1, num2, text1) VALUES (?, ?, ?)', [1, 2, 'hi guys!!!'], function(err){
if(err)
console.log("insert err: ", err);
});
}
});
}
function close_database(db) {
db.close((err) => {
if (err) {
return console.error(err.message);
}
console.log('database closed.');
});
}
Database requests are asynchronous, you have to deal with them in an asynchronous way.
Which can be :
Callback
Promise
Async/await
Otherwise you will try to perform a request on a database not initialized.
Here is an example using Promise.
const sqlite3 = require('sqlite3').verbose();
let dbPtr = false;
initialise_database()
.then((db) => {
dbPtr = db;
return check_and_update(dbPtr);
})
.then(() => {
close_database(dbPr);
// All is done
console.log('program ended.');
})
.catch((err) => {
// Deal with the error
});
function initialise_database() {
return new Promise((resolve, reject) => {
//Establishing a database connection.
const db = new sqlite3.Database('database1.db', (err) => {
if (err) {
console.error(err.message);
return reject(err);
}
db.run('...', function(err) {
if (err) {
console.log("Create table error: ", err);
return reject(err);
}
console.log("successfully created mytable table");
return resolve(db);
});
});
});
}
function check_and_update(db) {
return new Promise((resolve, reject) => {
db.all('...', function(err, data) {
if (err) {
console.log("select err: ", err);
return reject(err);
}
db.run('...', [1, 2, 'hi guys!!!'], function(err) {
if (err) {
console.log("insert err: ", err);
return reject(err);
}
return resolve();
});
});
});
}
function close_database(db) {
db.close();
}
#EDIT
Looking at the documentation it seems that db.close() do not take a callback in parameter. I've modified the snippet.
In Node.js, I need to read a file and validate it's contents, all in async. I m using Node.js 6.6, bluebird 3.4.6
Example code:
// pseudo function to read file contents - resolves when 'flag' is true, rejects when 'flag' is false.
function readFile(flag) {
return new Promise(function (resolve, reject) {
console.log('Reading file...');
if (flag) {
resolve('File contents');
} else {
reject('readFile error');
}
});
}
// pseudo function to validate file contents - resolves when 'flag' is true, rejects when 'flag' is false.
function validate(fileContents, flag) {
return new Promise(function (resolve, reject) {
console.log('Validating file: ', fileContents);
if (flag) {
resolve('Validate passed');
} else {
reject('validation failed');
}
});
}
readFile(false)
.then(function (fileContents) {
console.log('Successfully read the file:', fileContents);
return fileContents;
})
.catch(function (fileReadErr) {
console.log('Failed to read the file:', fileReadErr);
throw fileReadErr; // or, return Promise.reject(err);
})
.then(function (fileContents) {
return validate(fileContents, false);
})
.then(function (result) {
console.log('Successfully validated the file:', result);
})
.catch(function (err) {
console.log('Failed to validate the file:', err);
})
;
<script src="https://cdn.jsdelivr.net/bluebird/3.4.6/bluebird.min.js"></script>
The above code will print
Reading file...
Failed to read the file: readFile error
Failed to validate the file: readFile error
The above promise chain roughly translates to below sync code:
try {
let fileContents;
try {
fileContents = readFile(false);
console.log('Successfully read the file:', fileContents);
} catch (e) {
console.log('Failed to read the file:', e);
throw e;
}
let validationResult = validate(fileContents, false);
console.log('Successfully validated the file:', validationResult);
} catch (err) {
console.log('Failed to validate the file:', err);
}
And, throwing or rejecting in the first catch method will still invoke the 2nd catch method.
My question: Is there any way to break the chain once the file reading is failed? My objective is to return different HTTP status codes (file read error: 500, validation failed: 400) from an express.js route.
I know a solution using non-standard specialized catch method, but that requires special handling. In the sense, I need to throw errors or need some filtering key in the error object and both of which are not in my hands, and involves some work to achieve it. This solution is mentioned in bluebird docs & here: Handling multiple catches in promise chain
The simplest solution by far is to use what I call "insulated catches". ie, a pattern in which each .catch() is a specialist, associated with a particular step in the overall process, and the main chain comprises only .thens (and eventually a single, terminal catch).
Also, it is useful in this kind of circumstance to convey added information down the error path by re-throwing Error objects with added properties. This avoids the need for custom Errors.
Promise.resolve()
.then(function() {
return readFile(false)
.then(function (fileContents) {
console.log('Successfully read the file:', fileContents);
return fileContents;
})
.catch(function (error) {
error.code = 521; // or whatever
error.customMessage = 'Failed to read the file';
throw error;
})
})
.then(function (fileContents) {
return validate(fileContents, false)
.then(function (result) {
console.log('Successfully validated the file:', result);
return fileContents;
})
.catch(function (error) {
error.code = 522; // or whatever
error.customMessage = 'Failed to validate the file';
throw error;
});
})
.catch(function(error) { // terminal catch.
console.log(error);
// It's possible for unaugmented errors to reach this point,
// so be sure to test for the extra properties before trying to use them.
if(error.code) {...}
if(error.customMessage) {...}
// Note also that the original error.message is still intact.
});
The initial Promise.resolve() isn't strictly necessary, but helps keep everything else symetrical.
This will work with any Promises/A+ lib. Bluebird-sugar is not required.
You can create custom Error types like so:
ReadFileError = function() {};
ReadFileError.prototype = Error.prototype;
ValidationError = function() {};
ValidationError.prototype = Error.prototype;
Then, you can throw from a Promise instead of rejecting:
function validate(fileContents, flag) {
return new Promise(function (resolve, reject) {
console.log('Validating file: ', fileContents);
if (flag) {
resolve('Validate passed');
} else {
throw new ReadFileError('readFile error');
}
});
}
Then you can catch different errors based on their types:
readFile(false)
.then(function (fileContents) {
console.log('Successfully read the file:', fileContents);
return fileContents;
})
.then(function (fileContents) {
return validate(fileContents, false);
})
.then(function (result) {
console.log('Successfully validated the file:', result);
})
.catch(ReadFileError, function (err) {
console.log(..., err);
})
.catch(ValidationError, function (err) {
console.log(..., err);
})
catch(function(err) {
...
});
Maybe more people could get the same problem. I personally don't think this is the best way to do this, because then you have your app throwing pseudo error, which could mistakenly be processed by other error processing on your server. But it works like you proposed:
// pseudo function to read file contents - resolves when 'flag' is true, rejects when 'flag' is false.
function readFile(flag) {
return new Promise(function (resolve, reject) {
console.log('Reading file...');
if (flag) {
resolve('File contents');
} else {
throw new Error ('errorReading');
}
});
}
// pseudo function to validate file contents - resolves when 'flag' is true, rejects when 'flag' is false.
function validate(fileContents, flag) {
return new Promise(function (resolve, reject) {
console.log('Validating file: ', fileContents);
if (flag) {
resolve('Validate passed');
} else {
throw new Error ('validationFailed');
}
});
}
readFile(false)
.then(function (fileContents) {
console.log('Successfully read the file:', fileContents);
return fileContents;
})
.then(function (fileContents) {
return validate(fileContents, false);
})
.then(function (result) {
console.log('Successfully validated the file:', result);
})
.catch((error) => {
console.log(error.name);
console.log(error.message);
if (error.message === 'errorReading'){
console.log('error 500 - File could\'d be read');
// Maybe more custom error processing here
//return res.status(500).send(JSON.stringify({
// 'status' : 'error',
// 'message' : 'File could\'d be read'
//}));
} else if (error.message=== 'validationFailed'){
console.log('error 500 - Validation not OK');
// Maybe more custom error processing here
//return res.status(500).send(JSON.stringify({
// 'status' : 'error',
// 'message' : 'Validation not OK'
//}));
} else {
console.log('error 500 - Some really bad stuff!');
//return res.status(500).send(JSON.stringify({
// 'status' : 'error',
// 'message' : 'Some really bad stuff!',
// 'errorMessage': error
//}));
}
});
<script src="https://cdn.jsdelivr.net/bluebird/3.4.6/bluebird.min.js"></script>
Please note that I commented out the res.send of express to avoid errors on the processing of this snippet!
As far as i understand what you want to achieve i would suggest always using one single catch block (when can be avoided introducing nesting in promise logic which is totally ok in few use cases, but should be avoided when it can be, because you will potentially ends up with promise hell with indentation all around)
Can you handle all errors in your functions readFile, validate in uniform way like:
const error = new Error('something bad happened')
error.status = 500
return reject(error)
Then you could do you handle error logic within one single catch block based on status such as res.status(err.status || 500).json(...)
I anticipate a callback hell is beginning to form in my code so I decided to start using promises. But I can't wrap my head around implementing it. For example I have a function:
DB.prototype = {
findUser: function (username) {
this._pool.getConnection(function (err, connection) {
if (err) { return callback(true, false); }
connection.query('SELECT password_hash, password_salt FROM users WHERE email = ? AND admin = 1', username,
function (err, rows) {
connection.release();
if (rows.length === 1) { callback(false, rows[0]); }
else { callback(false, false); }
});
connection.on('error', function () { callback(true, false); });
});
}
};
How would I adapt this to using promises instead of callbacks? And how would I use this adapted db.findUser() ?
EDIT:
I got something working. It looks like this:
DB.prototype = {
getConnection: function() {
return this._pool.getConnectionAsync();
}
}
And the usage:
Promise.using(db.getConnection(), function(connection) {
return connection.queryAsync("SELECT password_hash, password_salt FROM users WHERE email = ? AND admin = 1", "exampleUser")
.then(function(rows) {
connection.release();
console.log("is there a row?", rows.length === 1, rows);
// do something with results
});
}).catch(function(err) {
// This is only run if an error is thrown
console.log("error is", err);
});
Is this a good implementation or could something be improved?
With this as a URL:
'api/support-tag/name/myTagName'
This function works properly:
getByName: function (req, res) {
model.Shared_SupportTag.findOne({name: req.params.name}).exec(function (err, results) {
if (err) {
return res.status(400).send({
message: errMsg.Util_ErrorMsg.getErrorMessage(err)
});
}
res.send(results);
})
}
But when I try to call a similar function from within the node server:
supportDoc.category = GetById(item.category);
function GetById(name){
model.Shared_SupportTag.findOne({name: name}).exec(function(err, result){
if(err){
console.log(err)
}else{
console.log(result);
}
})
}
The function does not execute, nor does the error catch, intellisense shows:
err= Reference error; err is not defined
result = Reference error; result is not defined
All I am trying to accomplish is a function call from within the server and not via a URL.
Any solution here? Thanks in advance
In the case of the findOne() method, the positive response (sans error) will either hold a mongoose object or null.
If the same query had been sent using just find(), the result would have been an empty array.
function GetById(name){
model.Shared_SupportTag.findOne({name: name}).exec(function(err, result){
if(err){
console.log(err)
}else{
if (result) console.log(result); //Check whether object exists.
else console.log('Not found!');
}
})
}
Solved:
model.Shared_SupportDoc.find({}).exec(function (err, collection) {
var supportDocs = require('../../data/_seed/support/supportDocs.json');
if (collection.length === 0) {
supportDocs.forEach(function (item) {
var supportDoc = new model.Shared_SupportDoc;
supportDoc.title = item.title;
supportDoc.created = item.date;
supportDoc.icon = item.icon;
supportDoc.likeCount = item.likeCount || 7;
-----> // requires callback - ie asynchronous
GetByName(item.category, function(tagId) {
supportDoc.categoryId = tagId;
-----> // must put save in the callback
supportDoc.save(function (err) {
if (err) {
console.log(supportDoc.categoryId)
console.log('Error: ' + err);
} else {
console.log('Support Doc Seed Complete');
}
});
});
})
}
});}
function GetByName(name, next) {
model.Shared_SupportTag.findOne({name : name}).exec(function (err, result) {
if (!result) {
console.log('Not Found');
next();
} else {
console.log(result._id);
next(result._id);
}
});}