-1

This is a reboot of the question I asked here: NodeJS then/catch in a function seems to be catching code outside the function I changed so many times, I think this is basically a different question, although similar.

My NodeJS code:

var express = require('express');
var app = express();

// config for your database
var config = {
    user: 'ReadOnlyUser1',
    password: 'Password1',
    server: 'localhost\\SQLEXPRESS', 
    database: 'StudentsOld' 
};

var lookupStudentId = 31; 


const sql = require('mssql');

var connPool = new sql.ConnectionPool(config);

function getStudent(studentID) 
{
    console.log("getStudent"); 

    sql.connect(config).then(pool => {
        // Query 
        return pool.request()
        .input('input_parameter', sql.Int, studentID)
        .query('select student_firstname, student_lastname from students where student_id = @input_parameter')
    }).then(function(result) {
        console.log("getStudent:then(result=>"); 
        console.dir(result);
        sql.close(); 
        //return result; 
    })
    .catch(err => {
        // ... error checks 
        console.log("DB Error1: " + err); 
    })

    sql.on('error', err => {
        // ... error handler 
        console.log("DB Error2: " + err); 
    })
}


app.get('/student', function(request, response){
    console.log('Neal Test1 - start app.get for /student lookupStudentId = ' + lookupStudentId); 
    getStudent(lookupStudentId)
        .then (function(recordset)  {  /* this is line 82 of the error */
            objType = Object.prototype.toString.call(recordset);
            console.log('Back from getStudent objType=' + objType  ); 
            console.dir('recordSet=' + recordSet); 
            response.status(200).send(recordset); 
        })
        .catch (function(err) {
            objType = Object.prototype.toString.call(recordset);
            console.log('ERR: Back from getStudent objType=' + objType  ); 
            console.log("error400=" + err); 
            console.log("empty test=" + Object.keys(err).length); 
            response.status(400).send(err);
        })
    return;
});

app.listen(3000, function () {
    console.log('Express server is listening on port 3000');
});

Console.Log:

Express server is listening on port 3000
Neal Test1 - start app.get for /student lookupStudentId = 31
getStudent
TypeError: Cannot read property 'then' of undefined
    at C:\Software\nodejs\wisdomcalls\indexPromises.js:82:9
    at Layer.handle [as handle_request] (C:\Software\nodejs\wisdomcalls\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Software\nodejs\wisdomcalls\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Software\nodejs\wisdomcalls\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Software\nodejs\wisdomcalls\node_modules\express\lib\router\layer.js:95:5)
    at C:\Software\nodejs\wisdomcalls\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\Software\nodejs\wisdomcalls\node_modules\express\lib\router\index.js:335:12)
    at next (C:\Software\nodejs\wisdomcalls\node_modules\express\lib\router\index.js:275:10)
    at expressInit (C:\Software\nodejs\wisdomcalls\node_modules\express\lib\middleware\init.js:40:5)
    at Layer.handle [as handle_request] (C:\Software\nodejs\wisdomcalls\node_modules\express\lib\router\layer.js:95:5)
getStudent:then(result=>
{ recordsets: [ [ [Object] ] ],
  recordset:
   [ { student_firstname: 'Jonah                ',
       student_lastname: 'Hill                    ' } ],
  output: {},
  rowsAffected: [ 1 ] }

So what this tells me is that the .then statement of the calling routine is running and getting the "undefined" probably while the function is still trying to get it's database connection.

How do I keep the Async best practice/model, and be able to handle my data properly after it has been retrieved?

I read this question: Node exits before async function completes which seems on target - but if that's the answer, how would I wrap that around my SQL request? I'm going to try it, and if I get it, I will post answer here.

Revision 2

function getStudent(studentID) 
{
    console.log("---------getStudent"); 

    sql.on('error', err => {
        // ... error handler 
        console.log("DB Error2: " + err); 
    })

    return sql.connect(config).then(pool => {
            // Query 
            return pool.request()
            .input('input_parameter', sql.Int, studentID)
            .query('select student_firstname, student_lastname from students where student_id = @input_parameter')
        }).then(function(result) {
            console.log("getStudent:then(result=>"); 
            console.dir(result);
            sql.close(); 
            return result; 
        })
        .catch(err => {
            // ... error checks 
            console.log("DB Error1: " + err); 
        })

}


app.get('/student', function(request, response){
    console.log('==================Neal Test1 - start app.get for /student lookupStudentId = ' + lookupStudentId+ '======================='); 

    //process.on('unhandledRejection', r => function(){});

    getStudent(lookupStudentId)
        .then (function(recordset)  {
            console.log('Back from getStudent'); 
            objType = Object.prototype.toString.call(recordset);
            console.log('objType=' + objType  ); 
            console.dir('recordSet=' + recordSet); 
            response.status(200).send(recordset); 
        })
        .catch (function(err) {
            objType = Object.prototype.toString.call(recordset);
            console.log('ERR: Back from getStudent objType=' + objType  ); 
            console.log("error400=" + err); 
            console.log("empty test=" + Object.keys(err).length); 
            response.status(400).send(err);
        })
    return;
});

Console.Log:

    ==================Neal Test1 - start app.get for /student lookupStudentId = 31=======================
    ---------getStudent
    getStudent:then(result=>
    { recordsets: [ [ [Object] ] ],
      recordset:
       [ { student_firstname: 'Jonah                ',
           student_lastname: 'Hill                    ' } ],
      output: {},
      rowsAffected: [ 1 ] }
Back from getStudent
objType=[object Object]
(node:26212) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: recordset is not defined

At this point the program seems to hang. Never goes back to browser.

NealWalters
  • 17,197
  • 42
  • 141
  • 251

1 Answers1

1

getStudent does not return anything (so undefined), so it does not have the then property.

It should return a promise, so add return here:

return sql.connect(config).then(pool => {

... and move the sql.on call before that return.

Secondly, uncomment this line:

// return result;

Because that result needs to be passed along the promise chain. You'll fetch its value as recordset in the app.get callback function.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Okay, that helped a lot; i.e. the new error now appears after the SQL happens. Now I see this in console.log: Back from getStudent objType=[object Undefined] (node:16736) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: recordset is not defined – NealWalters Jul 31 '17 at 19:31
  • Uncomment the `// return result` you have, so that you actually pass on the result via the promise chain. – trincot Jul 31 '17 at 19:35
  • Still: UnhandledPromiseRejectionWarning (and nothing ever comes back to the browser). Added my current code as Revision2 to the original question. – NealWalters Jul 31 '17 at 19:52
  • When you have an unhandledPromiseRejected, the error description that follows it is most important. Is it still *recordset is not defined*? – trincot Jul 31 '17 at 19:58
  • It's in the console.log for Revision2. Instead of "TypeError: Cannot read property 'then' of undefined" it now says: "Unhandled promise rejection (rejection id: 1): ReferenceError: recordset is not defined" then hangs. It didn't hang before. – NealWalters Jul 31 '17 at 19:59
  • Also if I have "return result" and "return sql.connect" how does that work? Is the first return the "promise?" and the second return some type of object inside the promise? – NealWalters Jul 31 '17 at 20:00
  • But the log of revision 2 does not seem to correspond to the code where you have `'Back from getStudent objType='`, which I don't see in the log. Are you sure you are running the revised code? The first return is the promise, the second return is the promised value. – trincot Jul 31 '17 at 20:03
  • And you have `objType` in the `console.log`, but you don't define it (you commented that line). Can you please make sure the code and the logs correspond? – trincot Jul 31 '17 at 20:05
  • I just updated Rev2. Seems crazy that it doesn't complain about recordset in the objtype statement. But seems to hang on the "console.dir". – NealWalters Jul 31 '17 at 20:12
  • Sorry to make so many comments, but now I changed console.dir to be correct: console.dir(recordSet); and same issue. – NealWalters Jul 31 '17 at 20:15
  • Try to remove `sql.close()` for a minute: it may invalidate the recordset. – trincot Jul 31 '17 at 20:17
  • Same. Maybe I need to run in Visual Code debugger. Seems easy, but very frustrated trying to get something so simple to work. I'm new to Node and the latest features of JavaScript, but programming for 35 years. – NealWalters Jul 31 '17 at 20:22
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/150660/discussion-between-nealwalters-and-trincot). – NealWalters Jul 31 '17 at 20:39
  • `recordset` !== `recordSet` – Jaromanda X Jul 31 '17 at 23:16
  • Good eyes @jaromandaX - I'm used to using a strongly typed language where the compiler would identify that kind of "crap". – NealWalters Aug 01 '17 at 13:21