Executing SQL queries with tedious(Node.js) - javascript

I am currently working on a project that requires that I manipulate SQL tables pertinent to a time reporting application. My simple code to connect right now is as follows:
var Connection = require('tedious').Connection;
var config = {
userName: 'my_user_name',
password: 'my_password',
server: 'server_to_access',
database: 'database_in_SQL_Server_Management_Studio'
};
var connection = new Connection(config);
connection.on('connect', function(err) {
console.log("Connected");
});
It shows that a connection is made, but then when I run the following:
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var config = {
userName: 'my_user_name',
password: 'my_password',
server: 'server_to_access',
database: 'database_in_SQL_Server_Management_Studio'
};
var connection = new Connection(config);
connection.on('connect', function(err) {
console.log("Connected");
executeStatement();
});
function executeStatement() {
request = new Request("SELECT * FROM Employees", function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
});
request.on('row', function(columns) {
columns.forEach(function(column) {
console.log(column.value);
});
});
connection.execSql(request);
}
This is my output in cmd:
C:\Users\name\attempt>node test.js
Connected
{ [RequestError: Requests can only be made in the LoggedIn state, not the Connec
ting state]
message: 'Requests can only be made in the LoggedIn state, not the Connecting
state',
code: 'EINVALIDSTATE' }
C:\Users\name\attempt>
The application managing the SQL tables is MS SQL Server Management Studio 2008 R2.
Any direction as to what I'm doing wrong would be very appreciated.
Thanks!

You'll need to manage a queue of requests and process based on the availability of the connection (tedious-wrapper might help and I haven't used it in awhile https://github.com/mhingston/tedious-wrapper). This pseudocode is adapted (and not tested) from my own working solution:
connection.on('connect', (err)=>{ RequestWrapper.next(err); });
const queue = [];
class RequestWrapper(){
constructor(sql){ this.sql = sql; }
static next(err){
const next = queue.shift();
if(next) next(err);
}
queue(args){
return new Promise((ok, fail)=>{
queue.push((err)=>{
if(err) fail(err); else ok(this.request(args));
})
})
}
request(args){
if(!connection) return Promise.reject(new Error(`connection required`));
if(!connection.loggedIn || connection.state.name !== 'LoggedIn') return this.queue(args);
return new Promise((ok, fail)=>{
try{
const request = new tedious.Request(this.sql, (err, count, rows)=>{
RequestWrapper.next();
if(err) return fail(err);
ok(rows);
});
...add params here...
connection.execSql(request);
}catch(err){
RequestWrapper.next();
fail(err);
}
});
}
};

Related

How to retry database connection in Node.js when first connect is failed?

I am using SQL Server with Node.js. When the connection fails in first attempt the Node.js does not reattempt to connect. I am using setTimeout() to keep trying periodically until it connects.
const poolPromise = new sql.ConnectionPool(config.db);
poolPromise
.connect()
.then(pool => {
console.log('Connected to MSSQL');
return pool;
})
.catch(err => {
if (err && err.message.match(/Failed to connect to /)) {
console.log(new Date(), String(err));
// Wait for a bit, then try to connect again
setTimeout(function() {
console.log('Retrying first connect...');
poolPromise.connect().catch(() => {});
}, 5000);
} else {
console.error(new Date(), String(err.message));
}
});
The above code attempt to connect, fails and try for second time but does not continue for third, fourth and so on.
I wrote this small snippet that works. I wrapped connection part into a function and then invoke it using a recursive function.
In this example you'll see an infinity.
function sql() {
this.connect = function() {
return new Promise((resolve, reject) => reject("error connecting"));
}
}
function connect() {
return new Promise((resolve, reject) => {
// const poolPromise = new sql.ConnectionPool("config.db");
const poolPromise = new sql();
poolPromise
.connect()
.then(pool => {
console.log("connected");
resolve(pool);
})
.catch(err => {
console.error(err);
reject(err);
});
});
}
function establishConnection() {
var a = connect();
a.then(a => console.log("success"))
.catch(err => {
console.error("Retrying");
// I suggest using some variable to avoid the infinite loop.
setTimeout(establishConnection, 2000);
});
};
establishConnection();
After checking out the answers here I agree that callbacks are the way to go. I wrote the follow script to attempt to connect to MySQL until connection is established, and then to occasionally check that the connection is still valid, and if not, attempt connection again. I placed console.log's in a few places so that as things run you can see and understand what's happening.
var mysql = require('mysql');
var env = require('dotenv').config()
// ENVIRONMENT LOADS
var env = process.env.NODE_ENV.trim();
var host = process.env.MYSQL_HOST.trim();
var user = process.env.MYSQL_USER.trim();
var password = process.env.MYSQL_ROOT_PASSWORD.trim();
var database = process.env.MYSQL_DB.trim();
var port = process.env.MYSQL_PORT.trim();
console.log('\n\n********\n\nMySQL Credentials\n\n********\n\n');
if (env != 'production') {
console.log("Host: ", host, ":", port);
console.log("User: ", user);
console.log("Database: ", database);
console.log("Password: ", password);
}else{
console.log('Using Production Credentials');
}
console.log('\n\n************************\n\n');
let mysqlDB = null; // db handler
let connected = null; // default null / boolean
let connectFreq = 1000; // When database is disconnected, how often to attempt reconnect? Miliseconds
let testFreq = 5000; // After database is connected, how often to test connection is still good? Miliseconds
function attemptMySQLConnection(callback) {
console.log('attemptMySQLConnection')
if (host && user && database) {
mysqlDB = mysql.createPool({
host: host,
port: port, // Modified for Dev env
user: user,
password: password,
database: database,
connectionLimit: 300,
waitForConnections: true, // Default value.
queueLimit: 300, // Unlimited
acquireTimeout: 60000,
timeout: 60000,
debug: false
});
testConnection((result) => {
callback(result)
})
} else {
console.error('Check env variables: MYSQL_HOST, MYSQL_USER & MYSQL_DB')
callback(false)
}
}
function testConnection(cb) {
console.log('testConnection')
mysqlDB.query('SELECT 1 + 1 AS solution', (error, results, fields) => {
try {
if (error) {
throw new Error('No DB Connection');
} else {
if (results[0].solution) {
cb(true)
} else {
cb(false)
}
}
} catch (e) {
// console.error(e.name + ': ' + e.message);
cb(false)
}
});
}
function callbackCheckLogic(res) {
if (res) {
console.log('Connect was good. Scheduling next test for ', testFreq, 'ms')
setTimeout(testConnectionCB, testFreq);
} else {
console.log('Connection was bad. Scheduling connection attempt for ', connectFreq, 'ms')
setTimeout(connectMySQL, connectFreq);
}
}
function testConnectionCB() {
testConnection((result) => {
callbackCheckLogic(result);
})
}
function connectMySQL() {
attemptMySQLConnection(result => {
callbackCheckLogic(result);
});
}
connectMySQL(); // Start the process by calling this once
module.exports = mysqlDB;

How to access a function in a function with `this`

My question is similar to this.
However, mine runs in Node.js and it seems like a bit more complicated.
The server side wasn't built by me, but someone else that I can't contact. And he wrote code very differently.
And I have db.js and it looks like this:
And routes/email.js it uses db.js like this:
And when I click a button. I get this error:
db.emailRequest is not a function
in db.js, at the end of the file. It originally had this:
module.exports = new dbHelper;
And my style to use db.js in routers.
db.get().query(sql, input, function(err,res){
//TODO:
});
But it didn't work. So, I changed the end of db.js like this:
exports.get = function(){
console.log("exports.get");
return pool;
}
And also added some code in app.js like this:
db.connect(function(err){
if(err){
console.log('Unable to connect to MariaDB');
process.exit(1);
}
});
What should I do?
The full code of db.js is here:
const mariadb = require('mariadb');
var pool;
exports.connect = function(done){
console.log("Trying to connect DB...");
pool = mariadb.createPool({
host: 'localhost',
user: 'root',
password: 'xxxxxxx',
database:"XXXXX",
connectionLimit: 5 // Why 5 ???
});
pool.getConnection()
.then(conn => {
console.log("DB connected. id: " + conn.threadId);
conn.end(); //release to pool
}).catch(err => {
console.log("DB failed connection: " + err);
});
}
function makeToken(){
console.log("makeToken()");
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for(var i=0;i<32;i++){
text+=possible.charAt(Math.floor(Math.random()*possible.length));
}
return text;
}
function dbHelper() {
console.log("dbHelper()");
this.emailRequest = function(email,num){
console.log("emailRequest");
pool.getConnection().then(conn => {
conn.query("INSERT INTO email_verification(email, code) VALUES(?,?)",[email,num]);
conn.end(); //release to pool
})
.catch(err => {
console.log("not connected due to error: " + err);
});
}
// wait and process until getting return value because rv is needed.
this.verify = async function(email,num){
console.log("verify");
let conn;
var result = false;
try {
conn = await pool.getConnection();
// within 3minutes
const rows = await conn.query("SELECT count(*) FROM email_verificaiton WHERE email=? AND code=? AND req_time >= NOW() - INTERVAL 3 MINUTE",[email,num]);
if(rows[0]["count(*)"]>0){
result = true;
}
} catch (err) {
throw err;
} finally {
if (conn) conn.end();
}
return result;
}
this.verifyUpdate = function(email,num){
console.log("verifyUpdate");
pool.getConnection()
.then(conn => {
conn.query("UPDATE email_verification SET status = 1 WHERE email=? AND code=?",[email,num]);
conn.end(); //release to pool
})
.catch(err => {
console.log("not connected due to error: " + err);
});
}
// wait and process until getting return value because rv is needed.
this.emailRegister = async function(email,pass,nick,devid){
console.log("emailRegister");
let conn;
var result;
try {
conn = await pool.getConnection();
var rows = await conn.query("SELECT count(*) FROM email_verification WHERE email=? AND status = 1",[email]);
if(rows[0]["count(*)"]>0){
rows = await conn.query("SELECT count(*) FROM member WHERE email=?",[email]);
if(rows[0]["count(*)"]==0){
var token = makeToken();
rows = await conn.query("INSERT INTO member (email,password,username,device_id,login_method,token) VALUES(?,?,?,?,0,?)",[email,pass,nick,devid,token]);
if(rows["affectedRows"]>0){
result = {result:true, code:200, message: "success",data:[{email:email,token:token}]};
} else{
result = {result:false,code:401, message:"db error"};
}
}else {
result = {result:false,code:402, message:"already registered id"};
}
} else {
result = {result:false,code:403, meesage:"email not verified"};
}
} catch (err) {
throw err;
} finally {
if (conn) conn.end();
}
return result;
}
// wait and process until getting return value because rv is needed.
this.emailLogin = async function(email,pass,devid){
console.log("emailLogin");
let conn;
var result;
try {
conn = await pool.getConnection();
rows = await conn.query("SELECT * FROM member WHERE email=?",[email]);
if(rows.length==1){
if(rows[0]["password"]==pass){
var token = makeToken();
rows = await conn.query("UPDATE member SET device_id = ?, token = ? WHERE email=?",[devid,token,email]);
console.log(rows)
if(rows["affectedRows"]>0){
result = {result:true,message:"Sign up Success.", code:200, data:[{email:email,token:token}]};
} else{
result = {result:false,message:"db error",code:401};
}
} else {
result = {result:false,message:"wrong password",code:402};
}
}else {
result = {result:false,message:"not registered id",code:403};
}
} catch (err) {
throw err;
} finally {
if (conn) conn.end();
}
return result;
}
}
//module.exports = new dbHelper;
exports.get = function(){
console.log("exports.get");
return pool;
}

Javascript/ Node.js not waiting for sql query to come back with a response before it continues the code

I have a .js file that calls an external .js file that runs the following code:
const sql = require('../../node_modules/mysql');
module.exports =
{
connect_to_db: function (sql_query)
{
let con = sql.createConnection({
host: "localhost",
user: config.server_username,
password: config.server_password,
database: config.database_name
});
con.connect((err)=> {
if (err){
console.log("Problem connecting to the DB!");
return;
}
console.log("Connected to the DB!");
});
con.query(sql_query, (err, result) => {
if (err) throw err;
console.log('Data received from the DB');
console.log(result);
return result;
});
con.end((err) => {});
}
};
Which is run like:
const connect_to_DB = require('DB_Connection');
let sql_query = "SELECT * FROM table";
database_results.push(connect_to_DB.connect_to_db(sql_query));
console.log(database_results);
however this results in the code finishing before the sql query comes back with a result (data removed):
[ undefined ]
Connected to the DB!
Data received from the DB
[ RowDataPacket {
mail_id: ,
from: ,
to: ',
subject: ,
message: ,
date:,
read_date: } ]
Process finished with exit code 0
It looks like the push of the result is coming back as undefined as there is nothing to push at the point it does this. However I want it to wait until the response from the query comes back before it continues.
I was thinking of a promise perhaps but not sure if that would work something like:
const sql = require('../../node_modules/mysql');
module.exports =
{
connect_to_db: function (sql_query)
{
return new Promise((resolve, reject) => {
(async () => {
let con = sql.createConnection({
host: "localhost",
user: config.server_username,
password: config.server_password,
database: config.database_name
});
con.connect((err)=> {
if (err){
console.log("Problem connecting to the DB!");
return;
}
console.log("Connected to the DB!");
});
con.query(sql_query, (err, result) => {
if (err) throw err;
console.log('Data received from the DB');
console.log(result);
resolve();
return result;
});
con.end((err) => {});
})();
});
}
};
but when I run this I get this back:
[ Promise { <pending> } ]
I just need some help in order for the result to come back then the code to continue.
According to my view, The best possible way of solving this is by using callbacks in Node js.
Node js executes codes sychronously, let me explain by explaining what happened at your code
database_results.push(connect_to_DB.connect_to_db(sql_query));
console.log(database_results);
Here in your code console.log(database_results) is returned before executing the function connect_to_DB.connect_to_db(sql_query))
Your DBConnection.js can be modified as:
const sql = require('mysql');
exports.connect_to_db = function (sql_query, callback) {
let con = sql.createConnection({
host: "localhost",
user: config.server_username,
password: config.server_password,
database: config.database_name
});
con.connect((err) => {
if (err) {
console.log("Problem connecting to the DB!");
return;
}
console.log("Connected to the DB!");
});
con.query(sql_query, (err, result) => {
if (err) callback(err);
console.log('Data received from the DB');
console.log(result);
callback(result);
});
con.end((err) => { });
};
and the external js that calls the function connect_to_db function can be modified as:
'use strict';
const connect_to_DB = require('DB_Connection');
let sql_query = "SELECT * FROM table";
connect_to_DB.connect_to_db(sql_query, function (data, err) {
if (err) {
console.log(err);
}
else {
database_results.push(data);
}
});
console.log(database_results);
to know more about callbacks visit
You don't need to use promises and async/await in the same piece of code. Try something like this:
module.exports =
{
connect_to_db: async function (sql_query)
{
let con = sql.createConnection({
host: "localhost",
user: config.server_username,
password: config.server_password,
database: config.database_name
});
con.connect((err)=> {
if (err){
console.log("Problem connecting to the DB!");
return;
}
console.log("Connected to the DB!");
});
return await con.query(sql_query);
}
};
and then
const connect_to_DB = require('DB_Connection');
let sql_query = "SELECT * FROM table";
database_results.push(await connect_to_DB.connect_to_db(sql_query));
console.log(database_results);
Note that sice await keyword id only allowed inside async functions, this line database_results.push(await connect_to_DB.connect_to_db(sql_query)); should be inside an async function to work

How to check if the db connection is success or not in node js and mysql

I'm using mysql connection pool to create connection. The code looks like the following.
var pool = mysql.createPool(connectionProps);
by accessing pool, I'll get the an Object, even if the connection is not Successful. I checked it with starting and stopping mysql.
What I want is that, I need to check connection is successful or not as follows.
if(pool){ // mysql is started && connected successfully.
console.log('Connection Success');
doSomething();
}else{
console.log('Cant connect to db, Check ur db connection');
}
I want something like this. So how can we do this with the mysql pool Object. Can someone please help me?
Thanks n Regards
Commonly you would do something like select something arbitrary from the db, and catch an error if that failed. Example from the docs.
const pool = mysql.createPool(connectionProps);
pool.query('SELECT 1 + 1 AS solution', (error, results, fields) => {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
var pool = mysql.createPool(config.db);
exports.connection = {
query: function () {
var queryArgs = Array.prototype.slice.call(arguments),
events = [],
eventNameIndex = {};
pool.getConnection(function (err, conn) {
if (err) {
if (eventNameIndex.error) {
eventNameIndex.error();
}
}
if (conn) {
var q = conn.query.apply(conn, queryArgs);
q.on('end', function () {
conn.release();
});
events.forEach(function (args) {
q.on.apply(q, args);
});
}
});
return {
on: function (eventName, callback) {
events.push(Array.prototype.slice.call(arguments));
eventNameIndex[eventName] = callback;
return this;
}
};
}
};
And require to use it like:
db.connection.query("SELECT * FROM `table` WHERE `id` = ? ", row_id)
.on('result', function (row) {
setData(row);
})
.on('error', function (err) {
callback({error: true, err: err});
});

Node mysql based module not working

I have a node based app that will look into a database for data. Because the database is fairly large with several tables, I am writing a module to help modularize the task. The problem is that I cannot get the main code to return all the data from the database lookup because I believe the program exits before it is executed. How do I get my node module working? My intention is to have the DB helper functions reside in the SomethingHelper.js module. I have the main code silly.js that looks like this:
// silly.js
var sh = require('./SomethingHelpers.js');
helper = new sh();
helper.then(function(res) {
var promise = helper.getAllForUsername('sonny');
promise.then(function(res) {
console.log('worked', res);
});
promise.catch(function(err) {
console.log('err: ', err);
});
});
helper.catch(function(err) {
console('Could not create object: ', err);
});
SomethingHelpers.js looks like this:
var mysql = require("mysql");
function SomethingHelpers() {
return new Promise(function(resolve, reject) {
this.connectionPool = mysql.createPool({
connectionLimit: 100,
host: 'server.somewhere.com',
user: "username",
password: "somepass",
database: "sillyDB",
debug: false
});
});
}
SomethingHelpers.prototype.getAllSomethingForUsername = function(username) {
var result = [];
return new Promise(function(resolve, reject) {
this.connectionPool.getConnection(function(err, connection) {
if (err) {
console.log('Error connecting to the silly database.');
return;
} else {
console.log('Connection established to the silly database. Super-Duper!');
return connection.query('SELECT something FROM somethingTable where username=\"' + username + '\"',
function(err, rows, field) {
connection.release();
if (!err) {
//console.log (rows.something);
rows.forEach(function(item) {
var allSomething = JSON.parse(item.something);
console.log(allSomething.length);
result.push(allSomething);
for (var i = 0; i < allSomething.length; i++) {
console.log(allSomething[i].handle);
}
console.log('\n\n');
});
console.log('Done');
return result;
} else {
console.log('Eeeeeeeek!');
//console.log (result);
return result;
}
});
}
});
});
} // End of getAllSomething ()
module.exports = SomethingHelpers;
I figured out the answer to my own question. Here's how I solved it. First, SomethingHelpers.js:
//SomethingHelpers.js
var mysql = require('promise-mysql');
function SomethingHelpers () {
this.pool = mysql.createPool({
connectionLimit: 100,
host: 'server.somewhere.com',
user: "username",
password: "somepass",
database: "sillyDB",
debug: false
});
}
SomethingHelpers.prototype.getAllSomethingsForThisUsername = function (username) {
let pool = this.pool;
return new Promise(function (resolve, reject) {
pool.getConnection ().then(function(connection) {
connection.query('SELECT something FROM somethingsTable where username=\"'+
username+'\"').
then (function (rows) {
resolve (getAllSomethings (rows));
}).catch (function (error) {
console.log ('Error: ', error);
});
});
});
}
function getAllSomethings (rows)
{
var result = [];
rows.forEach (function (item) {
var allSomethings = JSON.parse(item.something);
result.push (allSomethings);
});
return result;
}
module.exports = SomethingHelpers;
With the glory of Promise, the bounty from the helper module can be enjoyed thusly:
//silly.js
var hh = require ('./SomethingHelpers');
helper = new hh ();
thePromiseOfSomething = helper.getAllSomethingsForThisUsername ('sonny');
thePromiseOfSomething.then(function (rows) {
console.log (rows);
});
Thus releasing me from the tyranny of asynchronous thinking (J/K).

Categories