How to make tedious Async in Meteor - node.js

I am using this module tedious to connect. I am having issues when I try to populate a collection with the data from MSSQL.
My code thus far:
http://pastebin.com/q4ByRCbW
Meteor.startup(function () {
var Request = Meteor.require('tedious').Request;
var Connection = Meteor.require('tedious').Connection;
var config = {
userName: 'xxxxx',
password: 'xxxx',
server: '197.xxx.xxx.xxx',
// If you're on Windows Azure, you will need this:
options: {
encrypt: true,
debug: {
packet: true,
data: true,
payload: true,
token: false,
log: true
}
}
};
var connection = new Connection(config);
var asnycWrapFunc = Async.wrap(connection.execSql);
var rettarr = [];
function executeStatement() {
Fiber(function(){
request = new Request("select * from AccountSummary", function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
});
request.on('row', function(columns) {
aaary = []; cnting = 0;
columns.forEach(function(column) {
console.log(column.value);
aaary.push(column.value);
});
if (AccountSummary.find().count() === 0){
AccountSummary.insert({ID:aaary[0], ClientNo:aaary[1], ClientName:aaary[2]});
}
});
//rettarr.push(aaary);
}).run();
asnycWrapFunc(request);
//return rettarr;
}
connection.on('connect', function(err) {
// If no error, then good to go...
var res = executeStatement();
// aaary = res[0];
console.log(res);
errr = err;
});
});

I have found that you have to use Future if you want to you a package like Tedious.
This mini tutorial has the answer

Related

SQL select all statement in a node.js application returns a tedious deprecated error

So I went to the Microsoft documentation for node.js and trying to connect to a database and I went through step by step, installed tedious and when I try to run my code it's throwing an error saying:
tedious deprecated In the next major version of tedious, creating a new Connection instance will no longer establish a connection to the server automatically. Please use the new connect helper function or call the .connect method on the newly created Connection object to silence this message. internal\process\task_queues.js:79:11.
Does anyone know what this means?
CODE:
const Discord = require('discord.js');
const bot = new Discord.Client();
const token = 'HIDDEN';
bot.on('ready', () => {
console.log('This bot is online!');
var Connection = require('tedious').Connection;
var config = {
server: '', //update me
authentication: {
type: 'default',
options: {
userName: '', //update me
password: '' //update me
}
},
options: {
// If you are on Microsoft Azure, you need encryption:
encrypt: true,
database: '' //update me
}
};
var connection = new Connection(config);
connection.on('connect', function(err) {
// If no error, then good to proceed.
if(!err)
{
console.log("Connected");
executeStatement();
}
});
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
function executeStatement() {
request = new Request("SELECT * from tblCustomer;", function(err) {
if (err) {
console.log(err);}
});
var result = "";
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
result+= column.value + " ";
}
});
console.log(result);
result ="";
});
request.on('done', function(rowCount, more) {
console.log(rowCount + ' rows returned');
});
connection.execSql(request);
}
})
bot.login(token);

Calling Azure SQL from Azure Functions node.js

I'm trying to use tedious library to inject simple insert from the incoming body. No error is thrown, but context.logs placed inside the functions are not displaying in logs. As a result in DB I have row with NULL values instead of what is passed. Any idea what am I doing wrong?
Is there any other library/method of accessing the Azure DB from Azure Functions or I am stuck with Tedious?
Of course I could probably use Azure Logic App but its more expensive to run than Azure Functions.
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
var globalheaders = {
Id: '1233',
Name: 'Ant',
Payment: "2019-10-09",
Type: 'Fixed cost',
Value: 156,
Cycle: '1',
Frequency: 'month'
}
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
globalheaders = req.body;
context.log(globalheaders);
var config = {
server: '********.database.windows.net', //update me
authentication: {
type: 'default',
options: {
userName: '*******', //update me
password: '*******' //update me
}
},
options: {
// If you are on Microsoft Azure, you need encryption:
encrypt: true,
database: 'cashmandb' //update me
}
};
var connection = new Connection(config);
await connection.on('connect', function(err) {
if (err) {
context.log(err);
context.res = {
status: 500,
body: "Unable to establish a connection."
};
context.done();
} else {
context.log('before execution');
executeStatement();
}
});
context.log('connection executed')
async function executeStatement() {
request = new Request("INSERT dbo.cost (Id, Name, Payment, Type, Value, Cycle, Frequency) OUTPUT INSERTED.Id VALUES (#Id, #Name, #Payment, #Type, #Value, #Cycle, #Frequency);", function(err) {
if (err) {
context.log(err);}
});
context.log('executestatement')
request.addParameter('Id', TYPES.NChar,globalheaders.id);
request.addParameter('Name', TYPES.NVarChar , globalheaders.name);
request.addParameter('Payment', TYPES.Date, globalheaders.payment);
request.addParameter('Type', TYPES.NVarChar,globalheaders.type);
request.addParameter('Value', TYPES.Int,globalheaders.value);
request.addParameter('Cycle', TYPES.NChar,globalheaders.cycle);
request.addParameter('Frequency', TYPES.NChar,globalheaders.frequency);
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
context.log('NULL');
} else {
context.log("Product id of inserted item is " + column.value);
}
});
});
await connection.execSql(request);
}
context.done();
};
Try this :
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
var config = {
server: 'xxxx.database.windows.net', //update me
authentication: {
type: 'default',
options: {
userName: 'xxx', //update me
password: 'xxx' //update me
}
},
options: {
// If you are on Microsoft Azure, you need encryption:
encrypt: true,
database: 'xxx' //update me
}
};
var connection = new Connection(config);
await connection.on('connect', function(err) {
if (err) {
context.log(err);
context.res = {
status: 500,
body: "Unable to establish a connection."
};
context.done();
} else {
executeStatement(req.body);
}
});
async function executeStatement(globalheaders) {
request = new Request("INSERT dbo.cost (Id, Name, Payment, Type, Value, Cycle, Frequency) OUTPUT INSERTED.Id VALUES (#Id, #Name, #Payment, #Type, #Value, #Cycle, #Frequency);", function(err) {
if (err) {
context.log(err);}
});
request.addParameter('Id', TYPES.NChar,globalheaders.Id);
request.addParameter('Name', TYPES.NVarChar , globalheaders.Name);
request.addParameter('Payment', TYPES.Date,globalheaders.Payment);
request.addParameter('Type', TYPES.NVarChar,globalheaders.Type);
request.addParameter('Value', TYPES.Int,globalheaders.Value);
request.addParameter('Cycle', TYPES.NChar,globalheaders.Cycle);
request.addParameter('Frequency', TYPES.NChar,globalheaders.Frequency);
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
context.log('NULL');
} else {
context.log("Product id of inserted item is " + column.value);
}
});
});
await connection.execSql(request);
}
context.done();
};
Test result on local :
Data has been insetted into Azure SQL DB successfully:
I believe the problem here is that you are mixing async/await and context.done(). You should just use 1 of the 2 as required.
Also, I believe tedious doesn't support async/await in the first place. So, removing the that and just having context.done() should do.
After long battle it appears that for some reason Azure Functions prefers adressing the property by value string:
request.addParameter('Id', TYPES.NChar,globalheaders['Id']);
request.addParameter('Name', TYPES.NVarChar , globalheaders['Name']);
request.addParameter('Payment', TYPES.Date, globalheaders['Payment']);
request.addParameter('Type', TYPES.NVarChar,globalheaders['Type']);
request.addParameter('Value', TYPES.Int,globalheaders['Value']);
request.addParameter('Cycle', TYPES.NChar,globalheaders['Cycle']);
request.addParameter('Frequency', TYPES.NChar,globalheaders['Frequency']);
After changing to this everything started to work
The correct way to achieve it is by using sync code. Tedious uses event based programming paradigm and do not support async programming paradigms. So to explicitly mark the completion of azure function we use context.done() method. So the right code would be as follows:
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
var config = {
server: 'xxxx.database.windows.net', //update me
authentication: {
type: 'default',
options: {
userName: 'xxx', //update me
password: 'xxx' //update me
}
},
options: {
// If you are on Microsoft Azure, you need encryption:
encrypt: true,
database: 'xxx' //update me
}
};
var connection = new Connection(config);
connection.connect();
connection.on('connect', function(err) {
if (err) {
context.res = {
status: 500,
body: "Unable to establish a connection."
};
context.done();
} else {
executeStatement(req.body);
}
});
function executeStatement(globalheaders) {
request = new Request("INSERT dbo.cost (Id, Name, Payment, Type, Value, Cycle, Frequency) OUTPUT INSERTED.Id VALUES (#Id, #Name, #Payment, #Type, #Value, #Cycle, #Frequency);", function(err) {
if (err) {
context.log(err);}
});
request.addParameter('Id', TYPES.NChar,globalheaders.Id);
request.addParameter('Name', TYPES.NVarChar , globalheaders.Name);
request.addParameter('Payment', TYPES.Date,globalheaders.Payment);
request.addParameter('Type', TYPES.NVarChar,globalheaders.Type);
request.addParameter('Value', TYPES.Int,globalheaders.Value);
request.addParameter('Cycle', TYPES.NChar,globalheaders.Cycle);
request.addParameter('Frequency', TYPES.NChar,globalheaders.Frequency);
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
context.log('NULL');
} else {
context.log("Product id of inserted item is " + column.value);
}
});
});
request.on("requestCompleted", function (rowCount, more) {
connection.close();
context.res = {
status: 200, /* Defaults to 200 */
body: JSON.stringify(result),
headers: {
' Content-Type': 'application/json'
}
};
context.done();
});
connection.execSql(request);
}
};

net.isIP is not a function

i am trying to connect to an Azure SQL database on ionic framework using tedious.
i also installed browserify but when i run the code i get net.isIP is not a function
try {
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
var config = {
userName: 'xxxx',
password: 'xxxx',
server: 'xxxxx.database.windows.net',
options: {
database: 'xxxxx',
encrypt: true,
rowCollectionOnRequestCompletion: true
}
};
} catch (err) { alert(err.message); }
var errorVariable = document.getElementById("error");
$scope.Login = function(){
var username = document.getElementById("userName").value;
if(isEmpty(username)) {
errorVariable.style.display = 'block';
errorVariable.innerHTML = "Your Username Cannot be Empty";
} else {
alert("connecting");
try {
var connection = new Connection(config);
} catch (err) { alert(err.message); }
connection.on('connect', function (err) {
// If no error, then good to go...
alert("connected");
});
} catch (err) { alert(err.message); }
}
}

Node JS - function not executed

I have a module which i wrote myself. It contains 3 functions which i call as chained promises. The last one does not execute and i cannot figure out why.
The module geodata.js
require('use-strict');
var Promise = require('promise');
var NodeGeocoder = require('node-geocoder');
var mongoose = require('mongoose');
var User = require('../models/user');
var options = {
provider: 'google',
httpAdapter: 'https',
apiKey: 'AIzaSyA4v81WbNOMeRL7p911Mxr6PBZnidX0cIM',
formatter: null
};
module.exports = {
//*******************************************************
// Find user and return his adress (street + town)
//
//*******************************************************
findUser: function(username) {
return new Promise(function(resolve, reject) {
User.findOne({
'username': username
}, function(err, doc) {
if (!err) {
resolve(doc);
} else {
reject(err);
}
});
});
},
//*******************************************************
// Fetch geodata (latitude + longitude) to users record in
// the user collection.
//*******************************************************
fetchGeoData: function(userObj) {
return new Promise(function(resolve, reject) {
var geocoder = NodeGeocoder(options);
var adress = userObj.street + ' ' + userObj.town;
geocoder.geocode(adress, function(err, res) {
if (!err) {
var res2 = {
'username': userObj.username
}
console.log(res);
resolve([res, res2]);
} else {
reject(err);
}
});
});
},
//*******************************************************
// Fetch geodata (latitude + longitude) to users record in
// the user collection.
//*******************************************************
addGeoData: function(message) {
return new Promise(function(resolve, reject) {
User.findOne({
'username': message.username
}, function(err, doc) {
console.log(doc);
if (err) {
console.log(err);
reject(err);
}
if (!doc) {
console.log('User not found.');
reject('User not found.');
}
doc.longitude = String(message.longitude);
doc.latitude = String(message.latitude);
doc.save();
resolve(doc);
});
});
},
fixJSON: function(inpJSON) {
var strung = JSON.stringify(inpJSON);
obj = strung.substring(1, strung.length - 1);
return (JSON.parse(obj));
}
};
.. and here is the calling script:
require('use-strict');
var mongoose = require('mongoose');
var dbConfig = require('./db');
var geodata = require('./lib/geodata.js');
// Connect to DB
mongoose.connect(dbConfig.url, {
auth: {
authdb: "admin"
}
});
mongoose.set('debug', true);
geodata.findUser('jimmy').then(function(result) {
console.log('findUser() done');
return geodata.fetchGeoData(result);
}).then(function(result) {
console.log('fetchGeoData() done');
var res1Fixed = geodata.fixJSON(result[0]);
var params = {
username: result[1].username,
longitude: res1Fixed.longitude,
latitude: res1Fixed.latitude
}
console.log(params);
return geodata.addGeoData(params);
}).then(function(result) {
console.log('addGeoData() done');
});
mongoose.connection.close();
the execution stops after this line:
console.log('fetchGeoData() done');
and i can't figure out why?
Regards
Jimmy
If you are referring to mongoose.connection.close(); that is actually being run before your console.log('addGeoData() done');
Notice that mongoose.connection.close() is synchronous whereas the mongoose.findUser is asynchronous.

node js mongo db dependencies (doc not being found)

I have the following code:
var method = PushLoop.prototype;
var agent = require('./_header')
var request = require('request');
var User = require('../models/user_model.js');
var Message = require('../models/message_model.js');
var async = require('async')
function PushLoop() {};
method.startPushLoop = function() {
getUserList()
function getUserList() {
User.find({}, function(err, users) {
if (err) throw err;
if (users.length > 0) {
getUserMessages(users)
} else {
setTimeout(getUserList, 3000)
}
});
}
function getUserMessages(users) {
// console.log("getUserMessages")
async.eachSeries(users, function (user, callback) {
var params = {
email: user.email,
pwd: user.password,
token: user.device_token
}
messageRequest(params)
callback();
}, function (err) {
if (err) {
console.log(err)
setTimeout(getUserList, 3000)
}
});
}
function messageRequest(params) {
var url = "https://voip.ms/api/v1/rest.php?api_username="+ params.email +"&api_password="+ params.pwd +"&method=getSMS&type=1&limit=5"
request(url, function(err, response, body){
if (!err) {
var responseObject = JSON.parse(body);
var messages = responseObject.sms
if (responseObject["status"] == "success") {
async.eachSeries(messages, function(message, callback){
console.log(params.token)
saveMessage(message, params.token)
callback();
}, function(err) {
if (err) {
console.log(err)
}
// setTimeout(getUserList, 3000)
})
} else {
// setTimeout(getUserList, 3000)
}
} else {
console.log(err)
// setTimeout(getUserList, 3000)
}
});
setTimeout(getUserList, 3000)
}
function saveMessage(message, token) {
// { $and: [ { price: { $ne: 1.99 } }, { price: { $exists: true } }
// Message.find({ $and: [{ message_id: message.id}, {device_token: token}]}, function (err, doc){
Message.findOne({message_id: message.id}, function (err, doc){
if (!doc) {
console.log('emtpy today')
var m = new Message({
message_id: message.id,
did: message.did,
contact: message.contact,
message: message.message,
date: message.date,
created_at: new Date().toLocaleString(),
updated_at: new Date().toLocaleString(),
device_token: token
});
m.save(function(e) {
if (e) {
console.log(e)
} else {
agent.createMessage()
.device(token)
.alert(message.message)
.set('contact', message.contact)
.set('did', message.did)
.set('id', message.id)
.set('date', message.date)
.set('message', message.message)
.send();
}
});
}
}) //.limit(1);
}
};
module.exports = PushLoop;
Which actually works perfectly fine in my development environment - However in production (i'm using Openshift) the mongo documents get saved in an endless loop so it looks like the (if (!doc)) condition always return true therefore the document gets created each time. Not sure if this could be a mongoose issue - I also tried the "find" method instead of "findOne". My dev env has node 0.12.7 and Openshift has 0.10.x - this could be the issue, and i'm still investigating - but if anybody can spot an error I cannot see in my logic/code please let me know
thanks!
I solved this issue by using a "series" like pattern and using the shift method on the users array. The mongoose upsert findOneOrCreate is good however if there is a found document, the document is returned, if one isn't found and therefore created, it's also returned. Therefore I could not distinguish between the newly insert doc vs. a found doc, so used the same findOne function which returns null if no doc is found I just create it and send the push notification. Still abit ugly, and I know I could have used promises or the async lib, might refactor in the future. This works for now
function PushLoop() {};
var results = [];
method.go = function() {
var userArr = [];
startLoop()
function startLoop() {
User.find({},function(err, users) {
if (err) throw err;
users.forEach(function(u) {
userArr.push(u)
})
function async(arg, callback) {
var url = "https://voip.ms/api/v1/rest.php?api_username="+ arg.email +"&api_password="+ arg.password +"&method=getSMS&type=1&limit=5"
request.get(url, {timeout: 30000}, function(err, response, body){
if (!err) {
var responseObject = JSON.parse(body);
var messages = responseObject.sms
var status = responseObject.status
if (status === "success") {
messages.forEach(function(m) {
var message = new Message({
message_id: m.id,
did: m.did,
contact: m.contact,
message: m.message,
date: m.date,
created_at: new Date().toLocaleString(),
updated_at: new Date().toLocaleString(),
device_token: arg.device_token
});
var query = { $and : [{message_id: m.id}, {device_token: arg.device_token}] }
var query1 = { message_id: m.id }
Message.findOne(query).lean().exec(function (err, doc){
if (!doc || doc == null) {
message.save(function(e) {
console.log("message saved")
if (e) {
console.log("there is an error")
console.log(e)
} else {
console.log(message.device_token)
var messageStringCleaned = message.message.toString().replace(/\\/g,"");
var payload = {
"contact" : message.contact,
"did" : message.did,
"id" : message.message_id,
"date" : message.date,
"message" : messageStringCleaned
}
var note = new apns.Notification();
var myDevice = new apns.Device(message.device_token);
note.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.
note.badge = 3;
note.alert = messageStringCleaned;
note.payload = payload;
apnsConnection.pushNotification(note, myDevice);
}
})
}
});
});
}
else {
console.log(err)
}
}
});
setTimeout(function() {
callback(arg + "testing 12");
}, 1000);
}
// Final task (same in all the examples)
function series(item) {
if(item) {
async( item, function(result) {
results.push(result);
return series(userArr.shift());
});
} else {
return final();
}
}
function final() {
console.log('Done');
startLoop();
}
series(userArr.shift())
});
}
}
module.exports = PushLoop;

Resources