0

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();
};
6
  • Your references to "globalheaders" is case sensitive. Where you are adding your parameters change "globalheaders.id" to "globalheaders.Id" (capital I in Id), "globalheaders.payment" to "globalheaders.Payment" (capital P in Payment) and all the remaining. give that a try. Commented Jan 24, 2020 at 20:43
  • I followed your suggestion but nothing changes. Still nulls in the database and lack of ability to debug in portal due to context.logs not working e.g. the one before request.addparameter. Commented Jan 26, 2020 at 19:59
  • How's going? Has your issue been solved ? Commented Jan 28, 2020 at 1:25
  • I am getting close. I suspect the due to lack of support for async/await from tedious there is an issue that the whole function ends before executeStatement is invoked. I suspect req.body passed to function is undefined in that moment. When I put the following: executeStatement({ Id: '1233', Name: 'Ant', Payment: "2019-10-09", Type: 'Fixed cost', Value: 156, Cycle: '1', Frequency: 'month' }) Commented Jan 28, 2020 at 8:19
  • It works then - with (req.body) or (globalheaders) it does not work, hence I suspect that those are undefined in that moment Commented Jan 28, 2020 at 8:20

4 Answers 4

3

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 : enter image description here

Data has been insetted into Azure SQL DB successfully:

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

0

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

Comments

0

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);
}

};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.